diff options
Diffstat (limited to 'subversion/libsvn_fs_fs/fs_fs.c')
-rw-r--r-- | subversion/libsvn_fs_fs/fs_fs.c | 170 |
1 files changed, 170 insertions, 0 deletions
diff --git a/subversion/libsvn_fs_fs/fs_fs.c b/subversion/libsvn_fs_fs/fs_fs.c index 5cb1362d84515..76b053e232296 100644 --- a/subversion/libsvn_fs_fs/fs_fs.c +++ b/subversion/libsvn_fs_fs/fs_fs.c @@ -37,6 +37,7 @@ #include "cached_data.h" #include "id.h" #include "index.h" +#include "low_level.h" #include "rep-cache.h" #include "revprops.h" #include "transaction.h" @@ -2343,3 +2344,172 @@ svn_fs_fs__info_config_files(apr_array_header_t **files, result_pool); return SVN_NO_ERROR; } + +static svn_error_t * +ensure_representation_sha1(svn_fs_t *fs, + representation_t *rep, + apr_pool_t *pool) +{ + if (!rep->has_sha1) + { + svn_stream_t *contents; + svn_checksum_t *checksum; + + SVN_ERR(svn_fs_fs__get_contents(&contents, fs, rep, FALSE, pool)); + SVN_ERR(svn_stream_contents_checksum(&checksum, contents, + svn_checksum_sha1, pool, pool)); + + memcpy(rep->sha1_digest, checksum->digest, APR_SHA1_DIGESTSIZE); + rep->has_sha1 = TRUE; + } + + return SVN_NO_ERROR; +} + +static svn_error_t * +reindex_node(svn_fs_t *fs, + const svn_fs_id_t *id, + svn_revnum_t rev, + svn_fs_fs__revision_file_t *rev_file, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool) +{ + node_revision_t *noderev; + apr_off_t offset; + + if (svn_fs_fs__id_rev(id) != rev) + { + return SVN_NO_ERROR; + } + + if (cancel_func) + SVN_ERR(cancel_func(cancel_baton)); + + SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL, + svn_fs_fs__id_item(id), pool)); + + SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool)); + SVN_ERR(svn_fs_fs__read_noderev(&noderev, rev_file->stream, + pool, pool)); + + /* Make sure EXPANDED_SIZE has the correct value for every rep. */ + SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->data_rep, pool)); + SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->prop_rep, pool)); + + /* First reindex sub-directory to match write_final_rev() behavior. */ + if (noderev->kind == svn_node_dir) + { + apr_array_header_t *entries; + + SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev, pool, pool)); + + if (entries->nelts > 0) + { + int i; + apr_pool_t *iterpool; + + iterpool = svn_pool_create(pool); + for (i = 0; i < entries->nelts; i++) + { + const svn_fs_dirent_t *dirent; + + svn_pool_clear(iterpool); + + dirent = APR_ARRAY_IDX(entries, i, svn_fs_dirent_t *); + + SVN_ERR(reindex_node(fs, dirent->id, rev, rev_file, + cancel_func, cancel_baton, iterpool)); + } + svn_pool_destroy(iterpool); + } + } + + if (noderev->data_rep && noderev->data_rep->revision == rev && + noderev->kind == svn_node_file) + { + SVN_ERR(ensure_representation_sha1(fs, noderev->data_rep, pool)); + SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->data_rep, pool)); + } + + if (noderev->prop_rep && noderev->prop_rep->revision == rev) + { + SVN_ERR(ensure_representation_sha1(fs, noderev->prop_rep, pool)); + SVN_ERR(svn_fs_fs__set_rep_reference(fs, noderev->prop_rep, pool)); + } + + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__build_rep_cache(svn_fs_t *fs, + svn_revnum_t start_rev, + svn_revnum_t end_rev, + svn_fs_progress_notify_func_t progress_func, + void *progress_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *pool) +{ + fs_fs_data_t *ffd = fs->fsap_data; + apr_pool_t *iterpool; + svn_revnum_t rev; + + if (ffd->format < SVN_FS_FS__MIN_REP_SHARING_FORMAT) + { + return svn_error_createf(SVN_ERR_FS_REP_SHARING_NOT_SUPPORTED, NULL, + _("FSFS format (%d) too old for rep-sharing; " + "please upgrade the filesystem."), + ffd->format); + } + + if (!ffd->rep_sharing_allowed) + { + return svn_error_create(SVN_ERR_FS_REP_SHARING_NOT_ALLOWED, NULL, + _("Filesystem does not allow rep-sharing.")); + } + + /* Do not build rep-cache for revision zero to match + * svn_fs_fs__create() behavior. */ + if (start_rev == SVN_INVALID_REVNUM) + start_rev = 1; + + if (end_rev == SVN_INVALID_REVNUM) + SVN_ERR(svn_fs_fs__youngest_rev(&end_rev, fs, pool)); + + /* Do nothing for empty FS. */ + if (start_rev > end_rev) + { + return SVN_NO_ERROR; + } + + if (!ffd->rep_cache_db) + SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool)); + + iterpool = svn_pool_create(pool); + for (rev = start_rev; rev <= end_rev; rev++) + { + svn_fs_id_t *root_id; + svn_fs_fs__revision_file_t *file; + svn_error_t *err; + + svn_pool_clear(iterpool); + + if (progress_func) + progress_func(rev, progress_baton, iterpool); + + SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&file, fs, rev, + iterpool, iterpool)); + SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, rev, iterpool, iterpool)); + + SVN_ERR(svn_sqlite__begin_transaction(ffd->rep_cache_db)); + err = reindex_node(fs, root_id, rev, file, cancel_func, cancel_baton, iterpool); + SVN_ERR(svn_sqlite__finish_transaction(ffd->rep_cache_db, err)); + + SVN_ERR(svn_fs_fs__close_revision_file(file)); + } + + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} |