diff options
Diffstat (limited to 'subversion/libsvn_fs_fs/rep-cache.c')
-rw-r--r-- | subversion/libsvn_fs_fs/rep-cache.c | 161 |
1 files changed, 99 insertions, 62 deletions
diff --git a/subversion/libsvn_fs_fs/rep-cache.c b/subversion/libsvn_fs_fs/rep-cache.c index 0082266..437d603 100644 --- a/subversion/libsvn_fs_fs/rep-cache.c +++ b/subversion/libsvn_fs_fs/rep-cache.c @@ -50,19 +50,12 @@ path_rep_cache_db(const char *fs_path, return svn_dirent_join(fs_path, REP_CACHE_DB_NAME, result_pool); } -/* Check that REP refers to a revision that exists in FS. */ -static svn_error_t * -rep_has_been_born(representation_t *rep, - svn_fs_t *fs, - apr_pool_t *pool) -{ - SVN_ERR_ASSERT(rep); - - SVN_ERR(svn_fs_fs__revision_exists(rep->revision, fs, pool)); - - return SVN_NO_ERROR; -} - +#define SVN_ERR_CLOSE(x, db) do \ +{ \ + svn_error_t *svn__err = (x); \ + if (svn__err) \ + return svn_error_compose_create(svn__err, svn_sqlite__close(db)); \ +} while (0) /** Library-private API's. **/ @@ -81,7 +74,7 @@ open_rep_cache(void *baton, int version; /* Open (or create) the sqlite database. It will be automatically - closed when fs->pool is destoyed. */ + closed when fs->pool is destroyed. */ db_path = path_rep_cache_db(fs->path, pool); #ifndef WIN32 { @@ -94,7 +87,7 @@ open_rep_cache(void *baton, if (!exists) { const char *current = svn_fs_fs__path_current(fs, pool); - svn_error_t *err = svn_io_file_create(db_path, "", pool); + svn_error_t *err = svn_io_file_create_empty(db_path, pool); if (err && !APR_STATUS_IS_EEXIST(err->apr_err)) /* A real error. */ @@ -110,15 +103,15 @@ open_rep_cache(void *baton, #endif SVN_ERR(svn_sqlite__open(&sdb, db_path, svn_sqlite__mode_rwcreate, statements, - 0, NULL, + 0, NULL, 0, fs->pool, pool)); - SVN_ERR(svn_sqlite__read_schema_version(&version, sdb, pool)); + SVN_ERR_CLOSE(svn_sqlite__read_schema_version(&version, sdb, pool), sdb); if (version < REP_CACHE_SCHEMA_FORMAT) { /* Must be 0 -- an uninitialized (no schema) database. Create the schema. Results in schema version of 1. */ - SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA)); + SVN_ERR_CLOSE(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA), sdb); } /* This is used as a flag that the database is available so don't @@ -135,7 +128,25 @@ svn_fs_fs__open_rep_cache(svn_fs_t *fs, fs_fs_data_t *ffd = fs->fsap_data; svn_error_t *err = svn_atomic__init_once(&ffd->rep_cache_db_opened, open_rep_cache, fs, pool); - return svn_error_quick_wrap(err, _("Couldn't open rep-cache database")); + return svn_error_quick_wrapf(err, + _("Couldn't open rep-cache database '%s'"), + svn_dirent_local_style( + path_rep_cache_db(fs->path, pool), pool)); +} + +svn_error_t * +svn_fs_fs__close_rep_cache(svn_fs_t *fs) +{ + fs_fs_data_t *ffd = fs->fsap_data; + + if (ffd->rep_cache_db) + { + SVN_ERR(svn_sqlite__close(ffd->rep_cache_db)); + ffd->rep_cache_db = NULL; + ffd->rep_cache_db_opened = 0; + } + + return SVN_NO_ERROR; } svn_error_t * @@ -188,7 +199,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *fs, max = svn_sqlite__column_revnum(stmt, 0); SVN_ERR(svn_sqlite__reset(stmt)); if (SVN_IS_VALID_REVNUM(max)) /* The rep-cache could be empty. */ - SVN_ERR(svn_fs_fs__revision_exists(max, fs, iterpool)); + SVN_ERR(svn_fs_fs__ensure_revision_exists(max, fs, iterpool)); } SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, @@ -203,6 +214,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *fs, representation_t *rep; const char *sha1_digest; svn_error_t *err; + svn_checksum_t *checksum; /* Clear ITERPOOL occasionally. */ if (iterations++ % 16 == 0) @@ -218,14 +230,17 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *fs, /* Construct a representation_t. */ rep = apr_pcalloc(iterpool, sizeof(*rep)); + svn_fs_fs__id_txn_reset(&rep->txn_id); sha1_digest = svn_sqlite__column_text(stmt, 0, iterpool); - err = svn_checksum_parse_hex(&rep->sha1_checksum, - svn_checksum_sha1, sha1_digest, - iterpool); + err = svn_checksum_parse_hex(&checksum, svn_checksum_sha1, + sha1_digest, iterpool); if (err) return svn_error_compose_create(err, svn_sqlite__reset(stmt)); + + rep->has_sha1 = TRUE; + memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); rep->revision = svn_sqlite__column_revnum(stmt, 1); - rep->offset = svn_sqlite__column_int64(stmt, 2); + rep->item_index = svn_sqlite__column_int64(stmt, 2); rep->size = svn_sqlite__column_int64(stmt, 3); rep->expanded_size = svn_sqlite__column_int64(stmt, 4); @@ -275,9 +290,12 @@ svn_fs_fs__get_rep_reference(representation_t **rep, if (have_row) { *rep = apr_pcalloc(pool, sizeof(**rep)); - (*rep)->sha1_checksum = svn_checksum_dup(checksum, pool); + svn_fs_fs__id_txn_reset(&(*rep)->txn_id); + memcpy((*rep)->sha1_digest, checksum->digest, + sizeof((*rep)->sha1_digest)); + (*rep)->has_sha1 = TRUE; (*rep)->revision = svn_sqlite__column_revnum(stmt, 0); - (*rep)->offset = svn_sqlite__column_int64(stmt, 1); + (*rep)->item_index = svn_sqlite__column_int64(stmt, 1); (*rep)->size = svn_sqlite__column_int64(stmt, 2); (*rep)->expanded_size = svn_sqlite__column_int64(stmt, 3); } @@ -287,7 +305,16 @@ svn_fs_fs__get_rep_reference(representation_t **rep, SVN_ERR(svn_sqlite__reset(stmt)); if (*rep) - SVN_ERR(rep_has_been_born(*rep, fs, pool)); + { + /* Check that REP refers to a revision that exists in FS. */ + svn_error_t *err = svn_fs_fs__ensure_revision_exists((*rep)->revision, + fs, pool); + if (err) + return svn_error_createf(SVN_ERR_FS_CORRUPT, err, + "Checksum '%s' in rep-cache is beyond HEAD", + svn_checksum_to_cstring_display(checksum, + pool)); + } return SVN_NO_ERROR; } @@ -295,28 +322,30 @@ svn_fs_fs__get_rep_reference(representation_t **rep, svn_error_t * svn_fs_fs__set_rep_reference(svn_fs_t *fs, representation_t *rep, - svn_boolean_t reject_dup, apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__stmt_t *stmt; svn_error_t *err; + svn_checksum_t checksum; + checksum.kind = svn_checksum_sha1; + checksum.digest = rep->sha1_digest; SVN_ERR_ASSERT(ffd->rep_sharing_allowed); if (! ffd->rep_cache_db) SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); /* We only allow SHA1 checksums in this table. */ - if (rep->sha1_checksum == NULL) + if (! rep->has_sha1) return svn_error_create(SVN_ERR_BAD_CHECKSUM_KIND, NULL, _("Only SHA1 checksums can be used as keys in the " "rep_cache table.\n")); SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db, STMT_SET_REP)); SVN_ERR(svn_sqlite__bindf(stmt, "siiii", - svn_checksum_to_cstring(rep->sha1_checksum, pool), + svn_checksum_to_cstring(&checksum, pool), (apr_int64_t) rep->revision, - (apr_int64_t) rep->offset, + (apr_int64_t) rep->item_index, (apr_int64_t) rep->size, (apr_int64_t) rep->expanded_size)); @@ -331,35 +360,11 @@ svn_fs_fs__set_rep_reference(svn_fs_t *fs, svn_error_clear(err); /* Constraint failed so the mapping for SHA1_CHECKSUM->REP - should exist. If so, and the value is the same one we were - about to write, that's cool -- just do nothing. If, however, - the value is *different*, that's a red flag! */ - SVN_ERR(svn_fs_fs__get_rep_reference(&old_rep, fs, rep->sha1_checksum, - pool)); + should exist. If so that's cool -- just do nothing. If not, + that's a red flag! */ + SVN_ERR(svn_fs_fs__get_rep_reference(&old_rep, fs, &checksum, pool)); - if (old_rep) - { - if (reject_dup && ((old_rep->revision != rep->revision) - || (old_rep->offset != rep->offset) - || (old_rep->size != rep->size) - || (old_rep->expanded_size != rep->expanded_size))) - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - apr_psprintf(pool, - _("Representation key for checksum '%%s' exists " - "in filesystem '%%s' with a different value " - "(%%ld,%%%s,%%%s,%%%s) than what we were about " - "to store (%%ld,%%%s,%%%s,%%%s)"), - APR_OFF_T_FMT, SVN_FILESIZE_T_FMT, - SVN_FILESIZE_T_FMT, APR_OFF_T_FMT, - SVN_FILESIZE_T_FMT, SVN_FILESIZE_T_FMT), - svn_checksum_to_cstring_display(rep->sha1_checksum, pool), - fs->path, old_rep->revision, old_rep->offset, old_rep->size, - old_rep->expanded_size, rep->revision, rep->offset, rep->size, - rep->expanded_size); - else - return SVN_NO_ERROR; - } - else + if (!old_rep) { /* Something really odd at this point, we failed to insert the checksum AND failed to read an existing checksum. Do we need @@ -391,9 +396,13 @@ svn_fs_fs__del_rep_reference(svn_fs_t *fs, return SVN_NO_ERROR; } -svn_error_t * -svn_fs_fs__lock_rep_cache(svn_fs_t *fs, - apr_pool_t *pool) +/* Start a transaction to take an SQLite reserved lock that prevents + other writes. + + See unlock_rep_cache(). */ +static svn_error_t * +lock_rep_cache(svn_fs_t *fs, + apr_pool_t *pool) { fs_fs_data_t *ffd = fs->fsap_data; @@ -404,3 +413,31 @@ svn_fs_fs__lock_rep_cache(svn_fs_t *fs, return SVN_NO_ERROR; } + +/* End the transaction started by lock_rep_cache(). */ +static svn_error_t * +unlock_rep_cache(svn_fs_t *fs, + apr_pool_t *pool) +{ + fs_fs_data_t *ffd = fs->fsap_data; + + SVN_ERR_ASSERT(ffd->rep_cache_db); /* was opened by lock_rep_cache() */ + + SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_UNLOCK_REP)); + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__with_rep_cache_lock(svn_fs_t *fs, + svn_error_t *(*body)(void *, + apr_pool_t *), + void *baton, + apr_pool_t *pool) +{ + svn_error_t *err; + + SVN_ERR(lock_rep_cache(fs, pool)); + err = body(baton, pool); + return svn_error_compose_create(err, unlock_rep_cache(fs, pool)); +} |