svn-3640

Version:

1.7.0

Bug Link:

http://subversion.tigris.org/issues/show_bug.cgi?id=3640

 

Patch Link:

source code patch: http://svn.apache.org/viewvc?view=revision&revision=946317

Symptom:

we cannot reintegrate (merge) the branch to a target trunk that has been moved.

We first make a branch, then move the trunk, and now if we try to reintegrate the branch back to the trunk, we will fail. The correct behavior should be reintegrate the branch without any failure.

How it is diagnosed:

source code analysis & dumped messages (couldn’t reproduce the bug)

 

Step1) make a branch A_COPY from the trunk, A.

Step2) make some changes on branch A_COPY and reintegrate back to the trunk

Step3) make another changes on branch A_COPY.

Step4) move the trunk to other location

                ‘svn move ^/A ^/A_MOVED –m “Move the trunk’

Step5) update the working copy

                ‘svn up’

Step6) reintegrate the branch to the trunk

                ‘svn merge ^/A_COPY A_MOVED –reintegrate

 

Then, error happens:

svn: File not found: revision 7, path '/A_MOVED'

If SVN is compiled with ‘--enable-maintainer-mode’, we will also see the following in the log:

..\..\..\subversion\svn\merge-cmd.c:358: (apr_err=160013)

..\..\..\subversion\libsvn_client\merge.c:9777: (apr_err=160013)

..\..\..\subversion\libsvn_client\merge.c:9747: (apr_err=160013)

..\..\..\subversion\libsvn_client\merge.c:9654: (apr_err=160013)

..\..\..\subversion\libsvn_client\ra.c:753: (apr_err=160013)

..\..\..\subversion\libsvn_client\mergeinfo.c:740: (apr_err=160013)

..\..\..\subversion\libsvn_client\ra.c:548: (apr_err=160013)

..\..\..\subversion\libsvn_repos\rev_hunt.c:908: (apr_err=160013)

..\..\..\subversion\libsvn_repos\rev_hunt.c:607: (apr_err=160013)

..\..\..\subversion\libsvn_fs_fs\tree.c:2883: (apr_err=160013)

..\..\..\subversion\libsvn_fs_fs\tree.c:2883: (apr_err=160013)

..\..\..\subversion\libsvn_fs_fs\tree.c:667: (apr_err=160013) : open_path

Root Cause:

Brief:

It assumes that reintegrate target has not been moved after the reintegrate source was branched.

Detail:

‘calculate_left_hand_side’ function does not handle the modified source location, so the error message is printed out in the next function call.

 

static svn_error_t *fs_closest_copy(... ...)

{

  /* open_path is SVN library to open a file/directory. Its return value is always checked by SVN_ERR. In the incorrect execution, open_path returned SVN_ERR_FS_NOT_FOUND */

 /* Currently, path = “A_MOVED”, but the revision from which it is trying

     to open is an older revision (the revision when the branch was checked out),

     so A_MOVED did not exist in that revision, thus open_path returned failure.*/

   SVN_ERR(open_path(&parent_path, root, path, 0, NULL, pool));

}

static svn_error_t *

merge_reintegrate_locked(…)

{

  …

  SVN_ERR(svn_client__get_revision_number(&rev2, NULL, ctx->wc_ctx,

                                              source_repos_rel_path,

                                          ra_session, peg_revision,

                                          scratch_pool));

 /* calculate_left_hand_side is to calculate the “url1”, to be used later in “open_path”. In the buggy execution, url1 == “A_MOVED”, which is not the one in the original revision. The correct “url1” should be “A”. */

  SVN_ERR(calculate_left_hand_side(&url1, &rev1,

                                   &merged_to_source_mergeinfo_catalog,

                                   &unmerged_to_source_mergeinfo_catalog,

                                   target_repos_rel_path,

                                   wb.subtrees_with_mergeinfo,

                                   rev1,

                                   source_repos_rel_path,

                                   source_repos_root,

                                   rev2,

                                   ra_session,

                                       ctx,

                                   scratch_pool));

/* svn_client__get_youngest_common_ancestor will eventually call open_path, with the url1 calculated above. */  SVN_ERR(svn_client__get_youngest_common_ancestor(&yc_ancestor_path,

                                                   &yc_ancestor_rev,

                                                   url2, rev2,

                                                   url1, rev1,

                                                   ctx, scratch_pool));

// svn_client__get_youngest_common_ancestor generates the error message.

// it eventually reaches ‘open_path’ in ‘libsvn_fs_fs/tree.c’ and it prints out ‘SVN_FS__NOT_FOUND’ error message.

 

The patch:

 /* Simply modify the logic of calculate_left_hand_side, so the calculated url1 (ur) in calculate_left_hand_side now corresponds to the original path (“A”) instead of “A_MOVED”*/

--- subversion/trunk/subversion/libsvn_client/merge.c           2010/05/19 13:55:51            946186

+++ subversion/trunk/subversion/libsvn_client/merge.c        2010/05/19 18:05:01            946317

@@ -9525,20 +9525,32 @@ calculate_left_hand_side(const char **ur

           /* We've previously merged some or all of the target, up to

              youngest_merged_rev, from the target to the source.  Set *URL_LEFT

              and *REV_LEFT to cover the youngest part of this range. */

-          svn_opt_revision_t peg_revision;

+          svn_opt_revision_t peg_revision, youngest_rev, unspecified_rev;

+          svn_opt_revision_t *start_revision;

           const char *youngest_url;

+          const char *old_url;

 

           peg_revision.kind = svn_opt_revision_number;

-      peg_revision.value.number = youngest_merged_rev;

+      peg_revision.value.number = target_rev;

+

+          youngest_rev.kind = svn_opt_revision_number;

+      youngest_rev.value.number = youngest_merged_rev;

+          

+          unspecified_rev.kind = svn_opt_revision_unspecified;

+

+          *rev_left = youngest_rev.value.number;

+

+          /* Get the URL of the target_url@youngest_merged_rev. */

+      SVN_ERR(svn_ra_get_session_url(ra_session, &old_url, subpool));

+          SVN_ERR(svn_ra_reparent(ra_session, target_url, subpool));

+      SVN_ERR(svn_client__repos_locations(&youngest_url, &start_revision,

+                                              NULL, NULL, ra_session,

+                                          target_url, &peg_revision,

+                                          &youngest_rev, &unspecified_rev,

+                                              ctx, subpool));

 

// get the current target url even if the target url has been moved.

 

-          *rev_left = youngest_merged_rev;

-      SVN_ERR(svn_client__derive_location(

-            &youngest_url, NULL,

-        svn_path_url_add_component2(source_repos_root,

-                                    target_repos_rel_path,

-                                        subpool),

-            &peg_revision, ra_session, ctx, subpool, subpool));

           *url_left = apr_pstrdup(pool, youngest_url);

+      SVN_ERR(svn_ra_reparent(ra_session, old_url, subpool));

         }

 

   svn_pool_destroy(subpool);

Is there any log message?

Yes

Failure symptom category

early termination

How can we automatically handle?

Frequent logging pattern return value check..  We cannot anticipate the root cause. However, we can anticipate this error later like the current error message.