You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ju...@apache.org on 2015/10/06 10:46:44 UTC

svn commit: r1706963 [3/6] - in /subversion/branches/move-tracking-2: ./ build/ subversion/ subversion/bindings/javahl/native/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_diff/ subversion/libsvn_fs_base/ ...

Modified: subversion/branches/move-tracking-2/subversion/libsvn_client/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_client/upgrade.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_client/upgrade.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_client/upgrade.c Tue Oct  6 08:46:43 2015
@@ -179,6 +179,122 @@ svn_client_upgrade(const char *path,
   return SVN_NO_ERROR;
 }
 
+/* Helper for upgrade_externals_from_properties: upgrades one external ITEM
+   in EXTERNALS_PARENT. Uses SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+upgrade_external_item(svn_client_ctx_t *ctx,
+                      const char *externals_parent_abspath,
+                      const char *externals_parent_url,
+                      const char *externals_parent_repos_root_url,
+                      svn_wc_external_item2_t *item,
+                      struct repos_info_baton *info_baton,
+                      apr_pool_t *scratch_pool)
+{
+  const char *resolved_url;
+  const char *external_abspath;
+  const char *repos_relpath;
+  const char *repos_root_url;
+  const char *repos_uuid;
+  svn_node_kind_t external_kind;
+  svn_revnum_t peg_revision;
+  svn_revnum_t revision;
+  svn_error_t *err;
+
+  external_abspath = svn_dirent_join(externals_parent_abspath,
+                                     item->target_dir,
+                                     scratch_pool);
+
+  SVN_ERR(svn_wc__resolve_relative_external_url(
+              &resolved_url,
+              item,
+              externals_parent_repos_root_url,
+              externals_parent_url,
+              scratch_pool, scratch_pool));
+
+  /* This is a hack. We only need to call svn_wc_upgrade() on external
+   * dirs, as file externals are upgraded along with their defining
+   * WC.  Reading the kind will throw an exception on an external dir,
+   * saying that the wc must be upgraded.  If it's a file, the lookup
+   * is done in an adm_dir belonging to the defining wc (which has
+   * already been upgraded) and no error is returned.  If it doesn't
+   * exist (external that isn't checked out yet), we'll just get
+   * svn_node_none. */
+  err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx,
+                          external_abspath, TRUE, FALSE, scratch_pool);
+  if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
+    {
+      svn_error_clear(err);
+
+      SVN_ERR(svn_client_upgrade(external_abspath, ctx, scratch_pool));
+    }
+  else if (err)
+    return svn_error_trace(err);
+
+  /* The upgrade of any dir should be done now, get the now reliable
+   * kind. */
+  SVN_ERR(svn_wc_read_kind2(&external_kind, ctx->wc_ctx, external_abspath,
+                            TRUE, FALSE, scratch_pool));
+
+  /* Update the EXTERNALS table according to the root URL,
+   * relpath and uuid known in the upgraded external WC. */
+
+  /* We should probably have a function that provides all three
+   * of root URL, repos relpath and uuid at once, but here goes... */
+
+  /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
+   * when the node is not present in the file system.
+   * svn_wc__node_get_repos_info() would try to derive the URL. */
+  SVN_ERR(svn_wc__node_get_repos_info(NULL,
+                                      &repos_relpath,
+                                      &repos_root_url,
+                                      &repos_uuid,
+                                      ctx->wc_ctx,
+                                      external_abspath,
+                                      scratch_pool, scratch_pool));
+
+  /* If we haven't got any information from the checked out external,
+   * or if the URL information mismatches the external's definition,
+   * ask fetch_repos_info() to find out the repos root. */
+  if (0 != strcmp(resolved_url,
+                  svn_path_url_add_component2(repos_root_url,
+                                              repos_relpath,
+                                              scratch_pool)))
+    {
+      SVN_ERR(fetch_repos_info(&repos_root_url, &repos_uuid, info_baton,
+                               resolved_url, scratch_pool, scratch_pool));
+
+      repos_relpath = svn_uri_skip_ancestor(repos_root_url,
+                                            resolved_url,
+                                            scratch_pool);
+
+      /* There's just the URL, no idea what kind the external is.
+       * That's fine, as the external isn't even checked out yet.
+       * The kind will be set during the next 'update'. */
+      external_kind = svn_node_unknown;
+    }
+
+  peg_revision = (item->peg_revision.kind == svn_opt_revision_number
+                     ? item->peg_revision.value.number
+                     : SVN_INVALID_REVNUM);
+
+  revision = (item->revision.kind == svn_opt_revision_number
+                 ? item->revision.value.number
+                 : SVN_INVALID_REVNUM);
+
+  SVN_ERR(svn_wc__upgrade_add_external_info(ctx->wc_ctx,
+                                            external_abspath,
+                                            external_kind,
+                                            externals_parent_abspath,
+                                            repos_relpath,
+                                            repos_root_url,
+                                            repos_uuid,
+                                            peg_revision,
+                                            revision,
+                                            scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 upgrade_externals_from_properties(svn_client_ctx_t *ctx,
                                   const char *local_abspath,
@@ -207,34 +323,32 @@ upgrade_externals_from_properties(svn_cl
        hi = apr_hash_next(hi))
     {
       int i;
-      const char *externals_parent_abspath;
       const char *externals_parent_url;
       const char *externals_parent_repos_root_url;
       const char *externals_parent_repos_relpath;
-      const char *externals_parent = apr_hash_this_key(hi);
+      const char *externals_parent_abspath = apr_hash_this_key(hi);
       svn_string_t *external_desc = apr_hash_this_val(hi);
       apr_array_header_t *externals_p;
       svn_error_t *err;
 
       svn_pool_clear(iterpool);
+
+      /* svn_client_propget5() has API promise to return absolute paths. */
+      SVN_ERR_ASSERT(svn_dirent_is_absolute(externals_parent_abspath));
+
       externals_p = apr_array_make(iterpool, 1,
                                    sizeof(svn_wc_external_item2_t*));
 
       /* In this loop, an error causes the respective externals definition, or
        * the external (inner loop), to be skipped, so that upgrade carries on
        * with the other externals. */
-
-      err = svn_dirent_get_absolute(&externals_parent_abspath,
-                                    externals_parent, iterpool);
-
-      if (!err)
-        err = svn_wc__node_get_repos_info(NULL,
-                                          &externals_parent_repos_relpath,
-                                          &externals_parent_repos_root_url,
-                                          NULL,
-                                          ctx->wc_ctx,
-                                          externals_parent_abspath,
-                                          iterpool, iterpool);
+      err = svn_wc__node_get_repos_info(NULL,
+                                        &externals_parent_repos_relpath,
+                                        &externals_parent_repos_root_url,
+                                        NULL,
+                                        ctx->wc_ctx,
+                                        externals_parent_abspath,
+                                        iterpool, iterpool);
 
       if (!err)
         externals_parent_url = svn_path_url_add_component2(
@@ -248,7 +362,7 @@ upgrade_externals_from_properties(svn_cl
       if (err)
         {
           svn_wc_notify_t *notify =
-              svn_wc_create_notify(externals_parent,
+              svn_wc_create_notify(externals_parent_abspath,
                                    svn_wc_notify_failed_external,
                                    scratch_pool);
           notify->err = err;
@@ -265,130 +379,21 @@ upgrade_externals_from_properties(svn_cl
       for (i = 0; i < externals_p->nelts; i++)
         {
           svn_wc_external_item2_t *item;
-          const char *resolved_url;
-          const char *external_abspath;
-          const char *repos_relpath;
-          const char *repos_root_url;
-          const char *repos_uuid;
-          svn_node_kind_t external_kind;
-          svn_revnum_t peg_revision;
-          svn_revnum_t revision;
 
           item = APR_ARRAY_IDX(externals_p, i, svn_wc_external_item2_t*);
 
           svn_pool_clear(iterpool2);
-          external_abspath = svn_dirent_join(externals_parent_abspath,
-                                             item->target_dir,
-                                             iterpool2);
-
-          err = svn_wc__resolve_relative_external_url(
-                                              &resolved_url,
-                                              item,
-                                              externals_parent_repos_root_url,
-                                              externals_parent_url,
-                                              scratch_pool, scratch_pool);
-          if (err)
-            goto handle_error;
-
-          /* This is a hack. We only need to call svn_wc_upgrade() on external
-           * dirs, as file externals are upgraded along with their defining
-           * WC.  Reading the kind will throw an exception on an external dir,
-           * saying that the wc must be upgraded.  If it's a file, the lookup
-           * is done in an adm_dir belonging to the defining wc (which has
-           * already been upgraded) and no error is returned.  If it doesn't
-           * exist (external that isn't checked out yet), we'll just get
-           * svn_node_none. */
-          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx,
-                                  external_abspath, TRUE, FALSE, iterpool2);
-          if (err && err->apr_err == SVN_ERR_WC_UPGRADE_REQUIRED)
-            {
-              svn_error_clear(err);
-
-              err = svn_client_upgrade(external_abspath, ctx, iterpool2);
-              if (err)
-                goto handle_error;
-            }
-          else if (err)
-            goto handle_error;
-
-          /* The upgrade of any dir should be done now, get the now reliable
-           * kind. */
-          err = svn_wc_read_kind2(&external_kind, ctx->wc_ctx, external_abspath,
-                                  TRUE, FALSE, iterpool2);
-          if (err)
-            goto handle_error;
-
-          /* Update the EXTERNALS table according to the root URL,
-           * relpath and uuid known in the upgraded external WC. */
-
-          /* We should probably have a function that provides all three
-           * of root URL, repos relpath and uuid at once, but here goes... */
-
-          /* First get the relpath, as that returns SVN_ERR_WC_PATH_NOT_FOUND
-           * when the node is not present in the file system.
-           * svn_wc__node_get_repos_info() would try to derive the URL. */
-          err = svn_wc__node_get_repos_info(NULL,
-                                            &repos_relpath,
-                                            &repos_root_url,
-                                            &repos_uuid,
-                                            ctx->wc_ctx,
-                                            external_abspath,
-                                            iterpool2, iterpool2);
-          if (err)
-            goto handle_error;
-
-          /* If we haven't got any information from the checked out external,
-           * or if the URL information mismatches the external's definition,
-           * ask fetch_repos_info() to find out the repos root. */
-          if (0 != strcmp(resolved_url,
-                          svn_path_url_add_component2(repos_root_url,
-                                                      repos_relpath,
-                                                      scratch_pool)))
-            {
-              err = fetch_repos_info(&repos_root_url,
-                                     &repos_uuid,
-                                     info_baton,
-                                     resolved_url,
-                                     scratch_pool, scratch_pool);
-              if (err)
-                goto handle_error;
-
-              repos_relpath = svn_uri_skip_ancestor(repos_root_url,
-                                                    resolved_url,
-                                                    iterpool2);
-
-              /* There's just the URL, no idea what kind the external is.
-               * That's fine, as the external isn't even checked out yet.
-               * The kind will be set during the next 'update'. */
-              external_kind = svn_node_unknown;
-            }
-
-          if (err)
-            goto handle_error;
+          err = upgrade_external_item(ctx, externals_parent_abspath,
+                                      externals_parent_url,
+                                      externals_parent_repos_root_url,
+                                      item, info_baton, iterpool2);
 
-          peg_revision = (item->peg_revision.kind == svn_opt_revision_number
-                          ? item->peg_revision.value.number
-                          : SVN_INVALID_REVNUM);
-
-          revision = (item->revision.kind == svn_opt_revision_number
-                      ? item->revision.value.number
-                      : SVN_INVALID_REVNUM);
-
-          err = svn_wc__upgrade_add_external_info(ctx->wc_ctx,
-                                                  external_abspath,
-                                                  external_kind,
-                                                  externals_parent,
-                                                  repos_relpath,
-                                                  repos_root_url,
-                                                  repos_uuid,
-                                                  peg_revision,
-                                                  revision,
-                                                  iterpool2);
-handle_error:
           if (err)
             {
               svn_wc_notify_t *notify =
-                  svn_wc_create_notify(external_abspath,
+                  svn_wc_create_notify(svn_dirent_join(externals_parent_abspath,
+                                                       item->target_dir,
+                                                       iterpool2),
                                        svn_wc_notify_failed_external,
                                        scratch_pool);
               notify->err = err;

Modified: subversion/branches/move-tracking-2/subversion/libsvn_diff/diff_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_diff/diff_file.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_diff/diff_file.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_diff/diff_file.c Tue Oct  6 08:46:43 2015
@@ -1242,17 +1242,20 @@ svn_diff_file_options_parse(svn_diff_fil
 {
   apr_getopt_t *os;
   struct opt_parsing_error_baton_t opt_parsing_error_baton;
-  /* Make room for each option (starting at index 1) plus trailing NULL. */
-  const char **argv = apr_palloc(pool, sizeof(char*) * (args->nelts + 2));
+  apr_array_header_t *argv;
 
   opt_parsing_error_baton.err = NULL;
   opt_parsing_error_baton.pool = pool;
 
-  argv[0] = "";
-  memcpy(argv + 1, args->elts, sizeof(char*) * args->nelts);
-  argv[args->nelts + 1] = NULL;
-
-  apr_getopt_init(&os, pool, args->nelts + 1, argv);
+  /* Make room for each option (starting at index 1) plus trailing NULL. */
+  argv = apr_array_make(pool, args->nelts + 2, sizeof(char*));
+  APR_ARRAY_PUSH(argv, const char *) = "";
+  apr_array_cat(argv, args);
+  APR_ARRAY_PUSH(argv, const char *) = NULL;
+
+  apr_getopt_init(&os, pool, 
+                  argv->nelts - 1 /* Exclude trailing NULL */,
+                  (const char *const *) argv->elts);
 
   /* Capture any error message from apr_getopt_long().  This will typically
    * say which option is wrong, which we would not otherwise know. */
@@ -1416,6 +1419,10 @@ typedef struct svn_diff__file_output_bat
 
   int context_size;
 
+  /* Cancel handler */
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
+
   apr_pool_t *pool;
 } svn_diff__file_output_baton_t;
 
@@ -1597,10 +1604,15 @@ static APR_INLINE svn_error_t *
 output_unified_diff_range(svn_diff__file_output_baton_t *output_baton,
                           int source,
                           svn_diff__file_output_unified_type_e type,
-                          apr_off_t until)
+                          apr_off_t until,
+                          svn_cancel_func_t cancel_func,
+                          void *cancel_baton)
 {
   while (output_baton->current_line[source] < until)
     {
+      if (cancel_func)
+        SVN_ERR(cancel_func(cancel_baton));
+
       SVN_ERR(output_unified_line(output_baton, type, source));
     }
   return SVN_NO_ERROR;
@@ -1626,7 +1638,8 @@ output_unified_flush_hunk(svn_diff__file
   /* Add trailing context to the hunk */
   SVN_ERR(output_unified_diff_range(baton, 0 /* original */,
                                     svn_diff__file_output_unified_context,
-                                    target_line));
+                                    target_line,
+                                    baton->cancel_func, baton->cancel_baton));
 
   old_start = baton->hunk_start[0];
   new_start = baton->hunk_start[1];
@@ -1714,7 +1727,9 @@ output_unified_diff_modified(void *baton
         /* Original: Output the context preceding the changed range */
         SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                           svn_diff__file_output_unified_context,
-                                          original_start));
+                                          original_start,
+                                          output_baton->cancel_func,
+                                          output_baton->cancel_baton));
       }
   }
 
@@ -1722,7 +1737,9 @@ output_unified_diff_modified(void *baton
      to display */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_skip,
-                                    original_start - context_prefix_length));
+                                    original_start - context_prefix_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Note that the above skip stores data for the show_c_function support below */
 
@@ -1768,20 +1785,28 @@ output_unified_diff_modified(void *baton
   /* Modified: Skip lines until we are at the start of the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
                                     svn_diff__file_output_unified_skip,
-                                    modified_start));
+                                    modified_start,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Original: Output the context preceding the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_context,
-                                    original_start));
+                                    original_start,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   /* Both: Output the changed range */
   SVN_ERR(output_unified_diff_range(output_baton, 0 /* original */,
                                     svn_diff__file_output_unified_delete,
-                                    original_start + original_length));
+                                    original_start + original_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
   SVN_ERR(output_unified_diff_range(output_baton, 1 /* modified */,
                                     svn_diff__file_output_unified_insert,
-                                    modified_start + modified_length));
+                                    modified_start + modified_length,
+                                    output_baton->cancel_func,
+                                    output_baton->cancel_baton));
 
   return SVN_NO_ERROR;
 }
@@ -1842,6 +1867,8 @@ svn_diff_file_output_unified4(svn_stream
 
       memset(&baton, 0, sizeof(baton));
       baton.output_stream = output_stream;
+      baton.cancel_func = cancel_func;
+      baton.cancel_baton = cancel_baton;
       baton.pool = pool;
       baton.header_encoding = header_encoding;
       baton.path[0] = original_path;

Modified: subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_diff/parse-diff.c Tue Oct  6 08:46:43 2015
@@ -64,7 +64,7 @@ struct svn_diff__hunk_range {
 
 struct svn_diff_hunk_t {
   /* The patch this hunk belongs to. */
-  svn_patch_t *patch;
+  const svn_patch_t *patch;
 
   /* APR file handle to the patch file this hunk came from. */
   apr_file_t *apr_file;
@@ -93,7 +93,7 @@ struct svn_diff_hunk_t {
 
 struct svn_diff_binary_patch_t {
   /* The patch this hunk belongs to. */
-  svn_patch_t *patch;
+  const svn_patch_t *patch;
 
   /* APR file handle to the patch file this hunk came from. */
   apr_file_t *apr_file;
@@ -117,7 +117,7 @@ struct svn_diff_binary_patch_t {
 static svn_error_t *
 add_or_delete_single_line(svn_diff_hunk_t **hunk_out,
                           const char *line,
-                          svn_patch_t *patch,
+                          const svn_patch_t *patch,
                           svn_boolean_t add,
                           apr_pool_t *result_pool,
                           apr_pool_t *scratch_pool)
@@ -202,11 +202,12 @@ add_or_delete_single_line(svn_diff_hunk_
 svn_error_t *
 svn_diff_hunk__create_adds_single_line(svn_diff_hunk_t **hunk_out,
                                        const char *line,
-                                       svn_patch_t *patch,
+                                       const svn_patch_t *patch,
                                        apr_pool_t *result_pool,
                                        apr_pool_t *scratch_pool)
 {
-  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, TRUE,
+  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, 
+                                    (!patch->reverse),
                                     result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
@@ -214,11 +215,12 @@ svn_diff_hunk__create_adds_single_line(s
 svn_error_t *
 svn_diff_hunk__create_deletes_single_line(svn_diff_hunk_t **hunk_out,
                                           const char *line,
-                                          svn_patch_t *patch,
+                                          const svn_patch_t *patch,
                                           apr_pool_t *result_pool,
                                           apr_pool_t *scratch_pool)
 {
-  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch, FALSE,
+  SVN_ERR(add_or_delete_single_line(hunk_out, line, patch,
+                                    patch->reverse,
                                     result_pool, scratch_pool));
   return SVN_NO_ERROR;
 }
@@ -653,6 +655,7 @@ hunk_readline_original_or_modified(apr_f
   apr_off_t pos;
   svn_stringbuf_t *str;
   const char *eol_p;
+  apr_pool_t *last_pool;
 
   if (!eol)
     eol = &eol_p;
@@ -669,13 +672,19 @@ hunk_readline_original_or_modified(apr_f
   pos = 0;
   SVN_ERR(svn_io_file_seek(file, APR_CUR, &pos,  scratch_pool));
   SVN_ERR(svn_io_file_seek(file, APR_SET, &range->current, scratch_pool));
+
+  /* It's not ITERPOOL because we use data allocated in LAST_POOL out
+     of the loop. */
+  last_pool = svn_pool_create(scratch_pool);
   do
     {
+      svn_pool_clear(last_pool);
+
       max_len = range->end - range->current;
       SVN_ERR(svn_io_file_readline(file, &str, eol, eof, max_len,
-                                   result_pool, scratch_pool));
+                                   last_pool, last_pool));
       range->current = 0;
-      SVN_ERR(svn_io_file_seek(file, APR_CUR, &range->current, scratch_pool));
+      SVN_ERR(svn_io_file_seek(file, APR_CUR, &range->current, last_pool));
       filtered = (str->data[0] == verboten || str->data[0] == '\\');
     }
   while (filtered && ! *eof);
@@ -697,7 +706,7 @@ hunk_readline_original_or_modified(apr_f
       *stringbuf = svn_stringbuf_dup(str, result_pool);
     }
 
-  if (!filtered && *eof && !*eol && !no_final_eol && *str->data)
+  if (!filtered && *eof && !*eol && *str->data)
     {
       /* Ok, we miss a final EOL in the patch file, but didn't see a
          no eol marker line.
@@ -705,7 +714,7 @@ hunk_readline_original_or_modified(apr_f
          We should report that we had an EOL or the patch code will
          misbehave (and it knows nothing about no eol markers) */
 
-      if (eol != &eol_p)
+      if (!no_final_eol && eol != &eol_p)
         {
           apr_off_t start = 0;
 
@@ -723,6 +732,7 @@ hunk_readline_original_or_modified(apr_f
     }
   SVN_ERR(svn_io_file_seek(file, APR_SET, &pos, scratch_pool));
 
+  svn_pool_destroy(last_pool);
   return SVN_NO_ERROR;
 }
 
@@ -1139,12 +1149,12 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
                 }
 
               SVN_ERR(svn_io_file_seek(apr_file, APR_SET, &pos, iterpool));
+              /* Set for the type and context by using != the other type */
+              if (last_line_type != modified_line)
+                original_no_final_eol = TRUE;
+              if (last_line_type != original_line)
+                modified_no_final_eol = TRUE;
             }
-          /* Set for the type and context by using != the other type */
-          if (last_line_type != modified_line)
-            original_no_final_eol = TRUE;
-          if (last_line_type != original_line)
-            modified_no_final_eol = TRUE;
 
           continue;
         }
@@ -1157,7 +1167,13 @@ parse_next_hunk(svn_diff_hunk_t **hunk,
           SVN_ERR(parse_mergeinfo(&found_mergeinfo, line, *hunk, patch,
                                   result_pool, iterpool));
           if (found_mergeinfo)
-            continue; /* Proceed to the next line in the patch. */
+            continue; /* Proceed to the next line in the svn:mergeinfo hunk. */
+          else
+            {
+              /* Perhaps we can also use original_lines/modified_lines here */
+
+              in_hunk = FALSE; /* On to next property */
+            }
         }
 
       if (in_hunk)
@@ -1590,10 +1606,11 @@ git_plus(enum parse_state *new_state, ch
 }
 
 /* Helper for git_old_mode() and git_new_mode().  Translate the git
- * file mode MODE_STR into a binary "executable?" notion EXECUTABLE_P. */
+ * file mode MODE_STR into a binary "executable?" and "symlink?" state. */
 static svn_error_t *
-parse_bits_into_executability(svn_tristate_t *executable_p,
-                              const char *mode_str)
+parse_git_mode_bits(svn_tristate_t *executable_p,
+                    svn_tristate_t *symlink_p,
+                    const char *mode_str)
 {
   apr_uint64_t mode;
   SVN_ERR(svn_cstring_strtoui64(&mode, mode_str,
@@ -1629,6 +1646,24 @@ parse_bits_into_executability(svn_trista
         break;
     }
 
+  switch (mode & 0170000 /* S_IFMT */)
+    {
+      case 0120000: /* S_IFLNK */
+        *symlink_p = svn_tristate_true;
+        break;
+
+      case 0100000: /* S_IFREG */
+      case 0040000: /* S_IFDIR */
+        *symlink_p = svn_tristate_false;
+        break;
+
+      default:
+        /* Ignore unknown values.
+           (Including those generated by Subversion <= 1.9) */
+        *symlink_p = svn_tristate_unknown;
+        break;
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -1637,12 +1672,13 @@ static svn_error_t *
 git_old_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  SVN_ERR(parse_bits_into_executability(&patch->old_executable_p,
-                                        line + STRLEN_LITERAL("old mode ")));
+  SVN_ERR(parse_git_mode_bits(&patch->old_executable_bit,
+                              &patch->old_symlink_bit,
+                              line + STRLEN_LITERAL("old mode ")));
 
 #ifdef SVN_DEBUG
   /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
-  SVN_ERR_ASSERT(patch->old_executable_p != svn_tristate_unknown);
+  SVN_ERR_ASSERT(patch->old_executable_bit != svn_tristate_unknown);
 #endif
 
   *new_state = state_old_mode_seen;
@@ -1654,12 +1690,13 @@ static svn_error_t *
 git_new_mode(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  SVN_ERR(parse_bits_into_executability(&patch->new_executable_p,
-                                        line + STRLEN_LITERAL("new mode ")));
+  SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                              &patch->new_symlink_bit,
+                              line + STRLEN_LITERAL("new mode ")));
 
 #ifdef SVN_DEBUG
   /* If this assert trips, the "old mode" is neither ...644 nor ...755 . */
-  SVN_ERR_ASSERT(patch->new_executable_p != svn_tristate_unknown);
+  SVN_ERR_ASSERT(patch->new_executable_bit != svn_tristate_unknown);
 #endif
 
   /* Don't touch patch->operation. */
@@ -1668,6 +1705,39 @@ git_new_mode(enum parse_state *new_state
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+git_index(enum parse_state *new_state, char *line, svn_patch_t *patch,
+          apr_pool_t *result_pool, apr_pool_t *scratch_pool)
+{
+  /* We either have something like "index 33e5b38..0000000" (which we just
+     ignore as we are not interested in git specific shas) or something like
+     "index 33e5b38..0000000 120000" which tells us the mode, that isn't
+     changed by applying this patch.
+
+     If the mode would have changed then we would see 'old mode' and 'new mode'
+     lines.
+  */
+  line = strchr(line + STRLEN_LITERAL("index "), ' ');
+
+  if (line && patch->new_executable_bit == svn_tristate_unknown
+           && patch->new_symlink_bit == svn_tristate_unknown
+           && patch->operation != svn_diff_op_added
+           && patch->operation != svn_diff_op_deleted)
+    {
+      SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                                  &patch->new_symlink_bit,
+                                  line + 1));
+
+      /* There is no change.. so set the old values to the new values */
+      patch->old_executable_bit = patch->new_executable_bit;
+      patch->old_symlink_bit = patch->new_symlink_bit;
+    }
+
+  /* This function doesn't change the state! */
+  /* *new_state = *new_state */
+  return SVN_NO_ERROR;
+}
+
 /* Parse the 'rename from ' line of a git extended unidiff. */
 static svn_error_t *
 git_move_from(enum parse_state *new_state, char *line, svn_patch_t *patch,
@@ -1728,9 +1798,9 @@ static svn_error_t *
 git_new_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  SVN_ERR(
-    parse_bits_into_executability(&patch->new_executable_p,
-                                  line + STRLEN_LITERAL("new file mode ")));
+  SVN_ERR(parse_git_mode_bits(&patch->new_executable_bit,
+                              &patch->new_symlink_bit,
+                              line + STRLEN_LITERAL("new file mode ")));
 
   patch->operation = svn_diff_op_added;
 
@@ -1745,9 +1815,9 @@ static svn_error_t *
 git_deleted_file(enum parse_state *new_state, char *line, svn_patch_t *patch,
                  apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  SVN_ERR(
-    parse_bits_into_executability(&patch->old_executable_p,
-                                  line + STRLEN_LITERAL("deleted file mode ")));
+  SVN_ERR(parse_git_mode_bits(&patch->old_executable_bit,
+                              &patch->old_symlink_bit,
+                              line + STRLEN_LITERAL("deleted file mode ")));
 
   patch->operation = svn_diff_op_deleted;
 
@@ -1762,8 +1832,6 @@ static svn_error_t *
 binary_patch_start(enum parse_state *new_state, char *line, svn_patch_t *patch,
              apr_pool_t *result_pool, apr_pool_t *scratch_pool)
 {
-  patch->operation = svn_diff_op_modified;
-
   *new_state = state_binary_patch_found;
   return SVN_NO_ERROR;
 }
@@ -1896,7 +1964,6 @@ parse_binary_patch(svn_patch_t *patch, a
 
   bpatch->apr_file = apr_file;
 
-  patch->operation = svn_diff_op_modified;
   patch->prop_patches = apr_hash_make(result_pool);
 
   pos = 0;
@@ -2034,8 +2101,13 @@ static struct transition transitions[] =
 
   {"deleted file ",     state_git_diff_seen,    git_deleted_file},
 
+  {"index ",            state_git_diff_seen,    git_index},
+  {"index ",            state_git_tree_seen,    git_index},
+  {"index ",            state_git_mode_seen,    git_index},
+
   {"GIT binary patch",  state_git_diff_seen,    binary_patch_start},
   {"GIT binary patch",  state_git_tree_seen,    binary_patch_start},
+  {"GIT binary patch",  state_git_mode_seen,    binary_patch_start},
 };
 
 svn_error_t *
@@ -2061,8 +2133,10 @@ svn_diff_parse_next_patch(svn_patch_t **
     }
 
   patch = apr_pcalloc(result_pool, sizeof(*patch));
-  patch->old_executable_p = svn_tristate_unknown;
-  patch->new_executable_p = svn_tristate_unknown;
+  patch->old_executable_bit = svn_tristate_unknown;
+  patch->new_executable_bit = svn_tristate_unknown;
+  patch->old_symlink_bit = svn_tristate_unknown;
+  patch->new_symlink_bit = svn_tristate_unknown;
 
   pos = patch_file->next_patch_offset;
   SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &pos, scratch_pool));
@@ -2113,17 +2187,13 @@ svn_diff_parse_next_patch(svn_patch_t **
                && line_after_tree_header_read
                && !valid_header_line)
         {
-          /* git patches can contain an index line after the file mode line */
-          if (!starts_with(line->data, "index "))
-          {
-            /* We have a valid diff header for a patch with only tree changes.
-             * Rewind to the start of the line just read, so subsequent calls
-             * to this function don't end up skipping the line -- it may
-             * contain a patch. */
-            SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
-                    scratch_pool));
-            break;
-          }
+          /* We have a valid diff header for a patch with only tree changes.
+           * Rewind to the start of the line just read, so subsequent calls
+           * to this function don't end up skipping the line -- it may
+           * contain a patch. */
+          SVN_ERR(svn_io_file_seek(patch_file->apr_file, APR_SET, &last_line,
+                                   scratch_pool));
+          break;
         }
       else if (state == state_git_tree_seen
                || state == state_git_mode_seen)
@@ -2131,8 +2201,7 @@ svn_diff_parse_next_patch(svn_patch_t **
           line_after_tree_header_read = TRUE;
         }
       else if (! valid_header_line && state != state_start
-               && state != state_git_diff_seen
-               && !starts_with(line->data, "index "))
+               && state != state_git_diff_seen)
         {
           /* We've encountered an invalid diff header.
            *
@@ -2172,9 +2241,13 @@ svn_diff_parse_next_patch(svn_patch_t **
             break; /* Stays modify */
         }
 
-      ts_tmp = patch->old_executable_p;
-      patch->old_executable_p = patch->new_executable_p;
-      patch->new_executable_p = ts_tmp;
+      ts_tmp = patch->old_executable_bit;
+      patch->old_executable_bit = patch->new_executable_bit;
+      patch->new_executable_bit = ts_tmp;
+
+      ts_tmp = patch->old_symlink_bit;
+      patch->old_symlink_bit = patch->new_symlink_bit;
+      patch->new_symlink_bit = ts_tmp;
     }
 
   if (patch->old_filename == NULL || patch->new_filename == NULL)

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_base/tree.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_base/tree.c Tue Oct  6 08:46:43 2015
@@ -68,6 +68,7 @@
 #include "private/svn_fspath.h"
 #include "private/svn_fs_util.h"
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_sorts_private.h"
 
 
 /* ### I believe this constant will become internal to reps-strings.c.
@@ -2580,8 +2581,7 @@ verify_locks(const char *txn_name,
       apr_hash_this(hi, &key, NULL, NULL);
       APR_ARRAY_PUSH(changed_paths, const char *) = key;
     }
-  qsort(changed_paths->elts, changed_paths->nelts,
-        changed_paths->elt_size, svn_sort_compare_paths);
+  svn_sort__array(changed_paths, svn_sort_compare_paths);
 
   /* Now, traverse the array of changed paths, verify locks.  Note
      that if we need to do a recursive verification a path, we'll skip

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/cached_data.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/cached_data.c Tue Oct  6 08:46:43 2015
@@ -2636,27 +2636,27 @@ locate_dir_cache(svn_fs_t *fs,
                  apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  if (svn_fs_fs__id_is_txn(noderev->id))
+  if (!noderev->data_rep)
+    {
+      /* no data rep -> empty directory.
+         A NULL key causes a cache miss. */
+      *key = NULL;
+      return ffd->dir_cache;
+    }
+
+  if (svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
     {
       /* data in txns requires the expensive fs_id-based addressing mode */
       *key = svn_fs_fs__id_unparse(noderev->id, pool)->data;
+
       return ffd->txn_dir_cache;
     }
   else
     {
       /* committed data can use simple rev,item pairs */
-      if (noderev->data_rep)
-        {
-          pair_key->revision = noderev->data_rep->revision;
-          pair_key->second = noderev->data_rep->item_index;
-          *key = pair_key;
-        }
-      else
-        {
-          /* no data rep -> empty directory.
-             A NULL key causes a cache miss. */
-          *key = NULL;
-        }
+      pair_key->revision = noderev->data_rep->revision;
+      pair_key->second = noderev->data_rep->item_index;
+      *key = pair_key;
 
       return ffd->dir_cache;
     }

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c Tue Oct  6 08:46:43 2015
@@ -108,8 +108,8 @@ typedef struct path_order_t
   /* noderev predecessor count */
   int predecessor_count;
 
-  /* this is a directory node */
-  svn_boolean_t is_dir;
+  /* this is a node is the latest for this PATH in this rev / pack file */
+  svn_boolean_t is_head;
 
   /* length of the expanded representation content */
   apr_int64_t expanded_size;
@@ -746,7 +746,6 @@ copy_node_to_temp(pack_context_t *contex
   path_order->node_id = *svn_fs_fs__id_node_id(noderev->id);
   path_order->revision = svn_fs_fs__id_rev(noderev->id);
   path_order->predecessor_count = noderev->predecessor_count;
-  path_order->is_dir = noderev->kind == svn_node_dir;
   path_order->noderev_id = *svn_fs_fs__id_rev_item(noderev->id);
   APR_ARRAY_PUSH(context->path_order, path_order_t *) = path_order;
 
@@ -763,13 +762,8 @@ compare_path_order(const path_order_t *
   const path_order_t * lhs = *lhs_p;
   const path_order_t * rhs = *rhs_p;
 
-  /* cluster all directories */
-  int diff = rhs->is_dir - lhs->is_dir;
-  if (diff)
-    return diff;
-
   /* lexicographic order on path and node (i.e. latest first) */
-  diff = svn_prefix_string__compare(lhs->path, rhs->path);
+  int diff = svn_prefix_string__compare(lhs->path, rhs->path);
   if (diff)
     return diff;
 
@@ -816,6 +810,41 @@ roundness(int value)
   return value ? value - (value & (value - 1)) : INT_MAX;
 }
 
+/* For all paths in first COUNT entries in PATH_ORDER, mark their latest
+ * node as "HEAD".  PATH_ORDER must be ordered by path, revision.
+ */
+static void
+classify_nodes(path_order_t **path_order,
+               int count)
+{
+  const svn_prefix_string__t *path;
+  int i;
+
+  /* The logic below would fail for empty ranges. */
+  if (count == 0)
+    return;
+
+  /* All entries are sorted by path, followed by revision.
+   * So, the first index is also HEAD for the first path.
+   */
+  path = path_order[0]->path;
+  path_order[0]->is_head = TRUE;
+
+  /* Since the sorting implicitly groups all entries by path and then sorts
+   * by descending revision within the group, whenever we encounter a new
+   * path, the first entry is "HEAD" for that path.
+   */
+  for (i = 1; i < count; ++i)
+    {
+      /* New path? */
+      if (svn_prefix_string__compare(path, path_order[i]->path))
+        {
+          path = path_order[i]->path;
+          path_order[i]->is_head = TRUE;
+        }
+    }
+}
+
 /* Order a range of data collected in CONTEXT such that we can place them
  * in the desired order.  The input is taken from *PATH_ORDER, offsets FIRST
  * to LAST and then written in the final order to the same range in *TEMP.
@@ -953,7 +982,7 @@ static void
 sort_reps(pack_context_t *context)
 {
   apr_pool_t *temp_pool;
-  const path_order_t **temp, **path_order;
+  path_order_t **temp, **path_order;
   int i, count;
 
   /* We will later assume that there is at least one node / path.
@@ -979,7 +1008,10 @@ sort_reps(pack_context_t *context)
   temp = apr_pcalloc(temp_pool, count * sizeof(*temp));
   path_order = (void *)context->path_order->elts;
 
-  /* Sort those sub-sections separately. */
+  /* Mark nodes depending on what other nodes exist for the same path etc. */
+  classify_nodes(path_order, count);
+
+  /* Rearrange those sub-sections separately. */
   sort_reps_range(context, path_order, temp, 0, count);
 
   /* We now know the final ordering. */
@@ -1147,7 +1179,7 @@ copy_reps_from_temp(pack_context_t *cont
   apr_array_header_t *path_order = context->path_order;
   int i;
 
-  /* copy items in path order. */
+  /* copy items in path order.  Exclude the non-HEAD noderevs. */
   for (i = 0; i < path_order->nelts; ++i)
     {
       path_order_t *current_path;
@@ -1157,13 +1189,30 @@ copy_reps_from_temp(pack_context_t *cont
       svn_pool_clear(iterpool);
 
       current_path = APR_ARRAY_IDX(path_order, i, path_order_t *);
-      node_part = get_item(context, &current_path->noderev_id, TRUE);
+      if (current_path->is_head)
+        {
+          node_part = get_item(context, &current_path->noderev_id, TRUE);
+          if (node_part)
+            SVN_ERR(store_item(context, temp_file, node_part, iterpool));
+        }
+
       rep_part = get_item(context, &current_path->rep_id, TRUE);
+      if (rep_part)
+        SVN_ERR(store_item(context, temp_file, rep_part, iterpool));
+    }
 
+  /* copy the remaining non-head noderevs. */
+  for (i = 0; i < path_order->nelts; ++i)
+    {
+      path_order_t *current_path;
+      svn_fs_fs__p2l_entry_t *node_part;
+
+      svn_pool_clear(iterpool);
+
+      current_path = APR_ARRAY_IDX(path_order, i, path_order_t *);
+      node_part = get_item(context, &current_path->noderev_id, TRUE);
       if (node_part)
         SVN_ERR(store_item(context, temp_file, node_part, iterpool));
-      if (rep_part)
-        SVN_ERR(store_item(context, temp_file, rep_part, iterpool));
     }
 
   svn_pool_destroy(iterpool);

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/stats.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/stats.c Tue Oct  6 08:46:43 2015
@@ -70,8 +70,9 @@ typedef enum rep_kind_t
  */
 typedef struct rep_stats_t
 {
-  /* absolute offset in the file */
-  apr_off_t offset;
+  /* offset in the revision file (phys. addressing) /
+   * item index within REVISION (log. addressing) */
+  apr_uint64_t item_index;
 
   /* item length in bytes */
   apr_uint64_t size;
@@ -92,8 +93,36 @@ typedef struct rep_stats_t
   /* classification of the representation. values of rep_kind_t */
   char kind;
 
+  /* length of the delta chain, including this representation,
+   * saturated to 255 - if need be */
+  apr_byte_t chain_length;
 } rep_stats_t;
 
+/* Represents a link in the rep delta chain.  REVISION + ITEM_INDEX points
+ * to BASE_REVISION + BASE_ITEM_INDEX.  We collect this info while scanning
+ * a f7 repo in a single pass and resolve it afterwards. */
+typedef struct rep_ref_t
+{
+  /* Revision that contains this representation. */
+  svn_revnum_t revision;
+
+  /* Item index of this rep within REVISION. */
+  apr_uint64_t item_index;
+
+  /* Revision of the representation we deltified against.
+   * -1 if this representation is either PLAIN or a self-delta. */
+  svn_revnum_t base_revision;
+
+  /* Item index of that rep within BASE_REVISION. */
+  apr_uint64_t base_item_index;
+
+  /* Length of the PLAIN / DELTA line in the source file in bytes.
+   * We use this to update the info in the rep stats after scanning the
+   * whole file. */
+  apr_uint16_t header_size;
+
+} rep_ref_t;
+
 /* Represents a single revision.
  * There will be only one instance per revision. */
 typedef struct revision_info_t
@@ -328,13 +357,13 @@ add_change(svn_fs_fs__stats_t *stats,
 
 /* Comparator used for binary search comparing the absolute file offset
  * of a representation to some other offset. DATA is a *rep_stats_t,
- * KEY is a pointer to an apr_off_t.
+ * KEY is a pointer to an apr_uint64_t.
  */
 static int
-compare_representation_offsets(const void *data, const void *key)
+compare_representation_item_index(const void *data, const void *key)
 {
-  apr_off_t lhs = (*(const rep_stats_t *const *)data)->offset;
-  apr_off_t rhs = *(const apr_off_t *)key;
+  apr_uint64_t lhs = (*(const rep_stats_t *const *)data)->item_index;
+  apr_uint64_t rhs = *(const apr_uint64_t *)key;
 
   if (lhs < rhs)
     return -1;
@@ -345,7 +374,7 @@ compare_representation_offsets(const voi
  * return it in *REVISION_INFO. For performance reasons, we skip the
  * lookup if the info is already provided.
  *
- * In that revision, look for the rep_stats_t object for offset OFFSET.
+ * In that revision, look for the rep_stats_t object for item ITEM_INDEX.
  * If it already exists, set *IDX to its index in *REVISION_INFO's
  * representations list and return the representation object. Otherwise,
  * set the index to where it must be inserted and return NULL.
@@ -355,7 +384,7 @@ find_representation(int *idx,
                     query_t *query,
                     revision_info_t **revision_info,
                     svn_revnum_t revision,
-                    apr_off_t offset)
+                    apr_uint64_t item_index)
 {
   revision_info_t *info;
   *idx = -1;
@@ -375,14 +404,14 @@ find_representation(int *idx,
 
   /* look for the representation */
   *idx = svn_sort__bsearch_lower_bound(info->representations,
-                                       &offset,
-                                       compare_representation_offsets);
+                                       &item_index,
+                                       compare_representation_item_index);
   if (*idx < info->representations->nelts)
     {
       /* return the representation, if this is the one we were looking for */
       rep_stats_t *result
         = APR_ARRAY_IDX(info->representations, *idx, rep_stats_t *);
-      if (result->offset == offset)
+      if (result->item_index == item_index)
         return result;
     }
 
@@ -411,7 +440,7 @@ parse_representation(rep_stats_t **repre
 
   /* look it up */
   result = find_representation(&idx, query, &revision_info, rep->revision,
-                               (apr_off_t)rep->item_index);
+                               rep->item_index);
   if (!result)
     {
       /* not parsed, yet (probably a rep in the same revision).
@@ -420,7 +449,7 @@ parse_representation(rep_stats_t **repre
       result = apr_pcalloc(result_pool, sizeof(*result));
       result->revision = rep->revision;
       result->expanded_size = rep->expanded_size;
-      result->offset = (apr_off_t)rep->item_index;
+      result->item_index = rep->item_index;
       result->size = rep->size;
 
       /* In phys. addressing mode, follow link to the actual representation.
@@ -429,7 +458,8 @@ parse_representation(rep_stats_t **repre
       if (!svn_fs_fs__use_log_addressing(query->fs))
         {
           svn_fs_fs__rep_header_t *header;
-          apr_off_t offset = revision_info->offset + result->offset;
+          apr_off_t offset = revision_info->offset
+                           + (apr_off_t)rep->item_index;
 
           SVN_ERR_ASSERT(revision_info->rev_file);
           SVN_ERR(svn_io_file_seek(revision_info->rev_file->file, APR_SET,
@@ -439,6 +469,23 @@ parse_representation(rep_stats_t **repre
                                              scratch_pool, scratch_pool));
 
           result->header_size = header->header_size;
+
+          /* Determine length of the delta chain. */
+          if (header->type == svn_fs_fs__rep_delta)
+            {
+              int base_idx;
+              rep_stats_t *base_rep
+                = find_representation(&base_idx, query, NULL,
+                                      header->base_revision,
+                                      header->base_item_index);
+
+              result->chain_length = 1 + MIN(base_rep->chain_length,
+                                             (apr_byte_t)0xfe);
+            }
+          else
+            {
+              result->chain_length = 1;
+            }
         }
 
       svn_sort__array_insert(revision_info->representations, &result, idx);
@@ -867,6 +914,70 @@ read_item(svn_stringbuf_t **contents,
   return SVN_NO_ERROR;
 }
 
+/* Predicate comparing the two rep_ref_t** LHS and RHS by the respective
+ * representation's revision.
+ */
+static int
+compare_representation_refs(const void *lhs, const void *rhs)
+{
+  svn_revnum_t lhs_rev = (*(const rep_ref_t *const *)lhs)->revision;
+  svn_revnum_t rhs_rev = (*(const rep_ref_t *const *)rhs)->revision;
+
+  if (lhs_rev < rhs_rev)
+    return -1;
+  return (lhs_rev > rhs_rev ? 1 : 0);
+}
+
+/* Given all the presentations found in a single rev / pack file as
+ * rep_ref_t * in REP_REFS, update the delta chain lengths in QUERY.
+ * REP_REFS and its contents can then be discarded.
+ */
+static svn_error_t *
+resolve_representation_refs(query_t *query,
+                            apr_array_header_t *rep_refs)
+{
+  int i;
+
+  /* Because delta chains can only point to previous revs, after sorting
+   * REP_REFS, all base refs have already been updated. */
+  svn_sort__array(rep_refs, compare_representation_refs);
+
+  /* Build up the CHAIN_LENGTH values. */
+  for (i = 0; i < rep_refs->nelts; ++i)
+    {
+      int idx;
+      rep_ref_t *ref = APR_ARRAY_IDX(rep_refs, i, rep_ref_t *);
+      rep_stats_t *rep = find_representation(&idx, query, NULL,
+                                             ref->revision, ref->item_index);
+
+      /* No dangling pointers and all base reps have been processed. */
+      SVN_ERR_ASSERT(rep);
+      SVN_ERR_ASSERT(!rep->chain_length);
+
+      /* Set the HEADER_SIZE as we found it during the scan. */
+      rep->header_size = ref->header_size;
+
+      /* The delta chain got 1 element longer. */
+      if (ref->base_revision == SVN_INVALID_REVNUM)
+        {
+          rep->chain_length = 1;
+        }
+      else
+        {
+          rep_stats_t *base;
+
+          base = find_representation(&idx, query, NULL, ref->base_revision,
+                                     ref->base_item_index);
+          SVN_ERR_ASSERT(base);
+          SVN_ERR_ASSERT(base->chain_length);
+
+          rep->chain_length = 1 + MIN(base->chain_length, (apr_byte_t)0xfe);
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Process the logically addressed revision contents of revisions BASE to
  * BASE + COUNT - 1 in QUERY.
  *
@@ -887,6 +998,12 @@ read_log_rev_or_packfile(query_t *query,
   int i;
   svn_fs_fs__revision_file_t *rev_file;
 
+  /* We collect the delta chain links as we scan the file.  Afterwards,
+   * we determine the lengths of those delta chains and throw this
+   * temporary container away. */
+  apr_array_header_t *rep_refs = apr_array_make(scratch_pool, 64,
+                                                sizeof(rep_ref_t *));
+
   /* we will process every revision in the rev / pack file */
   for (i = 0; i < count; ++i)
     {
@@ -929,6 +1046,8 @@ read_log_rev_or_packfile(query_t *query,
       /* process all entries (and later continue with the next block) */
       for (i = 0; i < entries->nelts; ++i)
         {
+          svn_stringbuf_t *item;
+          revision_info_t *info;
           svn_fs_fs__p2l_entry_t *entry
             = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
 
@@ -941,32 +1060,64 @@ read_log_rev_or_packfile(query_t *query,
             continue;
 
           /* read and process interesting items */
+          info = APR_ARRAY_IDX(query->revisions, entry->item.revision,
+                               revision_info_t*);
+
           if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
             {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
               SVN_ERR(read_item(&item, rev_file, entry, iterpool, iterpool));
               SVN_ERR(read_noderev(query, item, info, result_pool, iterpool));
             }
           else if (entry->type == SVN_FS_FS__ITEM_TYPE_CHANGES)
             {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
               SVN_ERR(read_item(&item, rev_file, entry, iterpool, iterpool));
               info->change_count
                 = get_log_change_count(item->data + 0, item->len);
               info->changes_len += entry->size;
             }
+          else if (   (entry->type == SVN_FS_FS__ITEM_TYPE_FILE_REP)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_DIR_REP)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_FILE_PROPS)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_DIR_PROPS))
+            {
+              /* Collect the delta chain link. */
+              svn_fs_fs__rep_header_t *header;
+              rep_ref_t *ref = apr_pcalloc(scratch_pool, sizeof(*ref));
+
+              SVN_ERR(svn_io_file_aligned_seek(rev_file->file,
+                                               rev_file->block_size,
+                                               NULL, entry->offset,
+                                               iterpool));
+              SVN_ERR(svn_fs_fs__read_rep_header(&header,
+                                                 rev_file->stream,
+                                                 iterpool, iterpool));
+
+              ref->header_size = header->header_size;
+              ref->revision = entry->item.revision;
+              ref->item_index = entry->item.number;
+
+              if (header->type == svn_fs_fs__rep_delta)
+                {
+                  ref->base_item_index = header->base_item_index;
+                  ref->base_revision = header->base_revision;
+                }
+              else
+                {
+                  ref->base_item_index = SVN_FS_FS__ITEM_INDEX_UNUSED;
+                  ref->base_revision = SVN_INVALID_REVNUM;
+                }
+
+              APR_ARRAY_PUSH(rep_refs, rep_ref_t *) = ref;
+            }
 
           /* advance offset */
           offset += entry->size;
         }
     }
 
+  /* Resolve the delta chain links. */
+  SVN_ERR(resolve_representation_refs(query, rep_refs));
+
   /* clean up and close file handles */
   svn_pool_destroy(iterpool);
 
@@ -1093,6 +1244,7 @@ add_rep_stats(svn_fs_fs__representation_
 
   stats->references += rep->ref_count;
   stats->expanded_size += rep->ref_count * rep->expanded_size;
+  stats->chain_len += rep->chain_length;
 }
 
 /* Aggregate the info the in revision_info_t * array REVISIONS into the

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c Tue Oct  6 08:46:43 2015
@@ -1076,6 +1076,18 @@ svn_fs_fs__replace_dir_entry(void **data
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__reset_txn_filesize(void **data,
+                              apr_size_t *data_len,
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  dir_data_t *dir_data = (dir_data_t *)*data;
+  dir_data->txn_filesize = SVN_INVALID_FILESIZE;
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t  *
 svn_fs_fs__serialize_rep_header(void **data,
                                 apr_size_t *data_len,

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.h?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.h Tue Oct  6 08:46:43 2015
@@ -295,6 +295,17 @@ svn_fs_fs__replace_dir_entry(void **data
                              apr_pool_t *pool);
 
 /**
+ * Implements #svn_cache__partial_setter_func_t for a #svn_fs_fs__dir_data_t
+ * at @a *data, resetting its txn_filesize field to SVN_INVALID_FILESIZE.
+ * &a baton should be NULL.
+ */
+svn_error_t *
+svn_fs_fs__reset_txn_filesize(void **data,
+                              apr_size_t *data_len,
+                              void *baton,
+                              apr_pool_t *pool);
+
+/**
  * Implements #svn_cache__serialize_func_t for a #svn_fs_fs__rep_header_t.
  */
 svn_error_t *

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c Tue Oct  6 08:46:43 2015
@@ -576,16 +576,62 @@ unparse_dir_entry(svn_fs_dirent_t *diren
                   svn_stream_t *stream,
                   apr_pool_t *pool)
 {
-  const char *val
-    = apr_psprintf(pool, "%s %s",
-                   (dirent->kind == svn_node_file) ? SVN_FS_FS__KIND_FILE
-                                                   : SVN_FS_FS__KIND_DIR,
-                   svn_fs_fs__id_unparse(dirent->id, pool)->data);
-
-  SVN_ERR(svn_stream_printf(stream, pool, "K %" APR_SIZE_T_FMT "\n%s\n"
-                            "V %" APR_SIZE_T_FMT "\n%s\n",
-                            strlen(dirent->name), dirent->name,
-                            strlen(val), val));
+  apr_size_t to_write;
+  svn_string_t *id_str = svn_fs_fs__id_unparse(dirent->id, pool);
+  apr_size_t name_len = strlen(dirent->name);
+
+  /* Note that sizeof == len + 1, i.e. accounts for the space between
+   * type and ID. */
+  apr_size_t type_len = (dirent->kind == svn_node_file)
+                      ? sizeof(SVN_FS_FS__KIND_FILE)
+                      : sizeof(SVN_FS_FS__KIND_DIR);
+  apr_size_t value_len = type_len + id_str->len;
+
+  /* A buffer with sufficient space for 
+   * - both string lines
+   * - 4 newlines
+   * - 2 lines K/V lines containing a number each
+   */
+  char *buffer = apr_palloc(pool,   name_len + value_len
+                                  + 4
+                                  + 2 * (2 + SVN_INT64_BUFFER_SIZE));
+
+  /* Now construct the value. */
+  char *p = buffer;
+
+  /* The "K length(name)\n" line. */
+  p[0] = 'K';
+  p[1] = ' ';
+  p += 2;
+  p += svn__i64toa(p, name_len);
+  *(p++) = '\n';
+
+  /* The line with the key, i.e. dir entry name. */
+  memcpy(p, dirent->name, name_len);
+  p += name_len;
+  *(p++) = '\n';
+
+  /* The "V length(type+id)\n" line. */
+  p[0] = 'V';
+  p[1] = ' ';
+  p += 2;
+  p += svn__i64toa(p, value_len);
+  *(p++) = '\n';
+
+  /* The line with the type and ID. */
+  memcpy(p,
+         (dirent->kind == svn_node_file) ? SVN_FS_FS__KIND_FILE
+                                         : SVN_FS_FS__KIND_DIR,
+         type_len - 1);
+  p += type_len - 1;
+  *(p++) = ' ';
+  memcpy(p, id_str->data, id_str->len);
+  p+=id_str->len;
+  *(p++) = '\n';
+
+  /* Add the entry to the output stream. */
+  to_write = p - buffer;
+  SVN_ERR(svn_stream_write(stream, buffer, &to_write));
   return SVN_NO_ERROR;
 }
 
@@ -1503,8 +1549,6 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
       out = svn_stream_from_aprfile2(file, TRUE, pool);
       SVN_ERR(unparse_dir_entries(entries, out, subpool));
 
-      svn_pool_clear(subpool);
-
       /* Mark the node-rev's data rep as mutable. */
       rep = apr_pcalloc(pool, sizeof(*rep));
       rep->revision = SVN_INVALID_REVNUM;
@@ -1513,6 +1557,30 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
       parent_noderev->data_rep = rep;
       SVN_ERR(svn_fs_fs__put_node_revision(fs, parent_noderev->id,
                                            parent_noderev, FALSE, pool));
+
+      /* Immediately populate the txn dir cache to avoid re-reading
+       * the file we just wrote. */
+      if (ffd->txn_dir_cache)
+        {
+          const char *key
+            = svn_fs_fs__id_unparse(parent_noderev->id, subpool)->data;
+          svn_fs_fs__dir_data_t dir_data;
+          svn_filesize_t filesize;
+
+          /* Flush APR buffers. */
+          SVN_ERR(svn_io_file_flush(file, subpool));
+
+          /* Obtain final file size to update txn_dir_cache. */
+          SVN_ERR(svn_io_file_size_get(&filesize, file, subpool));
+
+          /* Store in the cache. */
+          dir_data.entries = entries;
+          dir_data.txn_filesize = filesize;
+          SVN_ERR(svn_cache__set(ffd->txn_dir_cache, key, &dir_data,
+                                 subpool));
+        }
+
+      svn_pool_clear(subpool);
     }
   else
     {
@@ -2180,6 +2248,10 @@ get_shared_rep(representation_t **old_re
   if (!ffd->rep_sharing_allowed)
     return SVN_NO_ERROR;
 
+  /* Can't look up if we don't know the key (happens for directories). */
+  if (!rep->has_sha1)
+    return SVN_NO_ERROR;
+
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out.  Start with the hash lookup
      because it is cheapest. */
@@ -2296,6 +2368,7 @@ get_shared_rep(representation_t **old_re
 }
 
 /* Copy the hash sum calculation results from MD5_CTX, SHA1_CTX into REP.
+ * SHA1 results are only be set if SHA1_CTX is not NULL.
  * Use POOL for allocations.
  */
 static svn_error_t *
@@ -2308,10 +2381,12 @@ digests_final(representation_t *rep,
 
   SVN_ERR(svn_checksum_final(&checksum, md5_ctx, pool));
   memcpy(rep->md5_digest, checksum->digest, svn_checksum_size(checksum));
-  SVN_ERR(svn_checksum_final(&checksum, sha1_ctx, pool));
-  rep->has_sha1 = checksum != NULL;
+  rep->has_sha1 = sha1_ctx != NULL;
   if (rep->has_sha1)
-    memcpy(rep->sha1_digest, checksum->digest, svn_checksum_size(checksum));
+    {
+      SVN_ERR(svn_checksum_final(&checksum, sha1_ctx, pool));
+      memcpy(rep->sha1_digest, checksum->digest, svn_checksum_size(checksum));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2516,6 +2591,8 @@ struct write_container_baton
   apr_size_t size;
 
   svn_checksum_ctx_t *md5_ctx;
+
+  /* SHA1 calculation is optional. If not needed, this will be NULL. */
   svn_checksum_ctx_t *sha1_ctx;
 };
 
@@ -2530,7 +2607,8 @@ write_container_handler(void *baton,
   struct write_container_baton *whb = baton;
 
   SVN_ERR(svn_checksum_update(whb->md5_ctx, data, *len));
-  SVN_ERR(svn_checksum_update(whb->sha1_ctx, data, *len));
+  if (whb->sha1_ctx)
+    SVN_ERR(svn_checksum_update(whb->sha1_ctx, data, *len));
 
   SVN_ERR(svn_stream_write(whb->stream, data, len));
   whb->size += *len;
@@ -2602,7 +2680,8 @@ write_container_rep(representation_t *re
                                   scratch_pool);
   whb->size = 0;
   whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
+  if (item_type != SVN_FS_FS__ITEM_TYPE_DIR_REP)
+    whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
   stream = svn_stream_create(whb, scratch_pool);
   svn_stream_set_write(stream, write_container_handler);
@@ -2741,7 +2820,8 @@ write_container_delta_rep(representation
                                         scratch_pool);
   whb->size = 0;
   whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
+  if (item_type != SVN_FS_FS__ITEM_TYPE_DIR_REP)
+    whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
   /* serialize the hash */
   stream = svn_stream_create(whb, scratch_pool);
@@ -2895,6 +2975,9 @@ get_final_id(svn_fs_fs__id_part_t *part,
    INITIAL_OFFSET is the offset of the proto-rev-file on entry to
    commit_body.
 
+   Collect the pair_cache_key_t of all directories written to the
+   committed cache in DIRECTORY_IDS.
+
    If REPS_TO_CACHE is not NULL, append to it a copy (allocated in
    REPS_POOL) of each data rep that is new in this revision.
 
@@ -2916,6 +2999,7 @@ write_final_rev(const svn_fs_id_t **new_
                 apr_uint64_t start_node_id,
                 apr_uint64_t start_copy_id,
                 apr_off_t initial_offset,
+                apr_array_header_t *directory_ids,
                 apr_array_header_t *reps_to_cache,
                 apr_hash_t *reps_hash,
                 apr_pool_t *reps_pool,
@@ -2958,14 +3042,17 @@ write_final_rev(const svn_fs_id_t **new_
           svn_pool_clear(subpool);
           SVN_ERR(write_final_rev(&new_id, file, rev, fs, dirent->id,
                                   start_node_id, start_copy_id, initial_offset,
-                                  reps_to_cache, reps_hash, reps_pool, FALSE,
-                                  subpool));
+                                  directory_ids, reps_to_cache, reps_hash,
+                                  reps_pool, FALSE, subpool));
           if (new_id && (svn_fs_fs__id_rev(new_id) == rev))
             dirent->id = svn_fs_fs__id_copy(new_id, pool);
         }
 
       if (noderev->data_rep && is_txn_rep(noderev->data_rep))
         {
+          pair_cache_key_t *key;
+          svn_fs_fs__dir_data_t dir_data;
+
           /* Write out the contents of this directory as a text rep. */
           noderev->data_rep->revision = rev;
           if (ffd->deltify_directories)
@@ -2981,6 +3068,23 @@ write_final_rev(const svn_fs_id_t **new_
                                         SVN_FS_FS__ITEM_TYPE_DIR_REP, pool));
 
           reset_txn_in_rep(noderev->data_rep);
+
+          /* Cache the new directory contents.  Otherwise, subsequent reads
+           * or commits will likely have to reconstruct, verify and parse
+           * it again. */
+          key = apr_array_push(directory_ids);
+          key->revision = noderev->data_rep->revision;
+          key->second = noderev->data_rep->item_index;
+
+          /* Store directory contents under the new revision number but mark
+           * it as "stale" by setting the file length to 0.  Committed dirs
+           * will report -1, in-txn dirs will report > 0, so that this can
+           * never match.  We reset that to -1 after the commit is complete.
+           */
+          dir_data.entries = entries;
+          dir_data.txn_filesize = 0;
+
+          SVN_ERR(svn_cache__set(ffd->dir_cache, key, &dir_data, subpool));
         }
     }
   else
@@ -3423,6 +3527,41 @@ svn_fs_fs__add_index_data(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Mark the directories cached in FS with the keys from DIRECTORY_IDS
+ * as "valid" now.  Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+promote_cached_directories(svn_fs_t *fs,
+                           apr_array_header_t *directory_ids,
+                           apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_pool_t *iterpool;
+  int i;
+
+  if (!ffd->dir_cache)
+    return SVN_NO_ERROR;
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < directory_ids->nelts; ++i)
+    {
+      const pair_cache_key_t *key
+        = &APR_ARRAY_IDX(directory_ids, i, pair_cache_key_t);
+
+      svn_pool_clear(iterpool);
+
+      /* Currently, the entry for KEY - if it still exists - is marked
+       * as "stale" and would not be used.  Mark it as current for in-
+       * revison data. */
+      SVN_ERR(svn_cache__set_partial(ffd->dir_cache, key,
+                                     svn_fs_fs__reset_txn_filesize, NULL,
+                                     iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton used for commit_body below. */
 struct commit_baton {
   svn_revnum_t *new_rev_p;
@@ -3452,6 +3591,8 @@ commit_body(void *baton, apr_pool_t *poo
   apr_off_t initial_offset, changed_path_offset;
   const svn_fs_fs__id_part_t *txn_id = svn_fs_fs__txn_get_id(cb->txn);
   apr_hash_t *changed_paths;
+  apr_array_header_t *directory_ids = apr_array_make(pool, 4,
+                                                     sizeof(pair_cache_key_t));
 
   /* Re-Read the current repository format.  All our repo upgrade and
      config evaluation strategies are such that existing information in
@@ -3505,8 +3646,8 @@ commit_body(void *baton, apr_pool_t *poo
   root_id = svn_fs_fs__id_txn_create_root(txn_id, pool);
   SVN_ERR(write_final_rev(&new_root_id, proto_file, new_rev, cb->fs, root_id,
                           start_node_id, start_copy_id, initial_offset,
-                          cb->reps_to_cache, cb->reps_hash, cb->reps_pool,
-                          TRUE, pool));
+                          directory_ids, cb->reps_to_cache, cb->reps_hash,
+                          cb->reps_pool, TRUE, pool));
 
   /* Write the changed-path information. */
   SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
@@ -3615,6 +3756,10 @@ commit_body(void *baton, apr_pool_t *poo
 
   ffd->youngest_rev_cache = new_rev;
 
+  /* Make the directory contents alreday cached for the new revision
+   * visible. */
+  SVN_ERR(promote_cached_directories(cb->fs, directory_ids, pool));
+
   /* Remove this transaction directory. */
   SVN_ERR(svn_fs_fs__purge_txn(cb->fs, cb->txn->id, pool));
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/multistatus.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/multistatus.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/multistatus.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_ra_serf/multistatus.c Tue Oct  6 08:46:43 2015
@@ -315,7 +315,7 @@ multistatus_closed(svn_ra_serf__xml_esta
           svn_ra_serf__xml_note(xes, MS_RESPONSE, "errcode", errcode);
         break;
       case MS_RESPONSE:
-        if ((status = svn_hash_gets(attrs, "status")) != NULL)
+        if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL)
           {
             error_item_t *item;
 
@@ -369,7 +369,7 @@ multistatus_closed(svn_ra_serf__xml_esta
         break;
 
       case MS_PROPSTAT:
-        if ((status = svn_hash_gets(attrs, "status")) != NULL)
+        if ((status = svn_hash__get_cstring(attrs, "status", NULL)) != NULL)
           {
             apr_hash_t *response_attrs;
             error_item_t *item;
@@ -428,7 +428,8 @@ multistatus_closed(svn_ra_serf__xml_esta
           item->http_status = server_error->handler->sline.code;
 
           /* Do we have a mod_dav specific message? */
-          item->message = svn_hash_gets(attrs, "human-readable");
+          item->message = svn_hash__get_cstring(attrs, "human-readable",
+                                                NULL);
 
           if (item->message)
             {
@@ -442,9 +443,6 @@ multistatus_closed(svn_ra_serf__xml_esta
 
               item->message = apr_pstrdup(server_error->pool, item->message);
             }
-          else
-            item->message = apr_pstrdup(server_error->pool,
-                                        svn_hash_gets(attrs, "description"));
 
 
           APR_ARRAY_PUSH(server_error->items, error_item_t *) = item;

Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/config.c Tue Oct  6 08:46:43 2015
@@ -359,22 +359,14 @@ for_each_option(svn_config_t *cfg, void
        sec_ndx != NULL;
        sec_ndx = apr_hash_next(sec_ndx))
     {
-      void *sec_ptr;
-      cfg_section_t *sec;
+      cfg_section_t *sec = apr_hash_this_val(sec_ndx);
       apr_hash_index_t *opt_ndx;
 
-      apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
-      sec = sec_ptr;
-
       for (opt_ndx = apr_hash_first(pool, sec->options);
            opt_ndx != NULL;
            opt_ndx = apr_hash_next(opt_ndx))
         {
-          void *opt_ptr;
-          cfg_option_t *opt;
-
-          apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
-          opt = opt_ptr;
+          cfg_option_t *opt = apr_hash_this_val(opt_ndx);
 
           if (callback(baton, sec, opt))
             return;
@@ -1030,11 +1022,8 @@ svn_config_enumerate_sections2(svn_confi
        sec_ndx != NULL;
        sec_ndx = apr_hash_next(sec_ndx))
     {
-      void *sec_ptr;
-      cfg_section_t *sec;
+      cfg_section_t *sec = apr_hash_this_val(sec_ndx);
 
-      apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
-      sec = sec_ptr;
       ++count;
       svn_pool_clear(iteration_pool);
       if (!callback(sec->name, baton, iteration_pool))
@@ -1066,13 +1055,9 @@ svn_config_enumerate(svn_config_t *cfg,
        opt_ndx != NULL;
        opt_ndx = apr_hash_next(opt_ndx))
     {
-      void *opt_ptr;
-      cfg_option_t *opt;
+      cfg_option_t *opt = apr_hash_this_val(opt_ndx);
       const char *temp_value;
 
-      apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
-      opt = opt_ptr;
-
       ++count;
       make_string_from_option(&temp_value, cfg, sec, opt, NULL);
       if (!callback(opt->name, temp_value, baton))
@@ -1104,13 +1089,9 @@ svn_config_enumerate2(svn_config_t *cfg,
        opt_ndx != NULL;
        opt_ndx = apr_hash_next(opt_ndx))
     {
-      void *opt_ptr;
-      cfg_option_t *opt;
+      cfg_option_t *opt = apr_hash_this_val(opt_ndx);
       const char *temp_value;
 
-      apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
-      opt = opt_ptr;
-
       ++count;
       make_string_from_option(&temp_value, cfg, sec, opt, NULL);
       svn_pool_clear(iteration_pool);

Modified: subversion/branches/move-tracking-2/subversion/libsvn_subr/opt.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_subr/opt.c?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_subr/opt.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_subr/opt.c Tue Oct  6 08:46:43 2015
@@ -350,41 +350,50 @@ print_command_info2(const svn_opt_subcom
   return SVN_NO_ERROR;
 }
 
-void
-svn_opt_print_generic_help2(const char *header,
-                            const svn_opt_subcommand_desc2_t *cmd_table,
-                            const apr_getopt_option_t *opt_table,
-                            const char *footer,
-                            apr_pool_t *pool, FILE *stream)
+/* The body for svn_opt_print_generic_help2() function with standard error
+ * handling semantic. Handling of errors implemented at caller side. */
+static svn_error_t *
+print_generic_help_body(const char *header,
+                        const svn_opt_subcommand_desc2_t *cmd_table,
+                        const apr_getopt_option_t *opt_table,
+                        const char *footer,
+                        apr_pool_t *pool, FILE *stream)
 {
   int i = 0;
-  svn_error_t *err;
 
   if (header)
-    if ((err = svn_cmdline_fputs(header, stream, pool)))
-      goto print_error;
+    SVN_ERR(svn_cmdline_fputs(header, stream, pool));
 
   while (cmd_table[i].name)
     {
-      if ((err = svn_cmdline_fputs("   ", stream, pool))
-          || (err = print_command_info2(cmd_table + i, opt_table,
-                                        NULL, FALSE,
-                                        pool, stream))
-          || (err = svn_cmdline_fputs("\n", stream, pool)))
-        goto print_error;
+      SVN_ERR(svn_cmdline_fputs("   ", stream, pool));
+      SVN_ERR(print_command_info2(cmd_table + i, opt_table,
+                                  NULL, FALSE,
+                                  pool, stream));
+      SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
       i++;
     }
 
-  if ((err = svn_cmdline_fputs("\n", stream, pool)))
-    goto print_error;
+  SVN_ERR(svn_cmdline_fputs("\n", stream, pool));
 
   if (footer)
-    if ((err = svn_cmdline_fputs(footer, stream, pool)))
-      goto print_error;
+    SVN_ERR(svn_cmdline_fputs(footer, stream, pool));
+
+  return SVN_NO_ERROR;
+}
+
+void
+svn_opt_print_generic_help2(const char *header,
+                            const svn_opt_subcommand_desc2_t *cmd_table,
+                            const apr_getopt_option_t *opt_table,
+                            const char *footer,
+                            apr_pool_t *pool, FILE *stream)
+{
+  svn_error_t *err;
 
-  return;
+  err = print_generic_help_body(header, cmd_table, opt_table, footer, pool,
+                                stream);
 
- print_error:
   /* Issue #3014:
    * Don't print anything on broken pipes. The pipe was likely
    * closed by the process at the other end. We expect that
@@ -392,7 +401,7 @@ svn_opt_print_generic_help2(const char *
    *
    * ### This assumes that there is only one error in a chain for
    * ### SVN_ERR_IO_PIPE_WRITE_ERROR. See svn_cmdline_fputs(). */
-  if (err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
+  if (err && err->apr_err != SVN_ERR_IO_PIPE_WRITE_ERROR)
     svn_handle_error2(err, stderr, FALSE, "svn: ");
   svn_error_clear(err);
 }

Modified: subversion/branches/move-tracking-2/subversion/libsvn_wc/diff.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_wc/diff.h?rev=1706963&r1=1706962&r2=1706963&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_wc/diff.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_wc/diff.h Tue Oct  6 08:46:43 2015
@@ -52,6 +52,7 @@ svn_error_t *
 svn_wc__diff_local_only_file(svn_wc__db_t *db,
                              const char *local_abspath,
                              const char *relpath,
+                             const char *moved_from_relpath,
                              const svn_diff_tree_processor_t *processor,
                              void *processor_parent_baton,
                              svn_boolean_t diff_pristine,
@@ -75,6 +76,7 @@ svn_wc__diff_local_only_dir(svn_wc__db_t
                             const char *local_abspath,
                             const char *relpath,
                             svn_depth_t depth,
+                            const char *moved_from_relpath,
                             const svn_diff_tree_processor_t *processor,
                             void *processor_parent_baton,
                             svn_boolean_t diff_pristine,