You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2013/10/16 00:57:09 UTC
svn commit: r1532583 [4/10] - in /subversion/branches/fsfs-improvements: ./
build/ac-macros/ build/generator/ build/generator/templates/ build/win32/
contrib/client-side/emacs/ notes/ subversion/bindings/javahl/native/
subversion/bindings/javahl/src/or...
Modified: subversion/branches/fsfs-improvements/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/include/svn_repos.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/include/svn_repos.h (original)
+++ subversion/branches/fsfs-improvements/subversion/include/svn_repos.h Tue Oct 15 22:57:03 2013
@@ -1794,6 +1794,9 @@ svn_repos_node_location_segments(svn_rep
* filesystem, as limited by @a paths. In the latter case those revisions
* are skipped and @a receiver is not invoked.
*
+ * @a move_behavior defines which changes are being reported as moves.
+ * See #svn_move_behavior_t for the various options.
+ *
* If @a revprops is NULL, retrieve all revision properties; else, retrieve
* only the revision properties named by the (const char *) array elements
* (i.e. retrieve none if the array is empty).
@@ -1818,8 +1821,33 @@ svn_repos_node_location_segments(svn_rep
*
* Use @a pool for temporary allocations.
*
+ * @since New in 1.9.
+ */
+svn_error_t *
+svn_repos_get_logs5(svn_repos_t *repos,
+ const apr_array_header_t *paths,
+ svn_revnum_t start,
+ svn_revnum_t end,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
+ const apr_array_header_t *revprops,
+ svn_repos_authz_func_t authz_read_func,
+ void *authz_read_baton,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ apr_pool_t *pool);
+
+/**
+ * Same as svn_repos_get_logs5(), but with @a move_behavior being set to
+ * #svn_fs_move_behavior_no_moves.
+ *
* @since New in 1.5.
+ * @deprecated Provided for backward compatibility with the 1.8 API.
*/
+SVN_DEPRECATED
svn_error_t *
svn_repos_get_logs4(svn_repos_t *repos,
const apr_array_header_t *paths,
Modified: subversion/branches/fsfs-improvements/subversion/include/svn_types.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/include/svn_types.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/include/svn_types.h (original)
+++ subversion/branches/fsfs-improvements/subversion/include/svn_types.h Tue Oct 15 22:57:03 2013
@@ -64,6 +64,26 @@ extern "C" {
#endif
+/** Macro used to mark experimental functions.
+ *
+ * @since New in 1.9.
+ */
+#ifndef SVN_EXPERIMENTAL
+# if !defined(SWIGPERL) && !defined(SWIGPYTHON) && !defined(SWIGRUBY)
+# if !defined(__clang__) && defined(__GNUC__) \
+ && (__GNUC__ >= 4 || (__GNUC__==3 && __GNUC_MINOR__>=1))
+# define SVN_EXPERIMENTAL __attribute__((warning("experimental function used")))
+# elif defined(_MSC_VER) && _MSC_VER >= 1300
+# define SVN_EXPERIMENTAL __declspec(deprecated("experimental function used"))
+# else
+# define SVN_EXPERIMENTAL
+# endif
+# else
+# define SVN_EXPERIMENTAL
+# endif
+#endif
+
+
/** Indicate whether the current platform supports unaligned data access.
*
* On the majority of machines running SVN (x86 / x64), unaligned access
@@ -219,6 +239,16 @@ svn__apr_hash_index_val(const apr_hash_i
|| ((s) == APR_OS_START_SYSERR + ERROR_INVALID_NAME))
#endif
+/** On Windows, APR_STATUS_IS_EPIPE does not include ERROR_NO_DATA error.
+ * So we include it.*/
+/* ### These fixes should go into APR. */
+#ifndef WIN32
+#define SVN__APR_STATUS_IS_EPIPE(s) APR_STATUS_IS_EPIPE(s)
+#else
+#define SVN__APR_STATUS_IS_EPIPE(s) (APR_STATUS_IS_EPIPE(s) \
+ || ((s) == APR_OS_START_SYSERR + ERROR_NO_DATA))
+#endif
+
/** @} */
@@ -752,7 +782,7 @@ svn_commit_info_dup(const svn_commit_inf
*/
typedef struct svn_log_changed_path2_t
{
- /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify */
+ /** 'A'dd, 'D'elete, 'R'eplace, 'M'odify, mo'V'ed, move-replac'E'd */
char action;
/** Source path of copy (if any). */
@@ -991,6 +1021,28 @@ typedef svn_error_t *(*svn_log_message_r
const char *message,
apr_pool_t *pool);
+/**
+ * This enumeration contains the various options how SVN shall report
+ * and process explicit MOVes as well as ADD+DEL pairs.
+ *
+ * @since New in 1.9.
+ */
+typedef enum svn_move_behavior_t
+{
+ /* report all moves as ADD with history.
+ This also provides backward compatibility with 1.8 clients. */
+ svn_move_behavior_no_moves = 0,
+
+ /* report all changes, including moves, as they were reported.
+ This is option with the least overhead. */
+ svn_move_behavior_explicit_moves,
+
+ /* in addition to explicit moves, try to find matching DEL + ADD pairs
+ and report the ADD in those as moves as well. Which of the eligible
+ DEL + ADD pairs will be detected is implementation-dependent. */
+ svn_move_behavior_auto_moves
+} svn_move_behavior_t;
+
/** Callback function type for commits.
Modified: subversion/branches/fsfs-improvements/subversion/include/svn_version.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/include/svn_version.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/include/svn_version.h (original)
+++ subversion/branches/fsfs-improvements/subversion/include/svn_version.h Tue Oct 15 22:57:03 2013
@@ -28,15 +28,13 @@
#define SVN_VERSION_H
/* Hack to prevent the resource compiler from including
- apr_general.h. It doesn't resolve the include paths
- correctly and blows up without this.
- */
-#ifndef APR_STRINGIFY
+ apr and other headers. */
+#ifndef SVN_WIN32_RESOURCE_COMPILATION
#include <apr_general.h>
-#endif
#include <apr_tables.h>
#include "svn_types.h"
+#endif
#ifdef __cplusplus
extern "C" {
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/copy.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/copy.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/copy.c Tue Oct 15 22:57:03 2013
@@ -1945,6 +1945,9 @@ try_copy(svn_boolean_t *timestamp_sleep,
svn_boolean_t srcs_are_urls, dst_is_url;
int i;
+ /* Assert instead of crashing if the sources list is empty. */
+ SVN_ERR_ASSERT(sources->nelts > 0);
+
/* Are either of our paths URLs? Just check the first src_path. If
there are more than one, we'll check for homogeneity among them
down below. */
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/deprecated.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/deprecated.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/deprecated.c Tue Oct 15 22:57:03 2013
@@ -1498,6 +1498,28 @@ svn_client_ls(apr_hash_t **dirents,
}
/*** From log.c ***/
+
+svn_error_t *
+svn_client_log5(const apr_array_header_t *targets,
+ const svn_opt_revision_t *peg_revision,
+ const apr_array_header_t *revision_ranges,
+ int limit,
+ svn_boolean_t discover_changed_paths,
+ svn_boolean_t strict_node_history,
+ svn_boolean_t include_merged_revisions,
+ const apr_array_header_t *revprops,
+ svn_log_entry_receiver_t receiver,
+ void *receiver_baton,
+ svn_client_ctx_t *ctx,
+ apr_pool_t *pool)
+{
+ return svn_client_log6(targets, peg_revision, revision_ranges, limit,
+ discover_changed_paths, strict_node_history,
+ include_merged_revisions,
+ svn_move_behavior_no_moves, revprops, receiver,
+ receiver_baton, ctx, pool);
+}
+
svn_error_t *
svn_client_log4(const apr_array_header_t *targets,
const svn_opt_revision_t *peg_revision,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/externals.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/externals.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/externals.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/externals.c Tue Oct 15 22:57:03 2013
@@ -738,7 +738,7 @@ handle_external_item_change(svn_client_c
switch (ext_kind)
{
case svn_node_dir:
- SVN_ERR(switch_dir_external(local_abspath, new_url,
+ SVN_ERR(switch_dir_external(local_abspath, new_loc->url,
&(new_item->peg_revision),
&(new_item->revision),
parent_dir_abspath,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/log.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/log.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/log.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/log.c Tue Oct 15 22:57:03 2013
@@ -610,6 +610,7 @@ run_ra_get_log(apr_array_header_t *revis
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t real_receiver,
void *real_receiver_baton,
@@ -768,7 +769,7 @@ run_ra_get_log(apr_array_header_t *revis
passed_receiver_baton = &lb;
}
- SVN_ERR(svn_ra_get_log2(ra_session,
+ SVN_ERR(svn_ra_get_log3(ra_session,
paths,
range->range_start,
range->range_end,
@@ -776,6 +777,7 @@ run_ra_get_log(apr_array_header_t *revis
discover_changed_paths,
strict_node_history,
include_merged_revisions,
+ move_behavior,
passed_receiver_revprops,
passed_receiver,
passed_receiver_baton,
@@ -798,13 +800,14 @@ run_ra_get_log(apr_array_header_t *revis
/*** Public Interface. ***/
svn_error_t *
-svn_client_log5(const apr_array_header_t *targets,
+svn_client_log6(const apr_array_header_t *targets,
const svn_opt_revision_t *peg_revision,
const apr_array_header_t *opt_rev_ranges,
int limit,
svn_boolean_t discover_changed_paths,
svn_boolean_t strict_node_history,
svn_boolean_t include_merged_revisions,
+ svn_move_behavior_t move_behavior,
const apr_array_header_t *revprops,
svn_log_entry_receiver_t real_receiver,
void *real_receiver_baton,
@@ -890,8 +893,8 @@ svn_client_log5(const apr_array_header_t
SVN_ERR(run_ra_get_log(revision_ranges, relative_targets, log_segments,
actual_loc, ra_session, targets, limit,
discover_changed_paths, strict_node_history,
- include_merged_revisions, revprops, real_receiver,
- real_receiver_baton, ctx, pool));
+ include_merged_revisions, move_behavior, revprops,
+ real_receiver, real_receiver_baton, ctx, pool));
return SVN_NO_ERROR;
}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/merge.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/merge.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/merge.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/merge.c Tue Oct 15 22:57:03 2013
@@ -10715,7 +10715,7 @@ log_find_operative_revs(void *baton,
suffix = svn_relpath_skip_ancestor(subtree_missing_this_rev,
source_rel_path);
- if (suffix)
+ if (suffix && suffix[0] != '\0')
{
missing_path = apr_pstrmemdup(pool, path,
strlen(path) - strlen(suffix) - 1);
@@ -12301,7 +12301,16 @@ find_base_on_target(svn_client__pathrev_
return SVN_NO_ERROR;
}
-/* The body of client_find_automatic_merge(), which see.
+/* Find the last point at which the branch at S_T->source was completely
+ * merged to the branch at S_T->target or vice-versa.
+ *
+ * Fill in S_T->source_branch and S_T->target_branch and S_T->yca.
+ * Set *BASE_P to the merge base. Set *IS_REINTEGRATE_LIKE to true if
+ * an automatic merge from source to target would be a reintegration
+ * merge: that is, if the last automatic merge was in the opposite
+ * direction; or to false otherwise.
+ *
+ * If there is no youngest common ancestor, throw an error.
*/
static svn_error_t *
find_automatic_merge(svn_client__pathrev_t **base_p,
@@ -12371,6 +12380,9 @@ find_automatic_merge(svn_client__pathrev
* Like find_automatic_merge() except that the target is
* specified by @a target_path_or_url at @a target_revision, which must
* refer to a repository location, instead of by a WC path argument.
+ *
+ * Set *MERGE_P to a new structure with all fields filled in except the
+ * 'allow_*' flags.
*/
static svn_error_t *
find_automatic_merge_no_wc(automatic_merge_t **merge_p,
@@ -12446,6 +12458,8 @@ client_find_automatic_merge(automatic_me
source_and_target_t *s_t = apr_palloc(result_pool, sizeof(*s_t));
automatic_merge_t *merge = apr_palloc(result_pool, sizeof(*merge));
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(target_abspath));
+
/* "Open" the target WC. Check the target WC for mixed-rev, local mods and
* switched subtrees yet to faster exit and notify user before contacting
* with server. After we find out what kind of merge is required, then if a
@@ -12477,6 +12491,7 @@ client_find_automatic_merge(automatic_me
ctx, result_pool, scratch_pool));
merge->yca = s_t->yca;
merge->right = s_t->source;
+ merge->target = &s_t->target->loc;
merge->allow_mixed_rev = allow_mixed_rev;
merge->allow_local_mods = allow_local_mods;
merge->allow_switched_subtrees = allow_switched_subtrees;
@@ -12667,12 +12682,18 @@ svn_client_get_merging_summary(svn_boole
&& (target_revision->kind == svn_opt_revision_unspecified
|| target_revision->kind == svn_opt_revision_working);
if (target_is_wc)
- SVN_ERR(client_find_automatic_merge(
- &merge,
- source_path_or_url, source_revision,
- target_path_or_url,
- TRUE, TRUE, TRUE, /* allow_* */
- ctx, scratch_pool, scratch_pool));
+ {
+ const char *target_abspath;
+
+ SVN_ERR(svn_dirent_get_absolute(&target_abspath, target_path_or_url,
+ scratch_pool));
+ SVN_ERR(client_find_automatic_merge(
+ &merge,
+ source_path_or_url, source_revision,
+ target_abspath,
+ TRUE, TRUE, TRUE, /* allow_* */
+ ctx, scratch_pool, scratch_pool));
+ }
else
SVN_ERR(find_automatic_merge_no_wc(
&merge,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/mergeinfo.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/mergeinfo.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/mergeinfo.c Tue Oct 15 22:57:03 2013
@@ -1405,17 +1405,21 @@ filter_log_entry_with_rangelist(void *ba
obviously back. If it was added or replaced it's still around
possibly it was replaced one or more times, but it's back now.
Regardless, LOG_ENTRY->REVISION is *not* an eligible revision! */
- if (ancestor_is_self /* Explicit mergeinfo on TARGET_PATH_AFFECTED */
+ if (nearest_ancestor_mergeinfo &&
+ ancestor_is_self /* Explicit mergeinfo on TARGET_PATH_AFFECTED */
&& (change->action != 'M'))
{
svn_rangelist_t *rangelist =
svn_hash_gets(nearest_ancestor_mergeinfo, path);
- svn_merge_range_t *youngest_range = APR_ARRAY_IDX(
- rangelist, rangelist->nelts - 1, svn_merge_range_t *);
+ if (rangelist)
+ {
+ svn_merge_range_t *youngest_range = APR_ARRAY_IDX(
+ rangelist, rangelist->nelts - 1, svn_merge_range_t *);
- if (youngest_range
- && (youngest_range->end > log_entry->revision))
- continue;
+ if (youngest_range
+ && (youngest_range->end > log_entry->revision))
+ continue;
+ }
}
if (nearest_ancestor_mergeinfo)
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_client/ra.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_client/ra.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_client/ra.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_client/ra.c Tue Oct 15 22:57:03 2013
@@ -350,6 +350,10 @@ svn_client__open_ra_session_internal(svn
cbtable->get_client_string = get_client_string;
if (base_dir_abspath)
cbtable->get_wc_contents = get_wc_contents;
+ cbtable->check_tunnel_func = ctx->check_tunnel_func;
+ cbtable->open_tunnel_func = ctx->open_tunnel_func;
+ cbtable->close_tunnel_func = ctx->close_tunnel_func;
+ cbtable->tunnel_baton = ctx->tunnel_baton;
cb->commit_items = commit_items;
cb->ctx = ctx;
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_delta/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_delta/compat.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_delta/compat.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_delta/compat.c Tue Oct 15 22:57:03 2013
@@ -1330,17 +1330,6 @@ move_cb(void *baton,
return SVN_NO_ERROR;
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- SVN__NOT_IMPLEMENTED();
-}
-
-
static int
count_components(const char *relpath)
{
@@ -1888,7 +1877,6 @@ svn_delta__editor_from_delta(svn_editor_
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_delta/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_delta/editor.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_delta/editor.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_delta/editor.c Tue Oct 15 22:57:03 2013
@@ -391,16 +391,6 @@ svn_editor_setcb_move(svn_editor_t *edit
svn_error_t *
-svn_editor_setcb_rotate(svn_editor_t *editor,
- svn_editor_cb_rotate_t callback,
- apr_pool_t *scratch_pool)
-{
- editor->funcs.cb_rotate = callback;
- return SVN_NO_ERROR;
-}
-
-
-svn_error_t *
svn_editor_setcb_complete(svn_editor_t *editor,
svn_editor_cb_complete_t callback,
apr_pool_t *scratch_pool)
@@ -437,7 +427,6 @@ svn_editor_setcb_many(svn_editor_t *edit
COPY_CALLBACK(cb_delete);
COPY_CALLBACK(cb_copy);
COPY_CALLBACK(cb_move);
- COPY_CALLBACK(cb_rotate);
COPY_CALLBACK(cb_complete);
COPY_CALLBACK(cb_abort);
@@ -862,56 +851,6 @@ svn_editor_move(svn_editor_t *editor,
svn_error_t *
-svn_editor_rotate(svn_editor_t *editor,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions)
-{
- svn_error_t *err = SVN_NO_ERROR;
-
- SHOULD_NOT_BE_FINISHED(editor);
-#ifdef ENABLE_ORDERING_CHECK
- {
- int i;
- for (i = 0; i < relpaths->nelts; i++)
- {
- const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
-
- SVN_ERR_ASSERT(svn_relpath_is_canonical(relpath));
- SHOULD_NOT_BE_COMPLETED(editor, relpath);
- VERIFY_PARENT_MAY_EXIST(editor, relpath);
- CHILD_DELETIONS_ALLOWED(editor, relpath);
- }
- }
-#endif
-
- SVN_ERR(check_cancel(editor));
-
- if (editor->funcs.cb_rotate)
- {
- START_CALLBACK(editor);
- err = editor->funcs.cb_rotate(editor->baton, relpaths, revisions,
- editor->scratch_pool);
- END_CALLBACK(editor);
- }
-
-#ifdef ENABLE_ORDERING_CHECK
- {
- int i;
- for (i = 0; i < relpaths->nelts; i++)
- {
- const char *relpath = APR_ARRAY_IDX(relpaths, i, const char *);
- MARK_ALLOW_ALTER(editor, relpath);
- MARK_PARENT_STABLE(editor, relpath);
- }
- }
-#endif
-
- svn_pool_clear(editor->scratch_pool);
- return svn_error_trace(err);
-}
-
-
-svn_error_t *
svn_editor_complete(svn_editor_t *editor)
{
svn_error_t *err = SVN_NO_ERROR;
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs/editor.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs/editor.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs/editor.c Tue Oct 15 22:57:03 2013
@@ -177,7 +177,7 @@ can_modify(svn_fs_root_t *txn_root,
SVN_ERR(svn_fs_node_created_rev(&created_rev, txn_root, fspath,
scratch_pool));
- /* Uncommitted nodes (eg. a descendent of a copy/move/rotate destination)
+ /* Uncommitted nodes (eg. a descendent of a copy/move destination)
have no (committed) revision number. Let the caller go ahead and
modify these nodes.
@@ -195,7 +195,7 @@ can_modify(svn_fs_root_t *txn_root,
have supplied a valid revision number [that they expect to change].
The checks further below will determine the out-of-dateness of the
specified revision. */
- /* ### ugh. descendents of copy/move/rotate destinations carry along
+ /* ### ugh. descendents of copy/move destinations carry along
### their original immutable state and (thus) a valid CREATED_REV.
### but they are logically uncommitted, so the caller will pass
### SVN_INVALID_REVNUM. (technically, the caller could provide
@@ -205,7 +205,7 @@ can_modify(svn_fs_root_t *txn_root,
### for now, we will assume the caller knows what they are doing
### and an invalid revision implies such a descendent. in the
### future, we could examine the ancestor chain looking for a
- ### copy/move/rotate-here node and allow the modification (and the
+ ### copy/move-here node and allow the modification (and the
### converse: if no such ancestor, the caller must specify the
### correct/intended revision to modify).
*/
@@ -299,7 +299,7 @@ can_create(svn_fs_root_t *txn_root,
### test the ancestor to determine if it has been *-here in this
### txn, or just a simple modification. */
- /* Are any of the parents copied/moved/rotated-here? */
+ /* Are any of the parents copied/moved-here? */
for (cur_fspath = fspath;
strlen(cur_fspath) > 1; /* not the root */
cur_fspath = svn_fspath__dirname(cur_fspath, scratch_pool))
@@ -633,19 +633,6 @@ move_cb(void *baton,
}
-/* This implements svn_editor_cb_rotate_t */
-static svn_error_t *
-rotate_cb(void *baton,
- const apr_array_header_t *relpaths,
- const apr_array_header_t *revisions,
- apr_pool_t *scratch_pool)
-{
- struct edit_baton *eb = baton;
-
- UNUSED(eb); SVN__NOT_IMPLEMENTED();
-}
-
-
/* This implements svn_editor_cb_complete_t */
static svn_error_t *
complete_cb(void *baton,
@@ -714,7 +701,6 @@ make_editor(svn_editor_t **editor,
delete_cb,
copy_cb,
move_cb,
- rotate_cb,
complete_cb,
abort_cb
};
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.c Tue Oct 15 22:57:03 2013
@@ -24,6 +24,7 @@
#include <string.h>
#include <apr.h>
+#include <apr_atomic.h>
#include <apr_hash.h>
#include <apr_md5.h>
#include <apr_thread_mutex.h>
@@ -41,6 +42,7 @@
#include "svn_xml.h"
#include "svn_pools.h"
#include "svn_string.h"
+#include "svn_sorts.h"
#include "private/svn_fs_private.h"
#include "private/svn_fs_util.h"
@@ -70,6 +72,7 @@ struct fs_type_defn {
const char *fs_type;
const char *fsap_name;
fs_init_func_t initfunc;
+ fs_library_vtable_t *vtable;
struct fs_type_defn *next;
};
@@ -81,7 +84,9 @@ static struct fs_type_defn base_defn =
#else
NULL,
#endif
- NULL
+ NULL,
+ NULL /* End of static list: this needs to be reset to NULL if the
+ common_pool used when setting it has been cleared. */
};
static struct fs_type_defn fsx_defn =
@@ -92,6 +97,7 @@ static struct fs_type_defn fsx_defn =
#else
NULL,
#endif
+ NULL,
&base_defn
};
@@ -103,6 +109,7 @@ static struct fs_type_defn fsfs_defn =
#else
NULL,
#endif
+ NULL,
&fsx_defn
};
@@ -158,13 +165,20 @@ load_module(fs_init_func_t *initfunc, co
/* Fetch a library vtable by a pointer into the library definitions array. */
static svn_error_t *
get_library_vtable_direct(fs_library_vtable_t **vtable,
- const struct fs_type_defn *fst,
+ struct fs_type_defn *fst,
apr_pool_t *pool)
{
fs_init_func_t initfunc = NULL;
const svn_version_t *my_version = svn_fs_version();
const svn_version_t *fs_version;
+ /* most times, we get lucky */
+ *vtable = apr_atomic_casptr((volatile void **)&fst->vtable, NULL, NULL);
+ if (*vtable)
+ return SVN_NO_ERROR;
+
+ /* o.k. the first access needs to actually load the module, find the
+ vtable and check for version compatibility. */
initfunc = fst->initfunc;
if (! initfunc)
SVN_ERR(load_module(&initfunc, fst->fsap_name, pool));
@@ -201,6 +215,10 @@ get_library_vtable_direct(fs_library_vta
my_version->patch, my_version->tag,
fs_version->major, fs_version->minor,
fs_version->patch, fs_version->tag);
+
+ /* the vtable will not change. Remember it */
+ apr_atomic_casptr((volatile void **)&fst->vtable, *vtable, NULL);
+
return SVN_NO_ERROR;
}
@@ -364,6 +382,7 @@ svn_fs_initialize(apr_pool_t *pool)
return SVN_NO_ERROR;
common_pool = svn_pool_create(pool);
+ base_defn.next = NULL;
SVN_ERR(svn_mutex__init(&common_pool_lock, TRUE, common_pool));
/* ### This won't work if POOL is NULL and libsvn_fs is loaded as a DSO
@@ -467,8 +486,7 @@ svn_fs_create(svn_fs_t **fs_p, const cha
/* Perform the actual creation. */
*fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(*fs_p, path, pool, common_pool));
+ SVN_ERR(vtable->create(*fs_p, path, common_pool_lock, pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
return SVN_NO_ERROR;
@@ -482,8 +500,7 @@ svn_fs_open(svn_fs_t **fs_p, const char
SVN_ERR(fs_library_vtable(&vtable, path, pool));
*fs_p = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(*fs_p, path, pool, common_pool));
+ SVN_ERR(vtable->open_fs(*fs_p, path, common_pool_lock, pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(*fs_p, svn_fs_open));
return SVN_NO_ERROR;
@@ -503,11 +520,11 @@ svn_fs_upgrade2(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->upgrade_fs(fs, path,
- notify_func, notify_baton,
- cancel_func, cancel_baton,
- pool, common_pool));
+ SVN_ERR(vtable->upgrade_fs(fs, path,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ common_pool_lock,
+ pool, common_pool));
return SVN_NO_ERROR;
}
@@ -534,11 +551,11 @@ svn_fs_verify(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(fs_config, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->verify_fs(fs, path, start, end,
- notify_func, notify_baton,
- cancel_func, cancel_baton,
- pool, common_pool));
+ SVN_ERR(vtable->verify_fs(fs, path, start, end,
+ notify_func, notify_baton,
+ cancel_func, cancel_baton,
+ common_pool_lock,
+ pool, common_pool));
return SVN_NO_ERROR;
}
@@ -649,10 +666,9 @@ svn_fs_pack(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->pack_fs(fs, path, notify_func, notify_baton,
- cancel_func, cancel_baton, pool,
- common_pool));
+ SVN_ERR(vtable->pack_fs(fs, path, notify_func, notify_baton,
+ cancel_func, cancel_baton, common_pool_lock,
+ pool, common_pool));
return SVN_NO_ERROR;
}
@@ -667,9 +683,8 @@ svn_fs_recover(const char *path,
SVN_ERR(fs_library_vtable(&vtable, path, pool));
fs = fs_new(NULL, pool);
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs_for_recovery(fs, path, pool,
- common_pool));
+ SVN_ERR(vtable->open_fs_for_recovery(fs, path, common_pool_lock,
+ pool, common_pool));
return svn_error_trace(vtable->recover(fs, cancel_func, cancel_baton,
pool));
}
@@ -710,8 +725,7 @@ svn_fs_create_berkeley(svn_fs_t *fs, con
SVN_ERR(write_fs_type(path, SVN_FS_TYPE_BDB, fs->pool));
/* Perform the actual creation. */
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->create(fs, path, fs->pool, common_pool));
+ SVN_ERR(vtable->create(fs, path, common_pool_lock, fs->pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
return SVN_NO_ERROR;
@@ -723,8 +737,7 @@ svn_fs_open_berkeley(svn_fs_t *fs, const
fs_library_vtable_t *vtable;
SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
- SVN_MUTEX__WITH_LOCK(common_pool_lock,
- vtable->open_fs(fs, path, fs->pool, common_pool));
+ SVN_ERR(vtable->open_fs(fs, path, common_pool_lock, fs->pool, common_pool));
SVN_ERR(vtable->set_svn_fs_open(fs, svn_fs_open));
return SVN_NO_ERROR;
@@ -976,11 +989,177 @@ svn_fs_revision_root_revision(svn_fs_roo
return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
}
+/* Return TRUE, if CHANGE deleted the node previously found at its target
+ path. */
+static svn_boolean_t
+is_deletion(svn_fs_path_change2_t *change)
+{
+ return change->change_kind == svn_fs_path_change_movereplace
+ || change->change_kind == svn_fs_path_change_replace
+ || change->change_kind == svn_fs_path_change_delete;
+}
+
+/* Change all moves in CHANGES to ADD. Use POOL for temporary allocations.
+ */
+static void
+turn_moves_into_copies(apr_hash_t *changes,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_fs_path_change2_t *change;
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+
+ switch (change->change_kind)
+ {
+ case svn_fs_path_change_move:
+ change->change_kind = svn_fs_path_change_add;
+ break;
+
+ case svn_fs_path_change_movereplace:
+ change->change_kind = svn_fs_path_change_replace;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/* Replace ADDs with MOVes, if they are unique, have a matching deletion
+ * and if the copy-from revision is REVISION-1. Use POOL for temporary
+ * allocations.
+ */
+static void
+turn_unique_copies_into_moves(apr_hash_t *changes,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *hi;
+ apr_hash_t *unique_copy_sources;
+ const char **sources;
+ int i;
+
+ /* find all copy-from paths (ADD and MOV alike) */
+
+ svn_boolean_t any_deletion = FALSE;
+ apr_array_header_t *copy_sources
+ = apr_array_make(pool, apr_hash_count(changes), sizeof(const char*));
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ svn_fs_path_change2_t *change;
+ apr_hash_this(hi, NULL, NULL, (void**)&change);
+
+ if (change->copyfrom_path && change->copyfrom_rev == revision-1)
+ APR_ARRAY_PUSH(copy_sources, const char *)
+ = change->copyfrom_path;
+
+ any_deletion |= is_deletion(change);
+ }
+
+ /* no suitable copy-from or no deletion -> no moves */
+
+ if (!copy_sources->nelts || !any_deletion)
+ return;
+
+ /* identify copy-from paths that have been mentioned exactly once */
+
+ sources = (const char **)copy_sources->elts;
+ qsort(sources, copy_sources->nelts, copy_sources->elt_size,
+ (int (*)(const void *, const void *))svn_sort_compare_paths);
+
+ unique_copy_sources = apr_hash_make(pool);
+ for (i = 0; i < copy_sources->nelts; ++i)
+ if ( (i == 0 || strcmp(sources[i-1], sources[i]))
+ && (i == copy_sources->nelts-1 || strcmp(sources[i+1], sources[i])))
+ {
+ apr_hash_set(unique_copy_sources, sources[i],
+ APR_HASH_KEY_STRING, sources[i]);
+ }
+
+ /* no unique copy-from paths -> no moves */
+
+ if (!apr_hash_count(unique_copy_sources))
+ return;
+
+ /* Replace all additions, replacements with a unique copy-from path,
+ the correct copy-from rev and a matching deletion in this revision,
+ with moves and move-replacements, respectively. */
+
+ for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
+ {
+ const char *key;
+ apr_ssize_t klen;
+ svn_fs_path_change2_t *change, *copy_from_change;
+
+ apr_hash_this(hi, (const void **)&key, &klen, (void**)&change);
+ if ( change->copyfrom_rev != revision-1
+ || !change->copyfrom_path
+ || !apr_hash_get(unique_copy_sources, change->copyfrom_path,
+ APR_HASH_KEY_STRING))
+ continue;
+
+ copy_from_change = apr_hash_get(changes, change->copyfrom_path,
+ APR_HASH_KEY_STRING);
+ if (!copy_from_change || !is_deletion(copy_from_change))
+ continue;
+
+ /* There is a deletion of the ADD's copy-from path in *REVISION*.
+ This can either be the same as in REVISION-1 (o.k.) or must have
+ been replaced by some other node. However, that would imply that
+ it still got deleted as part of the replacement, i.e. both cases
+ are o.k. */
+
+ switch (change->change_kind)
+ {
+ case svn_fs_path_change_add:
+ change->change_kind = svn_fs_path_change_move;
+ break;
+
+ case svn_fs_path_change_replace:
+ change->change_kind = svn_fs_path_change_movereplace;
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+svn_error_t *
+svn_fs_paths_changed3(apr_hash_t **changed_paths_p,
+ svn_fs_root_t *root,
+ svn_move_behavior_t move_behavior,
+ apr_pool_t *pool)
+{
+ SVN_ERR(root->vtable->paths_changed(changed_paths_p, root, pool));
+ switch(move_behavior)
+ {
+ case svn_move_behavior_no_moves:
+ turn_moves_into_copies(*changed_paths_p, pool);
+ break;
+
+ case svn_move_behavior_auto_moves:
+ turn_unique_copies_into_moves(*changed_paths_p, root->rev, pool);
+ break;
+
+ default:
+ break;
+ }
+
+ 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);
+ return svn_fs_paths_changed3(changed_paths_p, root,
+ svn_move_behavior_no_moves, pool);
}
svn_error_t *
@@ -990,7 +1169,8 @@ svn_fs_paths_changed(apr_hash_t **change
apr_hash_t *changed_paths_new_structs;
apr_hash_index_t *hi;
- SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
+ SVN_ERR(svn_fs_paths_changed3(&changed_paths_new_structs, root,
+ svn_move_behavior_no_moves, pool));
*changed_paths_p = apr_hash_make(pool);
for (hi = apr_hash_first(pool, changed_paths_new_structs);
hi;
@@ -1224,6 +1404,15 @@ svn_fs_revision_link(svn_fs_root_t *from
}
svn_error_t *
+svn_fs_move(svn_fs_root_t *from_root, const char *from_path,
+ svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
+{
+ SVN_ERR(svn_fs__path_valid(to_path, pool));
+ return svn_error_trace(to_root->vtable->move(from_root, from_path,
+ to_root, to_path, pool));
+}
+
+svn_error_t *
svn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
const char *path, apr_pool_t *pool)
{
@@ -1623,7 +1812,7 @@ svn_error_t *
svn_fs_print_modules(svn_stringbuf_t *output,
apr_pool_t *pool)
{
- const struct fs_type_defn *defn = fs_modules;
+ struct fs_type_defn *defn = fs_modules;
fs_library_vtable_t *vtable;
apr_pool_t *iterpool = svn_pool_create(pool);
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs/fs-loader.h Tue Oct 15 22:57:03 2013
@@ -27,6 +27,7 @@
#include "svn_types.h"
#include "svn_fs.h"
+#include "private/svn_mutex.h"
#ifdef __cplusplus
extern "C" {
@@ -72,17 +73,22 @@ typedef struct fs_library_vtable_t
this statement, now that the minor version has increased. */
const svn_version_t *(*get_version)(void);
- /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions are
- serialized so that they may use the common_pool parameter to
- allocate fs-global objects such as the bdb env cache. */
- svn_error_t *(*create)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+ /* The open_fs/create/open_fs_for_recovery/upgrade_fs functions must
+ use the common_pool_lock to serialize the access to the common_pool
+ parameter for allocating fs-global objects such as an env cache. */
+ svn_error_t *(*create)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool);
- svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+ svn_error_t *(*open_fs)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool);
/* open_for_recovery() is like open(), but used to fill in an fs pointer
that will be passed to recover(). We assume that the open() method
might not be immediately appropriate for recovery. */
svn_error_t *(*open_fs_for_recovery)(svn_fs_t *fs, const char *path,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool);
svn_error_t *(*upgrade_fs)(svn_fs_t *fs,
@@ -91,6 +97,7 @@ typedef struct fs_library_vtable_t
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool);
svn_error_t *(*verify_fs)(svn_fs_t *fs, const char *path,
@@ -100,6 +107,7 @@ typedef struct fs_library_vtable_t
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool);
svn_error_t *(*delete_fs)(const char *path, apr_pool_t *pool);
@@ -115,6 +123,7 @@ typedef struct fs_library_vtable_t
svn_error_t *(*pack_fs)(svn_fs_t *fs, const char *path,
svn_fs_pack_notify_t notify_func, void *notify_baton,
svn_cancel_func_t cancel_func, void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool, apr_pool_t *common_pool);
/* Provider-specific functions should go here, even if they could go
@@ -301,6 +310,16 @@ typedef struct root_vtable_t
apr_pool_t *pool);
svn_error_t *(*delete_node)(svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
+ svn_error_t *(*copy)(svn_fs_root_t *from_root, const char *from_path,
+ svn_fs_root_t *to_root, const char *to_path,
+ apr_pool_t *pool);
+ svn_error_t *(*revision_link)(svn_fs_root_t *from_root,
+ svn_fs_root_t *to_root,
+ const char *path,
+ apr_pool_t *pool);
+ svn_error_t *(*move)(svn_fs_root_t *from_root, const char *from_path,
+ svn_fs_root_t *to_root, const char *to_path,
+ apr_pool_t *pool);
svn_error_t *(*copied_from)(svn_revnum_t *rev_p, const char **path_p,
svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
@@ -331,13 +350,6 @@ typedef struct root_vtable_t
apr_pool_t *pool);
svn_error_t *(*make_dir)(svn_fs_root_t *root, const char *path,
apr_pool_t *pool);
- svn_error_t *(*copy)(svn_fs_root_t *from_root, const char *from_path,
- svn_fs_root_t *to_root, const char *to_path,
- apr_pool_t *pool);
- svn_error_t *(*revision_link)(svn_fs_root_t *from_root,
- svn_fs_root_t *to_root,
- const char *path,
- apr_pool_t *pool);
/* Files */
svn_error_t *(*file_length)(svn_filesize_t *length_p, svn_fs_root_t *root,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/fs.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/fs.c Tue Oct 15 22:57:03 2013
@@ -729,7 +729,10 @@ populate_opened_fs(svn_fs_t *fs, apr_poo
}
static svn_error_t *
-base_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_create(svn_fs_t *fs,
+ const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool)
{
int format = SVN_FS_BASE__FORMAT_NUMBER;
@@ -805,7 +808,10 @@ check_format(int format)
}
static svn_error_t *
-base_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_open(svn_fs_t *fs,
+ const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool)
{
int format;
@@ -888,7 +894,10 @@ bdb_recover(const char *path, svn_boolea
}
static svn_error_t *
-base_open_for_recovery(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+base_open_for_recovery(svn_fs_t *fs,
+ const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool)
{
/* Just stash the path in the fs pointer - it's all we really need. */
@@ -904,6 +913,7 @@ base_upgrade(svn_fs_t *fs,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
@@ -946,7 +956,7 @@ base_upgrade(svn_fs_t *fs,
But it's better to use the existing encapsulation of "opening
the filesystem" rather than duplicating (or worse, partially
duplicating) that logic here. */
- SVN_ERR(base_open(fs, path, subpool, common_pool));
+ SVN_ERR(base_open(fs, path, common_pool_lock, subpool, common_pool));
/* Fetch the youngest rev, and record it */
SVN_ERR(svn_fs_base__youngest_rev(&youngest_rev, fs, subpool));
@@ -968,6 +978,7 @@ base_verify(svn_fs_t *fs, const char *pa
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
@@ -992,6 +1003,7 @@ base_bdb_pack(svn_fs_t *fs,
void *notify_baton,
svn_cancel_func_t cancel,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/tree.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_base/tree.c Tue Oct 15 22:57:03 2013
@@ -3277,6 +3277,18 @@ base_revision_link(svn_fs_root_t *from_r
}
+static svn_error_t *
+base_move(svn_fs_root_t *from_root,
+ const char *from_path,
+ svn_fs_root_t *to_root,
+ const char *to_path,
+ apr_pool_t *pool)
+{
+ /* BDB supports MOVes only as backward compatible ADD-with-history */
+ return base_copy(from_root, from_path, to_root, to_path, pool);
+}
+
+
struct copied_from_args
{
svn_fs_root_t *root; /* Root for the node whose ancestry we seek. */
@@ -5395,6 +5407,9 @@ static root_vtable_t root_vtable = {
base_node_origin_rev,
base_node_created_path,
base_delete_node,
+ base_copy,
+ base_revision_link,
+ base_move,
base_copied_from,
base_closest_copy,
base_node_prop,
@@ -5404,8 +5419,6 @@ static root_vtable_t root_vtable = {
base_dir_entries,
base_dir_optimal_order,
base_make_dir,
- base_copy,
- base_revision_link,
base_file_length,
base_file_checksum,
base_file_contents,
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c Tue Oct 15 22:57:03 2013
@@ -271,7 +271,7 @@ get_node_revision_body(node_revision_t *
{
/* noderevs in rev / pack files can be cached */
const svn_fs_fs__id_part_t *rev_item = svn_fs_fs__id_rev_offset(id);
- pair_cache_key_t key;
+ pair_cache_key_t key = { 0 };
key.revision = rev_item->revision;
key.second = rev_item->number;
@@ -1751,12 +1751,12 @@ get_dir_contents(apr_hash_t *entries,
apr_size_t len = noderev->data_rep->expanded_size
? (apr_size_t)noderev->data_rep->expanded_size
: (apr_size_t)noderev->data_rep->size;
- svn_stringbuf_t *text = svn_stringbuf_create_ensure(len, text_pool);
- text->len = len;
+ svn_stringbuf_t *text;
/* The representation is immutable. Read it normally. */
- SVN_ERR(svn_fs_fs__get_contents(&contents, fs, noderev->data_rep, text_pool));
- SVN_ERR(svn_stream_read(contents, text->data, &text->len));
+ SVN_ERR(svn_fs_fs__get_contents(&contents, fs, noderev->data_rep,
+ text_pool));
+ SVN_ERR(svn_stringbuf_from_stream(&text, contents, len, text_pool));
SVN_ERR(svn_stream_close(contents));
/* de-serialize hash */
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.h Tue Oct 15 22:57:03 2013
@@ -138,4 +138,4 @@ svn_fs_fs__get_changes(apr_array_header_
svn_revnum_t rev,
apr_pool_t *pool);
-#endif
\ No newline at end of file
+#endif
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/cached_data.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.c Tue Oct 15 22:57:03 2013
@@ -229,9 +229,12 @@ initialize_fs_struct(svn_fs_t *fs)
/* This implements the fs_library_vtable_t.create() API. Create a new
fsfs-backed Subversion filesystem at path PATH and link it into
*FS. Perform temporary allocations in POOL, and fs-global allocations
- in COMMON_POOL. */
+ in COMMON_POOL. The latter must be serialized using COMMON_POOL_LOCK. */
static svn_error_t *
-fs_create(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+fs_create(svn_fs_t *fs,
+ const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool)
{
SVN_ERR(svn_fs__check_fs(fs, FALSE));
@@ -241,7 +244,10 @@ fs_create(svn_fs_t *fs, const char *path
SVN_ERR(svn_fs_fs__create(fs, path, pool));
SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
- return fs_serialized_init(fs, common_pool, pool);
+ SVN_MUTEX__WITH_LOCK(common_pool_lock,
+ fs_serialized_init(fs, common_pool, pool));
+
+ return SVN_NO_ERROR;
}
@@ -251,17 +257,26 @@ fs_create(svn_fs_t *fs, const char *path
/* This implements the fs_library_vtable_t.open() API. Open an FSFS
Subversion filesystem located at PATH, set *FS to point to the
correct vtable for the filesystem. Use POOL for any temporary
- allocations, and COMMON_POOL for fs-global allocations. */
+ allocations, and COMMON_POOL for fs-global allocations.
+ The latter must be serialized using COMMON_POOL_LOCK. */
static svn_error_t *
-fs_open(svn_fs_t *fs, const char *path, apr_pool_t *pool,
+fs_open(svn_fs_t *fs,
+ const char *path,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
apr_pool_t *common_pool)
{
+ SVN_ERR(svn_fs__check_fs(fs, FALSE));
+
SVN_ERR(initialize_fs_struct(fs));
SVN_ERR(svn_fs_fs__open(fs, path, pool));
SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
- return fs_serialized_init(fs, common_pool, pool);
+ SVN_MUTEX__WITH_LOCK(common_pool_lock,
+ fs_serialized_init(fs, common_pool, pool));
+
+ return SVN_NO_ERROR;
}
@@ -270,7 +285,9 @@ fs_open(svn_fs_t *fs, const char *path,
static svn_error_t *
fs_open_for_recovery(svn_fs_t *fs,
const char *path,
- apr_pool_t *pool, apr_pool_t *common_pool)
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
+ apr_pool_t *common_pool)
{
/* Recovery for FSFS is currently limited to recreating the 'current'
file from the latest revision. */
@@ -288,7 +305,7 @@ fs_open_for_recovery(svn_fs_t *fs,
"0 1 1\n", pool));
/* Now open the filesystem properly by calling the vtable method directly. */
- return fs_open(fs, path, pool, common_pool);
+ return fs_open(fs, path, common_pool_lock, pool, common_pool);
}
@@ -301,14 +318,11 @@ fs_upgrade(svn_fs_t *fs,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
- SVN_ERR(svn_fs__check_fs(fs, FALSE));
- SVN_ERR(initialize_fs_struct(fs));
- SVN_ERR(svn_fs_fs__open(fs, path, pool));
- SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
- SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+ SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
return svn_fs_fs__upgrade(fs, notify_func, notify_baton,
cancel_func, cancel_baton, pool);
}
@@ -321,14 +335,11 @@ fs_verify(svn_fs_t *fs, const char *path
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
- SVN_ERR(svn_fs__check_fs(fs, FALSE));
- SVN_ERR(initialize_fs_struct(fs));
- SVN_ERR(svn_fs_fs__open(fs, path, pool));
- SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
- SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+ SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
return svn_fs_fs__verify(fs, start, end, notify_func, notify_baton,
cancel_func, cancel_baton, pool);
}
@@ -340,14 +351,11 @@ fs_pack(svn_fs_t *fs,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
- SVN_ERR(svn_fs__check_fs(fs, FALSE));
- SVN_ERR(initialize_fs_struct(fs));
- SVN_ERR(svn_fs_fs__open(fs, path, pool));
- SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
- SVN_ERR(fs_serialized_init(fs, common_pool, pool));
+ SVN_ERR(fs_open(fs, path, common_pool_lock, pool, common_pool));
return svn_fs_fs__pack(fs, notify_func, notify_baton,
cancel_func, cancel_baton, pool);
}
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/fs.h Tue Oct 15 22:57:03 2013
@@ -148,6 +148,9 @@ extern "C" {
/* The minimum format number that supports packed revprops. */
#define SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT 6
+/* Minimum format number that will record moves */
+#define SVN_FS_FS__MIN_MOVE_SUPPORT_FORMAT 7
+
/* The minimum format number that supports a configuration file (fsfs.conf) */
#define SVN_FS_FS__MIN_CONFIG_FILE 4
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/hotcopy.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/hotcopy.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.c Tue Oct 15 22:57:03 2013
@@ -50,6 +50,8 @@
#define ACTION_DELETE "delete"
#define ACTION_REPLACE "replace"
#define ACTION_RESET "reset"
+#define ACTION_MOVE "move"
+#define ACTION_MOVEREPLACE "movereplace"
/* True and False flags. */
#define FLAG_TRUE "true"
@@ -239,6 +241,14 @@ read_change(change_t **change_p,
{
info->change_kind = svn_fs_path_change_reset;
}
+ else if (strcmp(str, ACTION_MOVE) == 0)
+ {
+ info->change_kind = svn_fs_path_change_move;
+ }
+ else if (strcmp(str, ACTION_MOVEREPLACE) == 0)
+ {
+ info->change_kind = svn_fs_path_change_movereplace;
+ }
else
{
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -350,9 +360,11 @@ write_change_entry(svn_stream_t *stream,
svn_boolean_t include_node_kind,
apr_pool_t *pool)
{
- const char *idstr, *buf;
+ const char *idstr;
const char *change_string = NULL;
const char *kind_string = "";
+ svn_stringbuf_t *buf;
+ apr_size_t len;
switch (change->change_kind)
{
@@ -371,6 +383,12 @@ write_change_entry(svn_stream_t *stream,
case svn_fs_path_change_reset:
change_string = ACTION_RESET;
break;
+ case svn_fs_path_change_move:
+ change_string = ACTION_MOVE;
+ break;
+ case svn_fs_path_change_movereplace:
+ change_string = ACTION_MOVEREPLACE;
+ break;
default:
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid change type %d"),
@@ -391,22 +409,24 @@ write_change_entry(svn_stream_t *stream,
? SVN_FS_FS__KIND_DIR
: SVN_FS_FS__KIND_FILE);
}
- buf = apr_psprintf(pool, "%s %s%s %s %s %s\n",
- idstr, change_string, kind_string,
- change->text_mod ? FLAG_TRUE : FLAG_FALSE,
- change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
- path);
-
- SVN_ERR(svn_stream_puts(stream, buf));
+ buf = svn_stringbuf_createf(pool, "%s %s%s %s %s %s\n",
+ idstr, change_string, kind_string,
+ change->text_mod ? FLAG_TRUE : FLAG_FALSE,
+ change->prop_mod ? FLAG_TRUE : FLAG_FALSE,
+ path);
if (SVN_IS_VALID_REVNUM(change->copyfrom_rev))
{
- buf = apr_psprintf(pool, "%ld %s", change->copyfrom_rev,
- change->copyfrom_path);
- SVN_ERR(svn_stream_puts(stream, buf));
+ svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s",
+ change->copyfrom_rev,
+ change->copyfrom_path));
}
- return svn_error_trace(svn_stream_puts(stream, "\n"));
+ svn_stringbuf_appendbyte(buf, '\n');
+
+ /* Write all change info in one write call. */
+ len = buf->len;
+ return svn_error_trace(svn_stream_write(stream, buf->data, &len));
}
svn_error_t *
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/low_level.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/pack.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/recovery.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/recovery.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/revprops.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/revprops.h
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.c?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.c Tue Oct 15 22:57:03 2013
@@ -598,6 +598,33 @@ unparse_dir_entries(apr_hash_t **str_ent
return SVN_NO_ERROR;
}
+/* Copy the contents of NEW_CHANGE into OLD_CHANGE assuming that both
+ belong to the same path. Allocate copies in POOL.
+ */
+static void
+replace_change(svn_fs_path_change2_t *old_change,
+ const svn_fs_path_change2_t *new_change,
+ apr_pool_t *pool)
+{
+ /* An add at this point must be following a previous delete,
+ so treat it just like a replace. */
+ old_change->node_kind = new_change->node_kind;
+ old_change->node_rev_id = svn_fs_fs__id_copy(new_change->node_rev_id,
+ pool);
+ old_change->text_mod = new_change->text_mod;
+ old_change->prop_mod = new_change->prop_mod;
+ if (new_change->copyfrom_rev == SVN_INVALID_REVNUM)
+ {
+ old_change->copyfrom_rev = SVN_INVALID_REVNUM;
+ old_change->copyfrom_path = NULL;
+ }
+ else
+ {
+ old_change->copyfrom_rev = new_change->copyfrom_rev;
+ old_change->copyfrom_path = apr_pstrdup(pool,
+ new_change->copyfrom_path);
+ }
+}
/* Merge the internal-use-only CHANGE into a hash of public-FS
svn_fs_path_change2_t CHANGES, collapsing multiple changes into a
@@ -636,11 +663,13 @@ fold_change(apr_hash_t *changes,
_("Invalid change ordering: new node revision ID "
"without delete"));
- /* Sanity check: an add, replacement, or reset must be the first
+ /* Sanity check: an add, replacement, move, or reset must be the first
thing to follow a deletion. */
if ((old_change->change_kind == svn_fs_path_change_delete)
&& (! ((info->change_kind == svn_fs_path_change_replace)
|| (info->change_kind == svn_fs_path_change_reset)
+ || (info->change_kind == svn_fs_path_change_movereplace)
+ || (info->change_kind == svn_fs_path_change_move)
|| (info->change_kind == svn_fs_path_change_add))))
return svn_error_create
(SVN_ERR_FS_CORRUPT, NULL,
@@ -648,7 +677,8 @@ fold_change(apr_hash_t *changes,
/* Sanity check: an add can't follow anything except
a delete or reset. */
- if ((info->change_kind == svn_fs_path_change_add)
+ if (( (info->change_kind == svn_fs_path_change_add)
+ || (info->change_kind == svn_fs_path_change_move))
&& (old_change->change_kind != svn_fs_path_change_delete)
&& (old_change->change_kind != svn_fs_path_change_reset))
return svn_error_create
@@ -665,7 +695,8 @@ fold_change(apr_hash_t *changes,
break;
case svn_fs_path_change_delete:
- if (old_change->change_kind == svn_fs_path_change_add)
+ if ((old_change->change_kind == svn_fs_path_change_add)
+ || (old_change->change_kind == svn_fs_path_change_move))
{
/* If the path was introduced in this transaction via an
add, and we are deleting it, just remove the path
@@ -687,22 +718,16 @@ fold_change(apr_hash_t *changes,
case svn_fs_path_change_replace:
/* An add at this point must be following a previous delete,
so treat it just like a replace. */
+ replace_change(old_change, info, pool);
old_change->change_kind = svn_fs_path_change_replace;
- old_change->node_rev_id = svn_fs_fs__id_copy(info->node_rev_id,
- pool);
- old_change->text_mod = info->text_mod;
- old_change->prop_mod = info->prop_mod;
- if (info->copyfrom_rev == SVN_INVALID_REVNUM)
- {
- old_change->copyfrom_rev = SVN_INVALID_REVNUM;
- old_change->copyfrom_path = NULL;
- }
- else
- {
- old_change->copyfrom_rev = info->copyfrom_rev;
- old_change->copyfrom_path = apr_pstrdup(pool,
- info->copyfrom_path);
- }
+ break;
+
+ case svn_fs_path_change_move:
+ case svn_fs_path_change_movereplace:
+ /* A move at this point must be following a previous delete,
+ so treat it just like a replacing move. */
+ replace_change(old_change, info, pool);
+ old_change->change_kind = svn_fs_path_change_movereplace;
break;
case svn_fs_path_change_modify:
@@ -768,7 +793,8 @@ process_changes(apr_hash_t *changed_path
*/
if ((change->info.change_kind == svn_fs_path_change_delete)
- || (change->info.change_kind == svn_fs_path_change_replace))
+ || (change->info.change_kind == svn_fs_path_change_replace)
+ || (change->info.change_kind == svn_fs_path_change_movereplace))
{
apr_hash_index_t *hi;
@@ -1518,9 +1544,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
svn_fs_path_change2_t *change;
apr_hash_t *changes = apr_hash_make(pool);
+ /* Not using APR_BUFFERED to append change in one atomic write operation. */
SVN_ERR(svn_io_file_open(&file, path_txn_changes(fs, txn_id, pool),
- APR_APPEND | APR_WRITE | APR_CREATE
- | APR_BUFFERED, APR_OS_DEFAULT, pool));
+ APR_APPEND | APR_WRITE | APR_CREATE,
+ APR_OS_DEFAULT, pool));
change = svn_fs__path_change_create_internal(id, change_kind, pool);
change->text_mod = text_mod;
@@ -2661,23 +2688,34 @@ write_final_rev(const svn_fs_id_t **new_
return SVN_NO_ERROR;
}
-/* Write the changed path info from transaction TXN_ID in filesystem
- FS to the permanent rev-file FILE. *OFFSET_P is set the to offset
- in the file of the beginning of this information. Perform
- temporary allocations in POOL. */
+/* Write the changed path info CHANGED_PATHS to the permanent rev-file FILE
+ representing NEW_REV in filesystem FS. *OFFSET_P is set the to offset in
+ the file of the beginning of this information.
+ Perform temporary allocations in POOL. */
static svn_error_t *
write_final_changed_path_info(apr_off_t *offset_p,
apr_file_t *file,
svn_fs_t *fs,
- const svn_fs_fs__id_part_t *txn_id,
+ apr_hash_t *changed_paths,
+ svn_revnum_t new_rev,
apr_pool_t *pool)
{
- apr_hash_t *changed_paths;
apr_off_t offset;
+ apr_hash_index_t *hi;
SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
- SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, fs, txn_id, pool));
+ /* all moves specify the "copy-from-rev" as REV-1 */
+ if (svn_fs_fs__supports_move(fs))
+ for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+ {
+ svn_fs_path_change2_t *change;
+ apr_hash_this(hi, NULL, NULL, (void **)&change);
+
+ if ( (change->change_kind == svn_fs_path_change_move)
+ || (change->change_kind == svn_fs_path_change_movereplace))
+ change->copyfrom_rev = new_rev - 1;
+ }
SVN_ERR(svn_fs_fs__write_changes(svn_stream_from_aprfile2(file, TRUE, pool),
fs, changed_paths, TRUE, pool));
@@ -2836,6 +2874,169 @@ verify_locks(svn_fs_t *fs,
return SVN_NO_ERROR;
}
+/* If CHANGE is move, verify that there is no other move with the same
+ copy-from path in SOURCE_PATHS already (parent or sub-node moves are fine).
+ Add the source path to SOURCE_PATHS after successful verification.
+ Allocate the hashed strings in POOL. */
+static svn_error_t *
+check_for_duplicate_move_source(apr_hash_t *source_paths,
+ change_t *change,
+ apr_pool_t *pool)
+{
+ if ( change->info.change_kind == svn_fs_path_change_move
+ || change->info.change_kind == svn_fs_path_change_movereplace)
+ if (change->info.copyfrom_path)
+ {
+ apr_size_t len = strlen(change->info.copyfrom_path);
+ if (apr_hash_get(source_paths, change->info.copyfrom_path, len))
+ return svn_error_createf(SVN_ERR_FS_AMBIGUOUS_MOVE, NULL,
+ _("Path '%s' has been moved to more than one target"),
+ change->info.copyfrom_path);
+
+ apr_hash_set(source_paths,
+ apr_pstrmemdup(pool, change->info.copyfrom_path, len),
+ len,
+ change->info.copyfrom_path);
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Verify that the moves we are about to commit with TXN_ID in FS are unique
+ and the respective copy sources have been deleted. OLD_REV is the last
+ committed revision. CHANGED_PATHS is the list of changes paths in this
+ txn. Use POOL for temporary allocations. */
+static svn_error_t *
+verify_moves(svn_fs_t *fs,
+ const svn_fs_fs__id_part_t *txn_id,
+ svn_revnum_t old_rev,
+ apr_hash_t *changed_paths,
+ apr_pool_t *pool)
+{
+ apr_hash_t *source_paths = apr_hash_make(pool);
+ svn_revnum_t revision;
+ apr_pool_t *iter_pool = svn_pool_create(pool);
+ apr_hash_index_t *hi;
+ int i;
+ apr_array_header_t *moves
+ = apr_array_make(pool, 16, sizeof(svn_sort__item_t));
+ apr_array_header_t *deletions
+ = apr_array_make(pool, 16, sizeof(const char *));
+
+ /* extract moves and deletions from the current txn's change list */
+
+ for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+ {
+ const char *path;
+ apr_ssize_t len;
+ change_t *change;
+ apr_hash_this(hi, (const void**)&path, &len, (void**)&change);
+
+ if ( change->info.copyfrom_path
+ && ( change->info.change_kind == svn_fs_path_change_move
+ || change->info.change_kind == svn_fs_path_change_movereplace))
+ {
+ svn_sort__item_t *item = apr_array_push(moves);
+ item->key = path;
+ item->klen = len;
+ item->value = change;
+ }
+
+ if ( change->info.change_kind == svn_fs_path_change_delete
+ || change->info.change_kind == svn_fs_path_change_replace
+ || change->info.change_kind == svn_fs_path_change_movereplace)
+ APR_ARRAY_PUSH(deletions, const char *) = path;
+ }
+
+ /* no moves? -> done here */
+
+ if (moves->nelts == 0)
+ return SVN_NO_ERROR;
+
+ /* correct the deletions that refer to moved paths and make them refer to
+ the paths in OLD_REV */
+
+ qsort(moves->elts, moves->nelts, moves->elt_size,
+ svn_sort_compare_paths);
+
+ for (i = 0; i < deletions->nelts; ++i)
+ {
+ const char *deleted_path = APR_ARRAY_IDX(deletions, i, const char*);
+ int closest_move_idx
+ = svn_sort__bsearch_lower_bound(deleted_path, moves,
+ svn_sort_compare_paths);
+
+ if (closest_move_idx < moves->nelts)
+ {
+ svn_sort__item_t *closest_move_item
+ = &APR_ARRAY_IDX(moves, closest_move_idx, svn_sort__item_t);
+ const char *relpath
+ = svn_dirent_skip_ancestor(closest_move_item->key,
+ deleted_path);
+ if (relpath)
+ {
+ change_t *closed_move = closest_move_item->value;
+ APR_ARRAY_IDX(deletions, i, const char*)
+ = svn_dirent_join(closed_move->info.copyfrom_path, relpath,
+ pool);
+ }
+ }
+ }
+
+ qsort(deletions->elts, deletions->nelts, deletions->elt_size,
+ svn_sort_compare_paths);
+
+ /* The _same_ source paths must never occur more than once in any move
+ since our base revision. */
+
+ for (i = 0; moves->nelts; ++i)
+ SVN_ERR(check_for_duplicate_move_source (source_paths,
+ APR_ARRAY_IDX(moves, i, svn_sort__item_t).value,
+ pool));
+
+ for (revision = txn_id->revision + 1; revision <= old_rev; ++revision)
+ {
+ apr_array_header_t *changes;
+ change_t **changes_p;
+
+ svn_pool_clear(iter_pool);
+ svn_fs_fs__get_changes(&changes, fs, revision, iter_pool);
+
+ changes_p = (change_t **)&changes->elts;
+ for (i = 0; i < changes->nelts; ++i)
+ SVN_ERR(check_for_duplicate_move_source(source_paths, changes_p[i],
+ pool));
+ }
+
+ /* The move source paths must been deleted in this txn. */
+
+ for (i = 0; i < moves->nelts; ++i)
+ {
+ change_t *change = APR_ARRAY_IDX(moves, i, svn_sort__item_t).value;
+
+ /* there must be a deletion of move's copy-from path
+ (or any of its parents) */
+
+ int closest_deletion_idx
+ = svn_sort__bsearch_lower_bound(change->info.copyfrom_path, deletions,
+ svn_sort_compare_paths);
+ if (closest_deletion_idx < deletions->nelts)
+ {
+ const char *closest_deleted_path
+ = APR_ARRAY_IDX(deletions, closest_deletion_idx, const char *);
+ if (!svn_dirent_is_ancestor(closest_deleted_path,
+ change->info.copyfrom_path))
+ return svn_error_createf(SVN_ERR_FS_INCOMPLETE_MOVE, NULL,
+ _("Path '%s' has been moved without being deleted"),
+ change->info.copyfrom_path);
+ }
+ }
+
+ svn_pool_destroy(iter_pool);
+
+ return SVN_NO_ERROR;
+}
+
/* Baton used for commit_body below. */
struct commit_baton {
svn_revnum_t *new_rev_p;
@@ -2869,6 +3070,7 @@ commit_body(void *baton, apr_pool_t *poo
svn_prop_t prop;
const svn_fs_fs__id_part_t *txn_id = svn_fs_fs__txn_get_id(cb->txn);
svn_stringbuf_t *trailer;
+ apr_hash_t *changed_paths;
/* Get the current youngest revision. */
SVN_ERR(svn_fs_fs__youngest_rev(&old_rev, cb->fs, pool));
@@ -2885,6 +3087,16 @@ commit_body(void *baton, apr_pool_t *poo
discovered locks. */
SVN_ERR(verify_locks(cb->fs, txn_id, pool));
+ /* we need the changes list for verification as well as for writing it
+ to the final rev file */
+ SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
+ pool));
+
+ /* ensure that no change in this txn or any txn committed since the start
+ * of this txn violates our move semantics */
+ if (svn_fs_fs__supports_move(cb->fs))
+ SVN_ERR(verify_moves(cb->fs, txn_id, old_rev, changed_paths, pool));
+
/* Get the next node_id and copy_id to use. */
if (ffd->format < SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT)
SVN_ERR(get_next_revision_ids(&start_node_id, &start_copy_id, cb->fs,
@@ -2907,7 +3119,8 @@ commit_body(void *baton, apr_pool_t *poo
/* Write the changed-path information. */
SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
- cb->fs, txn_id, pool));
+ cb->fs, changed_paths, new_rev,
+ pool));
/* Write the final line. */
trailer = svn_fs_fs__unparse_revision_trailer
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.c
------------------------------------------------------------------------------
svn:eol-style = native
Modified: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h?rev=1532583&r1=1532582&r2=1532583&view=diff
==============================================================================
--- subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h (original)
+++ subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h Tue Oct 15 22:57:03 2013
@@ -280,4 +280,4 @@ svn_fs_fs__begin_txn(svn_fs_txn_t **txn_
apr_uint32_t flags,
apr_pool_t *pool);
-#endif
\ No newline at end of file
+#endif
Propchange: subversion/branches/fsfs-improvements/subversion/libsvn_fs_fs/transaction.h
------------------------------------------------------------------------------
svn:eol-style = native