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

Re: [PATCH] svn_fs_commit_txn

From: Karl Fogel <kfogel_at_galois.collab.net>
Date: 2001-03-06 23:50:44 CET

Yoshiki, have you read the section "Merge rules" in
libsvn_fs/structure, or looked at the interface to svn_fs_merge() in
svn_fs.h?

I think committing a transaction is a lot more complex than the patch
below implements. We can't just error out if a new revision has been
committed since the base revision against which we're trying to
commit. Subversion wouldn't be very usable then. :-)

I'm starting work on this right now, just wanted to send out this
feedback early.

Best,
-Karl

Yoshiki Hayashi <yoshiki@xemacs.org> writes:
> I examined nodes table and revisions table by db_dump and
> this works fine. There will also be test cases for this.
>
> * dag.c (make_node_immutable): New helper function for
> stabilize_node.
> * dag.c (stabilize_node): New helper function for
> svn_fs__dag_commit_txn.
> * dag.c (svn_fs__dag_commit_txn): New function.
> * dag.h (svn_fs__dag_commit_txn): Add svn_revnum_t argument
> so that svn_fs_commit_txn can get new revision number.
> * rev-table.c (svn_fs__youngest_rev): New function.
> * rev-table.c (txn_body_youngest_rev): Call
> svn_fs__youngest_rev.
> * rev-table.h (svn_fs__youngest_rev): New function declaration.
> * txn.c (struct commit_txn_args): New struct.
> * txn.c (txn_body_commit_txn): New helper function for
> svn_fs_commit_txn.
> * txn.c (svn_fs_commit_txn): Fill in this function.
>
> Index: subversion/libsvn_fs/dag.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/dag.c,v
> retrieving revision 1.70
> diff -u -r1.70 dag.c
> --- subversion/libsvn_fs/dag.c 2001/03/03 21:10:13 1.70
> +++ subversion/libsvn_fs/dag.c 2001/03/05 03:59:27
> @@ -574,6 +572,122 @@
> }
>
>
> +static svn_error_t *
> +make_node_immutable (dag_node_t *node, trail_t *trail)
> +{
> + skel_t *node_rev;
> + skel_t *header;
> + skel_t *flag, *prev = NULL;
> +
> + /* Go get a fresh NODE-REVISION for this node. */
> + SVN_ERR (get_node_revision (&node_rev, node, trail));
> + /* The node "header" is the first element of a node-revision skel,
> + itself a list. */
> + header = node_rev->children;
> +
> + /* Flag is the 3rd element of the header. */
> + for (flag = header->children->next->next; flag; flag = flag->next)
> + {
> + if (! flag->is_atom && svn_fs__matches_atom (flag->children, "mutable"))
> + {
> + /* We found it. */
> + if (prev)
> + prev->next = flag->next;
> + else
> + header->children->next->next = 0;
> +
> + SVN_ERR (set_node_revision (node, node_rev, trail));
> + return SVN_NO_ERROR;
> + }
> + prev = flag;
> + }
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +static svn_error_t *
> +stabilize_node (dag_node_t *node, trail_t *trail)
> +{
> + if (svn_fs__dag_is_directory (node))
> + {
> + skel_t *entries;
> + skel_t *entry;
> +
> + SVN_ERR (svn_fs__dag_dir_entries (&entries, node, trail));
> +
> + /* Each entry looks like (NAME ID). */
> + for (entry = entries->children; entry; entry = entry->next)
> + {
> + dag_node_t *child;
> + skel_t *id_skel = entry->children->next;
> + svn_boolean_t is_mutable;
> +
> + SVN_ERR (svn_fs__dag_get_node (&child, node->fs,
> + svn_fs_parse_id (id_skel->data,
> + id_skel->len,
> + trail->pool),
> + trail));
> + SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, child, trail));
> +
> + if (is_mutable)
> + SVN_ERR (stabilize_node (child, trail));
> + }
> + }
> + else if (svn_fs__dag_is_file (node)
> + || svn_fs__dag_is_copy (node))
> + ;
> + else
> + abort ();
> +
> + SVN_ERR (make_node_immutable (node, trail));
> + SVN_ERR (svn_fs__stable_node (node->fs, node->id, trail));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> +svn_error_t *
> +svn_fs__dag_commit_txn (svn_revnum_t *new_rev,
> + svn_fs_t *fs,
> + const char *svn_txn,
> + trail_t *trail)
> +{
> + dag_node_t *root;
> + svn_boolean_t is_mutable;
> +
> + SVN_ERR (svn_fs__dag_txn_root (&root, fs, svn_txn, trail));
> + SVN_ERR (svn_fs__dag_check_mutable (&is_mutable, root, trail));
> +
> + /* Nothing is changed in this transaction. */
> + if (! is_mutable)
> + return SVN_NO_ERROR;
> +
> + /* Make all mutable node immutable and stable. */
> + SVN_ERR (stabilize_node (root, trail));
> +
> + {
> + /* Add rew revision entry to `revisions' table. */
> + skel_t *new_revision_skel;
> + svn_string_t *id_string = svn_fs_unparse_id (root->id, trail->pool);
> +
> + new_revision_skel = svn_fs__make_empty_list (trail->pool);
> + svn_fs__prepend (svn_fs__make_empty_list (trail->pool),
> + new_revision_skel);
> + svn_fs__prepend (svn_fs__mem_atom (id_string->data,
> + id_string->len, trail->pool),
> + new_revision_skel);
> + svn_fs__prepend (svn_fs__str_atom ((char *) "revision", trail->pool),
> + new_revision_skel);
> + SVN_ERR (svn_fs__put_rev (new_rev, fs, new_revision_skel, trail));
> + }
> + /* Delete transaction from `transactions' table. */
> + SVN_ERR (svn_fs__delete_txn (fs, svn_txn, trail));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> /* Helper function for svn_fs__dag_clone_child.
> Given a PARENT directory, and the NAME of an entry in that
> directory, update the PARENT's ENTRY list item for the NAMEd entry
> Index: subversion/libsvn_fs/dag.h
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/dag.h,v
> retrieving revision 1.31
> diff -u -r1.31 dag.h
> --- subversion/libsvn_fs/dag.h 2001/03/02 20:32:36 1.31
> +++ subversion/libsvn_fs/dag.h 2001/03/05 03:59:27
> @@ -158,7 +158,8 @@
> trail_t *trail);
>
>
> -/* Commit the transaction SVN_TXN in FS, as part of TRAIL. This entails:
> +/* Commit the transaction SVN_TXN in FS, as part of TRAIL. Store the
> + new revision number in NEW_REV. This entails:
> - marking the tree of mutable nodes at SVN_TXN's root as immutable,
> and marking all their contents as stable
> - creating a new revision, with SVN_TXN's root as its root directory
> @@ -171,7 +172,8 @@
> Do any necessary temporary allocation in a subpool of TRAIL->pool.
> Consume temporary space at most proportional to the maximum depth
> of SVN_TXN's tree of mutable nodes. */
> -svn_error_t *svn_fs__dag_commit_txn (svn_fs_t *fs,
> +svn_error_t *svn_fs__dag_commit_txn (svn_revnum_t *new_rev,
> + svn_fs_t *fs,
> const char *svn_txn,
> trail_t *trail);
>
> Index: subversion/libsvn_fs/rev-table.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/rev-table.c,v
> retrieving revision 1.8
> diff -u -r1.8 rev-table.c
> --- subversion/libsvn_fs/rev-table.c 2001/03/03 10:18:01 1.8
> +++ subversion/libsvn_fs/rev-table.c 2001/03/05 03:59:27
> @@ -161,25 +161,16 @@
> /* Getting the youngest revision. */
>
>
> -struct youngest_rev_args {
> - svn_revnum_t *youngest_p;
> - svn_fs_t *fs;
> -};
> -
> -
> -static svn_error_t *
> -txn_body_youngest_rev (void *baton,
> - trail_t *trail)
> +svn_error_t *
> +svn_fs__youngest_rev (svn_revnum_t *youngest_p,
> + svn_fs_t *fs,
> + trail_t *trail)
> {
> - struct youngest_rev_args *args = baton;
> -
> int db_err;
> DBC *cursor = 0;
> DBT key, value;
> db_recno_t recno;
>
> - svn_fs_t *fs = args->fs;
> -
> /* Create a database cursor. */
> SVN_ERR (DB_WRAP (fs, "getting youngest revision (creating cursor)",
> fs->revisions->cursor (fs->revisions, trail->db_txn,
> @@ -218,7 +209,24 @@
> /* Turn the record number into a Subversion revision number.
> Revisions are numbered starting with zero; Berkeley DB record
> numbers begin with one. */
> - *args->youngest_p = recno - 1;
> + *youngest_p = recno - 1;
> +
> + return SVN_NO_ERROR;
> +}
> +
> +struct youngest_rev_args {
> + svn_revnum_t *youngest_p;
> + svn_fs_t *fs;
> +};
> +
> +
> +static svn_error_t *
> +txn_body_youngest_rev (void *baton,
> + trail_t *trail)
> +{
> + struct youngest_rev_args *args = baton;
> + SVN_ERR (svn_fs__youngest_rev (args->youngest_p, args->fs, trail));
> +
> return SVN_NO_ERROR;
> }
>
> Index: subversion/libsvn_fs/rev-table.h
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/rev-table.h,v
> retrieving revision 1.5
> diff -u -r1.5 rev-table.h
> --- subversion/libsvn_fs/rev-table.h 2001/03/03 10:18:01 1.5
> +++ subversion/libsvn_fs/rev-table.h 2001/03/05 03:59:27
> @@ -63,6 +63,13 @@
> trail_t *trail);
>
>
> +/* Set *YOUNGEST_P to the number of the youngest revision in filesystem FS,
> + as part of TRAIL. Use TRAIL->pool for all temporary allocation. */
> +svn_error_t *svn_fs__youngest_rev (svn_revnum_t *youngest_p,
> + svn_fs_t *fs,
> + trail_t *trail);
> +
> +
> #endif /* SVN_LIBSVN_FS_REV_TABLE_H */
>
>
> Index: subversion/libsvn_fs/txn.c
> ===================================================================
> RCS file: /cvs/subversion/subversion/libsvn_fs/txn.c,v
> retrieving revision 1.29
> diff -u -r1.29 txn.c
> --- subversion/libsvn_fs/txn.c 2001/03/03 17:25:38 1.29
> +++ subversion/libsvn_fs/txn.c 2001/03/05 05:34:51
> @@ -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"
>
>
> @@ -146,12 +148,50 @@
> }
>
>
> +struct commit_txn_args {
> + svn_revnum_t *new_rev;
> + svn_fs_txn_t *txn;
> +};
> +
> +
> +static svn_error_t *
> +txn_body_commit_txn (void *baton, trail_t *trail)
> +{
> + struct commit_txn_args *args = baton;
> +
> + svn_fs_txn_t *txn = args->txn;
> + svn_revnum_t youngest_rev;
> + svn_fs_id_t *ignored, *base_root_id, *current_root_id;
> +
> + /* Is there already a new revision? */
> + SVN_ERR (svn_fs__get_txn (&ignored, &base_root_id, txn->fs,
> + txn->id, trail));
> + SVN_ERR (svn_fs__youngest_rev (&youngest_rev, txn->fs, trail));
> + SVN_ERR (svn_fs__rev_get_root (&current_root_id, txn->fs,
> + youngest_rev, trail));
> + if (! svn_fs_id_eq (base_root_id, current_root_id))
> + return svn_error_createf (SVN_ERR_FS_CONFLICT, 0, 0, trail->pool,
> + "Trying to commit old transaction, ID `%s'",
> + txn->id);
> +
> + SVN_ERR (svn_fs__dag_commit_txn (args->new_rev, txn->fs, txn->id, trail));
> +
> + return SVN_NO_ERROR;
> +}
> +
> +
> svn_error_t *
> svn_fs_commit_txn (svn_revnum_t *new_rev,
> svn_fs_txn_t *txn)
> {
> + struct commit_txn_args args;
> +
> *new_rev = SVN_INVALID_REVNUM;
> - abort();
> + args.new_rev = new_rev;
> + args.txn = txn;
> +
> + SVN_ERR (svn_fs__retry_txn (txn->fs, txn_body_commit_txn, &args, txn->pool));
> +
> return SVN_NO_ERROR;
> }
>
>
>
> --
> Yoshiki Hayashi
Received on Sat Oct 21 14:36:25 2006

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