summaryrefslogtreecommitdiff
path: root/subversion/libsvn_wc/wc_db_pristine.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_wc/wc_db_pristine.c')
-rw-r--r--subversion/libsvn_wc/wc_db_pristine.c222
1 files changed, 134 insertions, 88 deletions
diff --git a/subversion/libsvn_wc/wc_db_pristine.c b/subversion/libsvn_wc/wc_db_pristine.c
index d9dc8f3..9118d70 100644
--- a/subversion/libsvn_wc/wc_db_pristine.c
+++ b/subversion/libsvn_wc/wc_db_pristine.c
@@ -26,8 +26,11 @@
#define SVN_WC__I_AM_WC_DB
#include "svn_pools.h"
+#include "svn_io.h"
#include "svn_dirent_uri.h"
+#include "private/svn_io_private.h"
+
#include "wc.h"
#include "wc_db.h"
#include "wc-queries.h"
@@ -67,7 +70,7 @@ get_pristine_fname(const char **pristine_abspath,
wcroot_abspath,
svn_wc_get_adm_dir(scratch_pool),
PRISTINE_STORAGE_RELPATH,
- NULL);
+ SVN_VA_NULL);
/* We should have a valid checksum and (thus) a valid digest. */
SVN_ERR_ASSERT(hexdigest != NULL);
@@ -78,14 +81,14 @@ get_pristine_fname(const char **pristine_abspath,
subdir[2] = '\0';
hexdigest = apr_pstrcat(scratch_pool, hexdigest, PRISTINE_STORAGE_EXT,
- (char *)NULL);
+ SVN_VA_NULL);
/* The file is located at DIR/.svn/pristine/XX/XXYYZZ...svn-base */
*pristine_abspath = svn_dirent_join_many(result_pool,
base_dir_abspath,
subdir,
hexdigest,
- NULL);
+ SVN_VA_NULL);
return SVN_NO_ERROR;
}
@@ -194,10 +197,20 @@ pristine_read_txn(svn_stream_t **contents,
}
/* 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. */
+ * 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)
- SVN_ERR(svn_stream_open_readonly(contents, pristine_abspath,
- result_pool, scratch_pool));
+ {
+ 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);
+ }
+
return SVN_NO_ERROR;
}
@@ -253,31 +266,9 @@ pristine_get_tempdir(svn_wc__db_wcroot_t *wcroot,
{
return svn_dirent_join_many(result_pool, wcroot->abspath,
svn_wc_get_adm_dir(scratch_pool),
- PRISTINE_TEMPDIR_RELPATH, (char *)NULL);
+ PRISTINE_TEMPDIR_RELPATH, SVN_VA_NULL);
}
-svn_error_t *
-svn_wc__db_pristine_get_tempdir(const char **temp_dir_abspath,
- svn_wc__db_t *db,
- const char *wri_abspath,
- apr_pool_t *result_pool,
- apr_pool_t *scratch_pool)
-{
- svn_wc__db_wcroot_t *wcroot;
- const char *local_relpath;
-
- SVN_ERR_ASSERT(temp_dir_abspath != NULL);
- SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
-
- SVN_ERR(svn_wc__db_wcroot_parse_local_abspath(&wcroot, &local_relpath, db,
- wri_abspath, scratch_pool, scratch_pool));
- VERIFY_USABLE_WCROOT(wcroot);
-
- *temp_dir_abspath = pristine_get_tempdir(wcroot, result_pool, scratch_pool);
- return SVN_NO_ERROR;
-}
-
-
/* 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.
@@ -290,7 +281,7 @@ svn_wc__db_pristine_get_tempdir(const char **temp_dir_abspath,
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. */
- const char *tempfile_abspath,
+ svn_stream_t *install_stream,
/* The target path for the file (within the pristine store). */
const char *pristine_abspath,
/* The pristine text's SHA-1 checksum. */
@@ -299,10 +290,8 @@ pristine_install_txn(svn_sqlite__db_t *sdb,
const svn_checksum_t *md5_checksum,
apr_pool_t *scratch_pool)
{
- apr_finfo_t finfo;
svn_sqlite__stmt_t *stmt;
svn_boolean_t have_row;
- svn_error_t *err;
/* If this pristine text is already present in the store, just keep it:
* delete the new one and return. */
@@ -310,6 +299,7 @@ pristine_install_txn(svn_sqlite__db_t *sdb,
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)
{
#ifdef SVN_DEBUG
@@ -317,8 +307,10 @@ pristine_install_txn(svn_sqlite__db_t *sdb,
* ### We could check much more. */
{
apr_finfo_t finfo1, finfo2;
- SVN_ERR(svn_io_stat(&finfo1, tempfile_abspath, APR_FINFO_SIZE,
- scratch_pool));
+
+ SVN_ERR(svn_stream__install_get_info(&finfo1, install_stream, APR_FINFO_SIZE,
+ scratch_pool));
+
SVN_ERR(svn_io_stat(&finfo2, pristine_abspath, APR_FINFO_SIZE,
scratch_pool));
if (finfo1.size != finfo2.size)
@@ -333,84 +325,94 @@ pristine_install_txn(svn_sqlite__db_t *sdb,
#endif
/* Remove the temp file: it's already there */
- SVN_ERR(svn_io_remove_file2(tempfile_abspath,
- FALSE /* ignore_enoent */, scratch_pool));
+ 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.) */
- err = svn_io_file_rename(tempfile_abspath, pristine_abspath,
- scratch_pool);
+ {
+ apr_finfo_t finfo;
+ SVN_ERR(svn_stream__install_get_info(&finfo, install_stream, APR_FINFO_SIZE,
+ 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, finfo.size));
+ SVN_ERR(svn_sqlite__insert(NULL, stmt));
+
+ SVN_ERR(svn_io_set_file_read_only(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;
+ return SVN_NO_ERROR;
+}
- err2 = svn_io_dir_make(svn_dirent_dirname(pristine_abspath,
- scratch_pool),
- APR_OS_DEFAULT, scratch_pool);
+struct svn_wc__db_install_data_t
+{
+ svn_wc__db_wcroot_t *wcroot;
+ svn_stream_t *inner_stream;
+};
- 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_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_t *db,
+ const char *wri_abspath,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_wc__db_wcroot_t *wcroot;
+ const char *local_relpath;
+ const char *temp_dir_abspath;
- SVN_ERR(svn_io_file_rename(tempfile_abspath, pristine_abspath,
- scratch_pool));
- }
- else
- SVN_ERR(err);
+ SVN_ERR_ASSERT(svn_dirent_is_absolute(wri_abspath));
- SVN_ERR(svn_io_stat(&finfo, pristine_abspath, APR_FINFO_SIZE,
- scratch_pool));
+ 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_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, finfo.size));
- SVN_ERR(svn_sqlite__insert(NULL, stmt));
+ temp_dir_abspath = pristine_get_tempdir(wcroot, scratch_pool, scratch_pool);
+
+ *install_data = apr_pcalloc(result_pool, sizeof(**install_data));
+ (*install_data)->wcroot = wcroot;
+
+ 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);
return SVN_NO_ERROR;
}
-
svn_error_t *
-svn_wc__db_pristine_install(svn_wc__db_t *db,
- const char *tempfile_abspath,
+svn_wc__db_pristine_install(svn_wc__db_install_data_t *install_data,
const svn_checksum_t *sha1_checksum,
const svn_checksum_t *md5_checksum,
apr_pool_t *scratch_pool)
{
- svn_wc__db_wcroot_t *wcroot;
- const char *local_relpath;
- const char *wri_abspath;
+ svn_wc__db_wcroot_t *wcroot = install_data->wcroot;
const char *pristine_abspath;
- SVN_ERR_ASSERT(svn_dirent_is_absolute(tempfile_abspath));
SVN_ERR_ASSERT(sha1_checksum != NULL);
SVN_ERR_ASSERT(sha1_checksum->kind == svn_checksum_sha1);
SVN_ERR_ASSERT(md5_checksum != NULL);
SVN_ERR_ASSERT(md5_checksum->kind == svn_checksum_md5);
- /* ### this logic assumes that TEMPFILE_ABSPATH follows this pattern:
- ### WCROOT_ABSPATH/COMPONENT/COMPONENT/TEMPFNAME
- ### if we change this (see PRISTINE_TEMPDIR_RELPATH), then this
- ### logic should change. */
- wri_abspath = svn_dirent_dirname(
- svn_dirent_dirname(
- svn_dirent_dirname(tempfile_abspath, scratch_pool),
- scratch_pool),
- scratch_pool);
-
- 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));
@@ -419,7 +421,7 @@ svn_wc__db_pristine_install(svn_wc__db_t *db,
* at the disk, to ensure no concurrent pristine install/delete txn. */
SVN_SQLITE__WITH_IMMEDIATE_TXN(
pristine_install_txn(wcroot->sdb,
- tempfile_abspath, pristine_abspath,
+ install_data->inner_stream, pristine_abspath,
sha1_checksum, md5_checksum,
scratch_pool),
wcroot->sdb);
@@ -427,6 +429,14 @@ svn_wc__db_pristine_install(svn_wc__db_t *db,
return SVN_NO_ERROR;
}
+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));
+}
+
svn_error_t *
svn_wc__db_pristine_get_md5(const svn_checksum_t **md5_checksum,
@@ -823,12 +833,44 @@ svn_wc__db_pristine_remove(svn_wc__db_t *db,
}
+/* Remove all unreferenced pristines in the WC DB in WCROOT.
+ *
+ * Look for pristine texts whose 'refcount' in the DB is zero, and remove
+ * them from the 'pristine' table and from disk.
+ *
+ * TODO: At least check that any zero refcount is really correct, before
+ * using it. See dev@ email thread "Pristine text missing - cleanup
+ * doesn't work", <http://svn.haxx.se/dev/archive-2013-04/0426.shtml>.
+ *
+ * TODO: Ideas for possible extra clean-up operations:
+ *
+ * * Check and correct all the refcounts. Identify any rows missing
+ * from the 'pristine' table. (Create a temporary index for speed
+ * if necessary?)
+ *
+ * * Check the checksums. (Very expensive to check them all, so find
+ * a way to not check them all.)
+ *
+ * * Check for pristine files missing from disk but referenced in the
+ * 'pristine' table.
+ *
+ * * Repair any pristine files missing from disk and/or rows missing
+ * from the 'pristine' table and/or bad checksums. Generally
+ * requires contacting the server, so requires support at a higher
+ * level than this function.
+ *
+ * * Identify any pristine text files on disk that are not referenced
+ * in the DB, and delete them.
+ *
+ * TODO: Provide feedback about any errors found and any corrections made.
+ */
static svn_error_t *
pristine_cleanup_wcroot(svn_wc__db_wcroot_t *wcroot,
apr_pool_t *scratch_pool)
{
svn_sqlite__stmt_t *stmt;
svn_error_t *err = NULL;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
/* Find each unreferenced pristine in the DB and remove it. */
SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -838,16 +880,20 @@ pristine_cleanup_wcroot(svn_wc__db_wcroot_t *wcroot,
svn_boolean_t have_row;
const svn_checksum_t *sha1_checksum;
+ svn_pool_clear(iterpool);
+
SVN_ERR(svn_sqlite__step(&have_row, stmt));
if (! have_row)
break;
SVN_ERR(svn_sqlite__column_checksum(&sha1_checksum, stmt, 0,
- scratch_pool));
+ iterpool));
err = pristine_remove_if_unreferenced(wcroot, sha1_checksum,
- scratch_pool);
+ iterpool);
}
+ svn_pool_destroy(iterpool);
+
return svn_error_trace(
svn_error_compose_create(err, svn_sqlite__reset(stmt)));
}