diff options
Diffstat (limited to 'subversion/libsvn_fs_x/hotcopy.c')
-rw-r--r-- | subversion/libsvn_fs_x/hotcopy.c | 367 |
1 files changed, 84 insertions, 283 deletions
diff --git a/subversion/libsvn_fs_x/hotcopy.c b/subversion/libsvn_fs_x/hotcopy.c index c9f0af2f7d5c8..431ecb2987684 100644 --- a/subversion/libsvn_fs_x/hotcopy.c +++ b/subversion/libsvn_fs_x/hotcopy.c @@ -243,6 +243,7 @@ hotcopy_io_copy_dir_recursively(svn_boolean_t *skipped_p, * 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 *skipped_p, 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 *skipped_p, 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 *skipped_p, 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 *skipped_p, 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(svn_fs_t *src_fs, 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, @@ -729,7 +555,7 @@ typedef struct hotcopy_body_baton_t { * An incremental hotcopy copies only changed or new files to the destination, * and removes files from the destination no longer present in the source. * While the incremental hotcopy is running, readers should still be able - * to access the destintation repository without error and should not see + * to access the destination repository without error and should not see * revisions currently in progress of being copied. Readers are able to see * new fully copied revisions even if the entire incremental hotcopy procedure * has not yet completed. @@ -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; -} + /* Hotcopied FS is complete. Stamp it with a format file. */ + SVN_ERR(svn_fs_x__write_format(dst_fs, TRUE, scratch_pool)); -/* 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; - - 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)); - - /* 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)); + hotcopy_body_baton_t hbb; - /* 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)); + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); - /* 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)); + SVN_ERR(svn_fs_x__open(src_fs, src_path, scratch_pool)); - return SVN_NO_ERROR; -} - -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_t *src_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; + + /* 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)); } - return SVN_NO_ERROR; -} - -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; } |