All of these changes are necessary to implement
svn_fs_abort_txn(). This was harder than I thought because
of some bugs. :-)
* dag.c (struct dag_node_t): Fix indentation.
* dag.c (svn_fs__dag_dir_entries): Fill in this function.
* dag.c (svn_fs__dag_clone_root): Update root node ID in
transaction table.
* dag.c (svn_fs__dag_delete): Delete node from nodes table
when node is mutable.
* dag.h (svn_fs__dag_delete): Doc fix.
* nodes-table.c (svn_fs__delete_node): New function.
* nodes-table.h (svn_fs__delete_node): New function declaration.
* txn-table.c (put_txn): Fix the order of prepend.
Transaction skel is (transaction ROOT-ID BASE-ROOT-ID).
* txn.c (delete_nodes): New function.
* txn.c (txn_body_abort_txn): New function.
* txn.c (svn_fs_abort_txn): New function.
Index: dag.c
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/dag.c,v
retrieving revision 1.59
diff -u -r1.59 dag.c
--- dag.c 2001/02/28 07:53:31 1.59
+++ dag.c 2001/02/28 10:11:30
@@ -65,7 +65,7 @@
this yourself, but you're probably better off just calling
`get_node_revision' and `set_node_revision', which take care of
things for you. */
- skel_t *node_revision;
+ skel_t *node_revision;
};
@@ -367,14 +367,37 @@
}
+
+svn_error_t *
+svn_fs__dag_dir_entries (skel_t **entries_p,
+ dag_node_t *node,
+ trail_t *trail)
+{
+ skel_t *node_rev, *entries, *entry;
+
+ if (! svn_fs__dag_is_directory (node))
+ return svn_error_create
+ (SVN_ERR_FS_NOT_DIRECTORY, 0, NULL, trail->pool,
+ "Attempted to get entry from *non*-directory node.");
+
+ /* Go get a fresh NODE-REVISION for this node. */
+ SVN_ERR (get_node_revision (&node_rev, node, trail));
+
+ /* Directory entries start at the second element of a node-revision
+ skel, itself is a list. */
+ entries = node_rev->children->next->children;
-svn_error_t *svn_fs__dag_dir_entries (skel_t **entries_p,
- dag_node_t *node,
- trail_t *trail)
-{
- abort();
- /* NOTREACHED */
- return NULL;
+ /* Check entries are well-formed. */
+ for (entry = entries; entry; entry = entry->next)
+ {
+ /* ENTRY must be a list which has two elements. */
+ if (svn_fs__list_length (entry) != 2)
+ return svn_error_create (SVN_ERR_FS_CORRUPT, 0, NULL, trail->pool,
+ "Malformed directory entry.");
+ }
+
+ *entries_p = entries;
+ return SVN_NO_ERROR;
}
@@ -674,6 +697,10 @@
/* One way or another, root_id now identifies a cloned root node. */
SVN_ERR (create_node (root_p, fs, root_id, trail));
+ /* Update root_id in transactions table. */
+ SVN_ERR (svn_fs__set_txn_root (fs, svn_txn, root_id, trail));
+
+
/* ... And when it is grown
* Then my own little clone
* Will be of the opposite sex!
@@ -726,10 +753,9 @@
new_dirent_list = svn_fs__copy_skel (node_rev->children->next,
trail->pool);
- entry = new_dirent_list->children;
old_entry = NULL;
- while (entry)
+ for (entry = new_dirent_list->children; entry; entry = entry->next)
{
if (svn_fs__matches_atom (entry->children, name))
{
@@ -747,10 +773,10 @@
id,
trail));
- if (svn_fs__matches_atom (entry_content->children->children,
- "dir"))
+ if (has_mutable_flag (entry_content))
{
- if (has_mutable_flag (entry_content))
+ if (svn_fs__matches_atom (entry_content->children->children,
+ "dir"))
{
int len =
svn_fs__list_length (entry_content->children->next);
@@ -761,15 +787,21 @@
"Attempted to delete *non-empty* directory `%s'.",
name);
}
- }
- /* Just "lose" this entry by setting the *previous* entry's
- next ptr to the current entry's next ptr. */
- if (! old_entry)
- /* Base case: the very *first* entry matched. */
- new_dirent_list->children = entry->next;
+ /* We are aborting a transaction. Mutable nodes must be
+ removed from `nodes' table. */
+ SVN_ERR (svn_fs__delete_node (parent->fs, id, trail));
+ }
else
- old_entry->next = entry->next;
+ {
+ /* Just "lose" this entry by setting the *previous* entry's
+ next ptr to the current entry's next ptr. */
+ if (! old_entry)
+ /* Base case: the very *first* entry matched. */
+ new_dirent_list->children = entry->next;
+ else
+ old_entry->next = entry->next;
+ }
deleted = TRUE;
break;
@@ -777,7 +809,6 @@
/* No match, move to next entry. */
old_entry = entry;
- entry = entry->next;
}
if (! deleted)
Index: dag.h
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/dag.h,v
retrieving revision 1.30
diff -u -r1.30 dag.h
--- dag.h 2001/02/27 22:03:46 1.30
+++ dag.h 2001/02/28 10:11:30
@@ -262,7 +262,8 @@
/* 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, it must be empty. */
+ node being deleted is mutable, it will vanish from the earth. If
+ it is a mutable directory, it must be empty. */
svn_error_t *svn_fs__dag_delete (dag_node_t *parent,
const char *name,
trail_t *trail);
Index: nodes-table.c
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/nodes-table.c,v
retrieving revision 1.9
diff -u -r1.9 nodes-table.c
--- nodes-table.c 2001/02/28 02:19:55 1.9
+++ nodes-table.c 2001/02/28 10:11:30
@@ -337,6 +337,27 @@
+/* Removing revisions. */
+
+
+svn_error_t *
+svn_fs__delete_node (svn_fs_t *fs,
+ const svn_fs_id_t *id,
+ trail_t *trail)
+{
+ DBT key;
+
+ SVN_ERR (DB_WRAP (fs, "deleting entry from `nodes' table",
+ fs->nodes->del (fs->nodes,
+ trail->db_txn,
+ svn_fs__id_to_dbt (&key, id, trail->pool),
+ 0)));
+
+ return SVN_NO_ERROR;
+}
+
+
+
/* Choosing node revision ID's. */
Index: nodes-table.h
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/nodes-table.h,v
retrieving revision 1.5
diff -u -r1.5 nodes-table.h
--- nodes-table.h 2001/02/13 16:17:24 1.5
+++ nodes-table.h 2001/02/28 10:11:30
@@ -52,6 +52,12 @@
trail_t *trail);
+/* Remove the node ID from `nodes' table of FS, as part of TRAIL. */
+svn_error_t *svn_fs__delete_node (svn_fs_t *fs,
+ const svn_fs_id_t *id,
+ trail_t *trail);
+
+
/* Check FS's `nodes' table to find an unused node number, and set
*ID_P to the ID of the first revision of an entirely new node in
FS, as part of TRAIL. Allocate the new ID, and do all temporary
Index: txn-table.c
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/txn-table.c,v
retrieving revision 1.16
diff -u -r1.16 txn-table.c
--- txn-table.c 2001/02/27 15:16:58 1.16
+++ txn-table.c 2001/02/28 10:11:30
@@ -80,12 +80,12 @@
skel_t *txn_skel = svn_fs__make_empty_list (pool);
DBT key, value;
- svn_fs__prepend (svn_fs__mem_atom (unparsed_root_id->data,
- unparsed_root_id->len,
- pool),
- txn_skel);
svn_fs__prepend (svn_fs__mem_atom (unparsed_base_root_id->data,
unparsed_base_root_id->len,
+ pool),
+ txn_skel);
+ svn_fs__prepend (svn_fs__mem_atom (unparsed_root_id->data,
+ unparsed_root_id->len,
pool),
txn_skel);
svn_fs__prepend (svn_fs__str_atom ((char *) "transaction", pool), txn_skel);
Index: txn.c
===================================================================
RCS file: /cvs/subversion/subversion/libsvn_fs/txn.c,v
retrieving revision 1.28
diff -u -r1.28 txn.c
--- txn.c 2001/02/24 09:13:31 1.28
+++ txn.c 2001/02/28 10:11:31
@@ -22,8 +22,10 @@
#include "txn.h"
#include "err.h"
#include "trail.h"
+#include "nodes-table.h"
#include "rev-table.h"
#include "txn-table.h"
+#include "dag.h"
#include "tree.h"
@@ -152,6 +154,112 @@
{
*new_rev = SVN_INVALID_REVNUM;
abort();
+ return SVN_NO_ERROR;
+}
+
+
+/* Helper function for svn_fs_abort_txn. Remove all mutable nodes
+ recursively. NODE must be a mutable directory. */
+static svn_error_t *
+delete_nodes (svn_fs_t *fs,
+ dag_node_t *node,
+ trail_t *trail)
+{
+ svn_boolean_t is_mutable;
+
+ SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, node, trail));
+
+ if (is_mutable && svn_fs__dag_is_directory (node))
+ {
+ skel_t *entries, *entry;
+ SVN_ERR (svn_fs__dag_dir_entries (&entries, node, trail));
+
+ for (entry = entries; entry; entry = entry->next)
+ {
+ dag_node_t *child;
+ skel_t *name_skel;
+ char *name;
+
+ /* ENTRY is guaranteed to be well-formed. (NAME ID). */
+ name_skel = entry->children;
+ name = apr_palloc (trail->pool, name_skel->len + 1);
+ memcpy (name, name_skel->data, name_skel->len);
+ name[name_skel->len] = '\0';
+ SVN_ERR (svn_fs__dag_open (&child, node,
+ name,
+ trail));
+
+ if (svn_fs__dag_is_file (child)
+ || svn_fs__dag_is_copy (child))
+ {
+ SVN_ERR (svn_fs__dag_delete (node, name, trail));
+ }
+ else if (svn_fs__dag_is_directory)
+ {
+ svn_boolean_t child_is_mutable;
+
+ SVN_ERR (svn_fs__dag_check_mutable (&child_is_mutable,
+ node, trail));
+ /* Recurse if this is mutable directory. */
+ if (child_is_mutable)
+ SVN_ERR (delete_nodes (fs, child, trail));
+
+ /* Delete this directory regardless of mutable flag. */
+ SVN_ERR (svn_fs__dag_delete (node, name, trail));
+ }
+ else
+ abort ();
+ }
+ }
+ else
+ /* NODE must be a mutable directory or we have logic error. */
+ abort ();
+
+ return SVN_NO_ERROR;
+}
+
+
+
+static svn_error_t *
+txn_body_abort_txn (void *baton,
+ trail_t *trail)
+{
+ svn_fs_txn_t *txn = baton;
+
+ dag_node_t *root_node;
+ svn_boolean_t is_mutable;
+
+ SVN_ERR (svn_fs__dag_txn_root (&root_node, txn->fs, txn->id, trail));
+
+ SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, root_node, trail));
+
+ /* It's possible no cloning is done. */
+ if (is_mutable)
+ {
+ /* Remove all mutable node from `nodes' table. */
+ SVN_ERR (delete_nodes (txn->fs, root_node, trail));
+
+ /* Remove root node itself */
+ SVN_ERR (svn_fs__delete_node (txn->fs,
+ svn_fs__dag_get_id (root_node),
+ trail));
+ }
+
+ /* Delete transaction from `transactions' table. */
+ SVN_ERR (svn_fs__delete_txn (txn->fs, txn->id, trail));
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_fs_abort_txn (svn_fs_txn_t *txn)
+{
+ /* Remove all mutable nodes reachable from transaction's root. */
+ SVN_ERR (svn_fs__retry_txn (txn->fs, txn_body_abort_txn, txn, txn->pool));
+
+ SVN_ERR (svn_fs_close_txn (txn));
+
return SVN_NO_ERROR;
}
--
Yoshiki Hayashi
Received on Sat Oct 21 14:36:23 2006