Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/diff_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/diff_editor.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/diff_editor.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/diff_editor.c Thu Feb 10 20:04:43 2022 @@ -75,6 +75,7 @@ #include "adm_files.h" #include "translate.h" #include "diff.h" +#include "textbase.h" #include "svn_private_config.h" @@ -476,15 +477,17 @@ svn_wc__diff_base_working_diff(svn_wc__d if (skip) return SVN_NO_ERROR; - SVN_ERR(svn_wc__db_pristine_get_path(&pristine_file, - db, local_abspath, checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&pristine_file, + db, local_abspath, checksum, + cancel_func, cancel_baton, + scratch_pool, scratch_pool)); if (diff_pristine) - SVN_ERR(svn_wc__db_pristine_get_path(&local_file, - db, local_abspath, - working_checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&local_file, + db, local_abspath, + working_checksum, + cancel_func, cancel_baton, + scratch_pool, scratch_pool)); else if (! (had_props || props_mod)) local_file = local_abspath; else if (files_same) @@ -1019,8 +1022,9 @@ svn_wc__diff_local_only_file(svn_wc__db_ right_props = svn_prop_hash_dup(pristine_props, scratch_pool); if (checksum) - SVN_ERR(svn_wc__db_pristine_get_path(&pristine_file, db, local_abspath, - checksum, scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&pristine_file, db, local_abspath, + checksum, cancel_func, cancel_baton, + scratch_pool, scratch_pool)); else pristine_file = NULL; @@ -1415,9 +1419,10 @@ svn_wc__diff_base_only_file(svn_wc__db_t if (skip) return SVN_NO_ERROR; - SVN_ERR(svn_wc__db_pristine_get_path(&pristine_file, - db, local_abspath, checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&pristine_file, + db, local_abspath, checksum, + NULL, NULL, + scratch_pool, scratch_pool)); SVN_ERR(processor->file_deleted(relpath, left_src, @@ -2111,17 +2116,17 @@ apply_textdelta(void *file_baton, pool)); } - SVN_ERR(svn_wc__db_pristine_read(&source, NULL, - eb->db, fb->local_abspath, - fb->base_checksum, - pool, pool)); + SVN_ERR(svn_wc__textbase_get_contents(&source, + eb->db, fb->local_abspath, + fb->base_checksum, FALSE, + pool, pool)); } else if (fb->base_checksum) { - SVN_ERR(svn_wc__db_pristine_read(&source, NULL, - eb->db, fb->local_abspath, - fb->base_checksum, - pool, pool)); + SVN_ERR(svn_wc__textbase_get_contents(&source, + eb->db, fb->local_abspath, + fb->base_checksum, FALSE, + pool, pool)); } else source = svn_stream_empty(pool); @@ -2215,10 +2220,11 @@ close_file(void *file_baton, if (! repos_file) { assert(fb->base_checksum); - SVN_ERR(svn_wc__db_pristine_get_path(&repos_file, - eb->db, eb->anchor_abspath, - fb->base_checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&repos_file, + eb->db, fb->local_abspath, + fb->base_checksum, + eb->cancel_func, eb->cancel_baton, + scratch_pool, scratch_pool)); } } @@ -2251,10 +2257,11 @@ close_file(void *file_baton, eb->db, fb->local_abspath, scratch_pool, scratch_pool)); assert(checksum); - SVN_ERR(svn_wc__db_pristine_get_path(&localfile, - eb->db, eb->anchor_abspath, - checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(&localfile, + eb->db, fb->local_abspath, + checksum, + eb->cancel_func, eb->cancel_baton, + scratch_pool, scratch_pool)); } else {
Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/externals.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/externals.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/externals.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/externals.c Thu Feb 10 20:04:43 2022 @@ -53,6 +53,7 @@ #include "translate.h" #include "workqueue.h" #include "conflicts.h" +#include "textbase.h" #include "svn_private_config.h" @@ -631,19 +632,21 @@ apply_textdelta(void *file_baton, pool))); } - SVN_ERR(svn_wc__db_pristine_read(&src_stream, NULL, eb->db, - eb->wri_abspath, eb->original_checksum, - pool, pool)); + SVN_ERR(svn_wc__textbase_get_contents(&src_stream, eb->db, + eb->local_abspath, + eb->original_checksum, + FALSE, pool, pool)); } else src_stream = svn_stream_empty(pool); - SVN_ERR(svn_wc__db_pristine_prepare_install(&dest_stream, - &eb->install_data, - &eb->new_sha1_checksum, - &eb->new_md5_checksum, - eb->db, eb->wri_abspath, - eb->pool, pool)); + SVN_ERR(svn_wc__textbase_prepare_install(&dest_stream, + &eb->install_data, + &eb->new_sha1_checksum, + &eb->new_md5_checksum, + eb->db, eb->local_abspath, + TRUE, + eb->pool, pool)); svn_txdelta_apply(src_stream, dest_stream, NULL, eb->local_abspath, pool, handler, handler_baton); @@ -887,13 +890,43 @@ close_file(void *file_baton, } if (install_pristine) { + svn_stream_t *contents; + const char *tmpdir_abspath; + svn_stream_t *tmpstream; + const char *tmpfile_abspath; + + SVN_ERR(svn_wc__db_pristine_read(&contents, NULL, eb->db, + eb->wri_abspath, + eb->new_sha1_checksum, + pool, pool)); + if (!contents) + return svn_error_create(SVN_ERR_WC_PATH_UNEXPECTED_STATUS, + NULL, NULL); + + SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, + eb->db, eb->wri_abspath, + pool, pool)); + SVN_ERR(svn_stream_open_unique(&tmpstream, &tmpfile_abspath, + tmpdir_abspath, + svn_io_file_del_none, + pool, pool)); + SVN_ERR(svn_stream_copy3(contents, tmpstream, eb->cancel_func, + eb->cancel_baton, pool)); + SVN_ERR(svn_wc__wq_build_file_install(&work_item, eb->db, eb->local_abspath, - NULL, + tmpfile_abspath, eb->use_commit_times, TRUE, pool, pool)); all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); + + SVN_ERR(svn_wc__wq_build_file_remove(&work_item, eb->db, + eb->wri_abspath, + tmpfile_abspath, + pool, pool)); + + all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); } } else Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/questions.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/questions.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/questions.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/questions.c Thu Feb 10 20:04:43 2022 @@ -79,15 +79,14 @@ /* Set *MODIFIED_P to TRUE if (after translation) VERSIONED_FILE_ABSPATH - * (of VERSIONED_FILE_SIZE bytes) differs from PRISTINE_STREAM (of - * PRISTINE_SIZE bytes), else to FALSE if not. + * (of VERSIONED_FILE_SIZE bytes) differs from pristine file with checksum + * PRISTINE_CHECKSUM, else to FALSE if not. * * If EXACT_COMPARISON is FALSE, translate VERSIONED_FILE_ABSPATH's EOL * style and keywords to repository-normal form according to its properties, - * and compare the result with PRISTINE_STREAM. If EXACT_COMPARISON is - * TRUE, translate PRISTINE_STREAM's EOL style and keywords to working-copy - * form according to VERSIONED_FILE_ABSPATH's properties, and compare the - * result with VERSIONED_FILE_ABSPATH. + * calculate checksum and compare the result with PRISTINE_STREAM. + * If EXACT_COMPARISON is TRUE, also check that VERSIONED_FILE_ABSPATH + * contents remains the same when retranslated according to its properties. * * HAS_PROPS should be TRUE if the file had properties when it was not * modified, otherwise FALSE. @@ -95,8 +94,6 @@ * PROPS_MOD should be TRUE if the file's properties have been changed, * otherwise FALSE. * - * PRISTINE_STREAM will be closed before a successful return. - * * DB is a wc_db; use SCRATCH_POOL for temporary allocation. */ static svn_error_t * @@ -104,20 +101,20 @@ compare_and_verify(svn_boolean_t *modifi svn_wc__db_t *db, const char *versioned_file_abspath, svn_filesize_t versioned_file_size, - svn_stream_t *pristine_stream, - svn_filesize_t pristine_size, + const svn_checksum_t *pristine_checksum, svn_boolean_t has_props, svn_boolean_t props_mod, svn_boolean_t exact_comparison, apr_pool_t *scratch_pool) { - svn_boolean_t same; svn_subst_eol_style_t eol_style; const char *eol_str; apr_hash_t *keywords; svn_boolean_t special = FALSE; svn_boolean_t need_translation; svn_stream_t *v_stream; /* versioned_file */ + svn_checksum_t *v_checksum; + svn_error_t *err; SVN_ERR_ASSERT(svn_dirent_is_absolute(versioned_file_abspath)); @@ -133,6 +130,9 @@ compare_and_verify(svn_boolean_t *modifi !exact_comparison, scratch_pool, scratch_pool)); + if (eol_style == svn_subst_eol_style_unknown) + return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, NULL, NULL); + need_translation = svn_subst_translation_required(eol_style, eol_str, keywords, special, TRUE); @@ -140,13 +140,20 @@ compare_and_verify(svn_boolean_t *modifi else need_translation = FALSE; - if (! need_translation - && (versioned_file_size != pristine_size)) + if (! need_translation) { - *modified_p = TRUE; + svn_filesize_t pristine_size; + + SVN_ERR(svn_wc__db_pristine_read(NULL, &pristine_size, db, + versioned_file_abspath, pristine_checksum, + scratch_pool, scratch_pool)); + + if (versioned_file_size != pristine_size) + { + *modified_p = TRUE; - /* ### Why did we open the pristine? */ - return svn_error_trace(svn_stream_close(pristine_stream)); + return SVN_NO_ERROR; + } } /* ### Other checks possible? */ @@ -162,46 +169,97 @@ compare_and_verify(svn_boolean_t *modifi /* We don't use APR-level buffering because the comparison function * will do its own buffering. */ apr_file_t *file; - SVN_ERR(svn_io_file_open(&file, versioned_file_abspath, APR_READ, - APR_OS_DEFAULT, scratch_pool)); + err = svn_io_file_open(&file, versioned_file_abspath, APR_READ, + APR_OS_DEFAULT, scratch_pool); + /* Convert EACCESS on working copy path to WC specific error code. */ + if (err && APR_STATUS_IS_EACCES(err->apr_err)) + return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL); + else + SVN_ERR(err); v_stream = svn_stream_from_aprfile2(file, FALSE, scratch_pool); if (need_translation) { - if (!exact_comparison) + const char *pristine_eol_str; + + if (eol_style == svn_subst_eol_style_native) + pristine_eol_str = SVN_SUBST_NATIVE_EOL_STR; + else + pristine_eol_str = eol_str; + + if (exact_comparison) { - if (eol_style == svn_subst_eol_style_native) - eol_str = SVN_SUBST_NATIVE_EOL_STR; - else if (eol_style != svn_subst_eol_style_fixed - && eol_style != svn_subst_eol_style_none) - return svn_error_create(SVN_ERR_IO_UNKNOWN_EOL, - svn_stream_close(v_stream), NULL); + svn_checksum_t *working_checksum; + svn_checksum_t *detranslated_checksum; + svn_checksum_t *retranslated_checksum; + + v_stream = svn_stream_checksummed2(v_stream, + &working_checksum, NULL, + pristine_checksum->kind, TRUE, + scratch_pool); + + v_stream = svn_subst_stream_translated(v_stream, + pristine_eol_str, TRUE, + keywords, FALSE, + scratch_pool); + v_stream = svn_stream_checksummed2(v_stream, + &detranslated_checksum, NULL, + pristine_checksum->kind, TRUE, + scratch_pool); + + v_stream = svn_subst_stream_translated(v_stream, eol_str, FALSE, + keywords, TRUE, + scratch_pool); + v_stream = svn_stream_checksummed2(v_stream, + &retranslated_checksum, NULL, + pristine_checksum->kind, TRUE, + scratch_pool); + + err = svn_stream_copy3(v_stream, svn_stream_empty(scratch_pool), + NULL, NULL, scratch_pool); + /* Convert EACCESS on working copy path to WC specific error code. */ + if (err && APR_STATUS_IS_EACCES(err->apr_err)) + return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL); + else + SVN_ERR(err); + + if (svn_checksum_match(detranslated_checksum, pristine_checksum) && + svn_checksum_match(working_checksum, retranslated_checksum)) + { + *modified_p = FALSE; + } + else + { + *modified_p = TRUE; + } + return SVN_NO_ERROR; + } + else + { /* Wrap file stream to detranslate into normal form, * "repairing" the EOL style if it is inconsistent. */ v_stream = svn_subst_stream_translated(v_stream, - eol_str, + pristine_eol_str, TRUE /* repair */, keywords, FALSE /* expand */, scratch_pool); } - else - { - /* Wrap base stream to translate into working copy form, and - * arrange to throw an error if its EOL style is inconsistent. */ - pristine_stream = svn_subst_stream_translated(pristine_stream, - eol_str, FALSE, - keywords, TRUE, - scratch_pool); - } } } - SVN_ERR(svn_stream_contents_same2(&same, pristine_stream, v_stream, - scratch_pool)); + /* Get checksum of detranslated (normalized) content. */ + err = svn_stream_contents_checksum(&v_checksum, v_stream, + pristine_checksum->kind, + scratch_pool, scratch_pool); + /* Convert EACCESS on working copy path to WC specific error code. */ + if (err && APR_STATUS_IS_EACCES(err->apr_err)) + return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL); + else + SVN_ERR(err); - *modified_p = (! same); + *modified_p = (! svn_checksum_match(v_checksum, pristine_checksum)); return SVN_NO_ERROR; } @@ -213,8 +271,6 @@ svn_wc__internal_file_modified_p(svn_boo svn_boolean_t exact_comparison, apr_pool_t *scratch_pool) { - svn_stream_t *pristine_stream; - svn_filesize_t pristine_size; svn_wc__db_status_t status; svn_node_kind_t kind; const svn_checksum_t *checksum; @@ -302,27 +358,12 @@ svn_wc__internal_file_modified_p(svn_boo } compare_them: - SVN_ERR(svn_wc__db_pristine_read(&pristine_stream, &pristine_size, - db, local_abspath, checksum, - scratch_pool, scratch_pool)); - /* Check all bytes, and verify checksum if requested. */ - { - svn_error_t *err; - err = compare_and_verify(modified_p, db, + SVN_ERR(compare_and_verify(modified_p, db, local_abspath, dirent->filesize, - pristine_stream, pristine_size, - has_props, props_mod, + checksum, has_props, props_mod, exact_comparison, - scratch_pool); - - /* At this point we already opened the pristine file, so we know that - the access denied applies to the working copy path */ - if (err && APR_STATUS_IS_EACCES(err->apr_err)) - return svn_error_create(SVN_ERR_WC_PATH_ACCESS_DENIED, err, NULL); - else - SVN_ERR(err); - } + scratch_pool)); if (!*modified_p) { Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/revert.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/revert.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/revert.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/revert.c Thu Feb 10 20:04:43 2022 @@ -42,6 +42,7 @@ #include "wc.h" #include "adm_files.h" #include "workqueue.h" +#include "textbase.h" #include "svn_private_config.h" #include "private/svn_io_private.h" @@ -714,10 +715,21 @@ revert_wc_data(svn_boolean_t *run_wq, if (kind == svn_node_file) { svn_skel_t *work_item; + const char *install_from; + svn_skel_t *cleanup_work_item; + SVN_ERR(svn_wc__textbase_setaside_wq(&install_from, + &cleanup_work_item, + db, local_abspath, NULL, + cancel_func, cancel_baton, + scratch_pool, scratch_pool)); SVN_ERR(svn_wc__wq_build_file_install(&work_item, db, local_abspath, - NULL, use_commit_times, TRUE, + install_from, + use_commit_times, TRUE, scratch_pool, scratch_pool)); + work_item = svn_wc__wq_merge(work_item, cleanup_work_item, + scratch_pool); + SVN_ERR(svn_wc__db_wq_add(db, local_abspath, work_item, scratch_pool)); *run_wq = TRUE; Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/update_editor.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/update_editor.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/update_editor.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/update_editor.c Thu Feb 10 20:04:43 2022 @@ -48,6 +48,7 @@ #include "conflicts.h" #include "translate.h" #include "workqueue.h" +#include "textbase.h" #include "private/svn_subr_private.h" #include "private/svn_wc_private.h" @@ -439,7 +440,8 @@ struct handler_baton /* Get an empty file in the temporary area for WRI_ABSPATH. The file will not be set for automatic deletion, and the name will be returned in - TMP_FILENAME. + TMP_FILENAME_P. Set *CLEANUP_WORK_ITEM_P to a new work item that will + remove the temporary file. This implementation creates a new empty file with a unique name. @@ -451,19 +453,35 @@ struct handler_baton ### file name to create later. A better way may not be readily available. */ static svn_error_t * -get_empty_tmp_file(const char **tmp_filename, +get_empty_tmp_file(const char **tmp_filename_p, + svn_skel_t **cleanup_work_item_p, svn_wc__db_t *db, const char *wri_abspath, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { const char *temp_dir_abspath; + const char *tmp_filename; + svn_skel_t *work_item; + svn_error_t *err; SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&temp_dir_abspath, db, wri_abspath, scratch_pool, scratch_pool)); - SVN_ERR(svn_io_open_unique_file3(NULL, tmp_filename, temp_dir_abspath, + SVN_ERR(svn_io_open_unique_file3(NULL, &tmp_filename, temp_dir_abspath, svn_io_file_del_none, scratch_pool, scratch_pool)); + err = svn_wc__wq_build_file_remove(&work_item, db, wri_abspath, + tmp_filename, + result_pool, scratch_pool); + if (err) + { + return svn_error_compose_create( + err, + svn_io_remove_file2(tmp_filename, TRUE, scratch_pool)); + } + + *tmp_filename_p = tmp_filename; + *cleanup_work_item_p = work_item; return SVN_NO_ERROR; } @@ -3726,10 +3744,10 @@ lazy_open_source(svn_stream_t **stream, { struct file_baton *fb = baton; - SVN_ERR(svn_wc__db_pristine_read(stream, NULL, fb->edit_baton->db, - fb->local_abspath, - fb->original_checksum, - result_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_get_contents(stream, fb->edit_baton->db, + fb->local_abspath, + fb->original_checksum, FALSE, + result_pool, scratch_pool)); return SVN_NO_ERROR; @@ -3748,19 +3766,35 @@ lazy_open_target(svn_stream_t **stream_p svn_stream_t *pristine_install_stream; svn_wc__working_file_writer_t *file_writer; svn_stream_t *stream; + svn_boolean_t hydrated; + + if (fb->shadowed || fb->obstruction_found || fb->edit_obstructed) + { + hydrated = TRUE; + } + else if (fb->adding_file && !fb->add_existed) + { + /* Clean new file, hint that we don't need the text-base. */ + hydrated = FALSE; + } + else + { + hydrated = TRUE; + } /* By convention return value is undefined on error, but we rely on HB->INSTALL_DATA value in window_handler() and abort INSTALL_STREAM if is not NULL on error. So we store INSTALL_DATA to local variable first, to leave HB->INSTALL_DATA unchanged on error. */ - SVN_ERR(svn_wc__db_pristine_prepare_install(&pristine_install_stream, - &pristine_install_data, - &hb->new_text_base_sha1_checksum, - NULL, - fb->edit_baton->db, - fb->dir_baton->local_abspath, - result_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_prepare_install(&pristine_install_stream, + &pristine_install_data, + &hb->new_text_base_sha1_checksum, + NULL, + fb->edit_baton->db, + fb->local_abspath, + hydrated, + result_pool, scratch_pool)); if (fb->shadowed || fb->obstruction_found || fb->edit_obstructed) { @@ -4062,17 +4096,19 @@ svn_wc__perform_file_merge(svn_skel_t ** the textual changes into the working file. */ const char *oldrev_str, *newrev_str, *mine_str; const char *merge_left; - svn_boolean_t delete_left = FALSE; const char *path_ext = ""; const char *new_pristine_abspath; enum svn_wc_merge_outcome_t merge_outcome = svn_wc_merge_unchanged; svn_skel_t *work_item; + svn_skel_t *cleanup_queue = NULL; *work_items = NULL; - SVN_ERR(svn_wc__db_pristine_get_path(&new_pristine_abspath, - db, wri_abspath, new_checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside_wq(&new_pristine_abspath, &work_item, + db, local_abspath, new_checksum, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, result_pool); /* If we have any file extensions we're supposed to preserve in generated conflict file names, then find @@ -4106,14 +4142,19 @@ svn_wc__perform_file_merge(svn_skel_t ** if (! original_checksum) { - SVN_ERR(get_empty_tmp_file(&merge_left, db, wri_abspath, + SVN_ERR(get_empty_tmp_file(&merge_left, &work_item, db, wri_abspath, result_pool, scratch_pool)); - delete_left = TRUE; + cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, result_pool); } else - SVN_ERR(svn_wc__db_pristine_get_path(&merge_left, db, wri_abspath, - original_checksum, - result_pool, scratch_pool)); + { + SVN_ERR(svn_wc__textbase_setaside_wq(&merge_left, &work_item, + db, local_abspath, + original_checksum, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + cleanup_queue = svn_wc__wq_merge(cleanup_queue, work_item, result_pool); + } /* Merge the changes from the old textbase to the new textbase into the file we're updating. @@ -4134,16 +4175,9 @@ svn_wc__perform_file_merge(svn_skel_t ** result_pool, scratch_pool)); *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); - *found_conflict = (merge_outcome == svn_wc_merge_conflict); + *work_items = svn_wc__wq_merge(*work_items, cleanup_queue, result_pool); - /* If we created a temporary left merge file, get rid of it. */ - if (delete_left) - { - SVN_ERR(svn_wc__wq_build_file_remove(&work_item, db, wri_abspath, - merge_left, - result_pool, scratch_pool)); - *work_items = svn_wc__wq_merge(*work_items, work_item, result_pool); - } + *found_conflict = (merge_outcome == svn_wc_merge_conflict); return SVN_NO_ERROR; } @@ -4728,9 +4762,9 @@ close_file(void *file_baton, } else { - SVN_ERR(svn_wc__db_pristine_read(&src_stream, NULL, eb->db, - eb->wcroot_abspath, new_checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_get_contents(&src_stream, eb->db, + fb->local_abspath, new_checksum, + FALSE, scratch_pool, scratch_pool)); } SVN_ERR(svn_stream_copy3(src_stream, dst_stream, NULL, NULL, scratch_pool)); @@ -4870,6 +4904,7 @@ update_keywords_after_switch_cb(void *ba svn_boolean_t record_fileinfo; svn_skel_t *work_items; const char *install_from; + svn_skel_t *cleanup_work_item; propval = svn_hash_gets(props, SVN_PROP_KEYWORDS); if (!propval) @@ -4895,11 +4930,18 @@ update_keywords_after_switch_cb(void *ba SVN_ERR(svn_stream_copy3(working_stream, install_from_stream, eb->cancel_func, eb->cancel_baton, scratch_pool)); + SVN_ERR(svn_wc__wq_build_file_remove(&cleanup_work_item, eb->db, + local_abspath, install_from, + scratch_pool, scratch_pool)); record_fileinfo = FALSE; } else { - install_from = NULL; + SVN_ERR(svn_wc__textbase_setaside_wq(&install_from, + &cleanup_work_item, + eb->db, local_abspath, NULL, + eb->cancel_func, eb->cancel_baton, + scratch_pool, scratch_pool)); record_fileinfo = TRUE; } @@ -4908,15 +4950,7 @@ update_keywords_after_switch_cb(void *ba eb->use_commit_times, record_fileinfo, scratch_pool, scratch_pool)); - if (install_from) - { - svn_skel_t *work_item; - - SVN_ERR(svn_wc__wq_build_file_remove(&work_item, eb->db, - local_abspath, install_from, - scratch_pool, scratch_pool)); - work_items = svn_wc__wq_merge(work_items, work_item, scratch_pool); - } + work_items = svn_wc__wq_merge(work_items, cleanup_work_item, scratch_pool); SVN_ERR(svn_wc__db_wq_add(eb->db, local_abspath, work_items, scratch_pool)); @@ -5605,33 +5639,39 @@ svn_wc_add_repos_file4(svn_wc_context_t entry_props, pool, pool)); } + { + const char *tmp_dir_abspath; + + SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir_abspath, + db, dir_abspath, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_stream_open_unique(&tmp_base_contents, &tmp_text_base_abspath, + tmp_dir_abspath, svn_io_file_del_none, + scratch_pool, scratch_pool)); + } + /* Copy NEW_BASE_CONTENTS into a temporary file so our log can refer to it, and set TMP_TEXT_BASE_ABSPATH to its path. Compute its NEW_TEXT_BASE_MD5_CHECKSUM and NEW_TEXT_BASE_SHA1_CHECKSUM as we copy. */ if (copyfrom_url) { - SVN_ERR(svn_wc__db_pristine_prepare_install(&tmp_base_contents, - &install_data, - &new_text_base_sha1_checksum, - &new_text_base_md5_checksum, - wc_ctx->db, local_abspath, - scratch_pool, scratch_pool)); + svn_stream_t *install_stream; + + SVN_ERR(svn_wc__textbase_prepare_install(&install_stream, + &install_data, + &new_text_base_sha1_checksum, + &new_text_base_md5_checksum, + wc_ctx->db, local_abspath, + copyfrom_url != NULL, + scratch_pool, scratch_pool)); + + tmp_base_contents = svn_stream_tee(install_stream, + tmp_base_contents, + scratch_pool); } else { - const char *tmp_dir_abspath; - - /* We are not installing a PRISTINE file, but we use the same code to - create whatever we want to install */ - - SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmp_dir_abspath, - db, dir_abspath, - scratch_pool, scratch_pool)); - - SVN_ERR(svn_stream_open_unique(&tmp_base_contents, &tmp_text_base_abspath, - tmp_dir_abspath, svn_io_file_del_none, - scratch_pool, scratch_pool)); - new_text_base_sha1_checksum = NULL; new_text_base_md5_checksum = NULL; } @@ -5654,6 +5694,10 @@ svn_wc_add_repos_file4(svn_wc_context_t SVN_ERR(svn_stream_copy3(new_contents, tmp_contents, cancel_func, cancel_baton, pool)); } + else + { + source_abspath = tmp_text_base_abspath; + } /* Install new text base for copied files. Added files do NOT have a text base. */ @@ -5689,42 +5733,20 @@ svn_wc_add_repos_file4(svn_wc_context_t new_text_base_md5_checksum = NULL; } - /* For added files without NEW_CONTENTS, then generate the working file - from the provided "pristine" contents. */ - if (new_contents == NULL && copyfrom_url == NULL) - source_abspath = tmp_text_base_abspath; - - { - svn_boolean_t record_fileinfo; + /* Install the working copy file (with appropriate translation) from + the provided temporary file at SOURCE_ABSPATH. */ + SVN_ERR(svn_wc__wq_build_file_install(&work_item, + db, local_abspath, + source_abspath, + FALSE /* use_commit_times */, + TRUE /* record_fileinfo */, + pool, pool)); + all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); - /* If new contents were provided, then we do NOT want to record the - file information. We assume the new contents do not match the - "proper" values for RECORDED_SIZE and RECORDED_TIME. */ - record_fileinfo = (new_contents == NULL); - - /* Install the working copy file (with appropriate translation) from - the appropriate source. SOURCE_ABSPATH will be NULL, indicating an - installation from the pristine (available for copied/moved files), - or it will specify a temporary file where we placed a "pristine" - (for an added file) or a detranslated local-mods file. */ - SVN_ERR(svn_wc__wq_build_file_install(&work_item, - db, local_abspath, - source_abspath, - FALSE /* use_commit_times */, - record_fileinfo, - pool, pool)); - all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); - - /* If we installed from somewhere besides the official pristine, then - it is a temporary file, which needs to be removed. */ - if (source_abspath != NULL) - { - SVN_ERR(svn_wc__wq_build_file_remove(&work_item, db, local_abspath, - source_abspath, - pool, pool)); - all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); - } - } + SVN_ERR(svn_wc__wq_build_file_remove(&work_item, db, local_abspath, + source_abspath, + pool, pool)); + all_work_items = svn_wc__wq_merge(all_work_items, work_item, pool); SVN_ERR(svn_wc__db_op_copy_file(db, local_abspath, new_base_props, Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/upgrade.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/upgrade.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/upgrade.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/upgrade.c Thu Feb 10 20:04:43 2022 @@ -1078,6 +1078,7 @@ migrate_text_bases(apr_hash_t **text_bas SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, iterpool)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, iterpool)); SVN_ERR(svn_sqlite__bind_int64(stmt, 3, finfo.size)); + SVN_ERR(svn_sqlite__bind_int(stmt, 4, TRUE)); SVN_ERR(svn_sqlite__insert(NULL, stmt)); SVN_ERR(svn_wc__db_pristine_get_future_path(&pristine_path, Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/util.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/util.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/util.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/util.c Thu Feb 10 20:04:43 2022 @@ -37,6 +37,7 @@ #include "wc.h" /* just for prototypes of things in this .c file */ #include "entries.h" +#include "textbase.h" #include "private/svn_wc_private.h" #include "svn_private_config.h" @@ -505,8 +506,9 @@ svn_wc__fetch_base_func(const char **fil return SVN_NO_ERROR; } - SVN_ERR(svn_wc__db_pristine_get_path(filename, sfb->db, local_abspath, - checksum, scratch_pool, scratch_pool)); + SVN_ERR(svn_wc__textbase_setaside(filename, sfb->db, local_abspath, + checksum, NULL, NULL, + result_pool, scratch_pool)); return SVN_NO_ERROR; } Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-metadata.sql URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-metadata.sql?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-metadata.sql (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-metadata.sql Thu Feb 10 20:04:43 2022 @@ -570,6 +570,7 @@ CREATE UNIQUE INDEX I_EXTERNALS_DEFINED def_local_relpath, local_relpath); +/* ------------------------------------------------------------------------- */ /* Identify the WC format corresponding to the schema we have created. */ PRAGMA user_version = @@ -706,12 +707,84 @@ WHERE l.op_depth = 0 AND ((l.repos_id IS NOT r.repos_id) OR (l.repos_path IS NOT RELPATH_SKIP_JOIN(r.local_relpath, r.repos_path, l.local_relpath))) - /* ------------------------------------------------------------------------- */ -/* Format 32 .... */ + +/* Format 32 adds support for optional text-base contents with the + following schema changes: + - Add the 'hydrated' column to the PRISTINE table. + - Add the I_PRISTINE_UNREFERENCED index. + - Add the TEXTBASE_REFS table. */ -- STMT_UPGRADE_TO_32 +/* True iff the pristine contents are currently available on disk. */ +ALTER TABLE PRISTINE ADD COLUMN hydrated INTEGER NOT NULL DEFAULT 1; + + /* Note: we use checksums to detect if the file contents have been modified + in textbase.c and in the svn_wc__internal_file_modified_p() function. + + The new working copy format SHOULD incorporate a switch to a different + checksum type without known collisions. + + For the updated pristine table schema, we MAY want to add a new column + containing a checksum of the first 8KB of the file to allow saying that + the file is modified without reading all its content. That could speed + up the check for large modified files whose size did not change, for + example if they are allocated in certain extents. + */ + +CREATE INDEX I_PRISTINE_UNREFERENCED ON PRISTINE (refcount, refcount=0); + +/* This table contains references to the on disk text-base contents. + Every row corresponds to a row in NODES table with the same key. + While a row is present is this table, the contents identified by the + corresponding NODES.checksum cannot be dehydrated from the pristine store. + */ +CREATE TABLE TEXTBASE_REFS ( + /* Same key columns as in the NODES table */ + wc_id INTEGER NOT NULL, + local_relpath TEXT NOT NULL, + op_depth INTEGER NOT NULL, + + PRIMARY KEY (wc_id, local_relpath, op_depth) + ); + +DROP TRIGGER nodes_delete_trigger; + +CREATE TRIGGER nodes_delete_trigger +AFTER DELETE ON nodes +WHEN OLD.checksum IS NOT NULL +BEGIN + UPDATE pristine SET refcount = refcount - 1 + WHERE checksum = OLD.checksum; + DELETE FROM textbase_refs + WHERE wc_id = OLD.wc_id + AND local_relpath = OLD.local_relpath + AND op_depth = OLD.op_depth; +END; + +DROP TRIGGER nodes_update_checksum_trigger; + +CREATE TRIGGER nodes_update_checksum_trigger +AFTER UPDATE OF checksum ON nodes +WHEN NEW.checksum IS NOT OLD.checksum + /* AND (NEW.checksum IS NOT NULL OR OLD.checksum IS NOT NULL) */ +BEGIN + UPDATE pristine SET refcount = refcount + 1 + WHERE checksum = NEW.checksum; + UPDATE pristine SET refcount = refcount - 1 + WHERE checksum = OLD.checksum; + DELETE FROM textbase_refs + WHERE wc_id = OLD.wc_id + AND local_relpath = OLD.local_relpath + AND op_depth = OLD.op_depth; +END; + PRAGMA user_version = 32; +/* ------------------------------------------------------------------------- */ +/* Format 33 .... */ +/* -- STMT_UPGRADE_TO_33 +PRAGMA user_version = 33; */ + /* ------------------------------------------------------------------------- */ Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-queries.sql URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-queries.sql?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-queries.sql (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc-queries.sql Thu Feb 10 20:04:43 2022 @@ -884,23 +884,22 @@ SELECT id, work FROM work_queue ORDER BY DELETE FROM work_queue WHERE id = ?1 -- STMT_INSERT_OR_IGNORE_PRISTINE -INSERT OR IGNORE INTO pristine (checksum, md5_checksum, size, refcount) -VALUES (?1, ?2, ?3, 0) +INSERT OR IGNORE INTO pristine (checksum, md5_checksum, size, refcount, hydrated) +VALUES (?1, ?2, ?3, 0, ?4) --- STMT_INSERT_PRISTINE -INSERT INTO pristine (checksum, md5_checksum, size, refcount) -VALUES (?1, ?2, ?3, 0) +-- STMT_UPSERT_PRISTINE +/* ### Probably need to bump the minimum SQLite version for UPSERT support + https://www.sqlite.org/lang_UPSERT.html + */ +INSERT INTO pristine (checksum, md5_checksum, size, refcount, hydrated) +VALUES (?1, ?2, ?3, 0, ?4) +ON CONFLICT(checksum) DO UPDATE SET size=?3, hydrated=?4 -- STMT_SELECT_PRISTINE -SELECT md5_checksum +SELECT md5_checksum, size, hydrated FROM pristine WHERE checksum = ?1 --- STMT_SELECT_PRISTINE_SIZE -SELECT size -FROM pristine -WHERE checksum = ?1 LIMIT 1 - -- STMT_SELECT_PRISTINE_BY_MD5 SELECT checksum FROM pristine @@ -917,7 +916,7 @@ WHERE checksum = ?1 AND refcount = 0 -- STMT_SELECT_COPY_PRISTINES /* For the root itself */ -SELECT n.checksum, md5_checksum, size +SELECT n.checksum, md5_checksum, size, p.hydrated FROM nodes_current n LEFT JOIN pristine p ON n.checksum = p.checksum WHERE wc_id = ?1 @@ -925,7 +924,7 @@ WHERE wc_id = ?1 AND n.checksum IS NOT NULL UNION ALL /* And all descendants */ -SELECT n.checksum, md5_checksum, size +SELECT n.checksum, md5_checksum, size, p.hydrated FROM nodes n LEFT JOIN pristine p ON n.checksum = p.checksum WHERE wc_id = ?1 @@ -934,6 +933,10 @@ WHERE wc_id = ?1 (SELECT MAX(op_depth) FROM nodes WHERE wc_id = ?1 AND local_relpath = ?2) AND n.checksum IS NOT NULL +-- STMT_UPDATE_PRISTINE_HYDRATED +UPDATE pristine SET hydrated = ?2 +WHERE checksum = ?1 + -- STMT_VACUUM VACUUM @@ -1812,6 +1815,53 @@ SELECT lock_token, lock_owner, lock_comm FROM lock WHERE repos_id = ?1 AND (repos_relpath = ?2) +-- STMT_TEXTBASE_ADD_REF +INSERT OR IGNORE INTO textbase_refs (wc_id, local_relpath, op_depth) +VALUES (?1, ?2, ?3) + +-- STMT_TEXTBASE_REMOVE_REF +DELETE FROM textbase_refs +WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3 + +-- STMT_TEXTBASE_WALK +SELECT refs.wc_id IS NOT NULL, + nodes.local_relpath, nodes.op_depth, + nodes.checksum, nodes.properties, + nodes.translated_size, nodes.last_mod_time, + (SELECT properties FROM ACTUAL_NODE a + WHERE a.wc_id = ?1 + AND a.local_relpath = nodes.local_relpath + LIMIT 1), + (SELECT MAX(op_depth) + FROM NODES w + WHERE w.wc_id = ?1 + AND w.local_relpath = nodes.local_relpath) +FROM nodes +LEFT OUTER JOIN textbase_refs refs ON nodes.wc_id = refs.wc_id + AND nodes.local_relpath = refs.local_relpath + AND nodes.op_depth = refs.op_depth +WHERE nodes.wc_id = ?1 + AND (nodes.local_relpath = ?2 + OR IS_STRICT_DESCENDANT_OF(nodes.local_relpath, ?2)) + AND nodes.checksum IS NOT NULL + +-- STMT_TEXTBASE_SYNC +SELECT pristine.checksum, + MIN(pristine.hydrated != 0), + MAX(refs.wc_id IS NOT NULL), + nodes.repos_path, nodes.repos_id, nodes.revision +FROM nodes +JOIN pristine ON nodes.wc_id = ?1 + AND nodes.checksum = pristine.checksum + AND (nodes.local_relpath = ?2 + OR IS_STRICT_DESCENDANT_OF(nodes.local_relpath, ?2)) +LEFT OUTER JOIN textbase_refs refs ON nodes.wc_id = refs.wc_id + AND nodes.local_relpath = refs.local_relpath + AND nodes.op_depth = refs.op_depth +GROUP BY pristine.checksum +UNION ALL +SELECT pristine.checksum, pristine.hydrated, 0, NULL, NULL, NULL +FROM pristine WHERE refcount = 0 /* ------------------------------------------------------------------------- */ Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db.h URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db.h?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db.h (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db.h Thu Feb 10 20:04:43 2022 @@ -927,21 +927,6 @@ svn_wc__db_base_get_lock_tokens_recursiv @{ */ -/* Set *PRISTINE_ABSPATH to the path to the pristine text file - identified by SHA1_CHECKSUM. Error if it does not exist. - - ### This is temporary - callers should not be looking at the file - directly. - - Allocate the path in RESULT_POOL. */ -svn_error_t * -svn_wc__db_pristine_get_path(const char **pristine_abspath, - svn_wc__db_t *db, - const char *wri_abspath, - const svn_checksum_t *checksum, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool); - /* Set *PRISTINE_ABSPATH to the path under WCROOT_ABSPATH that will be used by the pristine text identified by SHA1_CHECKSUM. The file need not exist. @@ -986,6 +971,8 @@ typedef struct svn_wc__db_install_data_t set to the MD-5 and SHA-1 checksums respectively of that file. MD5_CHECKSUM and/or SHA1_CHECKSUM may be NULL if not wanted. + If HYDRATED is true, the contents of the pristine will be saved to disk. + Allocate the new stream, path and checksums in RESULT_POOL. */ svn_error_t * @@ -995,6 +982,7 @@ svn_wc__db_pristine_prepare_install(svn_ svn_checksum_t **md5_checksum, svn_wc__db_t *db, const char *wri_abspath, + svn_boolean_t hydrated, apr_pool_t *result_pool, apr_pool_t *scratch_pool); @@ -1077,14 +1065,26 @@ svn_wc__db_pristine_cleanup(svn_wc__db_t /* Set *PRESENT to true if the pristine store for WRI_ABSPATH in DB contains a pristine text with SHA-1 checksum SHA1_CHECKSUM, and to false otherwise. -*/ + If the pristine is present, set *HYDRATED to true if its contents are + currently available on disk, and to false otherwise. If the pristine + is not present, set *HYDRATED to false. */ svn_error_t * svn_wc__db_pristine_check(svn_boolean_t *present, + svn_boolean_t *hydrated, svn_wc__db_t *db, const char *wri_abspath, const svn_checksum_t *sha1_checksum, apr_pool_t *scratch_pool); +/* If the pristine store for WRI_ABSPATH in DB contains a pristine text with + SHA-1 checksum SHA1_CHECKSUM with its content available on disk, remove + that content and mark the pristine entry as "dehydrated". */ +svn_error_t * +svn_wc__db_pristine_dehydrate(svn_wc__db_t *db, + const char *wri_abspath, + const svn_checksum_t *sha1_checksum, + apr_pool_t *scratch_pool); + /* @defgroup svn_wc__db_external External management @{ */ @@ -3121,6 +3121,77 @@ svn_wc__db_wclock_owns_lock(svn_boolean_ svn_boolean_t exact, apr_pool_t *scratch_pool); +/* @} */ + + +/* @defgroup svn_wc__db_textbase Working with text-bases + @{ +*/ + +/* The callback invoked by svn_wc__db_textbase_walk(). */ +typedef svn_error_t * (*svn_wc__db_textbase_walk_cb_t)( + svn_boolean_t *referenced_p, + void *baton, + const char *local_abspath, + int op_depth, + const svn_checksum_t *checksum, + svn_boolean_t have_props, + svn_boolean_t props_mod, + svn_filesize_t recorded_size, + apr_time_t recorded_time, + int max_op_depth, + apr_pool_t *scratch_pool); + +/* Walk the text-bases referenced by the nodes in the LOCAL_ABSPATH + tree, invoking the CALLBACK with information about each text-base + for a node. + + If the callback sets *REFERENCED_P to true, ensure that a text-base + reference exists for the node. If the callback sets *REFERENCED_P to + false, ensure that a text-base reference does not exist for the node. + + See the description of the `TEXTBASE_REFS` table in the schema. + */ +svn_error_t * +svn_wc__db_textbase_walk(svn_wc__db_t *db, + const char *local_abspath, + svn_wc__db_textbase_walk_cb_t callback, + void *callback_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + +/* The callback invoked by svn_wc__db_textbase_sync(). */ +typedef svn_error_t * (*svn_wc__db_textbase_hydrate_cb_t)( + void *baton, + const char *repos_root_url, + const char *repos_relpath, + svn_revnum_t revision, + svn_stream_t *contents, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + +/* Synchronize the state of the text-bases in DB. + + If ALLOW_HYDRATE is true, fetch the referenced but missing text-base + contents using the provided HYDRATE_CALLBACK and HYDRATE_BATON. + If ALLOW_DEHYDRATE is true, remove the on disk text-base contents + that is no longer referenced. + */ +svn_error_t * +svn_wc__db_textbase_sync(svn_wc__db_t *db, + const char *local_abspath, + svn_boolean_t allow_hydrate, + svn_boolean_t allow_dehydrate, + svn_wc__db_textbase_hydrate_cb_t hydrate_callback, + void *hydrate_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + + +/* @} */ /* @defgroup svn_wc__db_temp Various temporary functions during transition Modified: subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db_pristine.c URL: http://svn.apache.org/viewvc/subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db_pristine.c?rev=1897946&r1=1897945&r2=1897946&view=diff ============================================================================== --- subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db_pristine.c (original) +++ subversion/branches/pristines-on-demand-on-mwf/subversion/libsvn_wc/wc_db_pristine.c Thu Feb 10 20:04:43 2022 @@ -94,50 +94,6 @@ get_pristine_fname(const char **pristine svn_error_t * -svn_wc__db_pristine_get_path(const char **pristine_abspath, - svn_wc__db_t *db, - const char *wri_abspath, - const svn_checksum_t *sha1_checksum, - apr_pool_t *result_pool, - apr_pool_t *scratch_pool) -{ - svn_wc__db_wcroot_t *wcroot; - const char *local_relpath; - svn_boolean_t present; - - SVN_ERR_ASSERT(pristine_abspath != NULL); - SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); - SVN_ERR_ASSERT(sha1_checksum != NULL); - /* ### Transitional: accept MD-5 and look up the SHA-1. Return an error - * if the pristine text is not in the store. */ - if (sha1_checksum->kind != svn_checksum_sha1) - SVN_ERR(svn_wc__db_pristine_get_sha1(&sha1_checksum, db, wri_abspath, - sha1_checksum, - scratch_pool, scratch_pool)); - SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); - - SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, - db, wri_abspath, - scratch_pool, scratch_pool)); - VERIFY_USABLE_WCROOT(wcroot); - - SVN_ERR(svn_wc__db_pristine_check(&present, db, wri_abspath, sha1_checksum, - scratch_pool)); - if (! present) - return svn_error_createf(SVN_ERR_WC_DB_ERROR, NULL, - _("The pristine text with checksum '%s' was " - "not found"), - svn_checksum_to_cstring_display(sha1_checksum, - scratch_pool)); - - SVN_ERR(get_pristine_fname(pristine_abspath, wcroot->abspath, - sha1_checksum, - result_pool, scratch_pool)); - - return SVN_NO_ERROR; -} - -svn_error_t * svn_wc__db_pristine_get_future_path(const char **pristine_abspath, const char *wcroot_abspath, const svn_checksum_t *sha1_checksum, @@ -152,9 +108,10 @@ svn_wc__db_pristine_get_future_path(cons /* Set *CONTENTS to a readable stream from which the pristine text * identified by SHA1_CHECKSUM and PRISTINE_ABSPATH can be read from the - * pristine store of WCROOT. If SIZE is not null, set *SIZE to the size - * in bytes of that text. If that text is not in the pristine store, - * return an error. + * pristine store of WCROOT. If the pristine contents are currently not + * available on disk, set *CONTENTS to NULL. If SIZE is not null, set + * *SIZE to the size in bytes of that text. If that text is not in + * the pristine store, return an error. * * Even if the pristine text is removed from the store while it is being * read, the stream will remain valid and readable until it is closed. @@ -176,16 +133,18 @@ pristine_read_txn(svn_stream_t **content { svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + svn_boolean_t hydrated; /* Check that this pristine text is present in the store. (The presence * of the file is not sufficient.) */ - SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, - STMT_SELECT_PRISTINE_SIZE)); + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); if (size) - *size = svn_sqlite__column_int64(stmt, 0); + *size = svn_sqlite__column_int64(stmt, 1); + + hydrated = svn_sqlite__column_boolean(stmt, 2); SVN_ERR(svn_sqlite__reset(stmt)); if (! have_row) @@ -196,19 +155,27 @@ pristine_read_txn(svn_stream_t **content sha1_checksum, scratch_pool)); } - /* Open the file as a readable stream. It will remain readable even when - * deleted from disk; APR guarantees that on Windows as well as Unix. - * - * We also don't enable APR_BUFFERED on this file to maximize throughput - * e.g. for fulltext comparison. As we use SVN__STREAM_CHUNK_SIZE buffers - * where needed in streams, there is no point in having another layer of - * buffers. */ if (contents) { - apr_file_t *file; - SVN_ERR(svn_io_file_open(&file, pristine_abspath, APR_READ, - APR_OS_DEFAULT, result_pool)); - *contents = svn_stream_from_aprfile2(file, FALSE, result_pool); + if (hydrated) + { + /* Open the file as a readable stream. It will remain readable even when + * deleted from disk; APR guarantees that on Windows as well as Unix. + * + * We also don't enable APR_BUFFERED on this file to maximize throughput + * e.g. for fulltext comparison. As we use SVN__STREAM_CHUNK_SIZE buffers + * where needed in streams, there is no point in having another layer of + * buffers. */ + + apr_file_t *file; + SVN_ERR(svn_io_file_open(&file, pristine_abspath, APR_READ, + APR_OS_DEFAULT, result_pool)); + *contents = svn_stream_from_aprfile2(file, FALSE, result_pool); + } + else + { + *contents = NULL; + } } return SVN_NO_ERROR; @@ -256,6 +223,53 @@ svn_wc__db_pristine_read(svn_stream_t ** } +struct svn_wc__db_install_data_t +{ + svn_wc__db_wcroot_t *wcroot; + svn_stream_t *inner_stream; + apr_off_t size; +}; + +static svn_error_t * +install_stream_write_fn(void *baton, const char *data, apr_size_t *len) +{ + svn_wc__db_install_data_t *install_data = baton; + + if (install_data->inner_stream) + SVN_ERR(svn_stream_write(install_data->inner_stream, data, len)); + + install_data->size += *len; + + return SVN_NO_ERROR; +} + +static svn_error_t * +install_stream_seek_fn(void *baton, const svn_stream_mark_t *mark) +{ + svn_wc__db_install_data_t *install_data = baton; + + if (!mark) + return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL); + + if (install_data->inner_stream) + SVN_ERR(svn_stream_reset(install_data->inner_stream)); + + install_data->size = 0; + + return SVN_NO_ERROR; +} + +static svn_error_t * +install_stream_close_fn(void *baton) +{ + svn_wc__db_install_data_t *install_data = baton; + + if (install_data->inner_stream) + SVN_ERR(svn_stream_close(install_data->inner_stream)); + + return SVN_NO_ERROR; +} + /* Return the absolute path to the temporary directory for pristine text files within WCROOT. */ static char * @@ -268,9 +282,8 @@ pristine_get_tempdir(svn_wc__db_wcroot_t PRISTINE_TEMPDIR_RELPATH, SVN_VA_NULL); } -/* Install the pristine text described by BATON into the pristine store of - * SDB. If it is already stored then just delete the new file - * BATON->tempfile_abspath. +/* Install the pristine text described by INSTALL_DATA into the pristine store + * of SDB. * * This function expects to be executed inside a SQLite txn that has already * acquired a 'RESERVED' lock. @@ -279,8 +292,7 @@ pristine_get_tempdir(svn_wc__db_wcroot_t */ static svn_error_t * pristine_install_txn(svn_sqlite__db_t *sdb, - /* The path to the source file that is to be moved into place. */ - svn_stream_t *install_stream, + svn_wc__db_install_data_t *install_data, /* The target path for the file (within the pristine store). */ const char *pristine_abspath, /* The pristine text's SHA-1 checksum. */ @@ -289,85 +301,73 @@ pristine_install_txn(svn_sqlite__db_t *s const svn_checksum_t *md5_checksum, apr_pool_t *scratch_pool) { + svn_stream_t *install_stream = install_data->inner_stream; svn_sqlite__stmt_t *stmt; svn_boolean_t have_row; + svn_boolean_t hydrated; - /* If this pristine text is already present in the store, just keep it: - * delete the new one and return. */ SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); - SVN_ERR(svn_sqlite__reset(stmt)); if (have_row) + hydrated = svn_sqlite__column_boolean(stmt, 2); + else + hydrated = FALSE; + + SVN_ERR(svn_sqlite__reset(stmt)); + + if (have_row && hydrated) { -#ifdef SVN_DEBUG - /* Consistency checks. Verify both files exist and match. - * ### We could check much more. */ - { - apr_finfo_t finfo; - apr_off_t size; - - SVN_ERR(svn_stream__install_finalize(NULL, &size, install_stream, - scratch_pool)); - - SVN_ERR(svn_io_stat(&finfo, pristine_abspath, APR_FINFO_SIZE, - scratch_pool)); - if (size != finfo.size) - { - return svn_error_createf( - SVN_ERR_WC_CORRUPT_TEXT_BASE, NULL, - _("New pristine text '%s' has different size: %s versus %s"), - svn_checksum_to_cstring_display(sha1_checksum, scratch_pool), - apr_off_t_toa(scratch_pool, size), - apr_off_t_toa(scratch_pool, finfo.size)); - } - } -#endif + /* For now, ensure that we do not inadvertently dehydrate an existing + * hydrated entry, as there could be references to its content. */ + + if (install_stream) + SVN_ERR(svn_stream__install_delete(install_stream, scratch_pool)); - /* Remove the temp file: it's already there */ - SVN_ERR(svn_stream__install_delete(install_stream, scratch_pool)); return SVN_NO_ERROR; } - /* Move the file to its target location. (If it is already there, it is - * an orphan file and it doesn't matter if we overwrite it.) */ - { - apr_off_t size; + if (install_stream) + { + /* Move the file to its target location. (If it is already there, it is + * an orphan file and it doesn't matter if we overwrite it.) */ - svn_stream__install_set_read_only(install_stream, TRUE); + svn_stream__install_set_read_only(install_stream, TRUE); - SVN_ERR(svn_stream__install_finalize(NULL, &size, install_stream, - scratch_pool)); - SVN_ERR(svn_stream__install_stream(install_stream, pristine_abspath, - TRUE, scratch_pool)); - - SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_PRISTINE)); - SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); - SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); - SVN_ERR(svn_sqlite__bind_int64(stmt, 3, size)); - SVN_ERR(svn_sqlite__insert(NULL, stmt)); - } + SVN_ERR(svn_stream__install_finalize(NULL, NULL, install_stream, + scratch_pool)); + SVN_ERR(svn_stream__install_stream(install_stream, pristine_abspath, + TRUE, scratch_pool)); + } + else + { + SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool)); + } + + SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_UPSERT_PRISTINE)); + SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); + SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); + SVN_ERR(svn_sqlite__bind_int64(stmt, 3, install_data->size)); + SVN_ERR(svn_sqlite__bind_int(stmt, 4, install_stream != NULL)); + SVN_ERR(svn_sqlite__insert(NULL, stmt)); return SVN_NO_ERROR; } -struct svn_wc__db_install_data_t -{ - svn_wc__db_wcroot_t *wcroot; - svn_stream_t *inner_stream; -}; - svn_error_t * -svn_wc__db_pristine_prepare_install(svn_stream_t **stream, - svn_wc__db_install_data_t **install_data, - svn_checksum_t **sha1_checksum, - svn_checksum_t **md5_checksum, +svn_wc__db_pristine_prepare_install(svn_stream_t **stream_p, + svn_wc__db_install_data_t **install_data_p, + svn_checksum_t **sha1_checksum_p, + svn_checksum_t **md5_checksum_p, svn_wc__db_t *db, const char *wri_abspath, + svn_boolean_t hydrated, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { + svn_stream_t *stream; + svn_wc__db_install_data_t *install_data; svn_wc__db_wcroot_t *wcroot; const char *local_relpath; const char *temp_dir_abspath; @@ -380,22 +380,37 @@ svn_wc__db_pristine_prepare_install(svn_ temp_dir_abspath = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool); - *install_data = apr_pcalloc(result_pool, sizeof(**install_data)); - (*install_data)->wcroot = wcroot; + install_data = apr_pcalloc(result_pool, sizeof(*install_data)); + install_data->wcroot = wcroot; + + if (hydrated) + { + SVN_ERR_W(svn_stream__create_for_install(&install_data->inner_stream, + temp_dir_abspath, + result_pool, scratch_pool), + _("Unable to create pristine install stream")); + } + else + { + install_data->inner_stream = NULL; + } + + install_data->size = 0; + + stream = svn_stream_create(install_data, result_pool); + svn_stream_set_write(stream, install_stream_write_fn); + svn_stream_set_seek(stream, install_stream_seek_fn); + svn_stream_set_close(stream, install_stream_close_fn); + + if (md5_checksum_p) + stream = svn_stream_checksummed2(stream, NULL, md5_checksum_p, + svn_checksum_md5, FALSE, result_pool); + if (sha1_checksum_p) + stream = svn_stream_checksummed2(stream, NULL, sha1_checksum_p, + svn_checksum_sha1, FALSE, result_pool); - SVN_ERR_W(svn_stream__create_for_install(stream, - temp_dir_abspath, - result_pool, scratch_pool), - _("Unable to create pristine install stream")); - - (*install_data)->inner_stream = *stream; - - if (md5_checksum) - *stream = svn_stream_checksummed2(*stream, NULL, md5_checksum, - svn_checksum_md5, FALSE, result_pool); - if (sha1_checksum) - *stream = svn_stream_checksummed2(*stream, NULL, sha1_checksum, - svn_checksum_sha1, FALSE, result_pool); + *stream_p = stream; + *install_data_p = install_data; return SVN_NO_ERROR; } @@ -422,7 +437,7 @@ svn_wc__db_pristine_install(svn_wc__db_i * at the disk, to ensure no concurrent pristine install/delete txn. */ SVN_SQLITE__WITH_IMMEDIATE_TXN( pristine_install_txn(wcroot->sdb, - install_data->inner_stream, pristine_abspath, + install_data, pristine_abspath, sha1_checksum, md5_checksum, scratch_pool), wcroot->sdb); @@ -434,8 +449,12 @@ svn_error_t * svn_wc__db_pristine_install_abort(svn_wc__db_install_data_t *install_data, apr_pool_t *scratch_pool) { - return svn_error_trace(svn_stream__install_delete(install_data->inner_stream, - scratch_pool)); + if (install_data->inner_stream) + SVN_ERR(svn_stream__install_delete(install_data->inner_stream, scratch_pool)); + + install_data->size = 0; + + return SVN_NO_ERROR; } @@ -516,84 +535,91 @@ svn_wc__db_pristine_get_sha1(const svn_c } /* Handle the moving of a pristine from SRC_WCROOT to DST_WCROOT. The existing - pristine in SRC_WCROOT is described by CHECKSUM, MD5_CHECKSUM and SIZE */ + pristine in SRC_WCROOT is described by CHECKSUM, MD5_CHECKSUM, SIZE and + HYDRATED. */ static svn_error_t * maybe_transfer_one_pristine(svn_wc__db_wcroot_t *src_wcroot, svn_wc__db_wcroot_t *dst_wcroot, const svn_checksum_t *checksum, const svn_checksum_t *md5_checksum, apr_int64_t size, + svn_boolean_t hydrated, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { - const char *pristine_abspath; svn_sqlite__stmt_t *stmt; - svn_stream_t *src_stream; - svn_stream_t *dst_stream; - const char *tmp_abspath; - const char *src_abspath; int affected_rows; - svn_error_t *err; SVN_ERR(svn_sqlite__get_statement(&stmt, dst_wcroot->sdb, STMT_INSERT_OR_IGNORE_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 2, md5_checksum, scratch_pool)); SVN_ERR(svn_sqlite__bind_int64(stmt, 3, size)); + SVN_ERR(svn_sqlite__bind_int(stmt, 4, hydrated)); SVN_ERR(svn_sqlite__update(&affected_rows, stmt)); if (affected_rows == 0) return SVN_NO_ERROR; - SVN_ERR(svn_stream_open_unique(&dst_stream, &tmp_abspath, - pristine_get_tempdir(dst_wcroot, - scratch_pool, - scratch_pool), - svn_io_file_del_on_pool_cleanup, - scratch_pool, scratch_pool)); + if (hydrated) + { + const char *pristine_abspath; + svn_stream_t *src_stream; + svn_stream_t *dst_stream; + const char *tmp_abspath; + const char *src_abspath; + svn_error_t *err; - SVN_ERR(get_pristine_fname(&src_abspath, src_wcroot->abspath, checksum, - scratch_pool, scratch_pool)); + SVN_ERR(svn_stream_open_unique(&dst_stream, &tmp_abspath, + pristine_get_tempdir(dst_wcroot, + scratch_pool, + scratch_pool), + svn_io_file_del_on_pool_cleanup, + scratch_pool, scratch_pool)); - SVN_ERR(svn_stream_open_readonly(&src_stream, src_abspath, - scratch_pool, scratch_pool)); + SVN_ERR(get_pristine_fname(&src_abspath, src_wcroot->abspath, checksum, + scratch_pool, scratch_pool)); - /* ### Should we verify the SHA1 or MD5 here, or is that too expensive? */ - SVN_ERR(svn_stream_copy3(src_stream, dst_stream, - cancel_func, cancel_baton, - scratch_pool)); + SVN_ERR(svn_stream_open_readonly(&src_stream, src_abspath, + scratch_pool, scratch_pool)); - SVN_ERR(get_pristine_fname(&pristine_abspath, dst_wcroot->abspath, checksum, - scratch_pool, scratch_pool)); + /* ### Should we verify the SHA1 or MD5 here, or is that too expensive? */ + SVN_ERR(svn_stream_copy3(src_stream, dst_stream, + cancel_func, cancel_baton, + scratch_pool)); - /* Move the file to its target location. (If it is already there, it is - * an orphan file and it doesn't matter if we overwrite it.) */ - err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, - scratch_pool); - - /* Maybe the directory doesn't exist yet? */ - if (err && APR_STATUS_IS_ENOENT(err->apr_err)) - { - svn_error_t *err2; - - err2 = svn_io_dir_make(svn_dirent_dirname(pristine_abspath, - scratch_pool), - APR_OS_DEFAULT, scratch_pool); - - if (err2) - /* Creating directory didn't work: Return all errors */ - return svn_error_trace(svn_error_compose_create(err, err2)); - else - /* We could create a directory: retry install */ - svn_error_clear(err); + SVN_ERR(get_pristine_fname(&pristine_abspath, dst_wcroot->abspath, checksum, + scratch_pool, scratch_pool)); - SVN_ERR(svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, - scratch_pool)); + /* Move the file to its target location. (If it is already there, it is + * an orphan file and it doesn't matter if we overwrite it.) */ + err = svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, + scratch_pool); + + /* Maybe the directory doesn't exist yet? */ + if (err && APR_STATUS_IS_ENOENT(err->apr_err)) + { + svn_error_t *err2; + + err2 = svn_io_dir_make(svn_dirent_dirname(pristine_abspath, + scratch_pool), + APR_OS_DEFAULT, scratch_pool); + + if (err2) + /* Creating directory didn't work: Return all errors */ + return svn_error_trace(svn_error_compose_create(err, err2)); + else + /* We could create a directory: retry install */ + svn_error_clear(err); + + SVN_ERR(svn_io_file_rename2(tmp_abspath, pristine_abspath, FALSE, + scratch_pool)); + } + else + SVN_ERR(err); } - else - SVN_ERR(err); return SVN_NO_ERROR; } @@ -625,6 +651,7 @@ pristine_transfer_txn(svn_wc__db_wcroot_ const svn_checksum_t *checksum; const svn_checksum_t *md5_checksum; apr_int64_t size; + svn_boolean_t hydrated; svn_error_t *err; svn_pool_clear(iterpool); @@ -632,9 +659,11 @@ pristine_transfer_txn(svn_wc__db_wcroot_ SVN_ERR(svn_sqlite__column_checksum(&checksum, stmt, 0, iterpool)); SVN_ERR(svn_sqlite__column_checksum(&md5_checksum, stmt, 1, iterpool)); size = svn_sqlite__column_int64(stmt, 2); + hydrated = svn_sqlite__column_boolean(stmt, 3); err = maybe_transfer_one_pristine(src_wcroot, dst_wcroot, checksum, md5_checksum, size, + hydrated, cancel_func, cancel_baton, iterpool); @@ -714,19 +743,7 @@ pristine_remove_if_unreferenced_txn(svn_ /* If we removed the DB row, then remove the file. */ if (affected_rows > 0) - { - /* If the file is not present, something has gone wrong, but at this - * point it no longer matters. In a debug build, raise an error, but - * in a release build, it is more helpful to ignore it and continue. */ -#ifdef SVN_DEBUG - svn_boolean_t ignore_enoent = FALSE; -#else - svn_boolean_t ignore_enoent = TRUE; -#endif - - SVN_ERR(svn_io_remove_file2(pristine_abspath, ignore_enoent, - scratch_pool)); - } + SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool)); return SVN_NO_ERROR; } @@ -887,6 +904,7 @@ svn_wc__db_pristine_cleanup(svn_wc__db_t svn_error_t * svn_wc__db_pristine_check(svn_boolean_t *present, + svn_boolean_t *hydrated, svn_wc__db_t *db, const char *wri_abspath, const svn_checksum_t *sha1_checksum, @@ -903,6 +921,9 @@ svn_wc__db_pristine_check(svn_boolean_t if (sha1_checksum->kind != svn_checksum_sha1) { *present = FALSE; + if (hydrated) + *hydrated = FALSE; + return SVN_NO_ERROR; } @@ -910,46 +931,50 @@ svn_wc__db_pristine_check(svn_boolean_t wri_abspath, scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - /* A filestat is much cheaper than a sqlite transaction especially on NFS, - so first check if there is a pristine file and then if we are allowed - to use it. */ - { - const char *pristine_abspath; - svn_node_kind_t kind_on_disk; - svn_error_t *err; - - SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, - sha1_checksum, scratch_pool, scratch_pool)); - err = svn_io_check_path(pristine_abspath, &kind_on_disk, scratch_pool); -#ifdef WIN32 - if (err && err->apr_err == APR_FROM_OS_ERROR(ERROR_ACCESS_DENIED)) - { - svn_error_clear(err); - /* Possible race condition: The filename is locked, but there is no - file or dir with this name. Let's fall back on checking the DB. - - This case is triggered by the pristine store tests on deleting - a file that is still open via another handle, where this other - handle has a FILE_SHARE_DELETE share mode. - */ - } - else -#endif - if (err) - return svn_error_trace(err); - else if (kind_on_disk != svn_node_file) - { - *present = FALSE; - return SVN_NO_ERROR; - } - } - /* Check that there is an entry in the PRISTINE table. */ SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_PRISTINE)); SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); SVN_ERR(svn_sqlite__step(&have_row, stmt)); + + if (hydrated) + *hydrated = svn_sqlite__column_boolean(stmt, 2); + SVN_ERR(svn_sqlite__reset(stmt)); *present = have_row; return SVN_NO_ERROR; } + + +svn_error_t * +svn_wc__db_pristine_dehydrate(svn_wc__db_t *db, + const char *wri_abspath, + const svn_checksum_t *sha1_checksum, + apr_pool_t *scratch_pool) +{ + svn_wc__db_wcroot_t *wcroot; + const char *local_relpath; + const char *pristine_abspath; + svn_sqlite__stmt_t *stmt; + + SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath)); + SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1); + + SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db, + wri_abspath, scratch_pool, scratch_pool)); + VERIFY_USABLE_WCROOT(wcroot); + + SVN_ERR(get_pristine_fname(&pristine_abspath, wcroot->abspath, + sha1_checksum, + scratch_pool, scratch_pool)); + + SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, + STMT_UPDATE_PRISTINE_HYDRATED)); + SVN_ERR(svn_sqlite__bind_checksum(stmt, 1, sha1_checksum, scratch_pool)); + SVN_ERR(svn_sqlite__bind_int(stmt, 2, FALSE)); + SVN_ERR(svn_sqlite__update(NULL, stmt)); + + SVN_ERR(svn_io_remove_file2(pristine_abspath, TRUE, scratch_pool)); + + return SVN_NO_ERROR; +}
