[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

Re: svn_fs_delete_tree bug fix.

From: Karl Fogel <kfogel_at_galois.collab.net>
Date: 2001-03-20 20:47:15 CET

Yoshiki Hayashi <yoshiki@xemacs.org> writes:
> Current implementation of svn_fs_delete_tree can't delete a
> non-empty mutable directory. Here's the fix. Essentialy,
> this patch adds new function svn_fs__dag_delete_tree which
> can delete a non-empty mutable directory. Other parts are
> just moving bits around. This patch also adds a new check
> to svn_fs_delete_tree and svn_fs_delete to see svn_fs_root_t
> is a transaction root.

Thanks for finding this! I've checked in a fix which is basically
your patch, with some more code factorization, plus more test code to
test expected failures as well as expected successes.

> Unless someone else adds the same
> check to functions like svn_fs_change_node_prop, I'll do it.

Good idea. Do you have the patch already? If not, I (or someone) can
just add them, let us know.

Thanks,
-K

> * svn_error.h (SVN_ERR_FS_NOT_TXN_ROOT): New error.
>
> * dag.c (svn_fs__dag_delete_tree): New function.
> * dag.c (delete_node): New function.
> * dag.c (svn_fs__dag_delete_mutable_node): Renamed from
> delete_from_id in txn.c. All callers are changed.
> * dag.h (svn_fs__dag_delete_tree): New declaration.
> * dag.h (svn_fs__dag_delete_mutable_node): New declaration.
> * tree.c (struct delete_args): Remove require_empty_dir arg.
> * tree.c (txn_body_delete): Check root object is a transaction
> root.
> * tree.c (svn_fs_delete): Remove require_empty_dir arg.
> * tree.c (txn_body_delete_tree): New function.
> * tree.c (svn_fs_delete_tree):
> * txn.c (delete_from_id): Moved to dag.c and renamed to
> svn_fs__dag_delete_mutable_node.
>
> * subversion/tests/libsvn_fs/fs-test.c (delete_tree): New test.
>
> Index: subversion/include/svn_error.h
> ===================================================================
> RCS file: /cvs/subversion/subversion/include/svn_error.h,v
> retrieving revision 1.86
> diff -u -r1.86 svn_error.h
> --- subversion/include/svn_error.h 2001/03/17 07:16:27 1.86
> +++ subversion/include/svn_error.h 2001/03/19 05:40:21
> @@ -173,6 +173,9 @@
> or create another node named /. */
> SVN_ERR_FS_ROOT_DIR,
>
> + /* The root object given is not transaction root. */
> + SVN_ERR_FS_NOT_TXN_ROOT,
> +
> /* The transaction could not be committed, because of a conflict with
> a prior change. */
> SVN_ERR_FS_CONFLICT,
> Index: subversion/libsvn_fs/dag.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/dag.c,v
> retrieving revision 1.87
> diff -u -r1.87 dag.c
> --- subversion/libsvn_fs/dag.c 2001/03/16 21:53:12 1.87
> +++ subversion/libsvn_fs/dag.c 2001/03/19 05:40:21
> @@ -1063,10 +1063,15 @@
> }
>
>
> -svn_error_t *
> -svn_fs__dag_delete (dag_node_t *parent,
> - const char *name,
> - trail_t *trail)
> +/* Delete the directory entry named NAME from PARENT, as part of
> + TRAIL. PARENT must be mutable. NAME must be a single path
> + component. If REQUIRE_EMPTY is true and the node being deleted is
> + mutable, it must be empty. */
> +static svn_error_t *
> +delete_node (dag_node_t *parent,
> + const char *name,
> + svn_boolean_t require_empty,
> + trail_t *trail)
> {
> skel_t *node_rev, *new_dirent_list, *prev_entry, *entry;
> int deleted = FALSE;
> @@ -1156,7 +1161,8 @@
> SVN_ERR (svn_fs__get_node_revision (&content, parent->fs,
> id, trail));
>
> - if (svn_fs__list_length (content->children->next) != 0)
> + if (svn_fs__list_length (content->children->next) != 0
> + && require_empty)
> {
> return
> svn_error_createf
> @@ -1167,7 +1173,7 @@
> }
>
> /* Delete the mutable node from the database. */
> - SVN_ERR (svn_fs__delete_node_revision (parent->fs, id, trail));
> + SVN_ERR (svn_fs__dag_delete_mutable_node (parent->fs, id, trail));
> }
>
> /* Just "lose" this entry by setting the *previous* entry's
> @@ -1197,6 +1203,62 @@
> node_rev,
> trail));
>
> + return SVN_NO_ERROR;
> +}
> +
> +
> +svn_error_t *
> +svn_fs__dag_delete (dag_node_t *parent,
> + const char *name,
> + trail_t *trail)
> +{
> + return delete_node (parent, name, TRUE, trail);
> +}
> +
> +
> +svn_error_t *
> +svn_fs__dag_delete_tree (dag_node_t *parent,
> + const char *name,
> + trail_t *trail)
> +{
> + return delete_node (parent, name, FALSE, trail);
> +}
> +
> +
> +svn_error_t *
> +svn_fs__dag_delete_mutable_node (svn_fs_t *fs,
> + svn_fs_id_t *id,
> + trail_t *trail)
> +{
> + svn_boolean_t is_mutable;
> + dag_node_t *node;
> +
> + SVN_ERR (svn_fs__dag_get_node (&node, fs, id, trail));
> +
> + /* If immutable, do nothing and return immediately. */
> + SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, node, trail));
> + if (! is_mutable)
> + return SVN_NO_ERROR;
> +
> + /* Else it's mutable. Recurse on directories... */
> + if (svn_fs__dag_is_directory (node))
> + {
> + skel_t *entries, *entry;
> + SVN_ERR (svn_fs__dag_dir_entries_skel (&entries, node, trail));
> +
> + for (entry = entries->children; entry; entry = entry->next)
> + {
> + skel_t *id_skel = entry->children->next;
> + svn_fs_id_t *this_id
> + = svn_fs_parse_id (id_skel->data, id_skel->len, trail->pool);
> +
> + SVN_ERR (svn_fs__dag_delete_mutable_node (fs, this_id, trail));
> + }
> + }
> +
> + /* ... then delete the node itself. */
> + SVN_ERR (svn_fs__delete_node_revision (fs, id, trail));
> +
> return SVN_NO_ERROR;
> }
>
> Index: subversion/libsvn_fs/dag.h
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/dag.h,v
> retrieving revision 1.40
> diff -u -r1.40 dag.h
> --- subversion/libsvn_fs/dag.h 2001/03/16 03:38:49 1.40
> +++ subversion/libsvn_fs/dag.h 2001/03/19 05:40:22
> @@ -310,6 +310,25 @@
> trail_t *trail);
>
>
> +/* Delete the directory entry named NAME from PARENT, as part of
> + TRAIL. PARENT must be mutable. NAME must be a single path
> + component; it cannot be a slash-separated directory path. If the
> + node being deleted is a mutable directory, remove all reachable
> + mutable nodes from there. */
> +svn_error_t *svn_fs__dag_delete_tree (dag_node_t *parent,
> + const char *name,
> + trail_t *trail);
> +
> +
> +/* Delete all mutable node revisions reachable from node ID, including
> + ID itself, from FS's `nodes' table, as part of TRAIL. ID may refer
> + to a file or directory, which may be mutable or immutable. */
> +svn_error_t *
> +svn_fs__dag_delete_mutable_node (svn_fs_t *fs,
> + svn_fs_id_t *id,
> + trail_t *trail);
> +
> +
> /* Create a new mutable directory named NAME in PARENT, as part of
> TRAIL. Set *CHILD_P to a reference to the new node, allocated in
> TRAIL->pool. The new directory has no contents, and no properties.
> Index: subversion/libsvn_fs/tree.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/tree.c,v
> retrieving revision 1.51
> diff -u -r1.51 tree.c
> --- subversion/libsvn_fs/tree.c 2001/03/16 20:07:57 1.51
> +++ subversion/libsvn_fs/tree.c 2001/03/19 05:40:22
> @@ -1760,7 +1760,6 @@
> {
> svn_fs_root_t *root;
> const char *path;
> - svn_boolean_t require_empty_dir;
> };
>
>
> @@ -1771,11 +1770,15 @@
> struct delete_args *args = baton;
> svn_fs_root_t *root = args->root;
> const char *path = args->path;
> - svn_boolean_t require_empty_dir = args->require_empty_dir;
> parent_path_t *parent_path;
>
> SVN_ERR (open_path (&parent_path, root, path, 0, trail));
>
> + if (root->kind != transaction_root)
> + return svn_error_create
> + (SVN_ERR_FS_NOT_TXN_ROOT, 0, NULL, trail->pool,
> + "root object must be a transaction root");
> +
> /* We can't remove the root of the filesystem. */
> if (! parent_path->parent)
> return svn_error_create (SVN_ERR_FS_ROOT_DIR, 0, NULL, trail->pool,
> @@ -1785,9 +1788,8 @@
> SVN_ERR (make_path_mutable (root, parent_path->parent, path, trail));
>
> /* If this is a directory, we have to check to see if it is required
> - by our caller to be empty before deleting it. */
> - if (svn_fs__dag_is_directory (parent_path->node)
> - && require_empty_dir)
> + by our caller to be empty before deleting it. */
> + if (svn_fs__dag_is_directory (parent_path->node))
> {
> skel_t *entries;
>
> @@ -1821,11 +1823,42 @@
>
> args.root = root;
> args.path = path;
> - args.require_empty_dir = TRUE;
> return svn_fs__retry_txn (root->fs, txn_body_delete, &args, pool);
> }
>
>
> +static svn_error_t *
> +txn_body_delete_tree (void *baton,
> + trail_t *trail)
> +{
> + struct delete_args *args = baton;
> + svn_fs_root_t *root = args->root;
> + const char *path = args->path;
> + parent_path_t *parent_path;
> +
> + SVN_ERR (open_path (&parent_path, root, path, 0, trail));
> +
> + if (root->kind != transaction_root)
> + return svn_error_create
> + (SVN_ERR_FS_NOT_TXN_ROOT, 0, NULL, trail->pool,
> + "root object must be a transaction root");
> +
> + /* We can't remove the root of the filesystem. */
> + if (! parent_path->parent)
> + return svn_error_create (SVN_ERR_FS_ROOT_DIR, 0, NULL, trail->pool,
> + "the root directory cannot be deleted");
> +
> + /* Make the parent directory mutable. */
> + SVN_ERR (make_path_mutable (root, parent_path->parent, path, trail));
> +
> + SVN_ERR (svn_fs__dag_delete_tree (parent_path->parent->node,
> + parent_path->entry,
> + trail));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> svn_error_t *
> svn_fs_delete_tree (svn_fs_root_t *root,
> const char *path,
> @@ -1835,8 +1868,7 @@
>
> args.root = root;
> args.path = path;
> - args.require_empty_dir = FALSE;
> - return svn_fs__retry_txn (root->fs, txn_body_delete, &args, pool);
> + return svn_fs__retry_txn (root->fs, txn_body_delete_tree, &args, pool);
> }
>
>
> Index: subversion/libsvn_fs/txn.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/txn.c,v
> retrieving revision 1.37
> diff -u -r1.37 txn.c
> --- subversion/libsvn_fs/txn.c 2001/03/14 00:21:28 1.37
> +++ subversion/libsvn_fs/txn.c 2001/03/19 05:40:22
> @@ -165,46 +165,7 @@
> };
>
>
> -/* Delete all mutable node revisions reachable from node ID, including
> - ID itself, from filesystem FS, as part of TRAIL. ID may refer to
> - a file or directory, which may be mutable or immutable. */
> static svn_error_t *
> -delete_from_id (svn_fs_t *fs, svn_fs_id_t *id, trail_t *trail)
> -{
> - svn_boolean_t is_mutable;
> - dag_node_t *node;
> -
> - SVN_ERR (svn_fs__dag_get_node (&node, fs, id, trail));
> -
> - /* If immutable, do nothing and return immediately. */
> - SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, node, trail));
> - if (! is_mutable)
> - return SVN_NO_ERROR;
> -
> - /* Else it's mutable. Recurse on directories... */
> - if (svn_fs__dag_is_directory (node))
> - {
> - skel_t *entries, *entry;
> - SVN_ERR (svn_fs__dag_dir_entries_skel (&entries, node, trail));
> -
> - for (entry = entries->children; entry; entry = entry->next)
> - {
> - skel_t *id_skel = entry->children->next;
> - svn_fs_id_t *this_id
> - = svn_fs_parse_id (id_skel->data, id_skel->len, trail->pool);
> -
> - SVN_ERR (delete_from_id (fs, this_id, trail));
> - }
> - }
> -
> - /* ... then delete the node itself. */
> - SVN_ERR (svn_fs__delete_node_revision (fs, id, trail));
> -
> - return SVN_NO_ERROR;
> -}
> -
> -
> -static svn_error_t *
> txn_body_abort_txn (void *baton, trail_t *trail)
> {
> struct abort_txn_args *args = baton;
> @@ -214,7 +175,7 @@
>
> SVN_ERR (svn_fs_txn_name (&txn_name, txn, txn->pool));
> SVN_ERR (svn_fs__get_txn (&root_id, &ignored_id, txn->fs, txn_name, trail));
> - SVN_ERR (delete_from_id (txn->fs, root_id, trail));
> + SVN_ERR (svn_fs__dag_delete_mutable_node (txn->fs, root_id, trail));
> SVN_ERR (svn_fs__delete_txn (txn->fs, txn->id, trail));
>
> return SVN_NO_ERROR;
> Index: subversion/tests/libsvn_fs/fs-test.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/tests/libsvn_fs/fs-test.c,v
> retrieving revision 1.57
> diff -u -r1.57 fs-test.c
> --- subversion/tests/libsvn_fs/fs-test.c 2001/03/16 20:08:02 1.57
> +++ subversion/tests/libsvn_fs/fs-test.c 2001/03/19 05:40:22
> @@ -3026,6 +3026,408 @@
> }
> /* Close the filesystem. */
> SVN_ERR (svn_fs_close_fs (fs));
> + return SVN_NO_ERROR;
> +}
> +
> +
> +/* Test svn_fs_delete_tree.
> +
> + NOTE: This function tests internal filesystem interfaces, not just
> + the public filesystem interface. */
> +static svn_error_t *
> +delete_tree (const char **msg)
> +{
> + svn_fs_t *fs;
> + svn_fs_txn_t *txn;
> + svn_fs_root_t *txn_root;
> + svn_revnum_t new_rev;
> +
> + *msg = "delete nodes tree";
> +
> + /* This function tests 5 cases:
> + *
> + * 1. Delete mutable file.
> + * 2. Delete mutable directory.
> + * 3. Delete mutable directory with immutable nodes.
> + * 4. Delete immutable file.
> + * 5. Delete immutable directory.
> + */
> +
> + /* Prepare a txn to receive the greek tree. */
> + SVN_ERR (create_fs_and_repos (&fs, "test-repo-del-tree"));
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* Create the greek tree. */
> + SVN_ERR (greek_tree_under_root (txn_root));
> +
> + /* 1 */
> + {
> + svn_fs_id_t *iota_id;
> + tree_test_entry_t expected_entries[] = {
> + /* path, is_dir, contents */
> + { "A", 1, "" },
> + { "A/mu", 0, "This is the file 'mu'.\n" },
> + { "A/B", 1, "" },
> + { "A/B/lambda", 0, "This is the file 'lambda'.\n" },
> + { "A/B/E", 1, "" },
> + { "A/B/E/alpha", 0, "This is the file 'alpha'.\n" },
> + { "A/B/E/beta", 0, "This is the file 'beta'.\n" },
> + { "A/B/F", 1, "" },
> + { "A/C", 1, "" },
> + { "A/D", 1, "" },
> + { "A/D/gamma", 0, "This is the file 'gamma'.\n" },
> + { "A/D/G", 1, "" },
> + { "A/D/G/pi", 0, "This is the file 'pi'.\n" },
> + { "A/D/G/rho", 0, "This is the file 'rho'.\n" },
> + { "A/D/G/tau", 0, "This is the file 'tau'.\n" },
> + { "A/D/H", 1, "" },
> + { "A/D/H/chi", 0, "This is the file 'chi'.\n" },
> + { "A/D/H/psi", 0, "This is the file 'psi'.\n" },
> + { "A/D/H/omega", 0, "This is the file 'omega'.\n" }
> + };
> + /* Check nodes revision ID is gone. */
> + SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
> + SVN_ERR (check_entry_present (txn_root, "", "iota"));
> + SVN_ERR (check_id_present (fs, iota_id));
> +
> + SVN_ERR (svn_fs_delete_tree (txn_root, "iota", pool));
> + SVN_ERR (check_entry_absent (txn_root, "", "iota"));
> + SVN_ERR (check_id_absent (fs, iota_id));
> +
> + /* Validate the tree. */
> + SVN_ERR (validate_tree (txn_root, expected_entries, 19));
> + }
> + /* Abort transaction. */
> + SVN_ERR (svn_fs_abort_txn (txn));
> +
> + /* Prepare a txn to receive the greek tree. */
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* Create the greek tree. */
> + SVN_ERR (greek_tree_under_root (txn_root));
> +
> + /* 2 */
> + {
> + svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
> + *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
> + *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id;
> +
> + tree_test_entry_t expected_entries[] = {
> + /* path, is_dir, contents */
> + { "iota", 0, "This is the file 'iota'.\n" }
> + };
> +
> + /* Check nodes revision ID is gone. */
> + SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
> + SVN_ERR (check_entry_present (txn_root, "", "A"));
> + SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "mu"));
> + SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "B"));
> + SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "lambda"));
> + SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "E"));
> + SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha"));
> + SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta"));
> + SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "F"));
> + SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "C"));
> + SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "D"));
> + SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "gamma"));
> + SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "H"));
> + SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi"));
> + SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi"));
> + SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega"));
> + SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "G"));
> + SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi"));
> + SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho"));
> + SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau"));
> +
> + SVN_ERR (svn_fs_delete_tree (txn_root, "A", pool));
> +
> + SVN_ERR (check_entry_absent (txn_root, "", "A"));
> + SVN_ERR (check_id_absent (fs, A_id));
> + SVN_ERR (check_id_absent (fs, mu_id));
> + SVN_ERR (check_id_absent (fs, B_id));
> + SVN_ERR (check_id_absent (fs, lambda_id));
> + SVN_ERR (check_id_absent (fs, E_id));
> + SVN_ERR (check_id_absent (fs, alpha_id));
> + SVN_ERR (check_id_absent (fs, beta_id));
> + SVN_ERR (check_id_absent (fs, F_id));
> + SVN_ERR (check_id_absent (fs, C_id));
> + SVN_ERR (check_id_absent (fs, D_id));
> + SVN_ERR (check_id_absent (fs, gamma_id));
> + SVN_ERR (check_id_absent (fs, H_id));
> + SVN_ERR (check_id_absent (fs, chi_id));
> + SVN_ERR (check_id_absent (fs, psi_id));
> + SVN_ERR (check_id_absent (fs, omega_id));
> + SVN_ERR (check_id_absent (fs, G_id));
> + SVN_ERR (check_id_absent (fs, pi_id));
> + SVN_ERR (check_id_absent (fs, rho_id));
> + SVN_ERR (check_id_absent (fs, tau_id));
> +
> + /* Validate the tree. */
> + SVN_ERR (validate_tree (txn_root, expected_entries, 1));
> + }
> +
> + /* Abort transaction. */
> + SVN_ERR (svn_fs_abort_txn (txn));
> +
> + /* Prepare a txn to receive the greek tree. */
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* Create the greek tree. */
> + SVN_ERR (greek_tree_under_root (txn_root));
> +
> + /* Commit the greek tree. */
> + {
> + const char *conflict;
> + SVN_ERR (svn_fs_commit_txn (&conflict, &new_rev, txn));
> + }
> + SVN_ERR (svn_fs_close_txn (txn));
> +
> + /* Create new transaction. */
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* 3 */
> + {
> + svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
> + *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
> + *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id, *sigma_id;
> +
> + tree_test_entry_t expected_entries[] = {
> + /* path, is_dir, contents */
> + { "iota", 0, "This is the file 'iota'.\n" }
> + };
> +
> + /* Create A/D/G/sigma. This makes all component of A/D/G
> + mutable. */
> + SVN_ERR (svn_fs_make_file (txn_root, "A/D/G/sigma", pool));
> + SVN_ERR (set_file_contents (txn_root, "A/D/G/sigma",
> + "This is another file 'sigma'.\n"));
> +
> + /* Check mutable nodes revision ID is removed and immutable ones
> + still exist. */
> + SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
> + SVN_ERR (check_entry_present (txn_root, "", "A"));
> + SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "mu"));
> + SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "B"));
> + SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "lambda"));
> + SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "E"));
> + SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha"));
> + SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta"));
> + SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "F"));
> + SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "C"));
> + SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "D"));
> + SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "gamma"));
> + SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "H"));
> + SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi"));
> + SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi"));
> + SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega"));
> + SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "G"));
> + SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi"));
> + SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho"));
> + SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau"));
> + SVN_ERR (svn_fs_node_id (&sigma_id, txn_root, "/A/D/G/sigma", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "sigma"));
> +
> + SVN_ERR (svn_fs_delete_tree (txn_root, "A", pool));
> +
> + SVN_ERR (check_entry_absent (txn_root, "", "A"));
> + SVN_ERR (check_id_absent (fs, A_id));
> + SVN_ERR (check_id_present (fs, mu_id));
> + SVN_ERR (check_id_present (fs, B_id));
> + SVN_ERR (check_id_present (fs, lambda_id));
> + SVN_ERR (check_id_present (fs, E_id));
> + SVN_ERR (check_id_present (fs, alpha_id));
> + SVN_ERR (check_id_present (fs, beta_id));
> + SVN_ERR (check_id_present (fs, F_id));
> + SVN_ERR (check_id_present (fs, C_id));
> + SVN_ERR (check_id_absent (fs, D_id));
> + SVN_ERR (check_id_present (fs, gamma_id));
> + SVN_ERR (check_id_present (fs, H_id));
> + SVN_ERR (check_id_present (fs, chi_id));
> + SVN_ERR (check_id_present (fs, psi_id));
> + SVN_ERR (check_id_present (fs, omega_id));
> + SVN_ERR (check_id_absent (fs, G_id));
> + SVN_ERR (check_id_present (fs, pi_id));
> + SVN_ERR (check_id_present (fs, rho_id));
> + SVN_ERR (check_id_present (fs, tau_id));
> + SVN_ERR (check_id_absent (fs, sigma_id));
> +
> + /* Validate the tree. */
> + SVN_ERR (validate_tree (txn_root, expected_entries, 1));
> + }
> +
> + /* Abort transaction. */
> + SVN_ERR (svn_fs_abort_txn (txn));
> +
> + /* Create new transaction. */
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* 4 */
> + {
> + svn_fs_id_t *iota_id;
> + tree_test_entry_t expected_entries[] = {
> + /* path, is_dir, contents */
> + { "A", 1, "" },
> + { "A/mu", 0, "This is the file 'mu'.\n" },
> + { "A/B", 1, "" },
> + { "A/B/lambda", 0, "This is the file 'lambda'.\n" },
> + { "A/B/E", 1, "" },
> + { "A/B/E/alpha", 0, "This is the file 'alpha'.\n" },
> + { "A/B/E/beta", 0, "This is the file 'beta'.\n" },
> + { "A/B/F", 1, "" },
> + { "A/C", 1, "" },
> + { "A/D", 1, "" },
> + { "A/D/gamma", 0, "This is the file 'gamma'.\n" },
> + { "A/D/G", 1, "" },
> + { "A/D/G/pi", 0, "This is the file 'pi'.\n" },
> + { "A/D/G/rho", 0, "This is the file 'rho'.\n" },
> + { "A/D/G/tau", 0, "This is the file 'tau'.\n" },
> + { "A/D/H", 1, "" },
> + { "A/D/H/chi", 0, "This is the file 'chi'.\n" },
> + { "A/D/H/psi", 0, "This is the file 'psi'.\n" },
> + { "A/D/H/omega", 0, "This is the file 'omega'.\n" }
> + };
> + /* Check nodes revision ID is present. */
> + SVN_ERR (svn_fs_node_id (&iota_id, txn_root, "iota", pool));
> + SVN_ERR (check_entry_present (txn_root, "", "iota"));
> + SVN_ERR (check_id_present (fs, iota_id));
> +
> + SVN_ERR (svn_fs_delete_tree (txn_root, "iota", pool));
> + SVN_ERR (check_entry_absent (txn_root, "", "iota"));
> + SVN_ERR (check_id_present (fs, iota_id));
> +
> + /* Validate the tree. */
> + SVN_ERR (validate_tree (txn_root, expected_entries, 19));
> + }
> +
> + /* Abort transaction. */
> + SVN_ERR (svn_fs_abort_txn (txn));
> +
> + /* Create new transaction. */
> + SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
> + SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
> +
> + /* 5 */
> + {
> + svn_fs_id_t *A_id, *mu_id, *B_id, *lambda_id, *E_id, *alpha_id,
> + *beta_id, *F_id, *C_id, *D_id, *gamma_id, *H_id, *chi_id,
> + *psi_id, *omega_id, *G_id, *pi_id, *rho_id, *tau_id;
> +
> + tree_test_entry_t expected_entries[] = {
> + /* path, is_dir, contents */
> + { "iota", 0, "This is the file 'iota'.\n" }
> + };
> +
> + /* Check nodes revision ID is present. */
> + SVN_ERR (svn_fs_node_id (&A_id, txn_root, "/A", pool));
> + SVN_ERR (check_entry_present (txn_root, "", "A"));
> + SVN_ERR (svn_fs_node_id (&mu_id, txn_root, "/A/mu", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "mu"));
> + SVN_ERR (svn_fs_node_id (&B_id, txn_root, "/A/B", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "B"));
> + SVN_ERR (svn_fs_node_id (&lambda_id, txn_root, "/A/B/lambda", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "lambda"));
> + SVN_ERR (svn_fs_node_id (&E_id, txn_root, "/A/B/E", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "E"));
> + SVN_ERR (svn_fs_node_id (&alpha_id, txn_root, "/A/B/E/alpha", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "alpha"));
> + SVN_ERR (svn_fs_node_id (&beta_id, txn_root, "/A/B/E/beta", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B/E", "beta"));
> + SVN_ERR (svn_fs_node_id (&F_id, txn_root, "/A/B/F", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/B", "F"));
> + SVN_ERR (svn_fs_node_id (&C_id, txn_root, "/A/C", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "C"));
> + SVN_ERR (svn_fs_node_id (&D_id, txn_root, "/A/D", pool));
> + SVN_ERR (check_entry_present (txn_root, "A", "D"));
> + SVN_ERR (svn_fs_node_id (&gamma_id, txn_root, "/A/D/gamma", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "gamma"));
> + SVN_ERR (svn_fs_node_id (&H_id, txn_root, "/A/D/H", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "H"));
> + SVN_ERR (svn_fs_node_id (&chi_id, txn_root, "/A/D/H/chi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "chi"));
> + SVN_ERR (svn_fs_node_id (&psi_id, txn_root, "/A/D/H/psi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "psi"));
> + SVN_ERR (svn_fs_node_id (&omega_id, txn_root, "/A/D/H/omega", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/H", "omega"));
> + SVN_ERR (svn_fs_node_id (&G_id, txn_root, "/A/D/G", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D", "G"));
> + SVN_ERR (svn_fs_node_id (&pi_id, txn_root, "/A/D/G/pi", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "pi"));
> + SVN_ERR (svn_fs_node_id (&rho_id, txn_root, "/A/D/G/rho", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "rho"));
> + SVN_ERR (svn_fs_node_id (&tau_id, txn_root, "/A/D/G/tau", pool));
> + SVN_ERR (check_entry_present (txn_root, "A/D/G", "tau"));
> +
> + SVN_ERR (svn_fs_delete_tree (txn_root, "A", pool));
> +
> + SVN_ERR (check_entry_absent (txn_root, "", "A"));
> + SVN_ERR (check_id_present (fs, A_id));
> + SVN_ERR (check_id_present (fs, mu_id));
> + SVN_ERR (check_id_present (fs, B_id));
> + SVN_ERR (check_id_present (fs, lambda_id));
> + SVN_ERR (check_id_present (fs, E_id));
> + SVN_ERR (check_id_present (fs, alpha_id));
> + SVN_ERR (check_id_present (fs, beta_id));
> + SVN_ERR (check_id_present (fs, F_id));
> + SVN_ERR (check_id_present (fs, C_id));
> + SVN_ERR (check_id_present (fs, D_id));
> + SVN_ERR (check_id_present (fs, gamma_id));
> + SVN_ERR (check_id_present (fs, H_id));
> + SVN_ERR (check_id_present (fs, chi_id));
> + SVN_ERR (check_id_present (fs, psi_id));
> + SVN_ERR (check_id_present (fs, omega_id));
> + SVN_ERR (check_id_present (fs, G_id));
> + SVN_ERR (check_id_present (fs, pi_id));
> + SVN_ERR (check_id_present (fs, rho_id));
> + SVN_ERR (check_id_present (fs, tau_id));
> +
> + /* Validate the tree. */
> + SVN_ERR (validate_tree (txn_root, expected_entries, 1));
> + }
> +
> + /* Close the transaction and fs. */
> + SVN_ERR (svn_fs_close_txn (txn));
> + SVN_ERR (svn_fs_close_fs (fs));
>
> return SVN_NO_ERROR;
> }
> @@ -3058,6 +3460,7 @@
> basic_commit,
> copy_test,
> merging_commit,
> + delete_tree,
> 0
> };
>
>
>
> --
> Yoshiki Hayashi
Received on Sat Oct 21 14:36:26 2006

This is an archived mail posted to the Subversion Dev mailing list.