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 */