diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-08-05 16:22:51 +0000 |
commit | cf46733632c7279a9fd0fe6ce26f9185a4ae82a9 (patch) | |
tree | da27775a2161723ef342e91af41a8b51fedef405 /subversion/libsvn_wc/copy.c | |
parent | bb0ef45f7c46b0ae221b26265ef98a768c33f820 (diff) | |
download | subversion-tarball-master.tar.gz |
subversion-1.9.7HEADsubversion-1.9.7master
Diffstat (limited to 'subversion/libsvn_wc/copy.c')
-rw-r--r-- | subversion/libsvn_wc/copy.c | 182 |
1 files changed, 142 insertions, 40 deletions
diff --git a/subversion/libsvn_wc/copy.c b/subversion/libsvn_wc/copy.c index 1e7d7cf..30a0db5 100644 --- a/subversion/libsvn_wc/copy.c +++ b/subversion/libsvn_wc/copy.c @@ -42,6 +42,7 @@ #include "svn_private_config.h" #include "private/svn_wc_private.h" +/* #define RECORD_MIXED_MOVE */ /*** Code. ***/ @@ -50,7 +51,14 @@ TMPDIR_ABSPATH and return the absolute path of the copy in *DST_ABSPATH. Return the node kind of SRC_ABSPATH in *KIND. If SRC_ABSPATH doesn't exist then set *DST_ABSPATH to NULL to indicate - that no copy was made. */ + that no copy was made. + + If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH. + RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of + SRC_ABSPATH, and RECORDED_TIME the recorded size or 0. + + These values will be used to avoid unneeded work. + */ static svn_error_t * copy_to_tmpdir(svn_skel_t **work_item, svn_node_kind_t *kind, @@ -60,6 +68,9 @@ copy_to_tmpdir(svn_skel_t **work_item, const char *tmpdir_abspath, svn_boolean_t file_copy, svn_boolean_t unversioned, + const svn_io_dirent2_t *dirent, + svn_filesize_t recorded_size, + apr_time_t recorded_time, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *result_pool, @@ -74,8 +85,14 @@ copy_to_tmpdir(svn_skel_t **work_item, *work_item = NULL; - SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special, - scratch_pool)); + if (dirent) + { + *kind = dirent->kind; + is_special = dirent->special; + } + else + SVN_ERR(svn_io_check_special_path(src_abspath, kind, &is_special, + scratch_pool)); if (*kind == svn_node_none) { return SVN_NO_ERROR; @@ -104,9 +121,21 @@ copy_to_tmpdir(svn_skel_t **work_item, the timestamp might match, than to examine the destination later as the destination timestamp will never match. */ - SVN_ERR(svn_wc__internal_file_modified_p(&modified, - db, src_abspath, - FALSE, scratch_pool)); + + if (dirent + && dirent->kind == svn_node_file + && recorded_size != SVN_INVALID_FILESIZE + && recorded_size == dirent->filesize + && recorded_time == dirent->mtime) + { + modified = FALSE; /* Recorded matches on-disk. Easy out */ + } + else + { + SVN_ERR(svn_wc__internal_file_modified_p(&modified, db, src_abspath, + FALSE, scratch_pool)); + } + if (!modified) { /* Why create a temp copy if we can just reinstall from pristine? */ @@ -117,6 +146,15 @@ copy_to_tmpdir(svn_skel_t **work_item, return SVN_NO_ERROR; } } + else if (*kind == svn_node_dir && !file_copy) + { + /* Just build a new direcory from the workqueue */ + SVN_ERR(svn_wc__wq_build_dir_install(work_item, + db, dst_abspath, + result_pool, scratch_pool)); + + return SVN_NO_ERROR; + } /* Set DST_TMP_ABSPATH to a temporary unique path. If *KIND is file, leave a file there and then overwrite it; otherwise leave no node on disk at @@ -172,7 +210,14 @@ copy_to_tmpdir(svn_skel_t **work_item, versioned file itself. This also works for versioned symlinks that are stored in the db as - svn_node_file with svn:special set. */ + svn_node_file with svn:special set. + + If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH. + RECORDED_SIZE (if not SVN_INVALID_FILESIZE) contains the recorded size of + SRC_ABSPATH, and RECORDED_TIME the recorded size or 0. + + These values will be used to avoid unneeded work. +*/ static svn_error_t * copy_versioned_file(svn_wc__db_t *db, const char *src_abspath, @@ -182,6 +227,9 @@ copy_versioned_file(svn_wc__db_t *db, svn_boolean_t metadata_only, svn_boolean_t conflicted, svn_boolean_t is_move, + const svn_io_dirent2_t *dirent, + svn_filesize_t recorded_size, + apr_time_t recorded_time, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, @@ -210,8 +258,9 @@ copy_versioned_file(svn_wc__db_t *db, svn_error_t *err; /* Is there a text conflict at the source path? */ - SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + db, src_abspath, + scratch_pool, scratch_pool)); err = svn_wc__conflict_read_text_conflict(&conflict_working, NULL, NULL, db, src_abspath, conflict, @@ -248,6 +297,7 @@ copy_versioned_file(svn_wc__db_t *db, dst_abspath, tmpdir_abspath, TRUE /* file_copy */, handle_as_unversioned /* unversioned */, + dirent, recorded_size, recorded_time, cancel_func, cancel_baton, scratch_pool, scratch_pool)); } @@ -265,10 +315,6 @@ copy_versioned_file(svn_wc__db_t *db, scratch_pool); notify->kind = svn_node_file; - /* When we notify that we performed a copy, make sure we already did */ - if (work_items != NULL) - SVN_ERR(svn_wc__wq_run(db, dst_abspath, - cancel_func, cancel_baton, scratch_pool)); (*notify_func)(notify_baton, notify, scratch_pool); } return SVN_NO_ERROR; @@ -282,6 +328,8 @@ copy_versioned_file(svn_wc__db_t *db, data in addition to copying the directory. WITHIN_ONE_WC is TRUE if the copy/move is within a single working copy (root) + + If DIRENT is not NULL, it contains the on-disk information of SRC_ABSPATH. */ static svn_error_t * copy_versioned_dir(svn_wc__db_t *db, @@ -291,6 +339,7 @@ copy_versioned_dir(svn_wc__db_t *db, const char *tmpdir_abspath, svn_boolean_t metadata_only, svn_boolean_t is_move, + const svn_io_dirent2_t *dirent, svn_cancel_func_t cancel_func, void *cancel_baton, svn_wc_notify_func2_t notify_func, @@ -314,6 +363,7 @@ copy_versioned_dir(svn_wc__db_t *db, tmpdir_abspath, FALSE /* file_copy */, FALSE /* unversioned */, + dirent, SVN_INVALID_FILESIZE, 0, cancel_func, cancel_baton, scratch_pool, scratch_pool)); } @@ -353,6 +403,7 @@ copy_versioned_dir(svn_wc__db_t *db, SVN_ERR(svn_wc__db_read_children_info(&versioned_children, &conflicted_children, db, src_abspath, + FALSE /* base_tree_only */, scratch_pool, iterpool)); for (hi = apr_hash_first(scratch_pool, versioned_children); hi; @@ -366,8 +417,8 @@ copy_versioned_dir(svn_wc__db_t *db, if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); - child_name = svn__apr_hash_index_key(hi); - info = svn__apr_hash_index_val(hi); + child_name = apr_hash_this_key(hi); + info = apr_hash_this_val(hi); child_src_abspath = svn_dirent_join(src_abspath, child_name, iterpool); child_dst_abspath = svn_dirent_join(dst_abspath, child_name, iterpool); @@ -394,6 +445,12 @@ copy_versioned_dir(svn_wc__db_t *db, tmpdir_abspath, metadata_only, info->conflicted, is_move, + disk_children + ? svn_hash_gets(disk_children, + child_name) + : NULL, + info->recorded_size, + info->recorded_time, cancel_func, cancel_baton, NULL, NULL, iterpool)); @@ -403,6 +460,10 @@ copy_versioned_dir(svn_wc__db_t *db, child_src_abspath, child_dst_abspath, dst_op_root_abspath, tmpdir_abspath, metadata_only, is_move, + disk_children + ? svn_hash_gets(disk_children, + child_name) + : NULL, cancel_func, cancel_baton, NULL, NULL, iterpool)); else @@ -421,7 +482,7 @@ copy_versioned_dir(svn_wc__db_t *db, child_dst_abspath, dst_op_root_abspath, is_move, NULL, iterpool)); - /* Don't recurse on children while all we do is creating not-present + /* Don't recurse on children when all we do is creating not-present children */ } else if (info->status == svn_wc__db_status_incomplete) @@ -467,7 +528,7 @@ copy_versioned_dir(svn_wc__db_t *db, for (hi = apr_hash_first(scratch_pool, disk_children); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); + const char *name = apr_hash_this_key(hi); const char *unver_src_abspath, *unver_dst_abspath; svn_skel_t *work_item; @@ -488,6 +549,7 @@ copy_versioned_dir(svn_wc__db_t *db, SVN_ERR(copy_to_tmpdir(&work_item, NULL, db, unver_src_abspath, unver_dst_abspath, tmpdir_abspath, TRUE /* recursive */, TRUE /* unversioned */, + NULL, SVN_INVALID_FILESIZE, 0, cancel_func, cancel_baton, scratch_pool, iterpool)); @@ -507,10 +569,10 @@ copy_versioned_dir(svn_wc__db_t *db, * The additional parameter IS_MOVE indicates whether this is a copy or * a move operation. * - * If MOVE_DEGRADED_TO_COPY is not NULL and a move had to be degraded - * to a copy, then set *MOVE_DEGRADED_TO_COPY. */ + * If RECORD_MOVE_ON_DELETE is not NULL and a move had to be degraded + * to a copy, then set *RECORD_MOVE_ON_DELETE to FALSE. */ static svn_error_t * -copy_or_move(svn_boolean_t *move_degraded_to_copy, +copy_or_move(svn_boolean_t *record_move_on_delete, svn_wc_context_t *wc_ctx, const char *src_abspath, const char *dst_abspath, @@ -533,6 +595,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, svn_boolean_t within_one_wc; svn_wc__db_status_t src_status; svn_error_t *err; + svn_filesize_t recorded_size; + apr_time_t recorded_time; SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath)); SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath)); @@ -550,7 +614,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, err = svn_wc__db_read_info(&src_status, &src_db_kind, NULL, &src_repos_relpath, &src_repos_root_url, &src_repos_uuid, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + &recorded_size, &recorded_time, NULL, &conflicted, NULL, NULL, NULL, NULL, NULL, NULL, db, src_abspath, scratch_pool, scratch_pool); @@ -643,10 +708,13 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, scratch_pool, scratch_pool)); else /* If not added, the node must have a base or we can't copy */ - SVN_ERR(svn_wc__db_scan_base_repos(NULL, &src_repos_root_url, - &src_repos_uuid, - db, src_abspath, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, + &src_repos_root_url, + &src_repos_uuid, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, + db, src_abspath, + scratch_pool, scratch_pool)); } if (!dst_repos_root_url) @@ -660,10 +728,13 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, scratch_pool, scratch_pool)); else /* If not added, the node must have a base or we can't copy */ - SVN_ERR(svn_wc__db_scan_base_repos(NULL, &dst_repos_root_url, - &dst_repos_uuid, - db, dstdir_abspath, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__db_base_get_info(NULL, NULL, NULL, NULL, + &dst_repos_root_url, + &dst_repos_uuid, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, + NULL, + db, dstdir_abspath, + scratch_pool, scratch_pool)); } if (strcmp(src_repos_root_url, dst_repos_root_url) != 0 @@ -751,8 +822,8 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, if (is_move && !within_one_wc) { - if (move_degraded_to_copy) - *move_degraded_to_copy = TRUE; + if (record_move_on_delete) + *record_move_on_delete = FALSE; is_move = FALSE; } @@ -768,6 +839,7 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, err = copy_versioned_file(db, src_abspath, dst_abspath, dst_abspath, tmpdir_abspath, metadata_only, conflicted, is_move, + NULL, recorded_size, recorded_time, cancel_func, cancel_baton, notify_func, notify_baton, scratch_pool); @@ -795,14 +867,17 @@ copy_or_move(svn_boolean_t *move_degraded_to_copy, scratch_pool), min_rev, max_rev); +#ifndef RECORD_MIXED_MOVE is_move = FALSE; - if (move_degraded_to_copy) - *move_degraded_to_copy = TRUE; + if (record_move_on_delete) + *record_move_on_delete = FALSE; +#endif } } err = copy_versioned_dir(db, src_abspath, dst_abspath, dst_abspath, tmpdir_abspath, metadata_only, is_move, + NULL /* dirent */, cancel_func, cancel_baton, notify_func, notify_baton, scratch_pool); @@ -871,7 +946,8 @@ remove_node_conflict_markers(svn_wc__db_t *db, { svn_skel_t *conflict; - SVN_ERR(svn_wc__db_read_conflict(&conflict, db, src_abspath, + SVN_ERR(svn_wc__db_read_conflict(&conflict, NULL, NULL, + db, src_abspath, scratch_pool, scratch_pool)); /* Do we have conflict markers that should be removed? */ @@ -923,6 +999,8 @@ static svn_error_t * remove_all_conflict_markers(svn_wc__db_t *db, const char *src_dir_abspath, const char *dst_dir_abspath, + svn_cancel_func_t cancel_func, + void *cancel_baton, apr_pool_t *scratch_pool) { apr_pool_t *iterpool = svn_pool_create(scratch_pool); @@ -936,14 +1014,18 @@ remove_all_conflict_markers(svn_wc__db_t *db, artillery. */ SVN_ERR(svn_wc__db_read_children_info(&nodes, &conflicts, db, src_dir_abspath, + FALSE /* base_tree_only */, scratch_pool, iterpool)); for (hi = apr_hash_first(scratch_pool, nodes); hi; hi = apr_hash_next(hi)) { - const char *name = svn__apr_hash_index_key(hi); - struct svn_wc__db_info_t *info = svn__apr_hash_index_val(hi); + const char *name = apr_hash_this_key(hi); + struct svn_wc__db_info_t *info = apr_hash_this_val(hi); + + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); if (info->conflicted) { @@ -961,6 +1043,7 @@ remove_all_conflict_markers(svn_wc__db_t *db, db, svn_dirent_join(src_dir_abspath, name, iterpool), svn_dirent_join(dst_dir_abspath, name, iterpool), + cancel_func, cancel_baton, iterpool)); } } @@ -982,7 +1065,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, apr_pool_t *scratch_pool) { svn_wc__db_t *db = wc_ctx->db; - svn_boolean_t move_degraded_to_copy = FALSE; + svn_boolean_t record_on_delete = TRUE; svn_node_kind_t kind; svn_boolean_t conflicted; @@ -994,7 +1077,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, svn_dirent_dirname(dst_abspath, scratch_pool), scratch_pool)); - SVN_ERR(copy_or_move(&move_degraded_to_copy, + SVN_ERR(copy_or_move(&record_on_delete, wc_ctx, src_abspath, dst_abspath, TRUE /* metadata_only */, TRUE /* is_move */, @@ -1018,7 +1101,25 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, is still in a valid state. So be careful when switching this over to the workqueue. */ if (!metadata_only) - SVN_ERR(svn_io_file_rename(src_abspath, dst_abspath, scratch_pool)); + { + svn_error_t *err; + + err = svn_error_trace(svn_io_file_rename(src_abspath, dst_abspath, + scratch_pool)); + + /* Let's try if we can keep wc.db consistent even when the move + fails. Deleting the target is a wc.db only operation, while + going forward (delaying the error) would try to change + conflict markers, which might also fail. */ + if (err) + return svn_error_trace( + svn_error_compose_create( + err, + svn_wc__db_op_delete(wc_ctx->db, dst_abspath, NULL, TRUE, + NULL, NULL, cancel_func, cancel_baton, + NULL, NULL, + scratch_pool))); + } SVN_ERR(svn_wc__db_read_info(NULL, &kind, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -1030,6 +1131,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, if (kind == svn_node_dir) SVN_ERR(remove_all_conflict_markers(db, src_abspath, dst_abspath, + cancel_func, cancel_baton, scratch_pool)); if (conflicted) @@ -1045,7 +1147,7 @@ svn_wc__move2(svn_wc_context_t *wc_ctx, } SVN_ERR(svn_wc__db_op_delete(db, src_abspath, - move_degraded_to_copy ? NULL : dst_abspath, + record_on_delete ? dst_abspath : NULL, TRUE /* delete_dir_externals */, NULL /* conflict */, NULL /* work_items */, cancel_func, cancel_baton, |