diff options
Diffstat (limited to 'subversion/libsvn_fs_fs/rep-cache.c')
| -rw-r--r-- | subversion/libsvn_fs_fs/rep-cache.c | 132 | 
1 files changed, 72 insertions, 60 deletions
| diff --git a/subversion/libsvn_fs_fs/rep-cache.c b/subversion/libsvn_fs_fs/rep-cache.c index 008226688f27..c2b42808becc 100644 --- a/subversion/libsvn_fs_fs/rep-cache.c +++ b/subversion/libsvn_fs_fs/rep-cache.c @@ -50,20 +50,6 @@ 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; -} - -  /** Library-private API's. **/ @@ -81,7 +67,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 +80,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,7 +96,7 @@ 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)); @@ -188,7 +174,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 +189,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 +205,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 +265,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 +280,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 +297,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 +335,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 +371,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 +388,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)); +} | 
