You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [20/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.c Mon Nov 30 10:24:16 2015
@@ -243,6 +243,7 @@ hotcopy_io_copy_dir_recursively(svn_bool
  * to DST_SUBDIR. Assume a sharding layout based on MAX_FILES_PER_DIR.
  * Set *SKIPPED_P to FALSE only if the file was copied, do not change the
  * value in *SKIPPED_P otherwise. SKIPPED_P may be NULL if not required.
+ * If PROPS is set, copy the revprops file, otherwise copy the rev data file.
  * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
 hotcopy_copy_shard_file(svn_boolean_t *skipped_p,
@@ -250,6 +251,7 @@ hotcopy_copy_shard_file(svn_boolean_t *s
                         const char *dst_subdir,
                         svn_revnum_t rev,
                         int max_files_per_dir,
+                        svn_boolean_t props,
                         apr_pool_t *scratch_pool)
 {
   const char *src_subdir_shard = src_subdir,
@@ -269,7 +271,9 @@ hotcopy_copy_shard_file(svn_boolean_t *s
 
   SVN_ERR(hotcopy_io_dir_file_copy(skipped_p,
                                    src_subdir_shard, dst_subdir_shard,
-                                   apr_psprintf(scratch_pool, "%ld", rev),
+                                   apr_psprintf(scratch_pool, "%c%ld",
+                                                props ? 'p' : 'r',
+                                                rev),
                                    scratch_pool));
   return SVN_NO_ERROR;
 }
@@ -296,9 +300,6 @@ hotcopy_copy_packed_shard(svn_boolean_t
   const char *dst_subdir;
   const char *packed_shard;
   const char *src_subdir_packed_shard;
-  svn_revnum_t revprop_rev;
-  apr_pool_t *iterpool;
-  svn_fs_x__data_t *src_ffd = src_fs->fsap_data;
 
   /* Copy the packed shard. */
   src_subdir = svn_dirent_join(src_fs->path, PATH_REVS_DIR, scratch_pool);
@@ -313,47 +314,6 @@ hotcopy_copy_packed_shard(svn_boolean_t
                                           NULL /* cancel_func */, NULL,
                                           scratch_pool));
 
-  /* Copy revprops belonging to revisions in this pack. */
-  src_subdir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR, scratch_pool);
-  dst_subdir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR, scratch_pool);
-
-  if (src_ffd->min_unpacked_rev < rev + max_files_per_dir)
-    {
-      /* copy unpacked revprops rev by rev */
-      iterpool = svn_pool_create(scratch_pool);
-      for (revprop_rev = rev;
-           revprop_rev < rev + max_files_per_dir;
-           revprop_rev++)
-        {
-          svn_pool_clear(iterpool);
-
-          SVN_ERR(hotcopy_copy_shard_file(skipped_p, src_subdir, dst_subdir,
-                                          revprop_rev, max_files_per_dir,
-                                          iterpool));
-        }
-      svn_pool_destroy(iterpool);
-    }
-  else
-    {
-      /* revprop for revision 0 will never be packed */
-      if (rev == 0)
-        SVN_ERR(hotcopy_copy_shard_file(skipped_p, src_subdir, dst_subdir,
-                                        0, max_files_per_dir,
-                                        scratch_pool));
-
-      /* packed revprops folder */
-      packed_shard = apr_psprintf(scratch_pool, "%ld" PATH_EXT_PACKED_SHARD,
-                                  rev / max_files_per_dir);
-      src_subdir_packed_shard = svn_dirent_join(src_subdir, packed_shard,
-                                                scratch_pool);
-      SVN_ERR(hotcopy_io_copy_dir_recursively(skipped_p,
-                                              src_subdir_packed_shard,
-                                              dst_subdir, packed_shard,
-                                              TRUE /* copy_perms */,
-                                              NULL /* cancel_func */, NULL,
-                                              scratch_pool));
-    }
-
   /* If necessary, update the min-unpacked rev file in the hotcopy. */
   if (*dst_min_unpacked_rev < rev + max_files_per_dir)
     {
@@ -379,98 +339,6 @@ hotcopy_remove_file(const char *path,
   return SVN_NO_ERROR;
 }
 
-
-/* Remove revision or revprop files between START_REV (inclusive) and
- * END_REV (non-inclusive) from folder DST_SUBDIR in DST_FS.  Assume
- * sharding as per MAX_FILES_PER_DIR.
- * Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-hotcopy_remove_files(svn_fs_t *dst_fs,
-                     const char *dst_subdir,
-                     svn_revnum_t start_rev,
-                     svn_revnum_t end_rev,
-                     int max_files_per_dir,
-                     apr_pool_t *scratch_pool)
-{
-  const char *shard;
-  const char *dst_subdir_shard;
-  svn_revnum_t rev;
-  apr_pool_t *iterpool;
-
-  /* Pre-compute paths for initial shard. */
-  shard = apr_psprintf(scratch_pool, "%ld", start_rev / max_files_per_dir);
-  dst_subdir_shard = svn_dirent_join(dst_subdir, shard, scratch_pool);
-
-  iterpool = svn_pool_create(scratch_pool);
-  for (rev = start_rev; rev < end_rev; rev++)
-    {
-      svn_pool_clear(iterpool);
-
-      /* If necessary, update paths for shard. */
-      if (rev != start_rev && rev % max_files_per_dir == 0)
-        {
-          shard = apr_psprintf(iterpool, "%ld", rev / max_files_per_dir);
-          dst_subdir_shard = svn_dirent_join(dst_subdir, shard, scratch_pool);
-        }
-
-      /* remove files for REV */
-      SVN_ERR(hotcopy_remove_file(svn_dirent_join(dst_subdir_shard,
-                                                  apr_psprintf(iterpool,
-                                                               "%ld", rev),
-                                                  iterpool),
-                                  iterpool));
-    }
-
-  svn_pool_destroy(iterpool);
-
-  return SVN_NO_ERROR;
-}
-
-/* Remove revisions between START_REV (inclusive) and END_REV (non-inclusive)
- * from DST_FS. Assume sharding as per MAX_FILES_PER_DIR.
- * Use SCRATCH_POOL for temporary allocations. */
-static svn_error_t *
-hotcopy_remove_rev_files(svn_fs_t *dst_fs,
-                         svn_revnum_t start_rev,
-                         svn_revnum_t end_rev,
-                         int max_files_per_dir,
-                         apr_pool_t *scratch_pool)
-{
-  SVN_ERR_ASSERT(start_rev <= end_rev);
-  SVN_ERR(hotcopy_remove_files(dst_fs,
-                               svn_dirent_join(dst_fs->path,
-                                               PATH_REVS_DIR,
-                                               scratch_pool),
-                               start_rev, end_rev,
-                               max_files_per_dir, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* Remove revision properties between START_REV (inclusive) and END_REV
- * (non-inclusive) from DST_FS. Assume sharding as per MAX_FILES_PER_DIR.
- * Use SCRATCH_POOL for temporary allocations.  Revision 0 revprops will
- * not be deleted. */
-static svn_error_t *
-hotcopy_remove_revprop_files(svn_fs_t *dst_fs,
-                             svn_revnum_t start_rev,
-                             svn_revnum_t end_rev,
-                             int max_files_per_dir,
-                             apr_pool_t *scratch_pool)
-{
-  SVN_ERR_ASSERT(start_rev <= end_rev);
-
-  /* don't delete rev 0 props */
-  SVN_ERR(hotcopy_remove_files(dst_fs,
-                               svn_dirent_join(dst_fs->path,
-                                               PATH_REVPROPS_DIR,
-                                               scratch_pool),
-                               start_rev ? start_rev : 1, end_rev,
-                               max_files_per_dir, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
 /* Verify that DST_FS is a suitable destination for an incremental
  * hotcopy from SRC_FS. */
 static svn_error_t *
@@ -506,29 +374,6 @@ hotcopy_incremental_check_preconditions(
   return SVN_NO_ERROR;
 }
 
-/* Remove folder PATH.  Ignore errors due to the sub-tree not being empty.
- * CANCEL_FUNC and CANCEL_BATON do the usual thing.
- * Use SCRATCH_POOL for temporary allocations.
- */
-static svn_error_t *
-remove_folder(const char *path,
-              svn_cancel_func_t cancel_func,
-              void *cancel_baton,
-              apr_pool_t *scratch_pool)
-{
-  svn_error_t *err = svn_io_remove_dir2(path, TRUE,
-                                        cancel_func, cancel_baton,
-                                        scratch_pool);
-
-  if (err && APR_STATUS_IS_ENOTEMPTY(err->apr_err))
-    {
-      svn_error_clear(err);
-      err = SVN_NO_ERROR;
-    }
-
-  return svn_error_trace(err);
-}
-
 /* Copy the revision and revprop files (possibly sharded / packed) from
  * SRC_FS to DST_FS.  Do not re-copy data which already exists in DST_FS.
  * When copying packed or unpacked shards, checkpoint the result in DST_FS
@@ -545,8 +390,6 @@ hotcopy_revisions(svn_fs_t *src_fs,
                   svn_boolean_t incremental,
                   const char *src_revs_dir,
                   const char *dst_revs_dir,
-                  const char *src_revprops_dir,
-                  const char *dst_revprops_dir,
                   svn_fs_hotcopy_notify_t notify_func,
                   void* notify_baton,
                   svn_cancel_func_t cancel_func,
@@ -624,26 +467,10 @@ hotcopy_revisions(svn_fs_t *src_fs,
       if (notify_func && !skipped)
         notify_func(notify_baton, rev, pack_end_rev, iterpool);
 
-      /* Remove revision files which are now packed. */
-      if (incremental)
-        {
-          SVN_ERR(hotcopy_remove_rev_files(dst_fs, rev,
-                                           rev + max_files_per_dir,
-                                           max_files_per_dir, iterpool));
-          SVN_ERR(hotcopy_remove_revprop_files(dst_fs, rev,
-                                               rev + max_files_per_dir,
-                                               max_files_per_dir,
-                                               iterpool));
-        }
-
       /* Now that all revisions have moved into the pack, the original
        * rev dir can be removed. */
-      SVN_ERR(remove_folder(svn_fs_x__path_rev_shard(dst_fs, rev, iterpool),
-                            cancel_func, cancel_baton, iterpool));
-      if (rev > 0)
-        SVN_ERR(remove_folder(svn_fs_x__path_revprops_shard(dst_fs, rev,
-                                                            iterpool),
-                              cancel_func, cancel_baton, iterpool));
+      SVN_ERR(svn_io_remove_dir2(svn_fs_x__path_shard(dst_fs, rev, iterpool),
+                                 TRUE, cancel_func, cancel_baton, iterpool));
     }
 
   if (cancel_func)
@@ -677,13 +504,12 @@ hotcopy_revisions(svn_fs_t *src_fs,
 
       /* Copy the rev file. */
       SVN_ERR(hotcopy_copy_shard_file(&skipped, src_revs_dir, dst_revs_dir,
-                                      rev, max_files_per_dir,
+                                      rev, max_files_per_dir, FALSE,
                                       iterpool));
 
       /* Copy the revprop file. */
-      SVN_ERR(hotcopy_copy_shard_file(&skipped, src_revprops_dir,
-                                      dst_revprops_dir,
-                                      rev, max_files_per_dir,
+      SVN_ERR(hotcopy_copy_shard_file(&skipped, src_revs_dir, dst_revs_dir,
+                                      rev, max_files_per_dir, TRUE,
                                       iterpool));
 
       /* Whenever this revision did not previously exist in the destination,
@@ -752,8 +578,6 @@ hotcopy_body(void *baton,
   void* cancel_baton = hbb->cancel_baton;
   svn_revnum_t src_youngest;
   svn_revnum_t dst_youngest;
-  const char *src_revprops_dir;
-  const char *dst_revprops_dir;
   const char *src_revs_dir;
   const char *dst_revs_dir;
   const char *src_subdir;
@@ -793,16 +617,10 @@ hotcopy_body(void *baton,
 
   src_revs_dir = svn_dirent_join(src_fs->path, PATH_REVS_DIR, scratch_pool);
   dst_revs_dir = svn_dirent_join(dst_fs->path, PATH_REVS_DIR, scratch_pool);
-  src_revprops_dir = svn_dirent_join(src_fs->path, PATH_REVPROPS_DIR,
-                                     scratch_pool);
-  dst_revprops_dir = svn_dirent_join(dst_fs->path, PATH_REVPROPS_DIR,
-                                     scratch_pool);
 
   /* Ensure that the required folders exist in the destination
    * before actually copying the revisions and revprops. */
   SVN_ERR(svn_io_make_dir_recursively(dst_revs_dir, scratch_pool));
-  SVN_ERR(svn_io_make_dir_recursively(dst_revprops_dir, scratch_pool));
-
   if (cancel_func)
     SVN_ERR(cancel_func(cancel_baton));
 
@@ -812,7 +630,6 @@ hotcopy_body(void *baton,
    * revision number, but also the next-ID counters). */
   SVN_ERR(hotcopy_revisions(src_fs, dst_fs, src_youngest, dst_youngest,
                             incremental, src_revs_dir, dst_revs_dir,
-                            src_revprops_dir, dst_revprops_dir,
                             notify_func, notify_baton,
                             cancel_func, cancel_baton, scratch_pool));
   SVN_ERR(svn_fs_x__write_current(dst_fs, src_youngest, scratch_pool));
@@ -832,16 +649,6 @@ hotcopy_body(void *baton,
                                         cancel_func, cancel_baton,
                                         scratch_pool));
 
-  /* Now copy the node-origins cache tree. */
-  src_subdir = svn_dirent_join(src_fs->path, PATH_NODE_ORIGINS_DIR,
-                               scratch_pool);
-  SVN_ERR(svn_io_check_path(src_subdir, &kind, scratch_pool));
-  if (kind == svn_node_dir)
-    SVN_ERR(hotcopy_io_copy_dir_recursively(NULL, src_subdir, dst_fs->path,
-                                            PATH_NODE_ORIGINS_DIR, TRUE,
-                                            cancel_func, cancel_baton,
-                                            scratch_pool));
-
   /*
    * NB: Data copied below is only read by writers, not readers.
    *     Writers are still locked out at this point.
@@ -857,6 +664,10 @@ hotcopy_body(void *baton,
       /* Copy the rep cache and then remove entries for revisions
        * that did not make it into the destination. */
       SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, scratch_pool));
+
+      /* The source might have r/o flags set on it - which would be
+         carried over to the copy. */
+      SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, scratch_pool));
       SVN_ERR(svn_fs_x__del_rep_reference(dst_fs, src_youngest,
                                           scratch_pool));
     }
@@ -871,64 +682,33 @@ hotcopy_body(void *baton,
    * used for the named atomics implementation. */
   SVN_ERR(svn_fs_x__reset_revprop_generation_file(dst_fs, scratch_pool));
 
-  return SVN_NO_ERROR;
-}
-
-/* Wrapper around hotcopy_body taking out all necessary source repository
- * locks.
- */
-static svn_error_t *
-hotcopy_locking_src_body(void *baton,
-                         apr_pool_t *scratch_pool)
-{
-  hotcopy_body_baton_t *hbb = baton;
+  /* Hotcopied FS is complete. Stamp it with a format file. */
+  SVN_ERR(svn_fs_x__write_format(dst_fs, TRUE, scratch_pool));
 
-  return svn_error_trace(svn_fs_x__with_pack_lock(hbb->src_fs, hotcopy_body,
-                                                  baton, scratch_pool));
+  return SVN_NO_ERROR;
 }
 
-/* Create an empty filesystem at DST_FS at DST_PATH with the same
- * configuration as SRC_FS (uuid, format, and other parameters).
- * After creation DST_FS has no revisions, not even revision zero. */
-static svn_error_t *
-hotcopy_create_empty_dest(svn_fs_t *src_fs,
-                          svn_fs_t *dst_fs,
-                          const char *dst_path,
-                          apr_pool_t *scratch_pool)
+svn_error_t *
+svn_fs_x__hotcopy(svn_fs_t *src_fs,
+                  svn_fs_t *dst_fs,
+                  const char *src_path,
+                  const char *dst_path,
+                  svn_boolean_t incremental,
+                  svn_fs_hotcopy_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 *scratch_pool,
+                  apr_pool_t *common_pool)
 {
-  svn_fs_x__data_t *src_ffd = src_fs->fsap_data;
-
-  /* Create the DST_FS repository with the same layout as SRC_FS. */
-  SVN_ERR(svn_fs_x__create_file_tree(dst_fs, dst_path, src_ffd->format,
-                                     src_ffd->max_files_per_dir,
-                                     scratch_pool));
+  hotcopy_body_baton_t hbb;
 
-  /* Copy the UUID.  Hotcopy destination receives a new instance ID, but
-   * has the same filesystem UUID as the source. */
-  SVN_ERR(svn_fs_x__set_uuid(dst_fs, src_fs->uuid, NULL, scratch_pool));
-
-  /* Remove revision 0 contents.  Otherwise, it may not get overwritten
-   * due to having a newer timestamp. */
-  SVN_ERR(hotcopy_remove_file(svn_fs_x__path_rev(dst_fs, 0, scratch_pool),
-                              scratch_pool));
-  SVN_ERR(hotcopy_remove_file(svn_fs_x__path_revprops(dst_fs, 0,
-                                                      scratch_pool),
-                              scratch_pool));
-
-  /* This filesystem is ready.  Stamp it with a format number.  Fail if
-   * the 'format' file should already exist. */
-  SVN_ERR(svn_fs_x__write_format(dst_fs, FALSE, scratch_pool));
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
 
-  return SVN_NO_ERROR;
-}
+  SVN_ERR(svn_fs_x__open(src_fs, src_path, scratch_pool));
 
-svn_error_t *
-svn_fs_x__hotcopy_prepare_target(svn_fs_t *src_fs,
-                                 svn_fs_t *dst_fs,
-                                 const char *dst_path,
-                                 svn_boolean_t incremental,
-                                 apr_pool_t *scratch_pool)
-{
   if (incremental)
     {
       const char *dst_format_abspath;
@@ -942,40 +722,53 @@ svn_fs_x__hotcopy_prepare_target(svn_fs_
                                 scratch_pool));
       if (dst_format_kind == svn_node_none)
         {
-          /* Destination doesn't exist yet. Perform a normal hotcopy to a
-           * empty destination using the same configuration as the source. */
-          SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path,
-                                            scratch_pool));
-        }
-      else
-        {
-          /* Check the existing repository. */
-          SVN_ERR(svn_fs_x__open(dst_fs, dst_path, scratch_pool));
-          SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs));
+          /* No destination?  Fallback to a non-incremental hotcopy. */
+          incremental = FALSE;
         }
     }
+
+  if (incremental)
+    {
+      /* Check the existing repository. */
+      SVN_ERR(svn_fs_x__open(dst_fs, dst_path, scratch_pool));
+      SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs));
+
+      SVN_ERR(svn_fs_x__initialize_shared_data(dst_fs, common_pool_lock,
+                                               scratch_pool, common_pool));
+      SVN_ERR(svn_fs_x__initialize_caches(dst_fs, scratch_pool));
+    }
   else
     {
       /* Start out with an empty destination using the same configuration
        * as the source. */
-      SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path,
-                                        scratch_pool));
-    }
+      svn_fs_x__data_t *src_ffd = src_fs->fsap_data;
 
-  return SVN_NO_ERROR;
-}
+      /* Create the DST_FS repository with the same layout as SRC_FS. */
+      SVN_ERR(svn_fs_x__create_file_tree(dst_fs, dst_path, src_ffd->format,
+                                         src_ffd->max_files_per_dir,
+                                         scratch_pool));
+
+      /* Copy the UUID.  Hotcopy destination receives a new instance ID, but
+       * has the same filesystem UUID as the source. */
+      SVN_ERR(svn_fs_x__set_uuid(dst_fs, src_fs->uuid, NULL, TRUE,
+                                 scratch_pool));
+
+      /* Remove revision 0 contents.  Otherwise, it may not get overwritten
+       * due to having a newer timestamp. */
+      SVN_ERR(hotcopy_remove_file(svn_fs_x__path_rev(dst_fs, 0,
+                                                     scratch_pool),
+                                  scratch_pool));
+      SVN_ERR(hotcopy_remove_file(svn_fs_x__path_revprops(dst_fs, 0,
+                                                          scratch_pool),
+                                  scratch_pool));
+
+      SVN_ERR(svn_fs_x__initialize_shared_data(dst_fs, common_pool_lock,
+                                               scratch_pool, common_pool));
+      SVN_ERR(svn_fs_x__initialize_caches(dst_fs, scratch_pool));
+    }
 
-svn_error_t *
-svn_fs_x__hotcopy(svn_fs_t *src_fs,
-                  svn_fs_t *dst_fs,
-                  svn_boolean_t incremental,
-                  svn_fs_hotcopy_notify_t notify_func,
-                  void *notify_baton,
-                  svn_cancel_func_t cancel_func,
-                  void *cancel_baton,
-                  apr_pool_t *scratch_pool)
-{
-  hotcopy_body_baton_t hbb;
+  if (cancel_func)
+    SVN_ERR(cancel_func(cancel_baton));
 
   hbb.src_fs = src_fs;
   hbb.dst_fs = dst_fs;
@@ -984,8 +777,16 @@ svn_fs_x__hotcopy(svn_fs_t *src_fs,
   hbb.notify_baton = notify_baton;
   hbb.cancel_func = cancel_func;
   hbb.cancel_baton = cancel_baton;
-  SVN_ERR(svn_fs_x__with_all_locks(dst_fs, hotcopy_locking_src_body, &hbb,
-                                   scratch_pool));
+
+  /* Lock the destination in the incremental mode.  For a non-incremental
+   * hotcopy, don't take any locks.  In that case the destination cannot be
+   * opened until the hotcopy finishes, and we don't have to worry about
+   * concurrency. */
+  if (incremental)
+    SVN_ERR(svn_fs_x__with_all_locks(dst_fs, hotcopy_body, &hbb,
+                                     scratch_pool));
+  else
+    SVN_ERR(hotcopy_body(&hbb, scratch_pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/hotcopy.h Mon Nov 30 10:24:16 2015
@@ -1,4 +1,4 @@
-/* hotcopy.h : interface to the native filesystem layer
+/* hotcopy.h : interface to the hot-copying functionality
  *
  * ====================================================================
  *    Licensed to the Apache Software Foundation (ASF) under one
@@ -20,34 +20,29 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__HOTCOPY_H
-#define SVN_LIBSVN_FS__HOTCOPY_H
+#ifndef SVN_LIBSVN_FS_X_HOTCOPY_H
+#define SVN_LIBSVN_FS_X_HOTCOPY_H
 
 #include "fs.h"
 
-/* Create an empty copy of the fsfs filesystem SRC_FS into a new DST_FS at
- * DST_PATH.  If INCREMENTAL is TRUE, perform a few pre-checks only if
- * a repo already exists at DST_PATH.
- * Use SCRATCH_POOL for temporary allocations. */
-svn_error_t *
-svn_fs_x__hotcopy_prepare_target(svn_fs_t *src_fs,
-                                 svn_fs_t *dst_fs,
-                                 const char *dst_path,
-                                 svn_boolean_t incremental,
-                                 apr_pool_t *scratch_pool);
-
-/* Copy the fsfs filesystem SRC_FS into DST_FS. If INCREMENTAL is TRUE, do
- * not re-copy data which already exists in DST_FS.  Indicate progress via
- * the optional NOTIFY_FUNC callback using NOTIFY_BATON.
- * Use SCRATCH_POOL for temporary allocations. */
+/* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at
+ * DST_PATH.  If INCREMENTAL is TRUE, do not re-copy data which already
+ * exists in DST_FS.  Indicate progress via the optional NOTIFY_FUNC
+ * callback using NOTIFY_BATON.  Use COMMON_POOL for process-wide and
+ * SCRATCH_POOL for temporary allocations.  Use COMMON_POOL_LOCK to ensure
+ * that the initialization of the shared data is serialized. */
 svn_error_t *
 svn_fs_x__hotcopy(svn_fs_t *src_fs,
                   svn_fs_t *dst_fs,
+                  const char *src_path,
+                  const char *dst_path,
                   svn_boolean_t incremental,
                   svn_fs_hotcopy_notify_t notify_func,
                   void *notify_baton,
                   svn_cancel_func_t cancel_func,
                   void *cancel_baton,
-                  apr_pool_t *scratch_pool);
+                  svn_mutex__t *common_pool_lock,
+                  apr_pool_t *scratch_pool,
+                  apr_pool_t *common_pool);
 
 #endif

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/index.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/index.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/index.c Mon Nov 30 10:24:16 2015
@@ -61,15 +61,9 @@ const apr_uint64_t off_t_max = (sizeof(a
  */
 #define P2L_PROTO_INDEX_ENTRY_SIZE (6 * sizeof(apr_uint64_t))
 
-/* We put this string in front of the L2P index header. */
-#define L2P_STREAM_PREFIX "L2P-INDEX\n"
-
-/* We put this string in front of the P2L index header. */
-#define P2L_STREAM_PREFIX "P2L-INDEX\n"
-
 /* Size of the buffer that will fit the index header prefixes. */
-#define STREAM_PREFIX_LEN MAX(sizeof(L2P_STREAM_PREFIX), \
-                              sizeof(P2L_STREAM_PREFIX))
+#define STREAM_PREFIX_LEN MAX(sizeof(SVN_FS_X__L2P_STREAM_PREFIX), \
+                              sizeof(SVN_FS_X__P2L_STREAM_PREFIX))
 
 /* Page tables in the log-to-phys index file exclusively contain entries
  * of this type to describe position and size of a given page.
@@ -257,7 +251,7 @@ static svn_error_t *
 packed_stream_read(svn_fs_x__packed_number_stream_t *stream)
 {
   unsigned char buffer[MAX_NUMBER_PREFETCH];
-  apr_size_t read = 0;
+  apr_size_t bytes_read = 0;
   apr_size_t i;
   value_position_pair_t *target;
   apr_off_t block_start = 0;
@@ -279,33 +273,34 @@ packed_stream_read(svn_fs_x__packed_numb
    * boundaries.  This shall prevent jumping back and forth between two
    * blocks because the extra data was not actually request _now_.
    */
-  read = sizeof(buffer);
+  bytes_read = sizeof(buffer);
   block_left = stream->block_size - (stream->next_offset - block_start);
-  if (block_left >= 10 && block_left < read)
-    read = (apr_size_t)block_left;
+  if (block_left >= 10 && block_left < bytes_read)
+    bytes_read = (apr_size_t)block_left;
 
   /* Don't read beyond the end of the file section that belongs to this
    * index / stream. */
-  read = (apr_size_t)MIN(read, stream->stream_end - stream->next_offset);
+  bytes_read = (apr_size_t)MIN(bytes_read,
+                               stream->stream_end - stream->next_offset);
 
-  err = apr_file_read(stream->file, buffer, &read);
+  err = apr_file_read(stream->file, buffer, &bytes_read);
   if (err && !APR_STATUS_IS_EOF(err))
     return stream_error_create(stream, err,
       _("Can't read index file '%s' at offset 0x%"));
 
   /* if the last number is incomplete, trim it from the buffer */
-  while (read > 0 && buffer[read-1] >= 0x80)
-    --read;
+  while (bytes_read > 0 && buffer[bytes_read-1] >= 0x80)
+    --bytes_read;
 
   /* we call read() only if get() requires more data.  So, there must be
    * at least *one* further number. */
-  if SVN__PREDICT_FALSE(read == 0)
+  if SVN__PREDICT_FALSE(bytes_read == 0)
     return stream_error_create(stream, err,
       _("Unexpected end of index file %s at offset 0x%"));
 
   /* parse file buffer and expand into stream buffer */
   target = stream->buffer;
-  for (i = 0; i < read;)
+  for (i = 0; i < bytes_read;)
     {
       if (buffer[i] < 0x80)
         {
@@ -348,20 +343,15 @@ packed_stream_read(svn_fs_x__packed_numb
   return SVN_NO_ERROR;
 }
 
-/* Create and open a packed number stream reading from offsets START to
- * END in FILE and return it in *STREAM.  Access the file in chunks of
- * BLOCK_SIZE bytes.  Expect the stream to be prefixed by STREAM_PREFIX.
- * Allocate *STREAM in RESULT_POOL and use SCRATCH_POOL for temporaries.
- */
-static svn_error_t *
-packed_stream_open(svn_fs_x__packed_number_stream_t **stream,
-                   apr_file_t *file,
-                   apr_off_t start,
-                   apr_off_t end,
-                   const char *stream_prefix,
-                   apr_size_t block_size,
-                   apr_pool_t *result_pool,
-                   apr_pool_t *scratch_pool)
+svn_error_t *
+svn_fs_x__packed_stream_open(svn_fs_x__packed_number_stream_t **stream,
+                             apr_file_t *file,
+                             apr_off_t start,
+                             apr_off_t end,
+                             const char *stream_prefix,
+                             apr_size_t block_size,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
 {
   char buffer[STREAM_PREFIX_LEN + 1] = { 0 };
   apr_size_t len = strlen(stream_prefix);
@@ -516,13 +506,13 @@ read_uint64_from_proto_index(apr_file_t
                              apr_pool_t *scratch_pool)
 {
   apr_byte_t buffer[sizeof(*value_p)];
-  apr_size_t read;
+  apr_size_t bytes_read;
 
   /* Read the full 8 bytes or our 64 bit value, unless we hit EOF.
    * Assert that we never read partial values. */
   SVN_ERR(svn_io_file_read_full2(proto_index, buffer, sizeof(buffer),
-                                 &read, eof, scratch_pool));
-  SVN_ERR_ASSERT((eof && *eof) || read == sizeof(buffer));
+                                 &bytes_read, eof, scratch_pool));
+  SVN_ERR_ASSERT((eof && *eof) || bytes_read == sizeof(buffer));
 
   /* If we did not hit EOF, reconstruct the uint64 value and return it. */
   if (!eof || !*eof)
@@ -702,7 +692,8 @@ svn_fs_x__l2p_proto_index_add_entry(apr_
  * read operations only.
  */
 static apr_size_t
-encode_uint(unsigned char *p, apr_uint64_t value)
+encode_uint(unsigned char *p,
+            apr_uint64_t value)
 {
   unsigned char *start = p;
   while (value >= 0x80)
@@ -720,7 +711,8 @@ encode_uint(unsigned char *p, apr_uint64
  * This maps signed ints onto unsigned ones.
  */
 static apr_size_t
-encode_int(unsigned char *p, apr_int64_t value)
+encode_int(unsigned char *p,
+           apr_int64_t value)
 {
   return encode_uint(p, (apr_uint64_t)(value < 0 ? -1 - 2*value : 2*value));
 }
@@ -742,7 +734,9 @@ stream_write_encoded(svn_stream_t *strea
  * Return the number of remaining entries in ARRAY after START.
  */
 static int
-rle_array(apr_array_header_t *array, int start, int end)
+rle_array(apr_array_header_t *array,
+          int start,
+          int end)
 {
   int i;
   int target = start;
@@ -969,8 +963,8 @@ svn_fs_x__l2p_index_append(svn_checksum_
               /* 1 page with up to L2P_PAGE_SIZE entries.
                * fsfs.conf settings validation guarantees this to fit into
                * our address space. */
-              apr_size_t last_buffer_size
-                = (apr_size_t)svn_spillbuf__get_size(buffer);
+              apr_uint64_t last_buffer_size
+                = (apr_uint64_t)svn_spillbuf__get_size(buffer);
 
               svn_pool_clear(iterpool);
 
@@ -1038,7 +1032,7 @@ svn_fs_x__l2p_index_append(svn_checksum_
 
 
   /* write header info */
-  SVN_ERR(svn_stream_puts(stream, L2P_STREAM_PREFIX));
+  SVN_ERR(svn_stream_puts(stream, SVN_FS_X__L2P_STREAM_PREFIX));
   SVN_ERR(stream_write_encoded(stream, revision));
   SVN_ERR(stream_write_encoded(stream, page_counts->nelts));
   SVN_ERR(stream_write_encoded(stream, ffd->l2p_page_size));
@@ -1074,7 +1068,8 @@ svn_fs_x__l2p_index_append(svn_checksum_
  * REVISION in FS.
  */
 static svn_revnum_t
-base_revision(svn_fs_t *fs, svn_revnum_t revision)
+base_revision(svn_fs_t *fs,
+              svn_revnum_t revision)
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
   return svn_fs_x__is_packed_rev(fs, revision)
@@ -1231,32 +1226,6 @@ expand_rle(apr_array_header_t *values,
   return SVN_NO_ERROR;
 }
 
-/* If REV_FILE->L2P_STREAM is NULL, create a new stream for the log-to-phys
- * index for REVISION in FS and return it in REV_FILE.
- */
-static svn_error_t *
-auto_open_l2p_index(svn_fs_x__revision_file_t *rev_file,
-                    svn_fs_t *fs,
-                    svn_revnum_t revision)
-{
-  if (rev_file->l2p_stream == NULL)
-    {
-      svn_fs_x__data_t *ffd = fs->fsap_data;
-
-      SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
-      SVN_ERR(packed_stream_open(&rev_file->l2p_stream,
-                                 rev_file->file,
-                                 rev_file->l2p_offset,
-                                 rev_file->p2l_offset,
-                                 L2P_STREAM_PREFIX,
-                                 (apr_size_t)ffd->block_size,
-                                 rev_file->pool,
-                                 rev_file->pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Read the header data structure of the log-to-phys index for REVISION
  * in FS and return it in *HEADER, allocated in RESULT_POOL.  Use REV_FILE
  * to access on-disk data.  Use SCRATCH_POOL for temporary allocations.
@@ -1279,41 +1248,48 @@ get_l2p_header_body(l2p_header_t **heade
   svn_revnum_t next_rev;
   apr_array_header_t *expanded_values
     = apr_array_make(scratch_pool, 16, sizeof(apr_uint64_t));
+  svn_fs_x__packed_number_stream_t *stream;
+  svn_fs_x__rev_file_info_t file_info;
+  svn_fs_x__index_info_t index_info;
 
+  /* What to look for. */
   svn_fs_x__pair_cache_key_t key;
-  key.revision = rev_file->start_revision;
-  key.second = rev_file->is_packed;
-
-  SVN_ERR(auto_open_l2p_index(rev_file, fs, revision));
-  packed_stream_seek(rev_file->l2p_stream, 0);
+  SVN_ERR(svn_fs_x__rev_file_info(&file_info, rev_file));
+  key.revision = file_info.start_revision;
+  key.second = file_info.is_packed;
+
+  /* Access the L2P index stream. */
+  SVN_ERR(svn_fs_x__rev_file_l2p_index(&stream, rev_file));
+  SVN_ERR(svn_fs_x__rev_file_l2p_info(&index_info, rev_file));
+  packed_stream_seek(stream, 0);
 
   /* Read the table sizes.  Check the data for plausibility and
    * consistency with other bits. */
-  SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->first_revision = (svn_revnum_t)value;
-  if (result->first_revision != rev_file->start_revision)
+  if (result->first_revision != file_info.start_revision)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                   _("Index rev / pack file revision numbers do not match"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->revision_count = (int)value;
   if (   result->revision_count != 1
       && result->revision_count != (apr_uint64_t)ffd->max_files_per_dir)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                             _("Invalid number of revisions in L2P index"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->page_size = (apr_uint32_t)value;
   if (!result->page_size || (result->page_size & (result->page_size - 1)))
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                             _("L2P index page size is not a power of two"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   page_count = (apr_size_t)value;
   if (page_count < result->revision_count)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                             _("Fewer L2P index pages than revisions"));
-  if (page_count > (rev_file->p2l_offset - rev_file->l2p_offset) / 2)
+  if (page_count > (index_info.end - index_info.start) / 2)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                             _("L2P index page count implausibly large"));
 
@@ -1333,8 +1309,7 @@ get_l2p_header_body(l2p_header_t **heade
   /* read per-revision page table sizes (i.e. number of pages per rev) */
   page_table_index = 0;
   result->page_table_index[0] = page_table_index;
-  SVN_ERR(expand_rle(expanded_values, rev_file->l2p_stream,
-                     result->revision_count));
+  SVN_ERR(expand_rle(expanded_values, stream, result->revision_count));
   for (i = 0; i < result->revision_count; ++i)
     {
       value = (apr_size_t)APR_ARRAY_IDX(expanded_values, i, apr_uint64_t);
@@ -1357,13 +1332,13 @@ get_l2p_header_body(l2p_header_t **heade
   /* read actual page tables */
   for (page = 0; page < page_count; ++page)
     {
-      SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+      SVN_ERR(packed_stream_get(&value, stream));
       if (value == 0)
         return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                                 _("Empty L2P index page"));
 
       result->page_table[page].size = (apr_uint32_t)value;
-      SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+      SVN_ERR(packed_stream_get(&value, stream));
       if (value > result->page_size)
         return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                                 _("Page exceeds L2P index page size"));
@@ -1372,7 +1347,7 @@ get_l2p_header_body(l2p_header_t **heade
     }
 
   /* correct the page description offsets */
-  offset = packed_stream_offset(rev_file->l2p_stream);
+  offset = packed_stream_offset(stream);
   for (page = 0; page < page_count; ++page)
     {
       result->page_table[page].offset = offset;
@@ -1437,11 +1412,13 @@ get_l2p_header(l2p_header_t **header,
 {
   svn_fs_x__data_t *ffd = fs->fsap_data;
   svn_boolean_t is_cached = FALSE;
+  svn_fs_x__rev_file_info_t file_info;
 
   /* first, try cache lookop */
   svn_fs_x__pair_cache_key_t key;
-  key.revision = rev_file->start_revision;
-  key.second = rev_file->is_packed;
+  SVN_ERR(svn_fs_x__rev_file_info(&file_info, rev_file));
+  key.revision = file_info.start_revision;
+  key.second = file_info.is_packed;
   SVN_ERR(svn_cache__get((void**)header, &is_cached, ffd->l2p_header_cache,
                          &key, result_pool));
   if (is_cached)
@@ -1454,16 +1431,12 @@ get_l2p_header(l2p_header_t **header,
   return SVN_NO_ERROR;
 }
 
-/* From the log-to-phys index file starting at START_REVISION in FS, read
- * the mapping page identified by TABLE_ENTRY and return it in *PAGE.
- * Use REV_FILE to access on-disk files.
- * Use RESULT_POOL for allocations.
+/* From the log-to-phys index in REV_FILE, read the mapping page identified
+ * by TABLE_ENTRY and return it in *PAGE, allocated in RESULT_POOL.
  */
 static svn_error_t *
 get_l2p_page(l2p_page_t **page,
              svn_fs_x__revision_file_t *rev_file,
-             svn_fs_t *fs,
-             svn_revnum_t start_revision,
              l2p_page_table_entry_t *table_entry,
              apr_pool_t *result_pool)
 {
@@ -1472,10 +1445,11 @@ get_l2p_page(l2p_page_t **page,
   l2p_page_t *result = apr_pcalloc(result_pool, sizeof(*result));
   apr_uint64_t container_count;
   apr_off_t *container_offsets;
+  svn_fs_x__packed_number_stream_t *stream;
 
   /* open index file and select page */
-  SVN_ERR(auto_open_l2p_index(rev_file, fs, start_revision));
-  packed_stream_seek(rev_file->l2p_stream, table_entry->offset);
+  SVN_ERR(svn_fs_x__rev_file_l2p_index(&stream, rev_file));
+  packed_stream_seek(stream, table_entry->offset);
 
   /* initialize the page content */
   result->entry_count = table_entry->entry_count;
@@ -1486,12 +1460,12 @@ get_l2p_page(l2p_page_t **page,
 
   /* container offsets array */
 
-  SVN_ERR(packed_stream_get(&container_count, rev_file->l2p_stream));
+  SVN_ERR(packed_stream_get(&container_count, stream));
   container_offsets = apr_pcalloc(result_pool,
                                   container_count * sizeof(*result));
   for (i = 0; i < container_count; ++i)
     {
-      SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+      SVN_ERR(packed_stream_get(&value, stream));
       last_value += value;
       container_offsets[i] = (apr_off_t)last_value - 1;
       /* '-1' is represented as '0' in the index file */
@@ -1500,7 +1474,7 @@ get_l2p_page(l2p_page_t **page,
   /* read all page entries (offsets in rev file and container sub-items) */
   for (i = 0; i < result->entry_count; ++i)
     {
-      SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+      SVN_ERR(packed_stream_get(&value, stream));
       if (value == 0)
         {
           result->offsets[i] = -1;
@@ -1509,7 +1483,7 @@ get_l2p_page(l2p_page_t **page,
       else if (value <= container_count)
         {
           result->offsets[i] = container_offsets[value - 1];
-          SVN_ERR(packed_stream_get(&value, rev_file->l2p_stream));
+          SVN_ERR(packed_stream_get(&value, stream));
           result->sub_items[i] = (apr_uint32_t)value;
         }
       else
@@ -1521,7 +1495,7 @@ get_l2p_page(l2p_page_t **page,
 
   /* After reading all page entries, the read cursor must have moved by
    * TABLE_ENTRY->SIZE bytes. */
-  if (   packed_stream_offset(rev_file->l2p_stream)
+  if (   packed_stream_offset(stream)
       != table_entry->offset + table_entry->size)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                 _("L2P actual page size does not match page table value."));
@@ -1690,9 +1664,8 @@ get_l2p_page_table(apr_array_header_t *p
 /* Utility function.  Read the l2p index pages for REVISION in FS from
  * STREAM and put them into the cache.  Skip page number EXLCUDED_PAGE_NO
  * (use -1 for 'skip none') and pages outside the MIN_OFFSET, MAX_OFFSET
- * range in the l2p index file.  The index is being identified by
- * FIRST_REVISION.  PAGES is a scratch container provided by the caller.
- * SCRATCH_POOL is used for temporary allocations.
+ * range in the l2p index file.  PAGES is a scratch container provided by
+ * the caller.  SCRATCH_POOL is used for temporary allocations.
  *
  * This function may be a no-op if the header cache lookup fails / misses.
  */
@@ -1700,7 +1673,6 @@ static svn_error_t *
 prefetch_l2p_pages(svn_boolean_t *end,
                    svn_fs_t *fs,
                    svn_fs_x__revision_file_t *rev_file,
-                   svn_revnum_t first_revision,
                    svn_revnum_t revision,
                    apr_array_header_t *pages,
                    int exlcuded_page_no,
@@ -1769,8 +1741,7 @@ prefetch_l2p_pages(svn_boolean_t *end,
           /* no in cache -> read from stream (data already buffered in APR)
            * and cache the result */
           l2p_page_t *page = NULL;
-          SVN_ERR(get_l2p_page(&page, rev_file, fs, first_revision,
-                               entry, iterpool));
+          SVN_ERR(get_l2p_page(&page, rev_file, entry, iterpool));
 
           SVN_ERR(svn_cache__set(ffd->l2p_page_cache, &key, page,
                                  iterpool));
@@ -1841,8 +1812,7 @@ l2p_index_lookup(apr_off_t *offset,
       apr_off_t min_offset = max_offset - ffd->block_size;
 
       /* read the relevant page */
-      SVN_ERR(get_l2p_page(&page, rev_file, fs, info_baton.first_revision,
-                           &info_baton.entry, scratch_pool));
+      SVN_ERR(get_l2p_page(&page, rev_file, &info_baton.entry, scratch_pool));
 
       /* cache the page and extract the result we need */
       SVN_ERR(svn_cache__set(ffd->l2p_page_cache, &key, page, scratch_pool));
@@ -1863,7 +1833,6 @@ l2p_index_lookup(apr_off_t *offset,
           svn_pool_clear(iterpool);
 
           SVN_ERR(prefetch_l2p_pages(&end, fs, rev_file,
-                                     info_baton.first_revision,
                                      prefetch_revision, pages,
                                      excluded_page_no, min_offset,
                                      max_offset, iterpool));
@@ -1877,7 +1846,6 @@ l2p_index_lookup(apr_off_t *offset,
           svn_pool_clear(iterpool);
 
           SVN_ERR(prefetch_l2p_pages(&end, fs, rev_file,
-                                     info_baton.first_revision,
                                      prefetch_revision, pages, -1,
                                      min_offset, max_offset, iterpool));
         }
@@ -1950,8 +1918,7 @@ svn_fs_x__l2p_get_max_ids(apr_array_head
   apr_pool_t *header_pool = svn_pool_create(scratch_pool);
 
   /* read index master data structure for the index covering START_REV */
-  SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start_rev,
-                                          header_pool, header_pool));
+  SVN_ERR(svn_fs_x__rev_file_init(&rev_file, fs, start_rev, header_pool));
   SVN_ERR(get_l2p_header(&header, rev_file, fs, start_rev, header_pool,
                          header_pool));
   SVN_ERR(svn_fs_x__close_revision_file(rev_file));
@@ -1972,8 +1939,8 @@ svn_fs_x__l2p_get_max_ids(apr_array_head
            * the number of items in a revision, i.e. there is no consistency
            * issue here. */
           svn_pool_clear(header_pool);
-          SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, revision,
-                                                  header_pool, header_pool));
+          SVN_ERR(svn_fs_x__rev_file_init(&rev_file, fs, revision,
+                                          header_pool));
           SVN_ERR(get_l2p_header(&header, rev_file, fs, revision,
                                  header_pool, header_pool));
           SVN_ERR(svn_fs_x__close_revision_file(rev_file));
@@ -2215,8 +2182,8 @@ svn_fs_x__p2l_index_append(svn_checksum_
 
   apr_uint64_t last_entry_end = 0;
   apr_uint64_t last_page_end = 0;
-  apr_size_t last_buffer_size = 0;  /* byte offset in the spill buffer at
-                                       the begin of the current revision */
+  apr_uint64_t last_buffer_size = 0;  /* byte offset in the spill buffer at
+                                         the begin of the current revision */
   apr_uint64_t file_size = 0;
 
   /* temporary data structures that collect the data which will be moved
@@ -2315,7 +2282,8 @@ svn_fs_x__p2l_index_append(svn_checksum_
                                   encode_uint(encoded, entry.size),
                                   iterpool));
       SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
-                                  encode_uint(encoded, entry.type + entry.item_count * 16),
+                                  encode_uint(encoded, entry.type
+                                                     + entry.item_count * 16),
                                   iterpool));
       SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
                                   encode_uint(encoded, entry.fnv1_checksum),
@@ -2359,7 +2327,7 @@ svn_fs_x__p2l_index_append(svn_checksum_
                                    result_pool);
 
   /* write the start revision, file size and page size */
-  SVN_ERR(svn_stream_puts(stream, P2L_STREAM_PREFIX));
+  SVN_ERR(svn_stream_puts(stream, SVN_FS_X__P2L_STREAM_PREFIX));
   SVN_ERR(stream_write_encoded(stream, revision));
   SVN_ERR(stream_write_encoded(stream, file_size));
   SVN_ERR(stream_write_encoded(stream, page_size));
@@ -2382,32 +2350,6 @@ svn_fs_x__p2l_index_append(svn_checksum_
   return SVN_NO_ERROR;
 }
 
-/* If REV_FILE->P2L_STREAM is NULL, create a new stream for the phys-to-log
- * index for REVISION in FS using the rev / pack file provided by REV_FILE.
- */
-static svn_error_t *
-auto_open_p2l_index(svn_fs_x__revision_file_t *rev_file,
-                    svn_fs_t *fs,
-                    svn_revnum_t revision)
-{
-  if (rev_file->p2l_stream == NULL)
-    {
-      svn_fs_x__data_t *ffd = fs->fsap_data;
-
-      SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
-      SVN_ERR(packed_stream_open(&rev_file->p2l_stream,
-                                 rev_file->file,
-                                 rev_file->p2l_offset,
-                                 rev_file->footer_offset,
-                                 P2L_STREAM_PREFIX,
-                                 (apr_size_t)ffd->block_size,
-                                 rev_file->pool,
-                                 rev_file->pool));
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Data structure that describes which p2l page info shall be extracted
  * from the cache and contains the fields that receive the result.
  */
@@ -2515,11 +2457,15 @@ get_p2l_header(p2l_header_t **header,
   apr_off_t offset;
   p2l_header_t *result;
   svn_boolean_t is_cached = FALSE;
+  svn_fs_x__packed_number_stream_t *stream;
+  svn_fs_x__rev_file_info_t file_info;
+  svn_fs_x__index_info_t l2p_index_info;
 
   /* look for the header data in our cache */
   svn_fs_x__pair_cache_key_t key;
-  key.revision = rev_file->start_revision;
-  key.second = rev_file->is_packed;
+  SVN_ERR(svn_fs_x__rev_file_info(&file_info, rev_file));
+  key.revision = file_info.start_revision;
+  key.second = file_info.is_packed;
 
   SVN_ERR(svn_cache__get((void**)header, &is_cached, ffd->p2l_header_cache,
                          &key, result_pool));
@@ -2528,32 +2474,33 @@ get_p2l_header(p2l_header_t **header,
 
   /* not found -> must read it from disk.
    * Open index file or position read pointer to the begin of the file */
-  SVN_ERR(auto_open_p2l_index(rev_file, fs, key.revision));
-  packed_stream_seek(rev_file->p2l_stream, 0);
+  SVN_ERR(svn_fs_x__rev_file_p2l_index(&stream, rev_file));
+  SVN_ERR(svn_fs_x__rev_file_l2p_info(&l2p_index_info, rev_file));
+  packed_stream_seek(stream, 0);
 
   /* allocate result data structure */
   result = apr_pcalloc(result_pool, sizeof(*result));
 
   /* Read table sizes, check them for plausibility and allocate page array. */
-  SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->first_revision = (svn_revnum_t)value;
-  if (result->first_revision != rev_file->start_revision)
+  if (result->first_revision != file_info.start_revision)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                   _("Index rev / pack file revision numbers do not match"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->file_size = value;
-  if (result->file_size != (apr_uint64_t)rev_file->l2p_offset)
+  if (result->file_size != (apr_uint64_t)l2p_index_info.start)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                    _("Index offset and rev / pack file size do not match"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->page_size = value;
   if (!result->page_size || (result->page_size & (result->page_size - 1)))
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
                             _("P2L index page size is not a power of two"));
 
-  SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   result->page_count = (apr_size_t)value;
   if (result->page_count != (result->file_size - 1) / result->page_size + 1)
     return svn_error_create(SVN_ERR_FS_INDEX_CORRUPTION, NULL,
@@ -2566,12 +2513,12 @@ get_p2l_header(p2l_header_t **header,
   result->offsets[0] = 0;
   for (i = 0; i < result->page_count; ++i)
     {
-      SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+      SVN_ERR(packed_stream_get(&value, stream));
       result->offsets[i+1] = result->offsets[i] + (apr_off_t)value;
     }
 
   /* correct the offset values */
-  offset = packed_stream_offset(rev_file->p2l_stream);
+  offset = packed_stream_offset(stream);
   for (i = 0; i <= result->page_count; ++i)
     result->offsets[i] += offset;
 
@@ -2732,14 +2679,15 @@ get_p2l_page(apr_array_header_t **entrie
     = apr_array_make(result_pool, 16, sizeof(svn_fs_x__p2l_entry_t));
   apr_off_t item_offset;
   apr_off_t offset;
+  svn_fs_x__packed_number_stream_t *stream;
 
   /* open index and navigate to page start */
-  SVN_ERR(auto_open_p2l_index(rev_file, fs, start_revision));
-  packed_stream_seek(rev_file->p2l_stream, start_offset);
+  SVN_ERR(svn_fs_x__rev_file_p2l_index(&stream, rev_file));
+  packed_stream_seek(stream, start_offset);
 
   /* read rev file offset of the first page entry (all page entries will
    * only store their sizes). */
-  SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+  SVN_ERR(packed_stream_get(&value, stream));
   item_offset = (apr_off_t)value;
 
   /* Special case: empty pages. */
@@ -2747,17 +2695,15 @@ get_p2l_page(apr_array_header_t **entrie
     {
       /* Empty page. This only happens if the first entry of the next page
        * also covers this page (and possibly more) completely. */
-      SVN_ERR(read_entry(rev_file->p2l_stream, &item_offset, start_revision,
-                         result));
+      SVN_ERR(read_entry(stream, &item_offset, start_revision, result));
     }
   else
     {
       /* Read non-empty page. */
       do
         {
-          SVN_ERR(read_entry(rev_file->p2l_stream, &item_offset,
-                             start_revision, result));
-          offset = packed_stream_offset(rev_file->p2l_stream);
+          SVN_ERR(read_entry(stream, &item_offset, start_revision, result));
+          offset = packed_stream_offset(stream);
         }
       while (offset < next_offset);
 
@@ -2771,9 +2717,9 @@ get_p2l_page(apr_array_header_t **entrie
        * entry of the next page */
       if (item_offset < page_start + page_size)
         {
-          SVN_ERR(packed_stream_get(&value, rev_file->p2l_stream));
+          SVN_ERR(packed_stream_get(&value, stream));
           item_offset = (apr_off_t)value;
-          SVN_ERR(read_entry(rev_file->p2l_stream, &item_offset,
+          SVN_ERR(read_entry(stream, &item_offset,
                              start_revision, result));
         }
     }
@@ -3203,7 +3149,8 @@ svn_fs_x__p2l_index_lookup(apr_array_hea
  * RHS.
  */
 static int
-compare_p2l_entry_offsets(const void *lhs, const void *rhs)
+compare_p2l_entry_offsets(const void *lhs,
+                          const void *rhs)
 {
   const svn_fs_x__p2l_entry_t *entry = (const svn_fs_x__p2l_entry_t *)lhs;
   apr_off_t offset = *(const apr_off_t *)rhs;
@@ -3503,15 +3450,13 @@ calc_fnv1(svn_fs_x__p2l_entry_t *entry,
     }
 
   /* Read the block and feed it to the checksum calculator. */
-  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &entry->offset,
-                           scratch_pool));
+  SVN_ERR(svn_fs_x__rev_file_seek(rev_file, NULL, entry->offset));
   while (size > 0)
     {
       apr_size_t to_read = size > sizeof(buffer)
                          ? sizeof(buffer)
                          : (apr_size_t)size;
-      SVN_ERR(svn_io_file_read_full2(rev_file->file, buffer, to_read, NULL,
-                                     NULL, scratch_pool));
+      SVN_ERR(svn_fs_x__rev_file_read(rev_file, buffer, to_read));
       SVN_ERR(svn_checksum_update(context, buffer, to_read));
       size -= to_read;
     }
@@ -3795,7 +3740,7 @@ svn_error_t *
 svn_fs_x__deserialize_l2p_header(void **out,
                                  void *data,
                                  apr_size_t data_len,
-                                 apr_pool_t *pool)
+                                 apr_pool_t *result_pool)
 {
   l2p_header_t *header = (l2p_header_t *)data;
 
@@ -3849,7 +3794,7 @@ svn_error_t *
 svn_fs_x__deserialize_l2p_page(void **out,
                                void *data,
                                apr_size_t data_len,
-                               apr_pool_t *pool)
+                               apr_pool_t *result_pool)
 {
   l2p_page_t *page = data;
 
@@ -3898,7 +3843,7 @@ svn_error_t *
 svn_fs_x__deserialize_p2l_header(void **out,
                                  void *data,
                                  apr_size_t data_len,
-                                 apr_pool_t *pool)
+                                 apr_pool_t *result_pool)
 {
   p2l_header_t *header = data;
 
@@ -3956,7 +3901,7 @@ svn_error_t *
 svn_fs_x__deserialize_p2l_page(void **out,
                                void *data,
                                apr_size_t data_len,
-                               apr_pool_t *pool)
+                               apr_pool_t *result_pool)
 {
   apr_array_header_t *page = (apr_array_header_t *)data;
   svn_fs_x__p2l_entry_t *entries;
@@ -3971,7 +3916,7 @@ svn_fs_x__deserialize_p2l_page(void **ou
     svn_temp_deserializer__resolve(entries, (void**)&entries[i].items);
 
   /* patch up members */
-  page->pool = pool;
+  page->pool = result_pool;
   page->nalloc = page->nelts;
 
   /* done */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/index.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/index.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/index.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/index.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS__INDEX_H
-#define SVN_LIBSVN_FS__INDEX_H
+#ifndef SVN_LIBSVN_FS_X_INDEX_H
+#define SVN_LIBSVN_FS_X_INDEX_H
 
 #include "fs.h"
 #include "rev_file.h"
@@ -53,6 +53,28 @@
 #define SVN_FS_X__ITEM_TYPE_REPS_CONT    10  /* item is a representations
                                                  container */
 
+/* We put this string in front of the L2P index header. */
+#define SVN_FS_X__L2P_STREAM_PREFIX "L2P-INDEX\n"
+
+/* We put this string in front of the P2L index header. */
+#define SVN_FS_X__P2L_STREAM_PREFIX "P2L-INDEX\n"
+
+
+/* Create and open a packed number stream reading from offsets START to
+ * END in FILE and return it in *STREAM.  Access the file in chunks of
+ * BLOCK_SIZE bytes.  Expect the stream to be prefixed by STREAM_PREFIX.
+ * Allocate *STREAM in RESULT_POOL and use SCRATCH_POOL for temporaries.
+ */
+svn_error_t *
+svn_fs_x__packed_stream_open(svn_fs_x__packed_number_stream_t **stream,
+                             apr_file_t *file,
+                             apr_off_t start,
+                             apr_off_t end,
+                             const char *stream_prefix,
+                             apr_size_t block_size,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
+
 /* (user visible) entry in the phys-to-log index.  It describes a section
  * of some packed / non-packed rev file as containing a specific item.
  * There must be no overlapping / conflicting entries.
@@ -350,7 +372,7 @@ svn_error_t *
 svn_fs_x__deserialize_l2p_header(void **out,
                                  void *data,
                                  apr_size_t data_len,
-                                 apr_pool_t *pool);
+                                 apr_pool_t *result_pool);
 
 /*
  * Implements svn_cache__serialize_func_t for l2p_page_t objects.
@@ -368,7 +390,7 @@ svn_error_t *
 svn_fs_x__deserialize_l2p_page(void **out,
                                void *data,
                                apr_size_t data_len,
-                               apr_pool_t *pool);
+                               apr_pool_t *result_pool);
 
 /*
  * Implements svn_cache__serialize_func_t for p2l_header_t objects.
@@ -386,7 +408,7 @@ svn_error_t *
 svn_fs_x__deserialize_p2l_header(void **out,
                                  void *data,
                                  apr_size_t data_len,
-                                 apr_pool_t *pool);
+                                 apr_pool_t *result_pool);
 
 /*
  * Implements svn_cache__serialize_func_t for apr_array_header_t objects
@@ -406,6 +428,6 @@ svn_error_t *
 svn_fs_x__deserialize_p2l_page(void **out,
                                void *data,
                                apr_size_t data_len,
-                               apr_pool_t *pool);
+                               apr_pool_t *result_pool);
 
 #endif

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/lock.c Mon Nov 30 10:24:16 2015
@@ -113,7 +113,8 @@ hash_fetch(apr_hash_t *hash,
 
 /* SVN_ERR_FS_CORRUPT: the lockfile for PATH in FS is corrupt.  */
 static svn_error_t *
-err_corrupt_lockfile(const char *fs_path, const char *path)
+err_corrupt_lockfile(const char *fs_path,
+                     const char *path)
 {
   return
     svn_error_createf(
@@ -234,7 +235,7 @@ write_digest_file(apr_hash_t *children,
   if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR,
                              scratch_pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Cannot write lock/entries hashfile '%s'"),
@@ -243,7 +244,7 @@ write_digest_file(apr_hash_t *children,
     }
 
   SVN_ERR(svn_stream_close(stream));
-  SVN_ERR(svn_io_file_rename(tmp_path, digest_path, scratch_pool));
+  SVN_ERR(svn_io_file_rename2(tmp_path, digest_path, FALSE, scratch_pool));
   SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, scratch_pool));
   return SVN_NO_ERROR;
 }
@@ -286,7 +287,7 @@ read_digest_file(apr_hash_t **children_p
   hash = apr_hash_make(pool);
   if ((err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Can't parse lock/entries hashfile '%s'"),
@@ -470,6 +471,12 @@ unlock_single(svn_fs_t *fs,
               svn_lock_t *lock,
               apr_pool_t *pool);
 
+/* Check if LOCK has been already expired. */
+static svn_boolean_t lock_expired(const svn_lock_t *lock)
+{
+  return lock->expiration_date && (apr_time_now() > lock->expiration_date);
+}
+
 /* Set *LOCK_P to the lock for PATH in FS.  HAVE_WRITE_LOCK should be
    TRUE if the caller (or one of its callers) has taken out the
    repository-wide write lock, FALSE otherwise.  If MUST_EXIST is
@@ -499,7 +506,7 @@ get_lock(svn_lock_t **lock_p,
     return must_exist ? SVN_FS__ERR_NO_SUCH_LOCK(fs, path) : SVN_NO_ERROR;
 
   /* Don't return an expired lock. */
-  if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
+  if (lock_expired(lock))
     {
       /* Only remove the lock if we have the write lock.
          Read operations shouldn't change the filesystem. */
@@ -546,68 +553,17 @@ get_lock_helper(svn_fs_t *fs,
 }
 
 
-/* Baton for locks_walker(). */
-typedef struct walk_locks_baton_t
-{
-  svn_fs_get_locks_callback_t get_locks_func;
-  void *get_locks_baton;
-  svn_fs_t *fs;
-} walk_locks_baton_t;
-
-/* Implements walk_digests_callback_t. */
-static svn_error_t *
-locks_walker(void *baton,
-             const char *fs_path,
-             const char *digest_path,
-             svn_lock_t *lock,
-             svn_boolean_t have_write_lock,
-             apr_pool_t *pool)
-{
-  walk_locks_baton_t *wlb = baton;
-
-  if (lock)
-    {
-      /* Don't report an expired lock. */
-      if (lock->expiration_date == 0
-          || (apr_time_now() <= lock->expiration_date))
-        {
-          if (wlb->get_locks_func)
-            SVN_ERR(wlb->get_locks_func(wlb->get_locks_baton, lock, pool));
-        }
-      else
-        {
-          /* Only remove the lock if we have the write lock.
-             Read operations shouldn't change the filesystem. */
-          if (have_write_lock)
-            SVN_ERR(unlock_single(wlb->fs, lock, pool));
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Callback type for walk_digest_files().
- *
- * LOCK come from a read_digest_file(digest_path) call.
- */
-typedef svn_error_t *(*walk_digests_callback_t)(void *baton,
-                                                const char *fs_path,
-                                                const char *digest_path,
-                                                svn_lock_t *lock,
-                                                svn_boolean_t have_write_lock,
-                                                apr_pool_t *pool);
-
-/* A function that calls WALK_DIGESTS_FUNC/WALK_DIGESTS_BATON for
-   all lock digest files in and under PATH in FS.
+/* A function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
+   all locks in and under PATH in FS.
    HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
    has the FS write lock. */
 static svn_error_t *
-walk_digest_files(const char *fs_path,
-                  const char *digest_path,
-                  walk_digests_callback_t walk_digests_func,
-                  void *walk_digests_baton,
-                  svn_boolean_t have_write_lock,
-                  apr_pool_t *pool)
+walk_locks(svn_fs_t *fs,
+           const char *digest_path,
+           svn_fs_get_locks_callback_t get_locks_func,
+           void *get_locks_baton,
+           svn_boolean_t have_write_lock,
+           apr_pool_t *pool)
 {
   apr_hash_index_t *hi;
   apr_hash_t *children;
@@ -615,10 +571,19 @@ walk_digest_files(const char *fs_path,
   svn_lock_t *lock;
 
   /* First, send up any locks in the current digest file. */
-  SVN_ERR(read_digest_file(&children, &lock, fs_path, digest_path, pool));
+  SVN_ERR(read_digest_file(&children, &lock, fs->path, digest_path, pool));
 
-  SVN_ERR(walk_digests_func(walk_digests_baton, fs_path, digest_path, lock,
-                            have_write_lock, pool));
+  if (lock && lock_expired(lock))
+    {
+      /* Only remove the lock if we have the write lock.
+         Read operations shouldn't change the filesystem. */
+      if (have_write_lock)
+        SVN_ERR(unlock_single(fs, lock, pool));
+    }
+  else if (lock)
+    {
+      SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+    }
 
   /* Now, report all the child entries (if any; bail otherwise). */
   if (! apr_hash_count(children))
@@ -630,39 +595,25 @@ walk_digest_files(const char *fs_path,
       svn_pool_clear(subpool);
 
       SVN_ERR(read_digest_file
-              (NULL, &lock, fs_path,
-               digest_path_from_digest(fs_path, digest, subpool), subpool));
+              (NULL, &lock, fs->path,
+               digest_path_from_digest(fs->path, digest, subpool), subpool));
 
-      SVN_ERR(walk_digests_func(walk_digests_baton, fs_path, digest_path, lock,
-                                have_write_lock, subpool));
+      if (lock && lock_expired(lock))
+        {
+          /* Only remove the lock if we have the write lock.
+             Read operations shouldn't change the filesystem. */
+          if (have_write_lock)
+            SVN_ERR(unlock_single(fs, lock, pool));
+        }
+      else if (lock)
+        {
+          SVN_ERR(get_locks_func(get_locks_baton, lock, pool));
+        }
     }
   svn_pool_destroy(subpool);
   return SVN_NO_ERROR;
 }
 
-/* A function that calls GET_LOCKS_FUNC/GET_LOCKS_BATON for
-   all locks in and under PATH in FS.
-   HAVE_WRITE_LOCK should be true if the caller (directly or indirectly)
-   has the FS write lock. */
-static svn_error_t *
-walk_locks(svn_fs_t *fs,
-           const char *digest_path,
-           svn_fs_get_locks_callback_t get_locks_func,
-           void *get_locks_baton,
-           svn_boolean_t have_write_lock,
-           apr_pool_t *pool)
-{
-  walk_locks_baton_t wlb;
-
-  wlb.get_locks_func = get_locks_func;
-  wlb.get_locks_baton = get_locks_baton;
-  wlb.fs = fs;
-  SVN_ERR(walk_digest_files(fs->path, digest_path, locks_walker, &wlb,
-                            have_write_lock, pool));
-  return SVN_NO_ERROR;
-}
-
-
 /* Utility function:  verify that a lock can be used.  Interesting
    errors returned from this function:
 
@@ -737,6 +688,35 @@ svn_fs_x__allow_locked_operation(const c
   return SVN_NO_ERROR;
 }
 
+/* Helper function called from the lock and unlock code.
+   UPDATES is a map from "const char *" parent paths to "apr_array_header_t *"
+   arrays of child paths.  For all of the parent paths of PATH this function
+   adds PATH to the corresponding array of child paths. */
+static void
+schedule_index_update(apr_hash_t *updates,
+                      const char *path,
+                      apr_pool_t *scratch_pool)
+{
+  apr_pool_t *hashpool = apr_hash_pool_get(updates);
+  const char *parent_path = path;
+
+  while (! svn_fspath__is_root(parent_path, strlen(parent_path)))
+    {
+      apr_array_header_t *children;
+
+      parent_path = svn_fspath__dirname(parent_path, scratch_pool);
+      children = svn_hash_gets(updates, parent_path);
+
+      if (! children)
+        {
+          children = apr_array_make(hashpool, 8, sizeof(const char *));
+          svn_hash_sets(updates, apr_pstrdup(hashpool, parent_path), children);
+        }
+
+      APR_ARRAY_PUSH(children, const char *) = path;
+    }
+}
+
 /* The effective arguments for lock_body() below. */
 typedef struct lock_baton_t {
   svn_fs_t *fs;
@@ -755,6 +735,7 @@ check_lock(svn_error_t **fs_err,
            const svn_fs_lock_target_t *target,
            lock_baton_t *lb,
            svn_fs_root_t *root,
+           svn_revnum_t youngest_rev,
            apr_pool_t *pool)
 {
   svn_node_kind_t kind;
@@ -791,6 +772,15 @@ check_lock(svn_error_t **fs_err,
   if (SVN_IS_VALID_REVNUM(target->current_rev))
     {
       svn_revnum_t created_rev;
+
+      if (target->current_rev > youngest_rev)
+        {
+          *fs_err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                                      _("No such revision %ld"),
+                                      target->current_rev);
+          return SVN_NO_ERROR;
+        }
+
       SVN_ERR(svn_fs_x__node_created_rev(&created_rev, root, path,
                                          pool));
 
@@ -849,7 +839,6 @@ check_lock(svn_error_t **fs_err,
 
 typedef struct lock_info_t {
   const char *path;
-  const char *component;
   svn_lock_t *lock;
   svn_error_t *fs_err;
 } lock_info_t;
@@ -866,20 +855,20 @@ typedef struct lock_info_t {
    type, and assumes that the write lock is held.
  */
 static svn_error_t *
-lock_body(void *baton, apr_pool_t *pool)
+lock_body(void *baton,
+          apr_pool_t *pool)
 {
   lock_baton_t *lb = baton;
   svn_fs_root_t *root;
   svn_revnum_t youngest;
   const char *rev_0_path;
-  int i, outstanding = 0;
+  int i;
+  apr_hash_t *index_updates = apr_hash_make(pool);
+  apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
-  lb->infos = apr_array_make(lb->result_pool, lb->targets->nelts,
-                             sizeof(lock_info_t));
-
   /* Until we implement directory locks someday, we only allow locks
-     on files or non-existent paths. */
+     on files. */
   /* Use fs->vtable->foo instead of svn_fs_foo to avoid circular
      library dependencies, which are not portable. */
   SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool));
@@ -889,34 +878,28 @@ lock_body(void *baton, apr_pool_t *pool)
     {
       const svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i,
                                                     svn_sort__item_t);
-      const svn_fs_lock_target_t *target = item->value;
       lock_info_t info;
 
       svn_pool_clear(iterpool);
 
       info.path = item->key;
-      SVN_ERR(check_lock(&info.fs_err, info.path, target, lb, root, iterpool));
       info.lock = NULL;
-      info.component = NULL;
-      APR_ARRAY_PUSH(lb->infos, lock_info_t) = info;
+      info.fs_err = SVN_NO_ERROR;
+
+      SVN_ERR(check_lock(&info.fs_err, info.path, item->value, lb, root,
+                         youngest, iterpool));
+
+      /* If no error occurred while pre-checking, schedule the index updates for
+         this path. */
       if (!info.fs_err)
-        ++outstanding;
+        schedule_index_update(index_updates, info.path, iterpool);
+
+      APR_ARRAY_PUSH(lb->infos, lock_info_t) = info;
     }
 
   rev_0_path = svn_fs_x__path_rev_absolute(lb->fs, 0, pool);
 
-  /* Given the paths:
-
-       /foo/bar/f
-       /foo/bar/g
-       /zig/x
-
-     we loop through repeatedly.  The first pass sees '/' on all paths
-     and writes the '/' index.  The second pass sees '/foo' twice and
-     writes that index followed by '/zig' and that index. The third
-     pass sees '/foo/bar' twice and writes that index, and then writes
-     the lock for '/zig/x'.  The fourth pass writes the locks for
-     '/foo/bar/f' and '/foo/bar/g'.
+  /* We apply the scheduled index updates before writing the actual locks.
 
      Writing indices before locks is correct: if interrupted it leaves
      indices without locks rather than locks without indices.  An
@@ -925,91 +908,50 @@ lock_body(void *baton, apr_pool_t *pool)
      index is inconsistent, svn_fs_x__allow_locked_operation will
      show locked on the file but unlocked on the parent. */
 
+  for (hi = apr_hash_first(pool, index_updates); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      apr_array_header_t *children = apr_hash_this_val(hi);
 
-  while (outstanding)
+      svn_pool_clear(iterpool);
+      SVN_ERR(add_to_digest(lb->fs->path, children, path, rev_0_path,
+                            iterpool));
+    }
+
+  for (i = 0; i < lb->infos->nelts; ++i)
     {
-      const char *last_path = NULL;
-      apr_array_header_t *paths;
+      struct lock_info_t *info = &APR_ARRAY_IDX(lb->infos, i,
+                                                struct lock_info_t);
+      svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i, svn_sort__item_t);
+      svn_fs_lock_target_t *target = item->value;
 
       svn_pool_clear(iterpool);
-      paths = apr_array_make(iterpool, 1, sizeof(const char *));
 
-      for (i = 0; i < lb->infos->nelts; ++i)
+      if (! info->fs_err)
         {
-          lock_info_t *info = &APR_ARRAY_IDX(lb->infos, i, lock_info_t);
-          const svn_sort__item_t *item = &APR_ARRAY_IDX(lb->targets, i,
-                                                        svn_sort__item_t);
-          const svn_fs_lock_target_t *target = item->value;
-
-          if (!info->fs_err && !info->lock)
-            {
-              if (!info->component)
-                {
-                  info->component = info->path;
-                  APR_ARRAY_PUSH(paths, const char *) = info->path;
-                  last_path = "/";
-                }
-              else
-                {
-                  info->component = strchr(info->component + 1, '/');
-                  if (!info->component)
-                    {
-                      /* The component is a path to lock, this cannot
-                         match a previous path that need to be indexed. */
-                      if (paths->nelts)
-                        {
-                          SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                                rev_0_path, iterpool));
-                          apr_array_clear(paths);
-                          last_path = NULL;
-                        }
-
-                      info->lock = svn_lock_create(lb->result_pool);
-                      if (target->token)
-                        info->lock->token = target->token;
-                      else
-                        SVN_ERR(svn_fs_x__generate_lock_token(
-                                  &(info->lock->token), lb->fs,
-                                  lb->result_pool));
-                      info->lock->path = info->path;
-                      info->lock->owner = lb->fs->access_ctx->username;
-                      info->lock->comment = lb->comment;
-                      info->lock->is_dav_comment = lb->is_dav_comment;
-                      info->lock->creation_date = apr_time_now();
-                      info->lock->expiration_date = lb->expiration_date;
-
-                      info->fs_err = set_lock(lb->fs->path, info->lock,
-                                              rev_0_path, iterpool);
-                      --outstanding;
-                    }
-                  else
-                    {
-                      /* The component is a path to an index. */
-                      apr_size_t len = info->component - info->path;
-
-                      if (last_path
-                          && (strncmp(last_path, info->path, len)
-                              || strlen(last_path) != len))
-                        {
-                          /* No match to the previous paths to index. */
-                          SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                                rev_0_path, iterpool));
-                          apr_array_clear(paths);
-                          last_path = NULL;
-                        }
-                      APR_ARRAY_PUSH(paths, const char *) = info->path;
-                      if (!last_path)
-                        last_path = apr_pstrndup(iterpool, info->path, len);
-                    }
-                }
-            }
-
-          if (last_path && i == lb->infos->nelts - 1)
-            SVN_ERR(add_to_digest(lb->fs->path, paths, last_path,
-                                  rev_0_path, iterpool));
+          info->lock = svn_lock_create(lb->result_pool);
+          if (target->token)
+            info->lock->token = apr_pstrdup(lb->result_pool, target->token);
+          else
+            SVN_ERR(svn_fs_x__generate_lock_token(&(info->lock->token), lb->fs,
+                                                  lb->result_pool));
+
+          /* The INFO->PATH is already allocated in LB->RESULT_POOL as a result
+             of svn_fspath__canonicalize() (see svn_fs_fs__lock()). */
+          info->lock->path = info->path;
+          info->lock->owner = apr_pstrdup(lb->result_pool,
+                                          lb->fs->access_ctx->username);
+          info->lock->comment = apr_pstrdup(lb->result_pool, lb->comment);
+          info->lock->is_dav_comment = lb->is_dav_comment;
+          info->lock->creation_date = apr_time_now();
+          info->lock->expiration_date = lb->expiration_date;
+
+          info->fs_err = set_lock(lb->fs->path, info->lock, rev_0_path,
+                                  iterpool);
         }
     }
 
+  svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
@@ -1050,10 +992,8 @@ check_unlock(svn_error_t **fs_err,
 
 typedef struct unlock_info_t {
   const char *path;
-  const char *component;
   svn_error_t *fs_err;
   svn_boolean_t done;
-  int components;
 } unlock_info_t;
 
 /* The body of svn_fs_x__unlock(), which see.
@@ -1068,18 +1008,18 @@ typedef struct unlock_info_t {
    type, and assumes that the write lock is held.
  */
 static svn_error_t *
-unlock_body(void *baton, apr_pool_t *pool)
+unlock_body(void *baton,
+            apr_pool_t *pool)
 {
   unlock_baton_t *ub = baton;
   svn_fs_root_t *root;
   svn_revnum_t youngest;
   const char *rev_0_path;
-  int i, max_components = 0, outstanding = 0;
+  int i;
+  apr_hash_t *indices_updates = apr_hash_make(pool);
+  apr_hash_index_t *hi;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
-  ub->infos = apr_array_make(ub->result_pool, ub->targets->nelts,
-                             sizeof( unlock_info_t));
-
   SVN_ERR(ub->fs->vtable->youngest_rev(&youngest, ub->fs, pool));
   SVN_ERR(ub->fs->vtable->revision_root(&root, ub->fs, youngest, pool));
 
@@ -1088,95 +1028,56 @@ unlock_body(void *baton, apr_pool_t *poo
       const svn_sort__item_t *item = &APR_ARRAY_IDX(ub->targets, i,
                                                     svn_sort__item_t);
       const char *token = item->value;
-      unlock_info_t info = { 0 };
+      unlock_info_t info;
 
       svn_pool_clear(iterpool);
 
       info.path = item->key;
+      info.fs_err = SVN_NO_ERROR;
+      info.done = FALSE;
+
       if (!ub->skip_check)
         SVN_ERR(check_unlock(&info.fs_err, info.path, token, ub, root,
                              iterpool));
-      if (!info.fs_err)
-        {
-          const char *s;
 
-          info.components = 1;
-          info.component = info.path;
-          while((s = strchr(info.component + 1, '/')))
-            {
-              info.component = s;
-              ++info.components;
-            }
-
-          if (info.components > max_components)
-            max_components = info.components;
+      /* If no error occurred while pre-checking, schedule the index updates for
+         this path. */
+      if (!info.fs_err)
+        schedule_index_update(indices_updates, info.path, iterpool);
 
-          ++outstanding;
-        }
       APR_ARRAY_PUSH(ub->infos, unlock_info_t) = info;
     }
 
   rev_0_path = svn_fs_x__path_rev_absolute(ub->fs, 0, pool);
 
-  for (i = max_components; i >= 0; --i)
+  /* Unlike the lock_body(), we need to delete locks *before* we start to
+     update indices. */
+
+  for (i = 0; i < ub->infos->nelts; ++i)
     {
-      const char *last_path = NULL;
-      apr_array_header_t *paths;
-      int j;
+      struct unlock_info_t *info = &APR_ARRAY_IDX(ub->infos, i,
+                                                  struct unlock_info_t);
 
       svn_pool_clear(iterpool);
-      paths = apr_array_make(pool, 1, sizeof(const char *));
 
-      for (j = 0; j < ub->infos->nelts; ++j)
+      if (! info->fs_err)
         {
-          unlock_info_t *info = &APR_ARRAY_IDX(ub->infos, j, unlock_info_t);
+          SVN_ERR(delete_lock(ub->fs->path, info->path, iterpool));
+          info->done = TRUE;
+        }
+    }
 
-          if (!info->fs_err && info->path)
-            {
+  for (hi = apr_hash_first(pool, indices_updates); hi; hi = apr_hash_next(hi))
+    {
+      const char *path = apr_hash_this_key(hi);
+      apr_array_header_t *children = apr_hash_this_val(hi);
 
-              if (info->components == i)
-                {
-                  SVN_ERR(delete_lock(ub->fs->path, info->path, iterpool));
-                  info->done = TRUE;
-                }
-              else if (info->components > i)
-                {
-                  apr_size_t len = info->component - info->path;
-
-                  if (last_path
-                      && strcmp(last_path, "/")
-                      && (strncmp(last_path, info->path, len)
-                          || strlen(last_path) != len))
-                    {
-                      SVN_ERR(delete_from_digest(ub->fs->path, paths, last_path,
-                                                 rev_0_path, iterpool));
-                      apr_array_clear(paths);
-                      last_path = NULL;
-                    }
-                  APR_ARRAY_PUSH(paths, const char *) = info->path;
-                  if (!last_path)
-                    {
-                      if (info->component > info->path)
-                        last_path = apr_pstrndup(pool, info->path, len);
-                      else
-                        last_path = "/";
-                    }
-
-                  if (info->component > info->path)
-                    {
-                      --info->component;
-                      while(info->component[0] != '/')
-                        --info->component;
-                    }
-                }
-            }
-
-          if (last_path && j == ub->infos->nelts - 1)
-            SVN_ERR(delete_from_digest(ub->fs->path, paths, last_path,
-                                       rev_0_path, iterpool));
-        }
+      svn_pool_clear(iterpool);
+      SVN_ERR(delete_from_digest(ub->fs->path, children, path, rev_0_path,
+                                 iterpool));
     }
 
+  svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
 }
 
@@ -1200,6 +1101,8 @@ unlock_single(svn_fs_t *fs,
 
   ub.fs = fs;
   ub.targets = targets;
+  ub.infos = apr_array_make(scratch_pool, targets->nelts,
+                            sizeof(struct unlock_info_t));
   ub.skip_check = TRUE;
   ub.result_pool = scratch_pool;
 
@@ -1228,6 +1131,7 @@ svn_fs_x__lock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1260,17 +1164,21 @@ svn_fs_x__lock(svn_fs_t *fs,
 
   lb.fs = fs;
   lb.targets = sorted_targets;
+  lb.infos = apr_array_make(result_pool, sorted_targets->nelts,
+                            sizeof(struct lock_info_t));
   lb.comment = comment;
   lb.is_dav_comment = is_dav_comment;
   lb.expiration_date = expiration_date;
   lb.steal_lock = steal_lock;
   lb.result_pool = result_pool;
 
-  err = svn_fs_x__with_write_lock(fs, lock_body, &lb, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_x__with_write_lock(fs, lock_body, &lb, iterpool);
   for (i = 0; i < lb.infos->nelts; ++i)
     {
       struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
                                                 struct lock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->lock && !info->fs_err)
@@ -1279,10 +1187,11 @@ svn_fs_x__lock(svn_fs_t *fs,
                                              info->path);
 
           cb_err = lock_callback(lock_baton, info->path, info->lock,
-                                 info->fs_err, scratch_pool);
+                                 info->fs_err, iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);
@@ -1322,6 +1231,7 @@ svn_fs_x__unlock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1350,14 +1260,18 @@ svn_fs_x__unlock(svn_fs_t *fs,
 
   ub.fs = fs;
   ub.targets = sorted_targets;
+  ub.infos = apr_array_make(result_pool, sorted_targets->nelts,
+                            sizeof(struct unlock_info_t));
   ub.skip_check = FALSE;
   ub.break_lock = break_lock;
   ub.result_pool = result_pool;
 
-  err = svn_fs_x__with_write_lock(fs, unlock_body, &ub, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_x__with_write_lock(fs, unlock_body, &ub, iterpool);
   for (i = 0; i < ub.infos->nelts; ++i)
     {
       unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i, unlock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->done && !info->fs_err)
@@ -1365,10 +1279,11 @@ svn_fs_x__unlock(svn_fs_t *fs,
                                              0, _("Failed to unlock '%s'"),
                                              info->path);
           cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
-                                 scratch_pool);
+                                 iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/lock.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/lock.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/lock.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/lock.h Mon Nov 30 10:24:16 2015
@@ -20,8 +20,8 @@
  * ====================================================================
  */
 
-#ifndef SVN_LIBSVN_FS_LOCK_H
-#define SVN_LIBSVN_FS_LOCK_H
+#ifndef SVN_LIBSVN_FS_X_LOCK_H
+#define SVN_LIBSVN_FS_X_LOCK_H
 
 #ifdef __cplusplus
 extern "C" {
@@ -113,4 +113,4 @@ svn_fs_x__allow_locked_operation(const c
 }
 #endif /* __cplusplus */
 
-#endif /* SVN_LIBSVN_FS_LOCK_H */
+#endif /* SVN_LIBSVN_FS_X_LOCK_H */