Hi All,
Find the attached patch and log.
With regards
Kamesh Jayachandran
Index: subversion/libsvn_fs_base/tree.c
===================================================================
--- subversion/libsvn_fs_base/tree.c (revision 21795)
+++ subversion/libsvn_fs_base/tree.c (working copy)
@@ -38,6 +38,7 @@
#include "svn_error.h"
#include "svn_path.h"
#include "svn_md5.h"
+#include "svn_mergeinfo.h"
#include "svn_fs.h"
#include "svn_sorts.h"
#include "fs.h"
@@ -1281,7 +1282,44 @@
return SVN_NO_ERROR;
}
+struct change_merge_info_args {
+ svn_fs_root_t *root;
+ const char *path;
+ const svn_string_t *value;
+};
+static svn_error_t *
+txn_body_change_merge_info(void *baton,
+ trail_t *trail)
+{
+ struct change_merge_info_args *args = baton;
+ SVN_ERR(svn_fs_base__set_txn_merge_info(args->root->fs, args->root->txn,
+ args->path, args->value,
+ trail, trail->pool));
+ return SVN_NO_ERROR;
+}
+
+/* Change the merge info for a given path. */
+static svn_error_t *
+base_change_merge_info(svn_fs_root_t *root,
+ const char *path,
+ apr_hash_t *merge_info,
+ apr_pool_t *pool)
+{
+ svn_stringbuf_t *minfostr;
+ struct change_merge_info_args args;
+
+ if (! root->is_txn_root)
+ return NOT_TXN(root);
+ SVN_ERR(svn_mergeinfo_to_string(&minfostr, merge_info, pool));
+ args.root = root;
+ args.path = path;
+ args.value = svn_string_create_from_buf(minfostr, pool);
+ SVN_ERR(svn_fs_base__retry_txn(root->fs, txn_body_change_merge_info, &args,
+ pool));
+ return SVN_NO_ERROR;
+}
+
struct change_node_prop_args {
svn_fs_root_t *root;
const char *path;
@@ -1291,6 +1329,24 @@
static svn_error_t *
+change_txn_merge_info(struct change_node_prop_args *args, trail_t *trail)
+{
+ const char *txn_id = args->root->txn;
+
+ /* At least for single file merges, nodes which are direct
+ children of the root are received without a leading slash
+ (e.g. "/file.txt" is received as "file.txt"), so must be made
+ absolute. */
+ const char *canon_path = svn_fs_base__canonicalize_abspath(args->path,
+ trail->pool);
+ SVN_ERR(svn_fs_base__set_txn_merge_info(args->root->fs, txn_id, canon_path,
+ args->value, trail, trail->pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
txn_body_change_node_prop(void *baton,
trail_t *trail)
{
@@ -1321,6 +1377,9 @@
if (! proplist)
proplist = apr_hash_make(trail->pool);
+ if (strcmp (args->name, SVN_PROP_MERGE_INFO) == 0)
+ SVN_ERR(change_txn_merge_info(args, trail));
+
/* Set the property. */
apr_hash_set(proplist, args->name, APR_HASH_KEY_STRING, args->value);
@@ -2382,8 +2441,7 @@
SVN_ERR(verify_locks(txn_name, trail, trail->pool));
/* Else, commit the txn. */
- SVN_ERR(svn_fs_base__dag_commit_txn(&(args->new_rev), fs, txn_name,
- trail, trail->pool));
+ SVN_ERR(svn_fs_base__dag_commit_txn(&(args->new_rev), txn, trail));
return SVN_NO_ERROR;
}
@@ -4374,7 +4432,7 @@
base_contents_changed,
base_get_file_delta_stream,
base_merge,
- NULL,
+ base_change_merge_info,
svn_fs_merge_info__get_merge_info
};
Index: subversion/libsvn_fs_base/dag.h
===================================================================
--- subversion/libsvn_fs_base/dag.h (revision 21795)
+++ subversion/libsvn_fs_base/dag.h (working copy)
@@ -214,10 +214,8 @@
Consume temporary space at most proportional to the maximum depth
of SVN_TXN's tree of mutable nodes. */
svn_error_t *svn_fs_base__dag_commit_txn(svn_revnum_t *new_rev,
- svn_fs_t *fs,
- const char *txn_id,
- trail_t *trail,
- apr_pool_t *pool);
+ svn_fs_txn_t *txn,
+ trail_t *trail);
Index: subversion/libsvn_fs_base/tree.h
===================================================================
--- subversion/libsvn_fs_base/tree.h (revision 21795)
+++ subversion/libsvn_fs_base/tree.h (working copy)
@@ -22,6 +22,14 @@
extern "C" {
#endif /* __cplusplus */
+/* A property specific for bdb repositories holding this property name
+ * against skel form of apr_hash_t (target wc path char*-> actual merge info)*/
+
+#include "svn_props.h"
+#include "trail.h"
+
+#define SVN_FS_PROP_TXN_MERGEINFO SVN_PROP_PREFIX "txn-mergeinfo"
+
/* These functions implement some of the calls in the FS loader
Index: subversion/libsvn_fs_base/revs-txns.c
===================================================================
--- subversion/libsvn_fs_base/revs-txns.c (revision 21795)
+++ subversion/libsvn_fs_base/revs-txns.c (working copy)
@@ -558,7 +558,50 @@
return put_txn(fs, txn, txn_name, trail, pool);
}
+svn_error_t *
+svn_fs_base__set_txn_merge_info(svn_fs_t *fs,
+ const char *txn_name,
+ const char *path,
+ const svn_string_t *value,
+ trail_t *trail,
+ apr_pool_t *pool)
+{
+ transaction_t *txn;
+ apr_hash_t *mergetarget_mergeinfo;
+ SVN_ERR(get_txn(&txn, fs, txn_name, FALSE, trail, pool));
+ if (txn->kind != transaction_kind_normal)
+ {
+ return svn_fs_base__err_txn_not_mutable(fs, txn_name);
+ }
+
+ /* If there's no proplist, but we're just deleting a property, exit now. */
+ if ((! txn->proplist) && (! value))
+ {
+ return SVN_NO_ERROR;
+ }
+
+ /* Now, if there's no proplist, we know we need to make one. */
+ if (! txn->proplist)
+ txn->proplist = apr_hash_make(pool);
+
+
+ mergetarget_mergeinfo = apr_hash_get(txn->proplist, SVN_FS_PROP_TXN_MERGEINFO,
+ APR_HASH_KEY_STRING);
+
+ if (! mergetarget_mergeinfo)
+ mergetarget_mergeinfo = apr_hash_make(pool);
+ /* Set the mergeinfo for the path. */
+ apr_hash_set(mergetarget_mergeinfo, path, APR_HASH_KEY_STRING, value);
+
+ /* Set the property. */
+ apr_hash_set(txn->proplist, SVN_FS_PROP_TXN_MERGEINFO,
+ APR_HASH_KEY_STRING, mergetarget_mergeinfo);
+
+ /* Now overwrite the transaction. */
+ return put_txn(fs, txn, txn_name, trail, pool);
+}
+
static svn_error_t *
txn_body_change_txn_prop(void *baton, trail_t *trail)
{
@@ -587,7 +630,37 @@
return SVN_NO_ERROR;
}
+/* txn_vtable's get_mergeinfo hook */
+static svn_error_t *
+base_txn_merge_info(apr_hash_t **table_p,
+ svn_fs_txn_t *txn,
+ apr_pool_t *pool)
+{
+ apr_hash_t *txnprops = NULL;
+ apr_hash_t *mergetarget_mergeinfo = NULL;
+ struct txn_proplist_args args;
+ svn_fs_t *fs = txn->fs;
+
+ SVN_ERR(svn_fs_base__check_fs(fs));
+
+ args.table_p = &txnprops;
+ args.id = txn->id;
+ SVN_ERR(svn_fs_base__retry(fs, txn_body_txn_proplist, &args, pool));
+
+ if (txnprops)
+ {
+ mergetarget_mergeinfo = apr_hash_get(txnprops, SVN_FS_PROP_TXN_MERGEINFO,
+ APR_HASH_KEY_STRING);
+ if (!mergetarget_mergeinfo)
+ mergetarget_mergeinfo = apr_hash_make(pool);
+ }
+ *table_p = mergetarget_mergeinfo;
+
+ return SVN_NO_ERROR;
+}
+
+
/* Creating a transaction */
@@ -598,7 +671,7 @@
svn_fs_base__txn_proplist,
svn_fs_base__change_txn_prop,
svn_fs_base__txn_root,
- NULL
+ base_txn_merge_info
};
Index: subversion/libsvn_fs_base/revs-txns.h
===================================================================
--- subversion/libsvn_fs_base/revs-txns.h (revision 21795)
+++ subversion/libsvn_fs_base/revs-txns.h (working copy)
@@ -144,6 +144,20 @@
apr_pool_t *pool);
+/* Set a PATH to VALUE on transaction TXN_NAME's proplist's
+ SVN_FS_PROP_TXN_MERGEINFO hash table in FS as part
+ of TRAIL. Use POOL for any necessary allocations.
+
+ Returns SVN_ERR_FS_TRANSACTION_NOT_MUTABLE if TXN_NAME refers to a
+ transaction that has already been committed. */
+svn_error_t *
+svn_fs_base__set_txn_merge_info(svn_fs_t *fs,
+ const char *txn_name,
+ const char *path,
+ const svn_string_t *value,
+ trail_t *trail,
+ apr_pool_t *pool);
+
/* Set a property NAME to VALUE on transaction TXN_NAME in FS as part
of TRAIL. Use POOL for any necessary allocations.
Index: subversion/libsvn_fs_base/dag.c
===================================================================
--- subversion/libsvn_fs_base/dag.c (revision 21795)
+++ subversion/libsvn_fs_base/dag.c (working copy)
@@ -34,6 +34,7 @@
#include "reps-strings.h"
#include "revs-txns.h"
#include "id.h"
+#include "tree.h" //needed for SVN_FS_PROP_TXN_MERGEINFO
#include "util/fs_skels.h"
@@ -44,6 +45,7 @@
#include "bdb/reps-table.h"
#include "bdb/strings-table.h"
+#include "private/svn_fs_merge_info.h"
#include "../libsvn_fs/fs-loader.h"
#include "svn_private_config.h"
@@ -1416,18 +1418,35 @@
svn_error_t *
svn_fs_base__dag_commit_txn(svn_revnum_t *new_rev,
- svn_fs_t *fs,
- const char *txn_id,
- trail_t *trail,
- apr_pool_t *pool)
+ svn_fs_txn_t *txn,
+ trail_t *trail)
{
revision_t revision;
svn_string_t date;
apr_hash_t *txnprops;
+ svn_fs_t *fs = txn->fs;
+ const char *txn_id = txn->id;
+ apr_pool_t *pool = trail->pool;
+ apr_hash_t *mergetarget_mergeinfo=NULL;
/* Remove any temporary transaction properties initially created by
begin_txn(). */
SVN_ERR(svn_fs_base__txn_proplist_in_trail(&txnprops, txn_id, trail));
+
+ /* Add new revision entry to `revisions' table. */
+ revision.txn_id = txn_id;
+ *new_rev = SVN_INVALID_REVNUM;
+ SVN_ERR(svn_fs_bdb__put_rev(new_rev, fs, &revision, trail, pool));
+
+ mergetarget_mergeinfo = apr_hash_get(txnprops, SVN_FS_PROP_TXN_MERGEINFO,
+ APR_HASH_KEY_STRING);
+ if (mergetarget_mergeinfo)
+ {
+ SVN_ERR(svn_fs_merge_info__update_index(txn, *new_rev, TRUE, pool));
+ SVN_ERR(svn_fs_base__set_txn_prop
+ (fs, txn_id, SVN_FS_PROP_TXN_MERGEINFO, NULL, trail, pool));
+ }
+
if (txnprops)
{
if (apr_hash_get(txnprops, SVN_FS_PROP_TXN_CHECK_OOD,
@@ -1440,12 +1459,6 @@
SVN_ERR(svn_fs_base__set_txn_prop
(fs, txn_id, SVN_FS_PROP_TXN_CHECK_LOCKS, NULL, trail, pool));
}
-
- /* Add new revision entry to `revisions' table. */
- revision.txn_id = txn_id;
- *new_rev = SVN_INVALID_REVNUM;
- SVN_ERR(svn_fs_bdb__put_rev(new_rev, fs, &revision, trail, pool));
-
/* Promote the unfinished transaction to a committed one. */
SVN_ERR(svn_fs_base__txn_make_committed(fs, txn_id, *new_rev,
trail, pool));
Index: subversion/libsvn_fs_base/util/fs_skels.c
===================================================================
--- subversion/libsvn_fs_base/util/fs_skels.c (revision 21795)
+++ subversion/libsvn_fs_base/util/fs_skels.c (working copy)
@@ -23,6 +23,7 @@
#include "fs_skels.h"
#include "skel.h"
#include "../id.h"
+#include "../tree.h" //needed for SVN_FS_PROP_TXN_MERGEINFO
static svn_error_t *
@@ -56,15 +57,35 @@
is_valid_proplist_skel(skel_t *skel)
{
int len = svn_fs_base__list_length(skel);
+ const char *propname = NULL;
+ apr_size_t propname_len = 0;
+ apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
if ((len >= 0) && (len & 1) == 0)
{
skel_t *elt;
for (elt = skel->children; elt; elt = elt->next)
- if (! elt->is_atom)
- return FALSE;
-
+ {
+ if ((propname_len == txn_mergeinfo_prop_length) &&
+ strncmp(propname,
+ SVN_FS_PROP_TXN_MERGEINFO,
+ txn_mergeinfo_prop_length) == 0)
+ {
+ if (elt->is_atom)
+ return FALSE;
+ len = svn_fs_base__list_length(elt);
+ if (len & 1 != 0)
+ return FALSE;
+ }
+ else
+ {
+ if (! elt->is_atom)
+ return FALSE;
+ }
+ propname = elt->data;
+ propname_len = elt->len;
+ }
return TRUE;
}
@@ -361,6 +382,33 @@
/*** Parsing (conversion from skeleton to native FS type) ***/
+static svn_error_t *
+parse_txn_merge_info_skel(apr_hash_t **mergetarget_mergeinfo_p,
+ skel_t *skel, apr_pool_t *pool)
+{
+ apr_hash_t *mergetarget_mergeinfo = NULL;
+ skel_t *elt;
+
+ /* Create the returned structure */
+ if (skel->children)
+ mergetarget_mergeinfo = apr_hash_make(pool);
+ for (elt = skel->children; elt; elt = elt->next->next)
+ {
+ svn_string_t *value = svn_string_ncreate(elt->next->data,
+ elt->next->len, pool);
+ apr_hash_set(mergetarget_mergeinfo,
+ apr_pstrmemdup(pool, elt->data, elt->len),
+ elt->len,
+ value);
+ }
+
+ /* Return the structure. */
+ *mergetarget_mergeinfo_p = mergetarget_mergeinfo;
+ return SVN_NO_ERROR;
+}
+
+/*** Parsing (conversion from skeleton to native FS type) ***/
+
svn_error_t *
svn_fs_base__parse_proplist_skel(apr_hash_t **proplist_p,
skel_t *skel,
@@ -368,6 +416,7 @@
{
apr_hash_t *proplist = NULL;
skel_t *elt;
+ apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
/* Validate the skel. */
if (! is_valid_proplist_skel(skel))
@@ -378,12 +427,27 @@
proplist = apr_hash_make(pool);
for (elt = skel->children; elt; elt = elt->next->next)
{
- svn_string_t *value = svn_string_ncreate(elt->next->data,
- elt->next->len, pool);
- apr_hash_set(proplist,
- apr_pstrmemdup(pool, elt->data, elt->len),
- elt->len,
- value);
+ if ((elt->len == txn_mergeinfo_prop_length) &&
+ strncmp(elt->data, SVN_FS_PROP_TXN_MERGEINFO,
+ txn_mergeinfo_prop_length) == 0)
+ {
+ apr_hash_t *mergetarget_mergeinfo;
+ SVN_ERR(parse_txn_merge_info_skel(&mergetarget_mergeinfo,
+ elt->next, pool));
+ apr_hash_set(proplist,
+ apr_pstrmemdup(pool, elt->data, elt->len),
+ elt->len,
+ mergetarget_mergeinfo);
+ }
+ else
+ {
+ svn_string_t *value = svn_string_ncreate(elt->next->data,
+ elt->next->len, pool);
+ apr_hash_set(proplist,
+ apr_pstrmemdup(pool, elt->data, elt->len),
+ elt->len,
+ value);
+ }
}
/* Return the structure. */
@@ -864,12 +928,53 @@
/*** Unparsing (conversion from native FS type to skeleton) ***/
svn_error_t *
+unparse_txn_merge_info_skel(skel_t **skel_p, apr_hash_t *mergetarget_mergeinfo,
+ apr_pool_t *pool)
+{
+ skel_t *skel = svn_fs_base__make_empty_list(pool);
+ apr_hash_index_t *hi;
+
+ /* Create the skel. */
+ if (mergetarget_mergeinfo)
+ {
+ /* Loop over hash entries */
+ for (hi = apr_hash_first(pool, mergetarget_mergeinfo);
+ hi;
+ hi = apr_hash_next(hi))
+ {
+ const void *key;
+ void *val;
+ apr_ssize_t klen;
+ svn_string_t *value;
+
+ apr_hash_this(hi, &key, &klen, &val);
+ value = val;
+
+ /* MERGEINFO */
+ svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
+ value->len, pool),
+ skel);
+
+ /* PATH */
+ svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool), skel);
+ }
+ }
+
+ /* Validate and return the skel. */
+ if (! is_valid_proplist_skel(skel))
+ return skel_err("proplist");
+ *skel_p = skel;
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
svn_fs_base__unparse_proplist_skel(skel_t **skel_p,
apr_hash_t *proplist,
apr_pool_t *pool)
{
skel_t *skel = svn_fs_base__make_empty_list(pool);
apr_hash_index_t *hi;
+ apr_size_t txn_mergeinfo_prop_length = strlen(SVN_FS_PROP_TXN_MERGEINFO);
/* Create the skel. */
if (proplist)
@@ -886,9 +991,28 @@
value = val;
/* VALUE */
- svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
- value->len, pool),
- skel);
+ if ((klen == txn_mergeinfo_prop_length) &&
+ strncmp(key,
+ SVN_FS_PROP_TXN_MERGEINFO,
+ txn_mergeinfo_prop_length) == 0)
+ {
+ apr_hash_t *mergetarget_mergeinfo = val;
+ skel_t *mergetarget_mergeinfo_skel;
+ if (apr_hash_count(mergetarget_mergeinfo))
+ {
+ unparse_txn_merge_info_skel(&mergetarget_mergeinfo_skel,
+ mergetarget_mergeinfo, pool);
+ svn_fs_base__prepend(mergetarget_mergeinfo_skel, skel);
+ }
+ else
+ continue;
+ }
+ else
+ {
+ svn_fs_base__prepend(svn_fs_base__mem_atom(value->data,
+ value->len, pool),
+ skel);
+ }
/* NAME */
svn_fs_base__prepend(svn_fs_base__mem_atom(key, klen, pool), skel);
[[[
Patch by: Kamesh Jayachandran <kamesh@collab.net>
Implement 'txn-mergeinfo' change, storage and retrieval for 'bdb' repositories.
The changes can be summarised as follows,
1. We now store the txn-mergeinfo as a temporary transaction property
'svn:txn-mergeinfo' with a value as list skel having
(path1 revlist1 path2 revlist2......)
2. Changing the signature of svn_fs_base__dag_commit_txn to accept
'svn_fs_txn_t *'(which is needed by svn_fs_merge_info__update_index).
Along with done one more refactoring to pass 'trail' alone as 'pool' can
be extracted out of trail.
From 'svn_fs_txn_t *' we can derive 'svn_fs_t*' and 'const char *txn_id'
so not passing them explicitly.
* subversion/libsvn_fs_base/dag.h
(svn_fs_base__dag_commit_txn): Changing the signature to accept
'svn_fs_txn_t *'(which is needed by svn_fs_merge_info__update_index).
Along with this done one more refactoring to pass 'trail' alone as 'pool' can
be extracted out of trail.
From 'svn_fs_txn_t *' we can derive 'svn_fs_t*' and 'const char *txn_id'
so not passing them explicitly.
* subversion/libsvn_fs_base/tree.c
(global): including "svn_mergeinfo.h" as we need this for mergeinfo alzebra.
(struct change_merge_info_args): New structure to hold the baton for
'txn_body_change_merge_info'
(txn_body_change_merge_info): New helper function for base_change_merge_info.
(base_change_merge_info): New hook function implementing root_vtable_t's
'change_merge_info' hook.
(change_txn_merge_info): New function to update the 'txn mergeinfo' upon
change property of 'svn:mergeinfo'.
(txn_body_change_node_prop): calls 'change_txn_merge_info' if property that
is getting modified is 'svn:mergeinfo'.
(txn_body_commit): calls svn_fs_base__dag_commit_txn with a new signature.
(root_vtable): Setting 'change_merge_info' hook to base_change_merge_info.
* subversion/libsvn_fs_base/tree.h
(global):
including svn_props.h to use 'SVN_PROP_PREFIX'
including trail.h to make sure 'trail_t' is defined so that 'trail unaware'
consumers like subversion/libsvn_fs_base/util/fs-skel.c can consume tree.h.
(SVN_FS_PROP_TXN_MERGEINFO): New macro.
* subversion/libsvn_fs_base/revs-txns.c
(svn_fs_base__set_txn_merge_info): New function records the txn mergeinfo.
(base_txn_merge_info): New function that retrieves the stored
txn mergeinfo and gives to libsvn_fs_util which records the mergeinfo in the
persistent mergeinfo db.
(txn_vtable): set 'get_mergeinfo' hook as 'base_txn_merge_info'.
* subversion/libsvn_fs_base/revs-txns.h
(global): prototype svn_fs_base__set_txn_merge_info.
* subversion/libsvn_fs_base/dag.c
(global):
include "tree.h" to make use of 'SVN_FS_PROP_TXN_MERGEINFO'.
include "private/svn_fs_merge_info.h" to make use of
'svn_fs_merge_info__update_index'.
(svn_fs_base__dag_commit_txn):
signature change as described by summary 2 above.
record mergeinfo by calling svn_fs_merge_info__update_index.
* subversion/libsvn_fs_base/util/fs_skels.c
(global): include "tree.h" to make use of 'SVN_FS_PROP_TXN_MERGEINFO'.
(is_valid_proplist_skel):
Changes as summarised in item 1 above.
(parse_txn_merge_info_skel): New function to parse the list skel of
'SVN_FS_PROP_TXN_MERGEINFO'.
(svn_fs_base__parse_proplist_skel): Changes as summarised at item 1 above.
(unparse_txn_merge_info_skel): New function to unparse the list skel of
'SVN_FS_PROP_TXN_MERGEINFO'.
(svn_fs_base__unparse_proplist_skel): Changes as summarised at item 1 above.
]]]
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@subversion.tigris.org
For additional commands, e-mail: dev-help@subversion.tigris.org
Received on Fri Oct 6 12:48:41 2006