On Mon, 2011-02-28, I (Julian Foad) wrote: > On Sat, 2011-02-26, Branko Čibej wrote: > > On 26.02.2011 20:40, Ivan Zhakov wrote: > > > Btw I think it makes sense rename file to tmp directory in working > > > copy instead of pristines directory, since it could be crash/failure > > > between rename and delete. In this case pristines directory will > > > polluted with orphaned pristines. > > > > That works as long as the pristine store lives in the WC root, so yes. > > This seems to be a good plan. Thanks for the help. I'll do it right > away.
Please see attached patch. (I might write a test or two before committing it or I might commit first.) - Julian
Update the pristine text store to guarantee that a pristine text stream being read will remain readable even if the text is deleted from the store. ### The '#ifdef WIN32' is here shown replaced with '#if 1' so it can be tested on Linux. * subversion/libsvn_wc/wc_db.h (svn_wc__db_pristine_read): State that the stream will remain readable. Also document 'db' and 'wri_abspath'. * subversion/libsvn_wc/wc_db_pristine.c (pristine_read_txn): Document that the stream will remain readable. (pristine_get_tempdir): New function, factored out of ... (svn_wc__db_pristine_get_tempdir): ... here. (remove_file): New function. (pristine_remove_baton_t): Add a 'wcroot' object. (pristine_remove_if_unreferenced_txn): Use remove_file() so that file removal can always be followed by re-creating a new file of the same name even on Windows. (pristine_remove_if_unreferenced): Initialize the new member of the pristine_remove_baton_t. --This line, and those below, will be ignored-- Index: subversion/libsvn_wc/wc_db.h =================================================================== --- subversion/libsvn_wc/wc_db.h (revision 1075304) +++ subversion/libsvn_wc/wc_db.h (working copy) @@ -890,7 +890,11 @@ svn_wc__db_pristine_get_future_path(cons /* Set *CONTENTS to a readable stream that will yield the pristine text - identified by CHECKSUM (### which should/must be its SHA-1 checksum?). + identified by SHA1_CHECKSUM (### which should/must be its SHA-1 checksum?) + within the WC identified by WRI_ABSPATH in DB. + + 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. Allocate the stream in RESULT_POOL. */ svn_error_t * Index: subversion/libsvn_wc/wc_db_pristine.c =================================================================== --- subversion/libsvn_wc/wc_db_pristine.c (revision 1075328) +++ subversion/libsvn_wc/wc_db_pristine.c (working copy) @@ -182,6 +182,9 @@ typedef struct pristine_read_baton_t * identified by BATON->sha1_checksum can be read from the pristine store of * SDB. 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. + * * Allocate the stream in BATON->result_pool. * * This function expects to be executed inside a SQLite txn. @@ -211,6 +214,8 @@ pristine_read_txn(void *baton, b->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. */ SVN_ERR(svn_stream_open_readonly(b->contents, b->pristine_abspath, b->result_pool, scratch_pool)); return SVN_NO_ERROR; @@ -258,6 +263,18 @@ svn_wc__db_pristine_read(svn_stream_t ** } +/* Return the absolute path to the temporary directory for pristine text + files within WCROOT. */ +static char * +pristine_get_tempdir(svn_wc__db_wcroot_t *wcroot, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_dirent_join_many(result_pool, wcroot->abspath, + svn_wc_get_adm_dir(scratch_pool), + PRISTINE_TEMPDIR_RELPATH, (char *)NULL); +} + svn_error_t * svn_wc__db_pristine_get_tempdir(const char **temp_dir_abspath, svn_wc__db_t *db, @@ -276,10 +293,7 @@ svn_wc__db_pristine_get_tempdir(const ch scratch_pool, scratch_pool)); VERIFY_USABLE_WCROOT(wcroot); - *temp_dir_abspath = svn_dirent_join_many(result_pool, wcroot->abspath, - svn_wc_get_adm_dir(scratch_pool), - PRISTINE_TEMPDIR_RELPATH, - NULL); + *temp_dir_abspath = pristine_get_tempdir(wcroot, result_pool, scratch_pool); return SVN_NO_ERROR; } @@ -499,9 +513,48 @@ svn_wc__db_pristine_get_sha1(const svn_c } +/* Remove the file at FILE_ABSPATH in such a way that we could re-create a + * new file of the same name at any time thereafter. + * + * On Windows, the file will not disappear immediately from the directory if + * it is still being read so the best thing to do is first rename it to a + * unique name. */ +static svn_error_t * +remove_file(const char *file_abspath, + svn_wc__db_wcroot_t *wcroot, + svn_boolean_t ignore_enoent, + apr_pool_t *scratch_pool) +{ +#if 1 /* ### #ifdef WIN32 */ + { + svn_error_t *err; + const char *temp_abspath; + const char *temp_dir_abspath + = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool); + + /* To rename the file to a unique name in the temp dir, first create a + * uniquely named file in the temp dir and then overwrite it. */ + SVN_ERR(svn_io_open_unique_file3(NULL, &temp_abspath, temp_dir_abspath, + svn_io_file_del_none, + scratch_pool, scratch_pool)); + err = svn_io_file_rename(file_abspath, temp_abspath, scratch_pool); + if (err && ignore_enoent && APR_STATUS_IS_ENOENT(err->apr_err)) + svn_error_clear(err); + else + SVN_ERR(err); + file_abspath = temp_abspath; + } +#endif + + SVN_ERR(svn_io_remove_file2(file_abspath, ignore_enoent, scratch_pool)); + + return SVN_NO_ERROR; +} + /* Data for pristine_remove_if_unreferenced_txn(). */ typedef struct pristine_remove_baton_t { + svn_wc__db_wcroot_t *wcroot; /* The pristine text's SHA-1 checksum. */ const svn_checksum_t *sha1_checksum; /* The path to the pristine file (within the pristine store). */ @@ -542,8 +595,8 @@ pristine_remove_if_unreferenced_txn(void svn_boolean_t ignore_enoent = TRUE; #endif - SVN_ERR(svn_io_remove_file2(b->pristine_abspath, ignore_enoent, - scratch_pool)); + SVN_ERR(remove_file(b->pristine_abspath, b->wcroot, ignore_enoent, + scratch_pool)); } return SVN_NO_ERROR; @@ -561,6 +614,7 @@ pristine_remove_if_unreferenced(svn_wc__ { pristine_remove_baton_t b; + b.wcroot = wcroot; b.sha1_checksum = sha1_checksum; SVN_ERR(get_pristine_fname(&b.pristine_abspath, wcroot->abspath, sha1_checksum, FALSE /* create_subdir */,