Author: stefan2
Date: Sun Jan 31 16:18:26 2016
New Revision: 1727838
URL: http://svn.apache.org/viewvc?rev=1727838&view=rev
Log:
Add the ability to emulate the old svn_fs_paths_changed2 through
svn_fs_paths_changed3. So, we've got a two-way emulation now and
we enable both for now such that all callers of the old API will
be redirected: old API -> new API -> old API vtable entry.
As a bonus, the enumated svn_fs_paths_changed2 now correctly reports
the IDs for in-revision nodes in FSFS. It also fails earlier on
corrupted change lists. Both is only true for "enumlated" mode.
* subversion/include/private/svn_fs_util.h
(svn_fs__get_deleted_node): Declare a new private utility API needed
to handle ID creation edge cases.
* subversion/libsvn_fs_util/fs-util.c
(svn_fs__prop_lists_equal): Implement.
* subversion/libsvn_fs/fs-loader.c
(SVN_FS_ENUMLATE_PATHS_CHANGED): Declare new control macro as we did
already for the new API.
(add_changed_path_baton_t,
add_changed_path): Callback implementation to emulate the old API
based on the new one.
(svn_fs_paths_changed2): Emulate when necessary or forced to do so.
* subversion/tests/cmdline/svnadmin_tests.py
(verify_invalid_path_changes): The correct ID construction in emulated
mode creates fewer repetitions of the
same error during verification. Update
test expectations accordingly.
Modified:
subversion/trunk/subversion/include/private/svn_fs_util.h
subversion/trunk/subversion/libsvn_fs/fs-loader.c
subversion/trunk/subversion/libsvn_fs_util/fs-util.c
subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
Modified: subversion/trunk/subversion/include/private/svn_fs_util.h
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_fs_util.h?rev=1727838&r1=1727837&r2=1727838&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_fs_util.h (original)
+++ subversion/trunk/subversion/include/private/svn_fs_util.h Sun Jan 31
16:18:26 2016
@@ -244,6 +244,22 @@ svn_fs__prop_lists_equal(apr_hash_t *a,
apr_hash_t *b,
apr_pool_t *pool);
+/* Determine the previous location of PATH under ROOT and return it as
+ * *NODE_PATH under *NODE_ROOT. This may be called for arbitrary nodes
+ * but is intended for nodes that got deleted in ROOT, i.e. when standard
+ * navigation fails. It also works if ROOT is transaction root.
+ *
+ * Allocate *NODE_PATH and *NODE_ROOT in RESULT_POOL while using
+ * SCRATCH_POOL for temporaries.
+ */
+svn_error_t *
+svn_fs__get_deleted_node(svn_fs_root_t **node_root,
+ const char **node_path,
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.c?rev=1727838&r1=1727837&r2=1727838&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.c Sun Jan 31 16:18:26 2016
@@ -59,6 +59,14 @@
#define FS_TYPE_FILENAME "fs-type"
+/* If a FS backend does not implement the PATHS_CHANGED vtable function,
+ it will get emulated. However, if this macro is defined to non-null
+ then the API will always be emulated when feasible, i.e. the calls
+ get "re-directed" to the old API implementation. */
+#ifndef SVN_FS_ENUMLATE_PATHS_CHANGED
+#define SVN_FS_ENUMLATE_PATHS_CHANGED TRUE
+#endif
+
/* If a FS backend does not implement the REPORT_CHANGES vtable function,
it will get emulated. However, if this macro is defined to non-null
then the API will always be emulated when feasible, i.e. the calls
@@ -1046,12 +1054,77 @@ svn_fs_revision_root_revision(svn_fs_roo
return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
}
+/* Baton type to be used with add_changed_path.
+ It contains extra parameters in and out of svn_fs_paths_changed2. */
+typedef struct add_changed_path_baton_t
+{
+ svn_fs_root_t *root;
+ apr_hash_t *changes;
+} add_changed_path_baton_t;
+
+/* Implements svn_fs_path_change_receiver_t.
+ Take the CHANGE, convert it into a svn_fs_path_change2_t and add
+ it to the CHANGES hash in the add_changed_path_baton_t BATON. */
+static svn_error_t *
+add_changed_path(void *baton,
+ svn_fs_path_change3_t *change,
+ apr_pool_t *scratch_pool)
+{
+ add_changed_path_baton_t *b = baton;
+ apr_pool_t *result_pool = apr_hash_pool_get(b->changes);
+
+ svn_fs_path_change2_t *copy;
+ const svn_fs_id_t *id_copy;
+
+ svn_fs_root_t *root = b->root;
+ const char *path = change->path.data;
+ if (change->change_kind == svn_fs_path_change_delete)
+ SVN_ERR(svn_fs__get_deleted_node(&root, &path, root, path,
+ scratch_pool, scratch_pool));
+
+ SVN_ERR(svn_fs_node_id(&id_copy, root, path, result_pool));
+
+ copy = svn_fs_path_change2_create(id_copy, change->change_kind,
+ result_pool);
+ copy->copyfrom_known = change->copyfrom_known;
+ if (copy->copyfrom_known && SVN_IS_VALID_REVNUM(change->copyfrom_rev))
+ {
+ copy->copyfrom_rev = change->copyfrom_rev;
+ copy->copyfrom_path = apr_pstrdup(result_pool, change->copyfrom_path);
+ }
+ copy->mergeinfo_mod = change->mergeinfo_mod;
+ copy->node_kind = change->node_kind;
+ copy->prop_mod = change->prop_mod;
+ copy->text_mod = change->text_mod;
+
+ svn_hash_sets(b->changes, apr_pstrmemdup(result_pool, change->path.data,
+ change->path.len), copy);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_fs_paths_changed2(apr_hash_t **changed_paths_p,
svn_fs_root_t *root,
apr_pool_t *pool)
{
- return root->vtable->paths_changed(changed_paths_p, root, pool);
+ svn_boolean_t emulate = !root->vtable->paths_changed
+ || SVN_FS_ENUMLATE_PATHS_CHANGED;
+
+ if (emulate)
+ {
+ add_changed_path_baton_t baton;
+ baton.root = root;
+ baton.changes = svn_hash__make(pool);
+ SVN_ERR(svn_fs_paths_changed3(root, add_changed_path, &baton, pool));
+ *changed_paths_p = baton.changes;
+ }
+ else
+ {
+ SVN_ERR(root->vtable->paths_changed(changed_paths_p, root, pool));
+ }
+
+ return SVN_NO_ERROR;
}
svn_error_t *
Modified: subversion/trunk/subversion/libsvn_fs_util/fs-util.c
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_util/fs-util.c?rev=1727838&r1=1727837&r2=1727838&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/trunk/subversion/libsvn_fs_util/fs-util.c Sun Jan 31 16:18:26
2016
@@ -347,3 +347,61 @@ svn_fs__prop_lists_equal(apr_hash_t *a,
/* No difference found. */
return TRUE;
}
+
+svn_error_t *
+svn_fs__get_deleted_node(svn_fs_root_t **node_root,
+ const char **node_path,
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ const char *parent_path, *name;
+ svn_fs_root_t *copy_root;
+ const char *copy_path;
+
+ /* History traversal does not work with transaction roots.
+ * Therefore, do it "by hand". */
+
+ /* If the parent got copied in ROOT, PATH got copied with it.
+ * Otherwise, we will find the node at PATH in the revision prior to ROOT.
+ */
+ svn_fspath__split(&parent_path, &name, path, scratch_pool);
+ SVN_ERR(svn_fs_closest_copy(©_root, ©_path, root, parent_path,
+ scratch_pool));
+
+ /* Copied in ROOT? */
+ if ( copy_root
+ && ( svn_fs_revision_root_revision(copy_root)
+ == svn_fs_revision_root_revision(root)))
+ {
+ svn_revnum_t copyfrom_rev;
+ const char *copyfrom_path;
+ const char *rel_path;
+ SVN_ERR(svn_fs_copied_from(©from_rev, ©from_path,
+ copy_root, copy_path, scratch_pool));
+
+ SVN_ERR(svn_fs_revision_root(node_root, svn_fs_root_fs(root),
+ copyfrom_rev, result_pool));
+ rel_path = svn_fspath__skip_ancestor(copy_path, path);
+ *node_path = svn_fspath__join(copyfrom_path, rel_path, result_pool);
+ }
+ else
+ {
+ svn_revnum_t revision;
+ svn_revnum_t previous_rev;
+
+ /* Determine the latest revision before ROOT. */
+ revision = svn_fs_revision_root_revision(root);
+ if (SVN_IS_VALID_REVNUM(revision))
+ previous_rev = revision - 1;
+ else
+ previous_rev = svn_fs_txn_root_base_revision(root);
+
+ SVN_ERR(svn_fs_revision_root(node_root, svn_fs_root_fs(root),
+ previous_rev, result_pool));
+ *node_path = apr_pstrdup(result_pool, path);
+ }
+
+ return SVN_NO_ERROR;
+}
Modified: subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py
URL:
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py?rev=1727838&r1=1727837&r2=1727838&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py (original)
+++ subversion/trunk/subversion/tests/cmdline/svnadmin_tests.py Sun Jan 31
16:18:26 2016
@@ -2286,35 +2286,134 @@ def verify_invalid_path_changes(sbox):
"--keep-going",
sbox.repo_dir)
- exp_out = svntest.verify.RegexListOutput([".*Verified revision 0.",
- ".*Verified revision 1.",
- ".*Verified revision 3.",
- ".*Verified revision 5.",
- ".*Verified revision 7.",
- ".*Verified revision 8.",
- ".*Verified revision 9.",
- ".*Verified revision 11.",
- ".*Verified revision 13.",
- ".*Verified revision 15.",
- ".*Verified revision 17.",
- ".*Verified revision 19.",
- ".*",
- ".*Summary.*",
- ".*r2: E160020:.*",
- ".*r2: E160020:.*",
- ".*r4: E160013:.*",
- ".*r6: E160013:.*",
- ".*r6: E160013:.*",
- ".*r10: E160013:.*",
- ".*r10: E160013:.*",
- ".*r12: E145001:.*",
- ".*r12: E145001:.*",
- ".*r14: E160013:.*",
- ".*r14: E160013:.*",
- ".*r16: E145001:.*",
- ".*r16: E145001:.*",
- ".*r18: E160013:.*",
- ".*r18: E160013:.*"])
+ # Errors generated by FSFS when CHANGED_PATHS is not forced into emulation
+ exp_out1 = svntest.verify.RegexListOutput([".*Verified revision 0.",
+ ".*Verified revision 1.",
+ ".*Verified revision 3.",
+ ".*Verified revision 5.",
+ ".*Verified revision 7.",
+ ".*Verified revision 8.",
+ ".*Verified revision 9.",
+ ".*Verified revision 11.",
+ ".*Verified revision 13.",
+ ".*Verified revision 15.",
+ ".*Verified revision 17.",
+ ".*Verified revision 19.",
+ ".*",
+ ".*Summary.*",
+ ".*r2: E160020:.*",
+ ".*r2: E160020:.*",
+ ".*r4: E160013:.*",
+ ".*r6: E160013:.*",
+ ".*r6: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r12: E145001:.*",
+ ".*r12: E145001:.*",
+ ".*r14: E160013:.*",
+ ".*r14: E160013:.*",
+ ".*r16: E145001:.*",
+ ".*r16: E145001:.*",
+ ".*r18: E160013:.*",
+ ".*r18: E160013:.*"])
+
+ exp_err1 = svntest.verify.RegexListOutput([".*Error verifying revision 2.",
+ "svnadmin: E160020:.*",
+ "svnadmin: E160020:.*",
+ ".*Error verifying revision 4.",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 6.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 10.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 12.",
+ "svnadmin: E145001:.*",
+ "svnadmin: E145001:.*",
+ ".*Error verifying revision 14.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 16.",
+ "svnadmin: E145001:.*",
+ "svnadmin: E145001:.*",
+ ".*Error verifying revision 18.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E160013:.*",
+ "svnadmin: E205012:.*"], False)
+
+ # If CHANGED_PATHS is emulated, FSFS fails earlier, generating fewer
+ # of the same messages per revision.
+ exp_out2 = svntest.verify.RegexListOutput([".*Verified revision 0.",
+ ".*Verified revision 1.",
+ ".*Verified revision 3.",
+ ".*Verified revision 5.",
+ ".*Verified revision 7.",
+ ".*Verified revision 8.",
+ ".*Verified revision 9.",
+ ".*Verified revision 11.",
+ ".*Verified revision 13.",
+ ".*Verified revision 15.",
+ ".*Verified revision 17.",
+ ".*Verified revision 19.",
+ ".*",
+ ".*Summary.*",
+ ".*r2: E160020:.*",
+ ".*r2: E160020:.*",
+ ".*r4: E160013:.*",
+ ".*r6: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r10: E160013:.*",
+ ".*r12: E145001:.*",
+ ".*r12: E145001:.*",
+ ".*r14: E160013:.*",
+ ".*r16: E145001:.*",
+ ".*r16: E145001:.*",
+ ".*r18: E160013:.*"])
+
+ exp_err2 = svntest.verify.RegexListOutput([".*Error verifying revision 2.",
+ "svnadmin: E160020:.*",
+ "svnadmin: E160020:.*",
+ ".*Error verifying revision 4.",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 6.",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 10.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 12.",
+ "svnadmin: E145001:.*",
+ "svnadmin: E145001:.*",
+ ".*Error verifying revision 14.",
+ "svnadmin: E160013:.*",
+ ".*Error verifying revision 16.",
+ "svnadmin: E145001:.*",
+ "svnadmin: E145001:.*",
+ ".*Error verifying revision 18.",
+ "svnadmin: E160013:.*",
+ "svnadmin: E205012:.*"], False)
+
+ # Determine which pattern to use.
+ # Note that index() will throw an exception if the string can't be found.
+ try:
+ rev6_line = errput.index('* Error verifying revision 6.\n');
+ rev10_line = errput.index('* Error verifying revision 10.\n');
+
+ error_count = 0
+ for line in errput[rev6_line+1:rev10_line]:
+ if "svnadmin: E" in line:
+ error_count = error_count + 1
+
+ if error_count == 1:
+ exp_out = exp_out2
+ exp_err = exp_err2
+ else:
+ exp_out = exp_out1
+ exp_err = exp_err1
+ except ValueError:
+ exp_out = exp_out1
+ exp_err = exp_err1
+
if (svntest.main.fs_has_rep_sharing()):
exp_out.insert(0, ".*Verifying.*metadata.*")
if svntest.main.options.fsfs_sharding is not None:
@@ -2323,32 +2422,6 @@ def verify_invalid_path_changes(sbox):
if svntest.main.is_fs_log_addressing():
exp_out.insert(0, ".*Verifying.*metadata.*")
- exp_err = svntest.verify.RegexListOutput([".*Error verifying revision 2.",
- "svnadmin: E160020:.*",
- "svnadmin: E160020:.*",
- ".*Error verifying revision 4.",
- "svnadmin: E160013:.*",
- ".*Error verifying revision 6.",
- "svnadmin: E160013:.*",
- "svnadmin: E160013:.*",
- ".*Error verifying revision 10.",
- "svnadmin: E160013:.*",
- "svnadmin: E160013:.*",
- ".*Error verifying revision 12.",
- "svnadmin: E145001:.*",
- "svnadmin: E145001:.*",
- ".*Error verifying revision 14.",
- "svnadmin: E160013:.*",
- "svnadmin: E160013:.*",
- ".*Error verifying revision 16.",
- "svnadmin: E145001:.*",
- "svnadmin: E145001:.*",
- ".*Error verifying revision 18.",
- "svnadmin: E160013:.*",
- "svnadmin: E160013:.*",
- "svnadmin: E205012:.*"], False)
-
-
if svntest.verify.verify_outputs("Unexpected error while running 'svnadmin
verify'.",
output, errput, exp_out, exp_err):
raise svntest.Failure