diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2020-05-31 20:58:28 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2020-05-31 20:58:28 +0000 |
commit | bbee6e0814d5875b85b81f26fd4ca7a28b6f9570 (patch) | |
tree | 726fcf32b39ca8976d7aa51b67c7236509f1bde4 /subversion/libsvn_fs_fs | |
parent | 38cef28c88864beaadac7a7cffdec6da952c3eb2 (diff) | |
download | src-bbee6e0814d5875b85b81f26fd4ca7a28b6f9570.tar.gz src-bbee6e0814d5875b85b81f26fd4ca7a28b6f9570.zip |
Vendor import svn-1.14.0.vendor/subversion/subversion-1.14.0vendor/subversion
Notes
Notes:
svn path=/vendor/subversion/dist/; revision=361669
svn path=/vendor/subversion/subversion-1.14.0/; revision=361670; tag=vendor/subversion/subversion-1.14.0
Diffstat (limited to 'subversion/libsvn_fs_fs')
25 files changed, 576 insertions, 84 deletions
diff --git a/subversion/libsvn_fs_fs/cached_data.c b/subversion/libsvn_fs_fs/cached_data.c index 1bd82481daa6..9778dba908f0 100644 --- a/subversion/libsvn_fs_fs/cached_data.c +++ b/subversion/libsvn_fs_fs/cached_data.c @@ -2337,7 +2337,7 @@ svn_fs_fs__get_contents_from_file(svn_stream_t **contents_p, rb->filehandle_pool)); /* Insert the access to REP as the first element of the delta chain. */ - svn_sort__array_insert(rb->rs_list, &rs, 0); + SVN_ERR(svn_sort__array_insert2(rb->rs_list, &rs, 0)); } /* Now, the baton is complete and we can assemble the stream around it. */ diff --git a/subversion/libsvn_fs_fs/cached_data.h b/subversion/libsvn_fs_fs/cached_data.h index 7b25fcf43cda..cdf3bfbc166f 100644 --- a/subversion/libsvn_fs_fs/cached_data.h +++ b/subversion/libsvn_fs_fs/cached_data.h @@ -171,7 +171,7 @@ svn_fs_fs__get_proplist(apr_hash_t **proplist, apr_pool_t *pool); /* Create a changes retrieval context object in *RESULT_POOL and return it - * in *CONTEXT. It will allow svn_fs_x__get_changes to fetch consecutive + * in *CONTEXT. It will allow svn_fs_fs__get_changes to fetch consecutive * blocks (one per invocation) from REV's changed paths list in FS. */ svn_error_t * svn_fs_fs__create_changes_context(svn_fs_fs__changes_context_t **context, diff --git a/subversion/libsvn_fs_fs/dag.c b/subversion/libsvn_fs_fs/dag.c index 714235dd0ee0..2630af5605cf 100644 --- a/subversion/libsvn_fs_fs/dag.c +++ b/subversion/libsvn_fs_fs/dag.c @@ -1166,7 +1166,7 @@ svn_fs_fs__dag_serialize(void **data, (const void * const *)&node->node_pool); /* serialize other sub-structures */ - svn_fs_fs__id_serialize(context, (const svn_fs_id_t **)&node->id); + svn_fs_fs__id_serialize(context, (const svn_fs_id_t *const *)&node->id); svn_fs_fs__id_serialize(context, &node->fresh_root_predecessor_id); svn_temp_serializer__add_string(context, &node->created_path); diff --git a/subversion/libsvn_fs_fs/dump-index.c b/subversion/libsvn_fs_fs/dump-index.c index c97be10a41fc..c62622b6491b 100644 --- a/subversion/libsvn_fs_fs/dump-index.c +++ b/subversion/libsvn_fs_fs/dump-index.c @@ -21,8 +21,8 @@ */ #include "svn_pools.h" -#include "private/svn_fs_fs_private.h" +#include "fs_fs.h" #include "index.h" #include "rev_file.h" #include "util.h" diff --git a/subversion/libsvn_fs_fs/fs.c b/subversion/libsvn_fs_fs/fs.c index 508ecdbaba33..5174da2e4941 100644 --- a/subversion/libsvn_fs_fs/fs.c +++ b/subversion/libsvn_fs_fs/fs.c @@ -47,6 +47,7 @@ #include "verify.h" #include "svn_private_config.h" #include "private/svn_fs_util.h" +#include "private/svn_fs_fs_private.h" #include "../libsvn_fs/fs-loader.h" @@ -254,6 +255,83 @@ fs_set_uuid(svn_fs_t *fs, } +static svn_error_t * +fs_ioctl(svn_fs_t *fs, svn_fs_ioctl_code_t ctlcode, + void *input_void, void **output_p, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + if (strcmp(ctlcode.fs_type, SVN_FS_TYPE_FSFS) == 0) + { + if (ctlcode.code == SVN_FS_FS__IOCTL_GET_STATS.code) + { + svn_fs_fs__ioctl_get_stats_input_t *input = input_void; + svn_fs_fs__ioctl_get_stats_output_t *output; + + output = apr_pcalloc(result_pool, sizeof(*output)); + SVN_ERR(svn_fs_fs__get_stats(&output->stats, fs, + input->progress_func, + input->progress_baton, + cancel_func, cancel_baton, + result_pool, scratch_pool)); + *output_p = output; + return SVN_NO_ERROR; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_DUMP_INDEX.code) + { + svn_fs_fs__ioctl_dump_index_input_t *input = input_void; + + SVN_ERR(svn_fs_fs__dump_index(fs, input->revision, + input->callback_func, + input->callback_baton, + cancel_func, cancel_baton, + scratch_pool)); + *output_p = NULL; + return SVN_NO_ERROR; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_LOAD_INDEX.code) + { + svn_fs_fs__ioctl_load_index_input_t *input = input_void; + + SVN_ERR(svn_fs_fs__load_index(fs, input->revision, input->entries, + scratch_pool)); + *output_p = NULL; + return SVN_NO_ERROR; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_REVISION_SIZE.code) + { + svn_fs_fs__ioctl_revision_size_input_t *input = input_void; + svn_fs_fs__ioctl_revision_size_output_t *output + = apr_pcalloc(result_pool, sizeof(*output)); + + SVN_ERR(svn_fs_fs__revision_size(&output->rev_size, + fs, input->revision, + scratch_pool)); + *output_p = output; + return SVN_NO_ERROR; + } + else if (ctlcode.code == SVN_FS_FS__IOCTL_BUILD_REP_CACHE.code) + { + svn_fs_fs__ioctl_build_rep_cache_input_t *input = input_void; + + SVN_ERR(svn_fs_fs__build_rep_cache(fs, + input->start_rev, + input->end_rev, + input->progress_func, + input->progress_baton, + cancel_func, + cancel_baton, + scratch_pool)); + + *output_p = NULL; + return SVN_NO_ERROR; + } + } + + return svn_error_create(SVN_ERR_FS_UNRECOGNIZED_IOCTL_CODE, NULL, NULL); +} /* The vtable associated with a specific open filesystem. */ static fs_vtable_t fs_vtable = { @@ -279,7 +357,8 @@ static fs_vtable_t fs_vtable = { fs_info, svn_fs_fs__verify_root, fs_freeze, - fs_set_errcall + fs_set_errcall, + fs_ioctl }; @@ -602,7 +681,8 @@ static fs_library_vtable_t library_vtable = { fs_logfiles, NULL /* parse_id */, fs_set_svn_fs_open, - fs_info_dup + fs_info_dup, + NULL /* ioctl */ }; svn_error_t * diff --git a/subversion/libsvn_fs_fs/fs_fs.c b/subversion/libsvn_fs_fs/fs_fs.c index 5cb1362d8451..76b053e23229 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; +} diff --git a/subversion/libsvn_fs_fs/fs_fs.h b/subversion/libsvn_fs_fs/fs_fs.h index cef95fe3209e..b233be1b2ea1 100644 --- a/subversion/libsvn_fs_fs/fs_fs.h +++ b/subversion/libsvn_fs_fs/fs_fs.h @@ -304,4 +304,75 @@ svn_fs_fs__initialize_txn_caches(svn_fs_t *fs, void svn_fs_fs__reset_txn_caches(svn_fs_t *fs); +/* Scan all contents of the repository FS and return statistics in *STATS, + * allocated in RESULT_POOL. Report progress through PROGRESS_FUNC with + * PROGRESS_BATON, if PROGRESS_FUNC is not NULL. + * Use SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats, + svn_fs_t *fs, + svn_fs_progress_notify_func_t progress_func, + void *progress_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Read the P2L index for the rev / pack file containing REVISION in FS. + * For each index entry, invoke CALLBACK_FUNC with CALLBACK_BATON. + * If not NULL, call CANCEL_FUNC with CANCEL_BATON from time to time. + * Use SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_fs__dump_index(svn_fs_t *fs, + svn_revnum_t revision, + svn_fs_fs__dump_index_func_t callback_func, + void *callback_baton, + svn_cancel_func_t cancel_func, + void *cancel_baton, + apr_pool_t *scratch_pool); + + +/* Rewrite the respective index information of the rev / pack file in FS + * containing REVISION and use the svn_fs_fs__p2l_entry_t * array ENTRIES + * as the new index contents. Allocate temporaries from SCRATCH_POOL. + * + * Note that this becomes a no-op if ENTRIES is empty. You may use a zero- + * sized empty entry instead. + */ +svn_error_t * +svn_fs_fs__load_index(svn_fs_t *fs, + svn_revnum_t revision, + apr_array_header_t *entries, + apr_pool_t *scratch_pool); + +/* Set *REV_SIZE to the total size of objects belonging to revision REVISION + * in FS. The size includes revision properties and excludes indexes. + */ +svn_error_t * +svn_fs_fs__revision_size(apr_off_t *rev_size, + svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool); + +/* Add missing entries to the rep-cache on the filesystem FS. Process data + * in revisions START_REV through END_REV inclusive. If START_REV is + * SVN_INVALID_REVNUM, start at revision 1; if END_REV is SVN_INVALID_REVNUM, + * end at the head revision. If the rep-cache does not exist, then create it. + * + * Indicate progress via the optional PROGRESS_FUNC callback using + * PROGRESS_BATON. The optional CANCEL_FUNC will periodically be called with + * CANCEL_BATON to allow cancellation. Use POOL for temporary allocations. + */ +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); + #endif diff --git a/subversion/libsvn_fs_fs/id.c b/subversion/libsvn_fs_fs/id.c index d22b8f776359..5f2730305a06 100644 --- a/subversion/libsvn_fs_fs/id.c +++ b/subversion/libsvn_fs_fs/id.c @@ -591,7 +591,8 @@ svn_fs_fs__id_parse(const svn_fs_id_t **id_p, svn_fs_id_t *id = id_parse(data, pool); if (id == NULL) return svn_error_createf(SVN_ERR_FS_MALFORMED_NODEREV_ID, NULL, - "Malformed node revision ID string"); + "Malformed node revision ID string '%s'", + data); *id_p = id; diff --git a/subversion/libsvn_fs_fs/index.c b/subversion/libsvn_fs_fs/index.c index 1cb8fba80ad6..b7ba79f96313 100644 --- a/subversion/libsvn_fs_fs/index.c +++ b/subversion/libsvn_fs_fs/index.c @@ -3191,9 +3191,9 @@ compare_p2l_entry_revision(const void *lhs, const void *rhs) { const svn_fs_fs__p2l_entry_t *lhs_entry - =*(const svn_fs_fs__p2l_entry_t **)lhs; + =*(const svn_fs_fs__p2l_entry_t *const *)lhs; const svn_fs_fs__p2l_entry_t *rhs_entry - =*(const svn_fs_fs__p2l_entry_t **)rhs; + =*(const svn_fs_fs__p2l_entry_t *const *)rhs; if (lhs_entry->item.revision < rhs_entry->item.revision) return -1; diff --git a/subversion/libsvn_fs_fs/libsvn_fs_fs.pc.in b/subversion/libsvn_fs_fs/libsvn_fs_fs.pc.in index 324a709eedea..2a2d624d9b21 100644 --- a/subversion/libsvn_fs_fs/libsvn_fs_fs.pc.in +++ b/subversion/libsvn_fs_fs/libsvn_fs_fs.pc.in @@ -6,7 +6,7 @@ includedir=@includedir@ Name: libsvn_fs_fs Description: Subversion FSFS Repository Filesystem Library Version: @PACKAGE_VERSION@ -Requires: apr-util-@SVN_APR_MAJOR_VERSION@ apr-@SVN_APR_MAJOR_VERSION@ -Requires.private: libsvn_delta libsvn_subr libsvn_fs_util -Libs: -L${libdir} -lsvn_fs_fs -Cflags: -I${includedir} +Requires: apr-util-@SVN_APR_MAJOR_VERSION@, apr-@SVN_APR_MAJOR_VERSION@ +Requires.private: libsvn_delta, libsvn_subr, libsvn_fs_util +Libs: -L${libdir} -lsvn_fs_fs-1 +Cflags: -I${includedir}/subversion-1 diff --git a/subversion/libsvn_fs_fs/load-index.c b/subversion/libsvn_fs_fs/load-index.c index 0ba66725d35c..8608cb204dd2 100644 --- a/subversion/libsvn_fs_fs/load-index.c +++ b/subversion/libsvn_fs_fs/load-index.c @@ -22,9 +22,9 @@ #include "svn_pools.h" -#include "private/svn_fs_fs_private.h" #include "private/svn_sorts_private.h" +#include "fs_fs.h" #include "index.h" #include "util.h" #include "transaction.h" @@ -83,9 +83,9 @@ compare_p2l_entry_revision(const void *lhs, const void *rhs) { const svn_fs_fs__p2l_entry_t *lhs_entry - =*(const svn_fs_fs__p2l_entry_t **)lhs; + =*(const svn_fs_fs__p2l_entry_t *const *)lhs; const svn_fs_fs__p2l_entry_t *rhs_entry - =*(const svn_fs_fs__p2l_entry_t **)rhs; + =*(const svn_fs_fs__p2l_entry_t *const *)rhs; if (lhs_entry->offset < rhs_entry->offset) return -1; diff --git a/subversion/libsvn_fs_fs/low_level.c b/subversion/libsvn_fs_fs/low_level.c index 2854bc6e2d84..906f47fc22dc 100644 --- a/subversion/libsvn_fs_fs/low_level.c +++ b/subversion/libsvn_fs_fs/low_level.c @@ -254,10 +254,10 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_offset, "P2L offset %s must be larger than L2P offset %s" " in r%ld footer", apr_psprintf(result_pool, - "%" APR_UINT64_T_HEX_FMT, + "0x%" APR_UINT64_T_HEX_FMT, (apr_uint64_t)*p2l_offset), apr_psprintf(result_pool, - "%" APR_UINT64_T_HEX_FMT, + "0x%" APR_UINT64_T_HEX_FMT, (apr_uint64_t)*l2p_offset), rev); @@ -506,7 +506,7 @@ svn_fs_fs__read_changes(apr_array_header_t **changes, SVN_ERR(read_change(&change, stream, result_pool, iterpool)); if (!change) break; - + APR_ARRAY_PUSH(*changes, change_t*) = change; } svn_pool_destroy(iterpool); @@ -670,7 +670,7 @@ svn_fs_fs__write_changes(svn_stream_t *stream, } if (terminate_list) - svn_stream_puts(stream, "\n"); + SVN_ERR(svn_stream_puts(stream, "\n")); svn_pool_destroy(iterpool); diff --git a/subversion/libsvn_fs_fs/pack.c b/subversion/libsvn_fs_fs/pack.c index 1119857998fc..c9e2b4dd4e55 100644 --- a/subversion/libsvn_fs_fs/pack.c +++ b/subversion/libsvn_fs_fs/pack.c @@ -315,12 +315,12 @@ initialize_pack_context(pack_context_t *context, context->file_props = apr_array_make(pool, max_items, sizeof(svn_fs_fs__p2l_entry_t *)); SVN_ERR(svn_io_open_unique_file3(&context->file_props_file, NULL, temp_dir, - svn_io_file_del_on_close, + svn_io_file_del_on_close, context->info_pool, pool)); context->dir_props = apr_array_make(pool, max_items, sizeof(svn_fs_fs__p2l_entry_t *)); SVN_ERR(svn_io_open_unique_file3(&context->dir_props_file, NULL, temp_dir, - svn_io_file_del_on_close, + svn_io_file_del_on_close, context->info_pool, pool)); /* noderev and representation item bucket */ @@ -2067,9 +2067,9 @@ pack_body(void *baton, if (fully_packed) { if (pb->notify_func) - (*pb->notify_func)(pb->notify_baton, - ffd->min_unpacked_rev / ffd->max_files_per_dir, - svn_fs_pack_notify_noop, pool); + SVN_ERR(pb->notify_func(pb->notify_baton, + ffd->min_unpacked_rev / ffd->max_files_per_dir, + svn_fs_pack_notify_noop, pool)); return SVN_NO_ERROR; } @@ -2122,7 +2122,7 @@ svn_fs_fs__pack(svn_fs_t *fs, if (!ffd->max_files_per_dir) { if (notify_func) - (*notify_func)(notify_baton, -1, svn_fs_pack_notify_noop, pool); + SVN_ERR(notify_func(notify_baton, -1, svn_fs_pack_notify_noop, pool)); return SVN_NO_ERROR; } @@ -2132,9 +2132,9 @@ svn_fs_fs__pack(svn_fs_t *fs, if (fully_packed) { if (notify_func) - (*notify_func)(notify_baton, - ffd->min_unpacked_rev / ffd->max_files_per_dir, - svn_fs_pack_notify_noop, pool); + SVN_ERR(notify_func(notify_baton, + ffd->min_unpacked_rev / ffd->max_files_per_dir, + svn_fs_pack_notify_noop, pool)); return SVN_NO_ERROR; } diff --git a/subversion/libsvn_fs_fs/recovery.c b/subversion/libsvn_fs_fs/recovery.c index eef06f65942a..09030f4e6f97 100644 --- a/subversion/libsvn_fs_fs/recovery.c +++ b/subversion/libsvn_fs_fs/recovery.c @@ -471,9 +471,15 @@ recover_body(void *baton, apr_pool_t *pool) } /* Prune younger-than-(newfound-youngest) revisions from the rep - cache if sharing is enabled taking care not to create the cache - if it does not exist. */ - if (ffd->rep_sharing_allowed) + cache, taking care not to create the cache if it does not exist. + + We do this whenever rep-cache.db exists, whether it's currently enabled + or not, to prevent a data loss that could result from having revisions + created after this 'recover' operation referring to rep-cache.db rows + that were created before the recover and that point to revisions younger- + than-(newfound-youngest). + */ + if (ffd->format >= SVN_FS_FS__MIN_REP_SHARING_FORMAT) { svn_boolean_t rep_cache_exists; diff --git a/subversion/libsvn_fs_fs/rep-cache-db.h b/subversion/libsvn_fs_fs/rep-cache-db.h index e66253810c9d..4cad0667a8fe 100644 --- a/subversion/libsvn_fs_fs/rep-cache-db.h +++ b/subversion/libsvn_fs_fs/rep-cache-db.h @@ -1,4 +1,4 @@ -/* This file is automatically generated from rep-cache-db.sql and subversion/libsvn_fs_fs/token-map.h. +/* This file is automatically generated from rep-cache-db.sql and token-map.h. * Do not edit this file -- edit the source and rerun gen-make.py */ #define STMT_CREATE_SCHEMA_V1 0 @@ -38,7 +38,7 @@ #define STMT_SET_REP 3 #define STMT_3_INFO {"STMT_SET_REP", NULL} #define STMT_3 \ - "INSERT OR FAIL INTO rep_cache (hash, revision, offset, size, expanded_size) " \ + "INSERT OR IGNORE INTO rep_cache (hash, revision, offset, size, expanded_size) " \ "VALUES (?1, ?2, ?3, ?4, ?5) " \ "" diff --git a/subversion/libsvn_fs_fs/rep-cache-db.sql b/subversion/libsvn_fs_fs/rep-cache-db.sql index cd89f35c63ee..a700a9dcd026 100644 --- a/subversion/libsvn_fs_fs/rep-cache-db.sql +++ b/subversion/libsvn_fs_fs/rep-cache-db.sql @@ -61,7 +61,7 @@ WHERE hash = ?1 -- STMT_SET_REP /* Works for both V1 and V2 schemas. */ -INSERT OR FAIL INTO rep_cache (hash, revision, offset, size, expanded_size) +INSERT OR IGNORE INTO rep_cache (hash, revision, offset, size, expanded_size) VALUES (?1, ?2, ?3, ?4, ?5) -- STMT_GET_REPS_FOR_RANGE diff --git a/subversion/libsvn_fs_fs/rep-cache.c b/subversion/libsvn_fs_fs/rep-cache.c index b0b81fad9ac3..c51cde3954b4 100644 --- a/subversion/libsvn_fs_fs/rep-cache.c +++ b/subversion/libsvn_fs_fs/rep-cache.c @@ -328,7 +328,6 @@ svn_fs_fs__set_rep_reference(svn_fs_t *fs, { 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; @@ -351,28 +350,7 @@ svn_fs_fs__set_rep_reference(svn_fs_t *fs, (apr_int64_t) rep->size, (apr_int64_t) rep->expanded_size)); - err = svn_sqlite__insert(NULL, stmt); - if (err) - { - representation_t *old_rep; - - if (err->apr_err != SVN_ERR_SQLITE_CONSTRAINT) - return svn_error_trace(err); - - svn_error_clear(err); - - /* Constraint failed so the mapping for SHA1_CHECKSUM->REP - 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) - { - /* Something really odd at this point, we failed to insert the - checksum AND failed to read an existing checksum. Do we need - to flag this? */ - } - } + SVN_ERR(svn_sqlite__insert(NULL, stmt)); return SVN_NO_ERROR; } diff --git a/subversion/libsvn_fs_fs/revprops.c b/subversion/libsvn_fs_fs/revprops.c index 6d41fd882d7e..bba40ce82027 100644 --- a/subversion/libsvn_fs_fs/revprops.c +++ b/subversion/libsvn_fs_fs/revprops.c @@ -261,7 +261,7 @@ cache_revprops(svn_boolean_t *is_cached, } /* Read the non-packed revprops for revision REV in FS, put them into the - * revprop cache if PROPULATE_CACHE is set and return them in *PROPERTIES. + * revprop cache if PROPULATE_CACHE is set and return them in *PROPERTIES. * * If the data could not be read due to an otherwise recoverable error, * leave *PROPERTIES unchanged. No error will be returned in that case. @@ -672,6 +672,64 @@ read_pack_revprop(packed_revprops_t **revprops, return SVN_NO_ERROR; } +svn_error_t * +svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *scratch_pool) +{ + fs_fs_data_t *ffd = fs->fsap_data; + + /* should they be available at all? */ + SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, scratch_pool)); + + /* if REV had not been packed when we began, try reading it from the + * non-packed shard. If that fails, we will fall through to packed + * shard reads. */ + if (!svn_fs_fs__is_packed_revprop(fs, rev)) + { + const char *path = svn_fs_fs__path_revprops(fs, rev, scratch_pool); + svn_error_t *err; + apr_file_t *file; + svn_filesize_t file_size; + + err = svn_io_file_open(&file, path, APR_FOPEN_READ, APR_OS_DEFAULT, + scratch_pool); + if (!err) + err = svn_io_file_size_get(&file_size, file, scratch_pool); + if (!err) + { + *props_size_p = (apr_off_t)file_size; + return SVN_NO_ERROR; + } + else if (!APR_STATUS_IS_ENOENT(err->apr_err) + || ffd->format < SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT) + { + return svn_error_trace(err); + } + + /* fall through: maybe the revision got packed while we were looking */ + svn_error_clear(err); + } + + /* Try reading packed revprops. If that fails, REV is most + * likely invalid (or its revprops highly contested). */ + { + packed_revprops_t *revprops; + + /* ### This is inefficient -- reading all the revprops in a pack. We + should just read the index. */ + SVN_ERR(read_pack_revprop(&revprops, fs, rev, + TRUE /*read_all*/, FALSE /*populate_cache*/, + scratch_pool)); + *props_size_p = (apr_off_t)APR_ARRAY_IDX(revprops->sizes, + rev - revprops->start_revision, + apr_size_t); + } + + return SVN_NO_ERROR; +} + /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P. * * Allocations will be done in POOL. diff --git a/subversion/libsvn_fs_fs/revprops.h b/subversion/libsvn_fs_fs/revprops.h index 37063f96e9ae..32df18387a68 100644 --- a/subversion/libsvn_fs_fs/revprops.h +++ b/subversion/libsvn_fs_fs/revprops.h @@ -62,6 +62,15 @@ svn_fs_fs__upgrade_cleanup_pack_revprops(svn_fs_t *fs, void svn_fs_fs__reset_revprop_cache(svn_fs_t *fs); +/* Set *PROPS_SIZE_P to the size in bytes on disk of the revprops for + * revision REV in FS. The size excludes indexes. + */ +svn_error_t * +svn_fs_fs__get_revision_props_size(apr_off_t *props_size_p, + svn_fs_t *fs, + svn_revnum_t rev, + apr_pool_t *scratch_pool); + /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P. * If REFRESH is set, clear the revprop cache before accessing the data. * diff --git a/subversion/libsvn_fs_fs/stats.c b/subversion/libsvn_fs_fs/stats.c index 36992dbaeb66..98a421f20a86 100644 --- a/subversion/libsvn_fs_fs/stats.c +++ b/subversion/libsvn_fs_fs/stats.c @@ -28,7 +28,6 @@ #include "private/svn_cache.h" #include "private/svn_sorts_private.h" #include "private/svn_string_private.h" -#include "private/svn_fs_fs_private.h" #include "index.h" #include "pack.h" @@ -37,6 +36,7 @@ #include "fs_fs.h" #include "cached_data.h" #include "low_level.h" +#include "revprops.h" #include "../libsvn_fs/fs-loader.h" @@ -488,7 +488,7 @@ parse_representation(rep_stats_t **representation, } } - svn_sort__array_insert(revision_info->representations, &result, idx); + SVN_ERR(svn_sort__array_insert2(revision_info->representations, &result, idx)); } *representation = result; @@ -1397,3 +1397,96 @@ svn_fs_fs__get_stats(svn_fs_fs__stats_t **stats, return SVN_NO_ERROR; } + +/* Baton for rev_size_index_entry_cb. */ +struct rev_size_baton_t { + svn_revnum_t revision; + apr_off_t rev_size; +}; + +/* Implements svn_fs_fs__dump_index_func_t, summing object sizes for + * revision BATON->revision into BATON->rev_size. + */ +static svn_error_t * +rev_size_index_entry_cb(const svn_fs_fs__p2l_entry_t *entry, + void *baton, + apr_pool_t *scratch_pool) +{ + struct rev_size_baton_t *b = baton; + + if (entry->item.revision == b->revision) + b->rev_size += entry->size; + return SVN_NO_ERROR; +} + +svn_error_t * +svn_fs_fs__revision_size(apr_off_t *rev_size, + svn_fs_t *fs, + svn_revnum_t revision, + apr_pool_t *scratch_pool) +{ + /* Get the size of the revision (excluding rev-props) */ + if (svn_fs_fs__use_log_addressing(fs)) + { + /* This works for a packed or a non-packed revision. + We could provide an optimized case for a non-packed revision + using svn_fs_fs__p2l_get_max_offset(). */ + struct rev_size_baton_t b = { 0, 0 }; + + b.revision = revision; + SVN_ERR(svn_fs_fs__dump_index(fs, revision, + rev_size_index_entry_cb, &b, + NULL, NULL, scratch_pool)); + *rev_size = b.rev_size; + } + else + { + svn_fs_fs__revision_file_t *rev_file; + svn_revnum_t min_unpacked_rev; + + SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision, + scratch_pool, scratch_pool)); + SVN_ERR(svn_fs_fs__min_unpacked_rev(&min_unpacked_rev, fs, + scratch_pool)); + if (revision < min_unpacked_rev) + { + int shard_size = svn_fs_fs__shard_size(fs); + apr_off_t start_offset, end_offset; + + SVN_ERR(svn_fs_fs__get_packed_offset(&start_offset, fs, revision, + scratch_pool)); + if (((revision + 1) % shard_size) == 0) + { + svn_filesize_t file_size; + + SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool)); + end_offset = (apr_off_t)file_size; + } + else + { + SVN_ERR(svn_fs_fs__get_packed_offset(&end_offset, fs, + revision + 1, scratch_pool)); + } + *rev_size = (end_offset - start_offset); + } + else + { + svn_filesize_t file_size; + + SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool)); + *rev_size = (apr_off_t)file_size; + } + + SVN_ERR(svn_fs_fs__close_revision_file(rev_file)); + } + + /* Add the size of the rev-props */ + { + apr_off_t size; + + SVN_ERR(svn_fs_fs__get_revision_props_size(&size, fs, revision, scratch_pool)); + *rev_size += size; + } + + return SVN_NO_ERROR; +} diff --git a/subversion/libsvn_fs_fs/temp_serializer.c b/subversion/libsvn_fs_fs/temp_serializer.c index f6e9e3a0971c..b4f6b86d8ed1 100644 --- a/subversion/libsvn_fs_fs/temp_serializer.c +++ b/subversion/libsvn_fs_fs/temp_serializer.c @@ -1013,13 +1013,13 @@ slowly_replace_dir_entry(void **data, APR_ARRAY_IDX(entries, idx, svn_fs_dirent_t *) = replace_baton->new_entry; else - svn_sort__array_insert(entries, &replace_baton->new_entry, idx); + SVN_ERR(svn_sort__array_insert2(entries, &replace_baton->new_entry, idx)); } else { /* Remove the old ENTRY. */ if (entry) - svn_sort__array_delete(entries, idx, 1); + SVN_ERR(svn_sort__array_delete2(entries, idx, 1)); } return svn_fs_fs__serialize_dir_entries(data, data_len, dir, pool); diff --git a/subversion/libsvn_fs_fs/temp_serializer.h b/subversion/libsvn_fs_fs/temp_serializer.h index 187c8d000206..32bb554ba87c 100644 --- a/subversion/libsvn_fs_fs/temp_serializer.h +++ b/subversion/libsvn_fs_fs/temp_serializer.h @@ -53,7 +53,7 @@ svn_fs_fs__noderev_deserialize(void *buffer, /** * Adds position information to the raw window data in WINDOW. */ -typedef struct +typedef struct svn_fs_fs__raw_cached_window_t { /* the (unprocessed) txdelta window byte sequence cached / to be cached */ svn_string_t window; @@ -89,7 +89,7 @@ svn_fs_fs__deserialize_raw_window(void **item, * #svn_txdelta_window_t is not sufficient for caching the data it * represents because data read process needs auxiliary information. */ -typedef struct +typedef struct svn_fs_fs__txdelta_cached_window_t { /* the txdelta window information cached / to be cached */ svn_txdelta_window_t *window; @@ -377,7 +377,7 @@ typedef struct svn_fs_fs__changes_list_t of elements in the list is a multiple of our block / range size. */ svn_boolean_t eol; - /* Array of #svn_fs_x__change_t * representing a consecutive sub-range of + /* Array of #svn_fs_fs__change_t * representing a consecutive sub-range of elements in a changed paths list. */ /* number of entries in the array */ diff --git a/subversion/libsvn_fs_fs/transaction.c b/subversion/libsvn_fs_fs/transaction.c index eb6fefaeae22..9e1e40c86ce9 100644 --- a/subversion/libsvn_fs_fs/transaction.c +++ b/subversion/libsvn_fs_fs/transaction.c @@ -587,7 +587,7 @@ unparse_dir_entry(svn_fs_dirent_t *dirent, : sizeof(SVN_FS_FS__KIND_DIR); apr_size_t value_len = type_len + id_str->len; - /* A buffer with sufficient space for + /* A buffer with sufficient space for * - both string lines * - 4 newlines * - 2 lines K/V lines containing a number each diff --git a/subversion/libsvn_fs_fs/tree.c b/subversion/libsvn_fs_fs/tree.c index 76209f368bf9..764052b3fa89 100644 --- a/subversion/libsvn_fs_fs/tree.c +++ b/subversion/libsvn_fs_fs/tree.c @@ -920,6 +920,25 @@ try_match_last_node(dag_node_t **node_p, return SVN_NO_ERROR; } +/* Helper for open_path() that constructs and returns an appropriate + SVN_ERR_FS_NOT_DIRECTORY error. */ +static svn_error_t * +err_not_directory(svn_fs_root_t *root, + const char *path, + apr_pool_t *scratch_pool) +{ + const char *msg; + + msg = root->is_txn_root + ? apr_psprintf(scratch_pool, + _("Failure opening '%s' in transaction '%s'"), + path, root->txn) + : apr_psprintf(scratch_pool, + _("Failure opening '%s' in revision %ld"), + path, root->rev); + + return svn_error_quick_wrap(SVN_FS__ERR_NOT_DIRECTORY(root->fs, path), msg); +} /* Open the node identified by PATH in ROOT, allocating in POOL. Set *PARENT_PATH_P to a path from the node up to ROOT. The resulting @@ -1016,12 +1035,26 @@ open_path(parent_path_t **parent_path_p, SVN_ERR(dag_node_cache_get(&here, root, directory, pool)); /* Did the shortcut work? */ - if (here) + if (here && svn_fs_fs__dag_node_kind(here) == svn_node_dir) { apr_size_t dirname_len = strlen(directory); path_so_far->len = dirname_len; rest = path + dirname_len + 1; } + else if (here) + { + /* The parent node is not a directory. We are looking for some + sub-path, so that sub-path will not exist. That will be o.k. + if we are just here to check for the path's existence, but + should result in an error otherwise. */ + if (flags & open_path_allow_null) + { + *parent_path_p = NULL; + return SVN_NO_ERROR; + } + else + return svn_error_trace(err_not_directory(root, directory, pool)); + } } } @@ -1144,8 +1177,6 @@ open_path(parent_path_t **parent_path_p, /* The path isn't finished yet; we'd better be in a directory. */ if (svn_fs_fs__dag_node_kind(child) != svn_node_dir) { - const char *msg; - /* Since this is not a directory and we are looking for some sub-path, that sub-path will not exist. That will be o.k., if we are just here to check for the path's existence. */ @@ -1156,14 +1187,8 @@ open_path(parent_path_t **parent_path_p, } /* It's really a problem ... */ - msg = root->is_txn_root - ? apr_psprintf(iterpool, - _("Failure opening '%s' in transaction '%s'"), - path, root->txn) - : apr_psprintf(iterpool, - _("Failure opening '%s' in revision %ld"), - path, root->rev); - SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far->data), msg); + return svn_error_trace( + err_not_directory(root, path_so_far->data, iterpool)); } rest = next; @@ -4619,7 +4644,7 @@ make_txn_root(svn_fs_root_t **root_p, svn_fs_fs__dag_deserialize, APR_HASH_KEY_STRING, 32, 20, FALSE, - apr_pstrcat(pool, txn, ":TXN", + apr_pstrcat(pool, root->txn, ":TXN", SVN_VA_NULL), root->pool)); diff --git a/subversion/libsvn_fs_fs/verify.c b/subversion/libsvn_fs_fs/verify.c index 7fe5ecbbd494..9d70d6cfbc8d 100644 --- a/subversion/libsvn_fs_fs/verify.c +++ b/subversion/libsvn_fs_fs/verify.c @@ -681,10 +681,10 @@ compare_p2l_to_rev(svn_fs_t *fs, NULL, _("p2l index entry for revision r%ld" " at offset %s contains invalid item" - " type %d"), + " type %u"), start, apr_off_t_toa(pool, offset), - entry->type); + (unsigned int)entry->type); /* There can be only one changes entry and that has a fixed type * and item number. Its presence and parse-ability will be checked @@ -694,11 +694,12 @@ compare_p2l_to_rev(svn_fs_t *fs, return svn_error_createf(SVN_ERR_FS_INDEX_CORRUPTION, NULL, _("p2l index entry for changes in" - " revision r%ld is item %ld of type" - " %d at offset %s"), + " revision r%ld is item" + " %"APR_UINT64_T_FMT + " of type %u at offset %s"), entry->item.revision, entry->item.number, - entry->type, + (unsigned int)entry->type, apr_off_t_toa(pool, offset)); /* Check contents. */ |