You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC
svn commit: r1717223 [15/50] - in /subversion/branches/ra-git: ./ build/
build/ac-macros/ build/generator/ build/generator/templates/
contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/
subversion/ subversion/bindings/ctypes-python/...
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.c Mon Nov 30 10:24:16 2015
@@ -622,8 +622,8 @@ svn_fs_fs__write_format(svn_fs_t *fs,
}
else
{
- SVN_ERR(svn_io_write_atomic(path, sb->data, sb->len,
- NULL /* copy_perms_path */, pool));
+ SVN_ERR(svn_io_write_atomic2(path, sb->data, sb->len,
+ NULL /* copy_perms_path */, TRUE, pool));
}
/* And set the perms to make it read only */
@@ -754,8 +754,8 @@ read_config(fs_fs_data_t *ffd,
CONFIG_SECTION_PACKED_REVPROPS,
CONFIG_OPTION_REVPROP_PACK_SIZE,
ffd->compress_packed_revprops
- ? 0x10
- : 0x4));
+ ? 0x40
+ : 0x10));
ffd->revprop_pack_size *= 1024;
}
@@ -962,9 +962,9 @@ write_config(svn_fs_t *fs,
"### latency and CPU usage reading and changing individual revprops." NL
"### Values smaller than 4 kByte will not improve latency any further and " NL
"### quickly render revprop packing ineffective." NL
-"### revprop-pack-size is 4 kBytes by default for non-compressed revprop" NL
-"### pack files and 16 kBytes when compression has been enabled." NL
-"# " CONFIG_OPTION_REVPROP_PACK_SIZE " = 4" NL
+"### revprop-pack-size is 16 kBytes by default for non-compressed revprop" NL
+"### pack files and 64 kBytes when compression has been enabled." NL
+"# " CONFIG_OPTION_REVPROP_PACK_SIZE " = 16" NL
"###" NL
"### To save disk space, packed revprop files may be compressed. Standard" NL
"### revprops tend to allow for very effective compression. Reading and" NL
@@ -1126,7 +1126,9 @@ svn_fs_fs__open(svn_fs_t *fs, const char
/* Global configuration options. */
SVN_ERR(read_global_config(fs));
- return get_youngest(&(ffd->youngest_rev_cache), fs, pool);
+ ffd->youngest_rev_cache = 0;
+
+ return SVN_NO_ERROR;
}
/* Wrapper around svn_io_file_create which ignores EEXIST. */
@@ -1377,41 +1379,31 @@ svn_fs_fs__file_length(svn_filesize_t *l
/* Treat "no representation" as "empty file". */
*length = 0;
}
- else if (data_rep->expanded_size)
+ else
{
- /* Standard case: a non-empty file. */
*length = data_rep->expanded_size;
}
- else
- {
- /* Work around a FSFS format quirk (see issue #4554).
- A plain representation may specify its EXPANDED LENGTH as "0"
- in which case, the SIZE value is what we want.
+ return SVN_NO_ERROR;
+}
+
+svn_boolean_t
+svn_fs_fs__noderev_same_rep_key(representation_t *a,
+ representation_t *b)
+{
+ if (a == b)
+ return TRUE;
+
+ if (a == NULL || b == NULL)
+ return FALSE;
- Because EXPANDED_LENGTH will also be 0 for empty files, while
- SIZE is non-null, we need to check wether the content is
- actually empty. We simply compare with the MD5 checksum of
- empty content (sha-1 is not always available).
- */
- svn_checksum_t *empty_md5
- = svn_checksum_empty_checksum(svn_checksum_md5, pool);
+ if (a->item_index != b->item_index)
+ return FALSE;
- if (memcmp(empty_md5->digest, data_rep->md5_digest,
- sizeof(data_rep->md5_digest)))
- {
- /* Contents is not empty, i.e. EXPANDED_LENGTH cannot be the
- actual file length. */
- *length = data_rep->size;
- }
- else
- {
- /* Contents is empty. */
- *length = 0;
- }
- }
+ if (a->revision != b->revision)
+ return FALSE;
- return SVN_NO_ERROR;
+ return memcmp(&a->uniquifier, &b->uniquifier, sizeof(a->uniquifier)) == 0;
}
svn_error_t *
@@ -1419,14 +1411,13 @@ svn_fs_fs__file_text_rep_equal(svn_boole
svn_fs_t *fs,
node_revision_t *a,
node_revision_t *b,
- svn_boolean_t strict,
apr_pool_t *scratch_pool)
{
svn_stream_t *contents_a, *contents_b;
representation_t *rep_a = a->data_rep;
representation_t *rep_b = b->data_rep;
- svn_boolean_t a_empty = !rep_a || rep_a->expanded_size == 0;
- svn_boolean_t b_empty = !rep_b || rep_b->expanded_size == 0;
+ svn_boolean_t a_empty = !rep_a;
+ svn_boolean_t b_empty = !rep_b;
/* This makes sure that neither rep will be NULL later on */
if (a_empty && b_empty)
@@ -1464,19 +1455,6 @@ svn_fs_fs__file_text_rep_equal(svn_boole
return SVN_NO_ERROR;
}
- /* Old repositories may not have the SHA1 checksum handy.
- This check becomes expensive. Skip it unless explicitly required.
-
- We already have seen that the ID is different, so produce a likely
- false negative as allowed by the API description - even though the
- MD5 matched, there is an extremely slim chance that the SHA1 wouldn't.
- */
- if (!strict)
- {
- *equal = FALSE;
- return SVN_NO_ERROR;
- }
-
SVN_ERR(svn_fs_fs__get_contents(&contents_a, fs, rep_a, TRUE,
scratch_pool));
SVN_ERR(svn_fs_fs__get_contents(&contents_b, fs, rep_b, TRUE,
@@ -1492,7 +1470,6 @@ svn_fs_fs__prop_rep_equal(svn_boolean_t
svn_fs_t *fs,
node_revision_t *a,
node_revision_t *b,
- svn_boolean_t strict,
apr_pool_t *scratch_pool)
{
representation_t *rep_a = a->prop_rep;
@@ -1512,28 +1489,33 @@ svn_fs_fs__prop_rep_equal(svn_boolean_t
&& !svn_fs_fs__id_txn_used(&rep_a->txn_id)
&& !svn_fs_fs__id_txn_used(&rep_b->txn_id))
{
- /* MD5 must be given. Having the same checksum is good enough for
- accepting the prop lists as equal. */
- *equal = memcmp(rep_a->md5_digest, rep_b->md5_digest,
- sizeof(rep_a->md5_digest)) == 0;
- return SVN_NO_ERROR;
+ /* Same representation? */
+ if ( (rep_a->revision == rep_b->revision)
+ && (rep_a->item_index == rep_b->item_index))
+ {
+ *equal = TRUE;
+ return SVN_NO_ERROR;
+ }
+
+ /* Known different content? MD5 must be given. */
+ if (memcmp(rep_a->md5_digest, rep_b->md5_digest,
+ sizeof(rep_a->md5_digest)))
+ {
+ *equal = FALSE;
+ return SVN_NO_ERROR;
+ }
}
- /* Same path in same txn? */
+ /* Same path in same txn?
+ *
+ * For committed reps, IDs cannot be the same here b/c we already know
+ * that they point to different representations. */
if (svn_fs_fs__id_eq(a->id, b->id))
{
*equal = TRUE;
return SVN_NO_ERROR;
}
- /* Skip the expensive bits unless we are in strict mode.
- Simply assume that there is a difference. */
- if (!strict)
- {
- *equal = FALSE;
- return SVN_NO_ERROR;
- }
-
/* At least one of the reps has been modified in a txn.
Fetch and compare them. */
SVN_ERR(svn_fs_fs__get_proplist(&proplist_a, fs, a, scratch_pool));
@@ -1884,9 +1866,9 @@ svn_fs_fs__set_uuid(svn_fs_t *fs,
/* We use the permissions of the 'current' file, because the 'uuid'
file does not exist during repository creation. */
- SVN_ERR(svn_io_write_atomic(uuid_path, contents->data, contents->len,
- svn_fs_fs__path_current(fs, pool) /* perms */,
- pool));
+ SVN_ERR(svn_io_write_atomic2(uuid_path, contents->data, contents->len,
+ svn_fs_fs__path_current(fs, pool) /* perms */,
+ TRUE, pool));
fs->uuid = apr_pstrdup(fs->pool, uuid);
@@ -1944,7 +1926,10 @@ get_node_origins_from_file(svn_fs_t *fs,
stream = svn_stream_from_aprfile2(fd, FALSE, pool);
*node_origins = apr_hash_make(pool);
- SVN_ERR(svn_hash_read2(*node_origins, stream, SVN_HASH_TERMINATOR, pool));
+ err = svn_hash_read2(*node_origins, stream, SVN_HASH_TERMINATOR, pool);
+ if (err)
+ return svn_error_quick_wrapf(err, _("malformed node origin data in '%s'"),
+ node_origins_file);
return svn_stream_close(stream);
}
@@ -2034,7 +2019,7 @@ set_node_origins_for_file(svn_fs_t *fs,
SVN_ERR(svn_stream_close(stream));
/* Rename the temp file as the real destination */
- return svn_io_file_rename(path_tmp, node_origins_path, pool);
+ return svn_io_file_rename2(path_tmp, node_origins_path, FALSE, pool);
}
@@ -2069,14 +2054,17 @@ svn_fs_fs__revision_prop(svn_string_t **
svn_fs_t *fs,
svn_revnum_t rev,
const char *propname,
- apr_pool_t *pool)
+ svn_boolean_t refresh,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_hash_t *table;
SVN_ERR(svn_fs__check_fs(fs, TRUE));
- SVN_ERR(svn_fs_fs__get_revision_proplist(&table, fs, rev, pool));
+ SVN_ERR(svn_fs_fs__get_revision_proplist(&table, fs, rev, refresh,
+ scratch_pool, scratch_pool));
- *value_p = svn_hash_gets(table, propname);
+ *value_p = svn_string_dup(svn_hash_gets(table, propname), result_pool);
return SVN_NO_ERROR;
}
@@ -2099,13 +2087,17 @@ change_rev_prop_body(void *baton, apr_po
{
struct change_rev_prop_baton *cb = baton;
apr_hash_t *table;
+ const svn_string_t *present_value;
- SVN_ERR(svn_fs_fs__get_revision_proplist(&table, cb->fs, cb->rev, pool));
+ /* We always need to read the current revprops from disk.
+ * Hence, always "refresh" here. */
+ SVN_ERR(svn_fs_fs__get_revision_proplist(&table, cb->fs, cb->rev, TRUE,
+ pool, pool));
+ present_value = svn_hash_gets(table, cb->name);
if (cb->old_value_p)
{
const svn_string_t *wanted_value = *cb->old_value_p;
- const svn_string_t *present_value = svn_hash_gets(table, cb->name);
if ((!wanted_value != !present_value)
|| (wanted_value && present_value
&& !svn_string_compare(wanted_value, present_value)))
@@ -2118,6 +2110,13 @@ change_rev_prop_body(void *baton, apr_po
}
/* Fall through. */
}
+
+ /* If the prop-set is a no-op, skip the actual write. */
+ if ((!present_value && !cb->value)
+ || (present_value && cb->value
+ && svn_string_compare(present_value, cb->value)))
+ return SVN_NO_ERROR;
+
svn_hash_sets(table, cb->name, cb->value);
return svn_fs_fs__set_revision_proplist(cb->fs, cb->rev, table, pool);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs_fs.h Mon Nov 30 10:24:16 2015
@@ -39,6 +39,15 @@ svn_error_t *svn_fs_fs__open(svn_fs_t *f
const char *path,
apr_pool_t *pool);
+/* Initialize parts of the FS data that are being shared across multiple
+ filesystem objects. Use COMMON_POOL for process-wide and POOL for
+ temporary allocations. Use COMMON_POOL_LOCK to ensure that the
+ initialization is serialized. */
+svn_error_t *svn_fs_fs__initialize_shared_data(svn_fs_t *fs,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
+ apr_pool_t *common_pool);
+
/* Upgrade the fsfs filesystem FS. Indicate progress via the optional
* NOTIFY_FUNC callback using NOTIFY_BATON. The optional CANCEL_FUNC
* will periodically be called with CANCEL_BATON to allow for preemption.
@@ -81,28 +90,29 @@ svn_error_t *svn_fs_fs__file_length(svn_
node_revision_t *noderev,
apr_pool_t *pool);
+/* Return TRUE if the representation keys in A and B both point to the
+ same representation, else return FALSE. */
+svn_boolean_t svn_fs_fs__noderev_same_rep_key(representation_t *a,
+ representation_t *b);
+
/* Set *EQUAL to TRUE if the text representations in A and B within FS
- have equal contents, else set it to FALSE. If STRICT is not set, allow
- for false negatives.
+ have equal contents, else set it to FALSE.
Use SCRATCH_POOL for temporary allocations. */
svn_error_t *
svn_fs_fs__file_text_rep_equal(svn_boolean_t *equal,
svn_fs_t *fs,
node_revision_t *a,
node_revision_t *b,
- svn_boolean_t strict,
apr_pool_t *scratch_pool);
/* Set *EQUAL to TRUE if the property representations in A and B within FS
- have equal contents, else set it to FALSE. If STRICT is not set, allow
- for false negatives.
+ have equal contents, else set it to FALSE.
Use SCRATCH_POOL for temporary allocations. */
svn_error_t *
svn_fs_fs__prop_rep_equal(svn_boolean_t *equal,
svn_fs_t *fs,
node_revision_t *a,
node_revision_t *b,
- svn_boolean_t strict,
apr_pool_t *scratch_pool);
@@ -215,13 +225,16 @@ svn_fs_fs__with_all_locks(svn_fs_t *fs,
void *baton,
apr_pool_t *pool);
-/* Find the value of the property named PROPNAME in transaction TXN.
+/* Find the value of the property named PROPNAME in revision REV.
Return the contents in *VALUE_P. The contents will be allocated
- from POOL. */
+ from RESULT_POOL and SCRATCH_POOL is used for temporaries.
+ Invalidate any revprop cache is REFRESH is set. */
svn_error_t *svn_fs_fs__revision_prop(svn_string_t **value_p, svn_fs_t *fs,
svn_revnum_t rev,
const char *propname,
- apr_pool_t *pool);
+ svn_boolean_t refresh,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
/* Change, add, or delete a property on a revision REV in filesystem
FS. NAME gives the name of the property, and value, if non-NULL,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.c Mon Nov 30 10:24:16 2015
@@ -982,6 +982,10 @@ hotcopy_body(void *baton, apr_pool_t *po
if (kind == svn_node_file)
{
SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, pool));
+
+ /* The source might have r/o flags set on it - which would be
+ carried over to the copy. */
+ SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, pool));
SVN_ERR(svn_fs_fs__del_rep_reference(dst_fs, src_youngest, pool));
}
}
@@ -991,65 +995,33 @@ hotcopy_body(void *baton, apr_pool_t *po
SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
PATH_TXN_CURRENT, pool));
- return SVN_NO_ERROR;
-}
-
-/* Wrapper around hotcopy_body taking out all necessary source repository
- * locks.
- */
-static svn_error_t *
-hotcopy_locking_src_body(void *baton, apr_pool_t *pool)
-{
- struct hotcopy_body_baton *hbb = baton;
- fs_fs_data_t *src_ffd = hbb->src_fs->fsap_data;
+ /* Hotcopied FS is complete. Stamp it with a format file. */
+ SVN_ERR(svn_fs_fs__write_format(dst_fs, TRUE, pool));
- return src_ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT
- ? svn_error_trace(svn_fs_fs__with_pack_lock(hbb->src_fs, hotcopy_body,
- baton, pool))
- : hotcopy_body(baton, pool);
+ return SVN_NO_ERROR;
}
-/* Create an empty filesystem at DST_FS at DST_PATH with the same
- * configuration as SRC_FS (uuid, format, and other parameters).
- * After creation DST_FS has no revisions, not even revision zero. */
-static svn_error_t *
-hotcopy_create_empty_dest(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- apr_pool_t *pool)
+svn_error_t *
+svn_fs_fs__hotcopy(svn_fs_t *src_fs,
+ svn_fs_t *dst_fs,
+ const char *src_path,
+ const char *dst_path,
+ svn_boolean_t incremental,
+ svn_fs_hotcopy_notify_t notify_func,
+ void *notify_baton,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
+ apr_pool_t *common_pool)
{
- fs_fs_data_t *src_ffd = src_fs->fsap_data;
+ struct hotcopy_body_baton hbb;
- /* Create the DST_FS repository with the same layout as SRC_FS. */
- SVN_ERR(svn_fs_fs__create_file_tree(dst_fs, dst_path, src_ffd->format,
- src_ffd->max_files_per_dir,
- src_ffd->use_log_addressing,
- pool));
-
- /* Copy the UUID. Hotcopy destination receives a new instance ID, but
- * has the same filesystem UUID as the source. */
- SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, NULL, pool));
-
- /* Remove revision 0 contents. Otherwise, it may not get overwritten
- * due to having a newer timestamp. */
- SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_rev(dst_fs, 0, pool), pool));
- SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_revprops(dst_fs, 0, pool),
- pool));
-
- /* This filesystem is ready. Stamp it with a format number. Fail if
- * the 'format' file should already exist. */
- SVN_ERR(svn_fs_fs__write_format(dst_fs, FALSE, pool));
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
- return SVN_NO_ERROR;
-}
+ SVN_ERR(svn_fs_fs__open(src_fs, src_path, pool));
-svn_error_t *
-svn_fs_fs__hotcopy_prepare_target(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- svn_boolean_t incremental,
- apr_pool_t *pool)
-{
if (incremental)
{
const char *dst_format_abspath;
@@ -1061,39 +1033,51 @@ svn_fs_fs__hotcopy_prepare_target(svn_fs
SVN_ERR(svn_io_check_path(dst_format_abspath, &dst_format_kind, pool));
if (dst_format_kind == svn_node_none)
{
- /* Destination doesn't exist yet. Perform a normal hotcopy to a
- * empty destination using the same configuration as the source. */
- SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path, pool));
- }
- else
- {
- /* Check the existing repository. */
- SVN_ERR(svn_fs_fs__open(dst_fs, dst_path, pool));
- SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs,
- pool));
+ /* No destination? Fallback to a non-incremental hotcopy. */
+ incremental = FALSE;
}
}
+
+ if (incremental)
+ {
+ /* Check the existing repository. */
+ SVN_ERR(svn_fs_fs__open(dst_fs, dst_path, pool));
+ SVN_ERR(hotcopy_incremental_check_preconditions(src_fs, dst_fs, pool));
+
+ SVN_ERR(svn_fs_fs__initialize_shared_data(dst_fs, common_pool_lock,
+ pool, common_pool));
+ SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool));
+ }
else
{
/* Start out with an empty destination using the same configuration
* as the source. */
- SVN_ERR(hotcopy_create_empty_dest(src_fs, dst_fs, dst_path, pool));
+ fs_fs_data_t *src_ffd = src_fs->fsap_data;
+
+ /* Create the DST_FS repository with the same layout as SRC_FS. */
+ SVN_ERR(svn_fs_fs__create_file_tree(dst_fs, dst_path, src_ffd->format,
+ src_ffd->max_files_per_dir,
+ src_ffd->use_log_addressing,
+ pool));
+
+ /* Copy the UUID. Hotcopy destination receives a new instance ID, but
+ * has the same filesystem UUID as the source. */
+ SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, NULL, pool));
+
+ /* Remove revision 0 contents. Otherwise, it may not get overwritten
+ * due to having a newer timestamp. */
+ SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_rev(dst_fs, 0, pool),
+ pool));
+ SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_revprops(dst_fs, 0, pool),
+ pool));
+
+ SVN_ERR(svn_fs_fs__initialize_shared_data(dst_fs, common_pool_lock,
+ pool, common_pool));
+ SVN_ERR(svn_fs_fs__initialize_caches(dst_fs, pool));
}
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__hotcopy(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- svn_boolean_t incremental,
- svn_fs_hotcopy_notify_t notify_func,
- void *notify_baton,
- svn_cancel_func_t cancel_func,
- void *cancel_baton,
- apr_pool_t *pool)
-{
- struct hotcopy_body_baton hbb;
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
hbb.src_fs = src_fs;
hbb.dst_fs = dst_fs;
@@ -1102,8 +1086,15 @@ svn_fs_fs__hotcopy(svn_fs_t *src_fs,
hbb.notify_baton = notify_baton;
hbb.cancel_func = cancel_func;
hbb.cancel_baton = cancel_baton;
- SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_locking_src_body, &hbb,
- pool));
+
+ /* Lock the destination in the incremental mode. For a non-incremental
+ * hotcopy, don't take any locks. In that case the destination cannot be
+ * opened until the hotcopy finishes, and we don't have to worry about
+ * concurrency. */
+ if (incremental)
+ SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_body, &hbb, pool));
+ else
+ SVN_ERR(hotcopy_body(&hbb, pool));
return SVN_NO_ERROR;
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/hotcopy.h Mon Nov 30 10:24:16 2015
@@ -25,27 +25,23 @@
#include "fs.h"
-/* Create an empty copy of the fsfs filesystem SRC_FS into a new DST_FS at
- * DST_PATH. If INCREMENTAL is TRUE, perform a few pre-checks only if
- * a repo already exists at DST_PATH. Use POOL for temporary allocations. */
-svn_error_t *
-svn_fs_fs__hotcopy_prepare_target(svn_fs_t *src_fs,
- svn_fs_t *dst_fs,
- const char *dst_path,
- svn_boolean_t incremental,
- apr_pool_t *pool);
-
-/* Copy the fsfs filesystem SRC_FS into DST_FS. If INCREMENTAL is TRUE, do
- * not re-copy data which already exists in DST_FS. Indicate progress via
- * the optional NOTIFY_FUNC callback using NOTIFY_BATON. Use POOL for
- * temporary allocations. */
+/* Copy the fsfs filesystem SRC_FS at SRC_PATH into a new copy DST_FS at
+ * DST_PATH. If INCREMENTAL is TRUE, do not re-copy data which already
+ * exists in DST_FS. Indicate progress via the optional NOTIFY_FUNC
+ * callback using NOTIFY_BATON. Use COMMON_POOL for process-wide and
+ * POOL for temporary allocations. Use COMMON_POOL_LOCK to ensure
+ * that the initialization of the shared data is serialized. */
svn_error_t * svn_fs_fs__hotcopy(svn_fs_t *src_fs,
svn_fs_t *dst_fs,
+ const char *src_path,
+ const char *dst_path,
svn_boolean_t incremental,
svn_fs_hotcopy_notify_t notify_func,
void *notify_baton,
svn_cancel_func_t cancel_func,
void *cancel_baton,
- apr_pool_t *pool);
+ svn_mutex__t *common_pool_lock,
+ apr_pool_t *pool,
+ apr_pool_t *common_pool);
#endif
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/id.c Mon Nov 30 10:24:16 2015
@@ -365,14 +365,21 @@ svn_fs_fs__id_check_related(const svn_fs
if (a == b)
return TRUE;
- /* If both node_ids start with _ and they have differing transaction
- IDs, then it is impossible for them to be related. */
- if (id_a->private_id.node_id.revision == SVN_INVALID_REVNUM)
+ /* If both node_ids have been created within _different_ transactions
+ (and are still uncommitted), then it is impossible for them to be
+ related.
+
+ Due to our txn-local temporary IDs, however, they might have been
+ given the same temporary node ID. We need to detect that case.
+ */
+ if ( id_a->private_id.node_id.revision == SVN_INVALID_REVNUM
+ && id_b->private_id.node_id.revision == SVN_INVALID_REVNUM)
{
- if ( !svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
- &id_b->private_id.txn_id)
- || !svn_fs_fs__id_txn_used(&id_a->private_id.txn_id))
+ if (!svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
+ &id_b->private_id.txn_id))
return FALSE;
+
+ /* At this point, matching node_ids implies relatedness. */
}
return svn_fs_fs__id_part_eq(&id_a->private_id.node_id,
@@ -385,7 +392,7 @@ svn_fs_fs__id_compare(const svn_fs_id_t
const svn_fs_id_t *b)
{
if (svn_fs_fs__id_eq(a, b))
- return svn_fs_node_same;
+ return svn_fs_node_unchanged;
return (svn_fs_fs__id_check_related(a, b) ? svn_fs_node_common_ancestor
: svn_fs_node_unrelated);
}
@@ -603,7 +610,9 @@ svn_fs_fs__id_serialize(svn_temp_seriali
if (id == NULL)
return;
- /* serialize the id data struct itself */
+ /* Serialize the id data struct itself.
+ * Note that the structure behind IN is actually larger than a mere
+ * svn_fs_id_t . */
svn_temp_serializer__add_leaf(context,
(const void * const *)in,
sizeof(fs_fs__id_t));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/index.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/index.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/index.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/index.c Mon Nov 30 10:24:16 2015
@@ -251,7 +251,7 @@ static svn_error_t *
packed_stream_read(svn_fs_fs__packed_number_stream_t *stream)
{
unsigned char buffer[MAX_NUMBER_PREFETCH];
- apr_size_t read = 0;
+ apr_size_t bytes_read = 0;
apr_size_t i;
value_position_pair_t *target;
apr_off_t block_start = 0;
@@ -273,33 +273,34 @@ packed_stream_read(svn_fs_fs__packed_num
* boundaries. This shall prevent jumping back and forth between two
* blocks because the extra data was not actually request _now_.
*/
- read = sizeof(buffer);
+ bytes_read = sizeof(buffer);
block_left = stream->block_size - (stream->next_offset - block_start);
- if (block_left >= 10 && block_left < read)
- read = (apr_size_t)block_left;
+ if (block_left >= 10 && block_left < bytes_read)
+ bytes_read = (apr_size_t)block_left;
/* Don't read beyond the end of the file section that belongs to this
* index / stream. */
- read = (apr_size_t)MIN(read, stream->stream_end - stream->next_offset);
+ bytes_read = (apr_size_t)MIN(bytes_read,
+ stream->stream_end - stream->next_offset);
- err = apr_file_read(stream->file, buffer, &read);
+ err = apr_file_read(stream->file, buffer, &bytes_read);
if (err && !APR_STATUS_IS_EOF(err))
return stream_error_create(stream, err,
_("Can't read index file '%s' at offset 0x%s"));
/* if the last number is incomplete, trim it from the buffer */
- while (read > 0 && buffer[read-1] >= 0x80)
- --read;
+ while (bytes_read > 0 && buffer[bytes_read-1] >= 0x80)
+ --bytes_read;
/* we call read() only if get() requires more data. So, there must be
* at least *one* further number. */
- if SVN__PREDICT_FALSE(read == 0)
+ if SVN__PREDICT_FALSE(bytes_read == 0)
return stream_error_create(stream, err,
_("Unexpected end of index file %s at offset 0x%s"));
/* parse file buffer and expand into stream buffer */
target = stream->buffer;
- for (i = 0; i < read;)
+ for (i = 0; i < bytes_read;)
{
if (buffer[i] < 0x80)
{
@@ -558,13 +559,13 @@ read_uint64_from_proto_index(apr_file_t
apr_pool_t *scratch_pool)
{
apr_byte_t buffer[sizeof(*value_p)];
- apr_size_t read;
+ apr_size_t bytes_read;
/* Read the full 8 bytes or our 64 bit value, unless we hit EOF.
* Assert that we never read partial values. */
SVN_ERR(svn_io_file_read_full2(proto_index, buffer, sizeof(buffer),
- &read, eof, scratch_pool));
- SVN_ERR_ASSERT((eof && *eof) || read == sizeof(buffer));
+ &bytes_read, eof, scratch_pool));
+ SVN_ERR_ASSERT((eof && *eof) || bytes_read == sizeof(buffer));
/* If we did not hit EOF, reconstruct the uint64 value and return it. */
if (!eof || !*eof)
@@ -3207,18 +3208,11 @@ svn_fs_fs__l2p_index_from_p2l_entries(co
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
int i;
svn_revnum_t last_revision = SVN_INVALID_REVNUM;
- svn_revnum_t revision = SVN_INVALID_REVNUM;
/* L2P index must be written in revision order.
* Sort ENTRIES accordingly. */
svn_sort__array(entries, compare_p2l_entry_revision);
- /* Find the first revision in the index
- * (must exist since no truly empty revs are allowed). */
- for (i = 0; i < entries->nelts && !SVN_IS_VALID_REVNUM(revision); ++i)
- revision = APR_ARRAY_IDX(entries, i, const svn_fs_fs__p2l_entry_t *)
- ->item.revision;
-
/* Create the temporary proto-rev file. */
SVN_ERR(svn_io_open_unique_file3(NULL, protoname, NULL,
svn_io_file_del_on_pool_cleanup,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/load-index.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/load-index.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/load-index.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/load-index.c Mon Nov 30 10:24:16 2015
@@ -23,53 +23,152 @@
#include "svn_pools.h"
#include "private/svn_fs_fs_private.h"
+#include "private/svn_sorts_private.h"
#include "index.h"
#include "util.h"
#include "transaction.h"
+/* From the ENTRIES array of svn_fs_fs__p2l_entry_t*, sorted by offset,
+ * return the first offset behind the last item. */
+static apr_off_t
+get_max_covered(apr_array_header_t *entries)
+{
+ const svn_fs_fs__p2l_entry_t *entry;
+ if (entries->nelts == 0)
+ return -1;
+
+ entry = APR_ARRAY_IDX(entries, entries->nelts - 1,
+ const svn_fs_fs__p2l_entry_t *);
+ return entry->offset + entry->size;
+}
+
+/* Make sure that the svn_fs_fs__p2l_entry_t* in ENTRIES are consecutive
+ * and non-overlapping. Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+check_all_covered(apr_array_header_t *entries,
+ apr_pool_t *scratch_pool)
+{
+ int i;
+ apr_off_t expected = 0;
+ for (i = 0; i < entries->nelts; ++i)
+ {
+ const svn_fs_fs__p2l_entry_t *entry
+ = APR_ARRAY_IDX(entries, i, const svn_fs_fs__p2l_entry_t *);
+
+ if (entry->offset < expected)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "Overlapping index data for offset %s",
+ apr_psprintf(scratch_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)expected));
+
+ if (entry->offset > expected)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "Missing index data for offset %s",
+ apr_psprintf(scratch_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)expected));
+
+ expected = entry->offset + entry->size;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* A svn_sort__array compatible comparator function, sorting the
+ * svn_fs_fs__p2l_entry_t** given in LHS, RHS by offset. */
+static int
+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 *rhs_entry
+ =*(const svn_fs_fs__p2l_entry_t **)rhs;
+
+ if (lhs_entry->offset < rhs_entry->offset)
+ return -1;
+
+ return lhs_entry->offset == rhs_entry->offset ? 0 : 1;
+}
+
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)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+ apr_pool_t *subpool = svn_pool_create(scratch_pool);
/* Check the FS format number. */
if (! svn_fs_fs__use_log_addressing(fs))
return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL, NULL);
+ /* P2L index must be written in offset order.
+ * Sort ENTRIES accordingly. */
+ svn_sort__array(entries, compare_p2l_entry_revision);
+
/* Treat an empty array as a no-op instead error. */
if (entries->nelts != 0)
{
const char *l2p_proto_index;
const char *p2l_proto_index;
svn_fs_fs__revision_file_t *rev_file;
+ svn_error_t *err;
+ apr_off_t max_covered = get_max_covered(entries);
+
+ /* Ensure that the index data is complete. */
+ SVN_ERR(check_all_covered(entries, scratch_pool));
/* Open rev / pack file & trim indexes + footer off it. */
SVN_ERR(svn_fs_fs__open_pack_or_rev_file_writable(&rev_file, fs,
- revision, iterpool,
- iterpool));
- SVN_ERR(svn_fs_fs__auto_read_footer(rev_file));
- SVN_ERR(svn_io_file_trunc(rev_file->file, rev_file->l2p_offset,
- iterpool));
+ revision, subpool,
+ subpool));
+
+ /* Remove the existing index info. */
+ err = svn_fs_fs__auto_read_footer(rev_file);
+ if (err)
+ {
+ /* Even the index footer cannot be read, even less be trusted.
+ * Take the range of valid data from the new index data. */
+ svn_error_clear(err);
+ SVN_ERR(svn_io_file_trunc(rev_file->file, max_covered,
+ subpool));
+ }
+ else
+ {
+ /* We assume that the new index data covers all contents.
+ * Error out if it doesn't. The user can always truncate
+ * the file themselves. */
+ if (max_covered != rev_file->l2p_offset)
+ return svn_error_createf(SVN_ERR_INVALID_INPUT, NULL,
+ "New index data ends at %s, old index ended at %s",
+ apr_psprintf(scratch_pool, "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)max_covered),
+ apr_psprintf(scratch_pool, "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t) rev_file->l2p_offset));
+
+ SVN_ERR(svn_io_file_trunc(rev_file->file, rev_file->l2p_offset,
+ subpool));
+ }
/* Create proto index files for the new index data
* (will be cleaned up automatically with iterpool). */
SVN_ERR(svn_fs_fs__p2l_index_from_p2l_entries(&p2l_proto_index, fs,
rev_file, entries,
- iterpool, iterpool));
+ subpool, subpool));
SVN_ERR(svn_fs_fs__l2p_index_from_p2l_entries(&l2p_proto_index, fs,
- entries, iterpool,
- iterpool));
+ entries, subpool,
+ subpool));
/* Combine rev data with new index data. */
SVN_ERR(svn_fs_fs__add_index_data(fs, rev_file->file, l2p_proto_index,
- p2l_proto_index, revision, iterpool));
+ p2l_proto_index,
+ rev_file->start_revision, subpool));
}
- svn_pool_destroy(iterpool);
+ svn_pool_destroy(subpool);
return SVN_NO_ERROR;
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/lock.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/lock.c Mon Nov 30 10:24:16 2015
@@ -222,7 +222,7 @@ write_digest_file(apr_hash_t *children,
svn_io_file_del_none, pool, pool));
if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool)))
{
- svn_error_clear(svn_stream_close(stream));
+ err = svn_error_compose_create(err, svn_stream_close(stream));
return svn_error_createf(err->apr_err,
err,
_("Cannot write lock/entries hashfile '%s'"),
@@ -230,7 +230,7 @@ write_digest_file(apr_hash_t *children,
}
SVN_ERR(svn_stream_close(stream));
- SVN_ERR(svn_io_file_rename(tmp_path, digest_path, pool));
+ SVN_ERR(svn_io_file_rename2(tmp_path, digest_path, FALSE, pool));
SVN_ERR(svn_io_copy_perms(perms_reference, digest_path, pool));
return SVN_NO_ERROR;
}
@@ -273,7 +273,7 @@ read_digest_file(apr_hash_t **children_p
hash = apr_hash_make(pool);
if ((err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, pool)))
{
- svn_error_clear(svn_stream_close(stream));
+ err = svn_error_compose_create(err, svn_stream_close(stream));
return svn_error_createf(err->apr_err,
err,
_("Can't parse lock/entries hashfile '%s'"),
@@ -715,6 +715,7 @@ check_lock(svn_error_t **fs_err,
const svn_fs_lock_target_t *target,
struct lock_baton *lb,
svn_fs_root_t *root,
+ svn_revnum_t youngest_rev,
apr_pool_t *pool)
{
svn_node_kind_t kind;
@@ -751,6 +752,15 @@ check_lock(svn_error_t **fs_err,
if (SVN_IS_VALID_REVNUM(target->current_rev))
{
svn_revnum_t created_rev;
+
+ if (target->current_rev > youngest_rev)
+ {
+ *fs_err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"),
+ target->current_rev);
+ return SVN_NO_ERROR;
+ }
+
SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, path,
pool));
@@ -837,7 +847,7 @@ lock_body(void *baton, apr_pool_t *pool)
apr_pool_t *iterpool = svn_pool_create(pool);
/* Until we implement directory locks someday, we only allow locks
- on files or non-existent paths. */
+ on files. */
/* Use fs->vtable->foo instead of svn_fs_foo to avoid circular
library dependencies, which are not portable. */
SVN_ERR(lb->fs->vtable->youngest_rev(&youngest, lb->fs, pool));
@@ -856,7 +866,7 @@ lock_body(void *baton, apr_pool_t *pool)
info.fs_err = SVN_NO_ERROR;
SVN_ERR(check_lock(&info.fs_err, info.path, item->value, lb, root,
- iterpool));
+ youngest, iterpool));
/* If no error occurred while pre-checking, schedule the index updates for
this path. */
@@ -1099,6 +1109,7 @@ svn_fs_fs__lock(svn_fs_t *fs,
apr_array_header_t *sorted_targets;
apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
apr_hash_index_t *hi;
+ apr_pool_t *iterpool;
svn_error_t *err, *cb_err = SVN_NO_ERROR;
int i;
@@ -1139,11 +1150,13 @@ svn_fs_fs__lock(svn_fs_t *fs,
lb.steal_lock = steal_lock;
lb.result_pool = result_pool;
- err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, scratch_pool);
+ iterpool = svn_pool_create(scratch_pool);
+ err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, iterpool);
for (i = 0; i < lb.infos->nelts; ++i)
{
struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
struct lock_info_t);
+ svn_pool_clear(iterpool);
if (!cb_err && lock_callback)
{
if (!info->lock && !info->fs_err)
@@ -1152,10 +1165,11 @@ svn_fs_fs__lock(svn_fs_t *fs,
info->path);
cb_err = lock_callback(lock_baton, info->path, info->lock,
- info->fs_err, scratch_pool);
+ info->fs_err, iterpool);
}
svn_error_clear(info->fs_err);
}
+ svn_pool_destroy(iterpool);
if (err && cb_err)
svn_error_compose(err, cb_err);
@@ -1195,6 +1209,7 @@ svn_fs_fs__unlock(svn_fs_t *fs,
apr_array_header_t *sorted_targets;
apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
apr_hash_index_t *hi;
+ apr_pool_t *iterpool;
svn_error_t *err, *cb_err = SVN_NO_ERROR;
int i;
@@ -1229,11 +1244,13 @@ svn_fs_fs__unlock(svn_fs_t *fs,
ub.break_lock = break_lock;
ub.result_pool = result_pool;
- err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, scratch_pool);
+ iterpool = svn_pool_create(scratch_pool);
+ err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, iterpool);
for (i = 0; i < ub.infos->nelts; ++i)
{
struct unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i,
struct unlock_info_t);
+ svn_pool_clear(iterpool);
if (!cb_err && lock_callback)
{
if (!info->done && !info->fs_err)
@@ -1241,10 +1258,11 @@ svn_fs_fs__unlock(svn_fs_t *fs,
0, _("Failed to unlock '%s'"),
info->path);
cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
- scratch_pool);
+ iterpool);
}
svn_error_clear(info->fs_err);
}
+ svn_pool_destroy(iterpool);
if (err && cb_err)
svn_error_compose(err, cb_err);
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.c Mon Nov 30 10:24:16 2015
@@ -189,6 +189,19 @@ svn_fs_fs__unparse_revision_trailer(apr_
changes_offset);
}
+/* If ERR is not NULL, wrap it MESSAGE. The latter must have an %ld
+ * format parameter that will be filled with REV. */
+static svn_error_t *
+wrap_footer_error(svn_error_t *err,
+ const char *message,
+ svn_revnum_t rev)
+{
+ if (err)
+ return svn_error_quick_wrapf(err, message, rev);
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t *
svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
svn_checksum_t **l2p_checksum,
@@ -196,6 +209,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
svn_checksum_t **p2l_checksum,
svn_stringbuf_t *footer,
svn_revnum_t rev,
+ apr_off_t footer_offset,
apr_pool_t *result_pool)
{
apr_int64_t val;
@@ -204,17 +218,20 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
/* Get the L2P offset. */
const char *str = svn_cstring_tokenize(" ", &last_str);
if (str == NULL)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- _("Invalid revision footer"));
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "Invalid r%ld footer", rev);
- SVN_ERR(svn_cstring_atoi64(&val, str));
+ SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+ footer_offset - 1, 10),
+ "Invalid L2P offset in r%ld footer",
+ rev));
*l2p_offset = (apr_off_t)val;
/* Get the L2P checksum. */
str = svn_cstring_tokenize(" ", &last_str);
if (str == NULL)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- _("Invalid revision footer"));
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "Invalid r%ld footer", rev);
SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str,
result_pool));
@@ -222,17 +239,33 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
/* Get the P2L offset. */
str = svn_cstring_tokenize(" ", &last_str);
if (str == NULL)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- _("Invalid revision footer"));
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "Invalid r%ld footer", rev);
- SVN_ERR(svn_cstring_atoi64(&val, str));
+ SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+ footer_offset - 1, 10),
+ "Invalid P2L offset in r%ld footer",
+ rev));
*p2l_offset = (apr_off_t)val;
+ /* The P2L indes follows the L2P index */
+ if (*p2l_offset <= *l2p_offset)
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "P2L offset %s must be larger than L2P offset %s"
+ " in r%ld footer",
+ apr_psprintf(result_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)*p2l_offset),
+ apr_psprintf(result_pool,
+ "%" APR_UINT64_T_HEX_FMT,
+ (apr_uint64_t)*l2p_offset),
+ rev);
+
/* Get the P2L checksum. */
str = svn_cstring_tokenize(" ", &last_str);
if (str == NULL)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- _("Invalid revision footer"));
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "Invalid r%ld footer", rev);
SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str,
result_pool));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/low_level.h Mon Nov 30 10:24:16 2015
@@ -67,6 +67,8 @@ svn_fs_fs__unparse_revision_trailer(apr_
* *P2L_OFFSET, respectively. Also, return the expected checksums in
* in *L2P_CHECKSUM and *P2L_CHECKSUM.
*
+ * FOOTER_OFFSET is used for validation.
+ *
* Note that REV is only used to construct nicer error objects that
* mention this revision. Allocate the checksums in RESULT_POOL.
*/
@@ -77,6 +79,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
svn_checksum_t **p2l_checksum,
svn_stringbuf_t *footer,
svn_revnum_t rev,
+ apr_off_t footer_offset,
apr_pool_t *result_pool);
/* Given the offset of the L2P index data in L2P_OFFSET, the content
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c Mon Nov 30 10:24:16 2015
@@ -108,8 +108,8 @@ typedef struct path_order_t
/* noderev predecessor count */
int predecessor_count;
- /* this is a directory node */
- svn_boolean_t is_dir;
+ /* this is a node is the latest for this PATH in this rev / pack file */
+ svn_boolean_t is_head;
/* length of the expanded representation content */
apr_int64_t expanded_size;
@@ -384,6 +384,8 @@ close_pack_context(pack_context_t *conte
SVN_ERR(svn_io_remove_file2(proto_l2p_index_path, FALSE, pool));
SVN_ERR(svn_io_remove_file2(proto_p2l_index_path, FALSE, pool));
+ /* Ensure that packed file is written to disk.*/
+ SVN_ERR(svn_io_file_flush_to_disk(context->pack_file, pool));
SVN_ERR(svn_io_file_close(context->pack_file, pool));
return SVN_NO_ERROR;
@@ -572,7 +574,7 @@ copy_rep_to_temp(pack_context_t *context
/* read & parse the representation header */
stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, stream, pool, pool));
- svn_stream_close(stream);
+ SVN_ERR(svn_stream_close(stream));
/* if the representation is a delta against some other rep, link the two */
if ( rep_header->type == svn_fs_fs__rep_delta
@@ -608,9 +610,6 @@ compare_dir_entries_format7(const svn_so
const svn_fs_dirent_t *lhs = (const svn_fs_dirent_t *) a->value;
const svn_fs_dirent_t *rhs = (const svn_fs_dirent_t *) b->value;
- if (lhs->kind != rhs->kind)
- return lhs->kind == svn_node_dir ? -1 : 1;
-
return strcmp(lhs->name, rhs->name);
}
@@ -643,17 +642,18 @@ compare_dir_entries_format6(const svn_so
apr_array_header_t *
svn_fs_fs__order_dir_entries(svn_fs_t *fs,
apr_hash_t *directory,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
apr_array_header_t *ordered
= svn_sort__hash(directory,
svn_fs_fs__use_log_addressing(fs)
? compare_dir_entries_format7
: compare_dir_entries_format6,
- pool);
+ scratch_pool);
apr_array_header_t *result
- = apr_array_make(pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
+ = apr_array_make(result_pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
int i;
for (i = 0; i < ordered->nelts; ++i)
@@ -714,7 +714,7 @@ copy_node_to_temp(pack_context_t *contex
/* read & parse noderev */
stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool, pool));
- svn_stream_close(stream);
+ SVN_ERR(svn_stream_close(stream));
/* create a copy of ENTRY, make it point to the copy destination and
* store it in CONTEXT */
@@ -736,9 +736,7 @@ copy_node_to_temp(pack_context_t *contex
{
path_order->rep_id.revision = noderev->data_rep->revision;
path_order->rep_id.number = noderev->data_rep->item_index;
- path_order->expanded_size = noderev->data_rep->expanded_size
- ? noderev->data_rep->expanded_size
- : noderev->data_rep->size;
+ path_order->expanded_size = noderev->data_rep->expanded_size;
}
/* Sort path is the key used for ordering noderevs and associated reps.
@@ -748,7 +746,6 @@ copy_node_to_temp(pack_context_t *contex
path_order->node_id = *svn_fs_fs__id_node_id(noderev->id);
path_order->revision = svn_fs_fs__id_rev(noderev->id);
path_order->predecessor_count = noderev->predecessor_count;
- path_order->is_dir = noderev->kind == svn_node_dir;
path_order->noderev_id = *svn_fs_fs__id_rev_item(noderev->id);
APR_ARRAY_PUSH(context->path_order, path_order_t *) = path_order;
@@ -765,13 +762,8 @@ compare_path_order(const path_order_t *
const path_order_t * lhs = *lhs_p;
const path_order_t * rhs = *rhs_p;
- /* cluster all directories */
- int diff = rhs->is_dir - lhs->is_dir;
- if (diff)
- return diff;
-
/* lexicographic order on path and node (i.e. latest first) */
- diff = svn_prefix_string__compare(lhs->path, rhs->path);
+ int diff = svn_prefix_string__compare(lhs->path, rhs->path);
if (diff)
return diff;
@@ -809,15 +801,6 @@ compare_ref_to_item(const reference_t *
return svn_fs_fs__id_part_compare(&(*lhs_p)->from, rhs_p);
}
-/* implements compare_fn_t. Finds the DIR / FILE boundary.
- */
-static int
-compare_is_dir(const path_order_t * const * lhs_p,
- const void *unused)
-{
- return (*lhs_p)->is_dir ? -1 : 0;
-}
-
/* Look for the least significant bit set in VALUE and return the smallest
* number with the same property, i.e. the largest power of 2 that is a
* factor in VALUE. */
@@ -827,19 +810,54 @@ roundness(int value)
return value ? value - (value & (value - 1)) : INT_MAX;
}
+/* For all paths in first COUNT entries in PATH_ORDER, mark their latest
+ * node as "HEAD". PATH_ORDER must be ordered by path, revision.
+ */
+static void
+classify_nodes(path_order_t **path_order,
+ int count)
+{
+ const svn_prefix_string__t *path;
+ int i;
+
+ /* The logic below would fail for empty ranges. */
+ if (count == 0)
+ return;
+
+ /* All entries are sorted by path, followed by revision.
+ * So, the first index is also HEAD for the first path.
+ */
+ path = path_order[0]->path;
+ path_order[0]->is_head = TRUE;
+
+ /* Since the sorting implicitly groups all entries by path and then sorts
+ * by descending revision within the group, whenever we encounter a new
+ * path, the first entry is "HEAD" for that path.
+ */
+ for (i = 1; i < count; ++i)
+ {
+ /* New path? */
+ if (svn_prefix_string__compare(path, path_order[i]->path))
+ {
+ path = path_order[i]->path;
+ path_order[i]->is_head = TRUE;
+ }
+ }
+}
+
/* Order a range of data collected in CONTEXT such that we can place them
* in the desired order. The input is taken from *PATH_ORDER, offsets FIRST
* to LAST and then written in the final order to the same range in *TEMP.
*/
static void
sort_reps_range(pack_context_t *context,
- const path_order_t **path_order,
- const path_order_t **temp,
+ path_order_t **path_order,
+ path_order_t **temp,
int first,
int last)
{
const svn_prefix_string__t *path;
- int i, dest, best;
+ int i, dest;
svn_fs_fs__id_part_t rep_id;
fs_fs_data_t *ffd = context->fs->fsap_data;
@@ -856,49 +874,47 @@ sort_reps_range(pack_context_t *context,
* We simply pick & chose from the existing path, rev order.
*/
dest = first;
- path = path_order[first]->path;
- best = first;
- /* (1) For each path, pick the "roundest" representation and put it in
- * front of all other nodes in the pack file. The "roundest" rep is
- * the one most likely to be referenced from future pack files, i.e. we
- * concentrate those potential "foreign link targets" in one section of
- * the pack file.
+ /* (1) There are two classes of representations that are likely to be
+ * referenced from future shards. These form a "hot zone" of mostly
+ * relevant data, i.e. we try to include as many reps as possible that
+ * are needed for future checkouts while trying to exclude as many as
+ * possible that are likely not needed in future checkouts.
+ *
+ * First, "very round" representations from frequently changing nodes.
+ * That excludes many in-between representations not accessed from HEAD.
*
- * And we only apply this to reps outside the linear deltification
- * sections because references *into* linear deltification ranges are
- * much less likely.
+ * The second class are infrequently changing nodes. Because they are
+ * unlikely to change often in the future, they will remain relevant for
+ * HEAD even over long spans of revisions. They are most likely the only
+ * thing we need from very old pack files.
*/
for (i = first; i < last; ++i)
{
- /* Investigated all nodes for the current path? */
- if (svn_prefix_string__compare(path, path_order[i]->path))
- {
- /* next path */
- path = path_order[i]->path;
-
- /* Pick roundest non-linear deltified node. */
- if (roundness(path_order[best]->predecessor_count)
- >= ffd->max_linear_deltification)
- {
- temp[dest++] = path_order[best];
- path_order[best] = NULL;
- best = i;
- }
- }
+ int round = roundness(path_order[i]->predecessor_count);
- /* next entry */
- if ( roundness(path_order[best]->predecessor_count)
- < roundness(path_order[i]->predecessor_count))
- best = i;
- }
+ /* Class 1:
+ * Pretty round _and_ a significant stop in the node's delta chain.
+ * This may pick up more than one representation from the same chain
+ * but that's rare not a problem. Prefer simple checks here. */
+ svn_boolean_t likely_target
+ = (round >= ffd->max_linear_deltification)
+ && (4 * round >= path_order[i]->predecessor_count);
+
+ /* Class 2:
+ * Anything from short node chains. The default of 16 is generous
+ * but we'd rather include to many than to few nodes here to keep
+ * seeks between different regions of this pack file at a minimum. */
+ svn_boolean_t likely_head
+ = path_order[i]->predecessor_count
+ < ffd->max_linear_deltification;
- /* Treat the last path the same as all others. */
- if (roundness(path_order[best]->predecessor_count)
- >= ffd->max_linear_deltification)
- {
- temp[dest++] = path_order[best];
- path_order[best] = NULL;
+ /* Pick any node that from either class. */
+ if (likely_target || likely_head)
+ {
+ temp[dest++] = path_order[i];
+ path_order[i] = NULL;
+ }
}
/* (2) For each (remaining) path, pick the nodes along the delta chain
@@ -964,8 +980,8 @@ static void
sort_reps(pack_context_t *context)
{
apr_pool_t *temp_pool;
- const path_order_t **temp, **path_order;
- int i, count, dir_count;
+ path_order_t **temp, **path_order;
+ int i, count;
/* We will later assume that there is at least one node / path.
*/
@@ -990,13 +1006,11 @@ sort_reps(pack_context_t *context)
temp = apr_pcalloc(temp_pool, count * sizeof(*temp));
path_order = (void *)context->path_order->elts;
- /* Find the boundary between DIR and FILE section. */
- dir_count = svn_sort__bsearch_lower_bound(context->path_order, NULL,
- (int (*)(const void *, const void *))compare_is_dir);
-
- /* Sort those sub-sections separately. */
- sort_reps_range(context, path_order, temp, 0, dir_count);
- sort_reps_range(context, path_order, temp, dir_count, count);
+ /* Mark nodes depending on what other nodes exist for the same path etc. */
+ classify_nodes(path_order, count);
+
+ /* Rearrange those sub-sections separately. */
+ sort_reps_range(context, path_order, temp, 0, count);
/* We now know the final ordering. */
for (i = 0; i < count; ++i)
@@ -1163,7 +1177,7 @@ copy_reps_from_temp(pack_context_t *cont
apr_array_header_t *path_order = context->path_order;
int i;
- /* copy items in path order. */
+ /* copy items in path order. Exclude the non-HEAD noderevs. */
for (i = 0; i < path_order->nelts; ++i)
{
path_order_t *current_path;
@@ -1173,13 +1187,30 @@ copy_reps_from_temp(pack_context_t *cont
svn_pool_clear(iterpool);
current_path = APR_ARRAY_IDX(path_order, i, path_order_t *);
- node_part = get_item(context, ¤t_path->noderev_id, TRUE);
+ if (current_path->is_head)
+ {
+ node_part = get_item(context, ¤t_path->noderev_id, TRUE);
+ if (node_part)
+ SVN_ERR(store_item(context, temp_file, node_part, iterpool));
+ }
+
rep_part = get_item(context, ¤t_path->rep_id, TRUE);
+ if (rep_part)
+ SVN_ERR(store_item(context, temp_file, rep_part, iterpool));
+ }
+
+ /* copy the remaining non-head noderevs. */
+ for (i = 0; i < path_order->nelts; ++i)
+ {
+ path_order_t *current_path;
+ svn_fs_fs__p2l_entry_t *node_part;
+ svn_pool_clear(iterpool);
+
+ current_path = APR_ARRAY_IDX(path_order, i, path_order_t *);
+ node_part = get_item(context, ¤t_path->noderev_id, TRUE);
if (node_part)
SVN_ERR(store_item(context, temp_file, node_part, iterpool));
- if (rep_part)
- SVN_ERR(store_item(context, temp_file, rep_part, iterpool));
}
svn_pool_destroy(iterpool);
@@ -1655,7 +1686,9 @@ pack_phys_addressed(const char *pack_fil
apr_pool_t *pool)
{
const char *pack_file_path, *manifest_file_path;
- svn_stream_t *pack_stream, *manifest_stream;
+ apr_file_t *pack_file;
+ apr_file_t *manifest_file;
+ svn_stream_t *manifest_stream;
svn_revnum_t end_rev, rev;
apr_off_t next_offset;
apr_pool_t *iterpool;
@@ -1664,13 +1697,18 @@ pack_phys_addressed(const char *pack_fil
pack_file_path = svn_dirent_join(pack_file_dir, PATH_PACKED, pool);
manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST, pool);
- /* Create the new directory and pack file. */
- SVN_ERR(svn_stream_open_writable(&pack_stream, pack_file_path, pool,
- pool));
+ /* Create the new directory and pack file.
+ * Use unbuffered apr_file_t since we're going to write using 16kb
+ * chunks. */
+ SVN_ERR(svn_io_file_open(&pack_file, pack_file_path,
+ APR_WRITE | APR_CREATE | APR_EXCL,
+ APR_OS_DEFAULT, pool));
/* Create the manifest file. */
- SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
- pool, pool));
+ SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+ APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+ APR_OS_DEFAULT, pool));
+ manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE, pool);
end_rev = start_rev + max_files_per_dir - 1;
next_offset = 0;
@@ -1697,16 +1735,24 @@ pack_phys_addressed(const char *pack_fil
/* Copy all the bits from the rev file to the end of the pack file. */
SVN_ERR(svn_stream_open_readonly(&rev_stream, path, iterpool, iterpool));
- SVN_ERR(svn_stream_copy3(rev_stream, svn_stream_disown(pack_stream,
- iterpool),
+ SVN_ERR(svn_stream_copy3(rev_stream,
+ svn_stream_from_aprfile2(pack_file, TRUE, pool),
cancel_func, cancel_baton, iterpool));
}
- /* disallow write access to the manifest file */
+ /* Close stream over APR file. */
SVN_ERR(svn_stream_close(manifest_stream));
+
+ /* Ensure that pack file is written to disk. */
+ SVN_ERR(svn_io_file_flush_to_disk(manifest_file, pool));
+ SVN_ERR(svn_io_file_close(manifest_file, pool));
+
+ /* disallow write access to the manifest file */
SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, iterpool));
- SVN_ERR(svn_stream_close(pack_stream));
+ /* Ensure that pack file is written to disk. */
+ SVN_ERR(svn_io_file_flush_to_disk(pack_file, pool));
+ SVN_ERR(svn_io_file_close(pack_file, pool));
svn_pool_destroy(iterpool);
@@ -1802,6 +1848,8 @@ synced_pack_shard(void *baton,
/* if enabled, pack the revprops in an equivalent way */
if (pb->revsprops_dir)
{
+ apr_int64_t pack_size_limit = 0.9 * ffd->revprop_pack_size;
+
revprops_pack_file_dir = svn_dirent_join(pb->revsprops_dir,
apr_psprintf(pool,
"%" APR_INT64_T_FMT PATH_EXT_PACKED_SHARD,
@@ -1815,7 +1863,7 @@ synced_pack_shard(void *baton,
revprops_shard_path,
pb->shard,
ffd->max_files_per_dir,
- (int)(0.9*ffd->revprop_pack_size),
+ pack_size_limit,
ffd->compress_packed_revprops
? SVN__COMPRESSION_ZLIB_DEFAULT
: SVN__COMPRESSION_NONE,
@@ -1915,6 +1963,34 @@ pack_shard(struct pack_baton *baton,
return SVN_NO_ERROR;
}
+/* Read the youngest rev and the first non-packed rev info for FS from disk.
+ Set *FULLY_PACKED when there is no completed unpacked shard.
+ Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+get_pack_status(svn_boolean_t *fully_packed,
+ svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
+{
+ fs_fs_data_t *ffd = fs->fsap_data;
+ apr_int64_t completed_shards;
+ svn_revnum_t youngest;
+
+ SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs,
+ scratch_pool));
+
+ SVN_ERR(svn_fs_fs__youngest_rev(&youngest, fs, scratch_pool));
+ completed_shards = (youngest + 1) / ffd->max_files_per_dir;
+
+ /* See if we've already completed all possible shards thus far. */
+ if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
+ *fully_packed = TRUE;
+ else
+ *fully_packed = FALSE;
+
+ return SVN_NO_ERROR;
+}
+
/* The work-horse for svn_fs_fs__pack, called with the FS write lock.
This implements the svn_fs_fs__with_write_lock() 'body' callback
type. BATON is a 'struct pack_baton *'.
@@ -1936,30 +2012,23 @@ pack_body(void *baton,
struct pack_baton *pb = baton;
fs_fs_data_t *ffd = pb->fs->fsap_data;
apr_int64_t completed_shards;
- svn_revnum_t youngest;
apr_pool_t *iterpool;
+ svn_boolean_t fully_packed;
- /* If the repository isn't a new enough format, we don't support packing.
- Return a friendly error to that effect. */
- if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT)
- return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
- _("FSFS format (%d) too old to pack; please upgrade the filesystem."),
- ffd->format);
-
- /* If we aren't using sharding, we can't do any packing, so quit. */
- if (!ffd->max_files_per_dir)
- return SVN_NO_ERROR;
-
- SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, pb->fs,
- pool));
-
- SVN_ERR(svn_fs_fs__youngest_rev(&youngest, pb->fs, pool));
- completed_shards = (youngest + 1) / ffd->max_files_per_dir;
+ /* Since another process might have already packed the repo,
+ we need to re-read the pack status. */
+ SVN_ERR(get_pack_status(&fully_packed, pb->fs, pool));
+ 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);
- /* See if we've already completed all possible shards thus far. */
- if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
- return SVN_NO_ERROR;
+ return SVN_NO_ERROR;
+ }
+ completed_shards = (ffd->youngest_rev_cache + 1) / ffd->max_files_per_dir;
pb->revs_dir = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, pool);
if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
pb->revsprops_dir = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR,
@@ -1993,7 +2062,37 @@ svn_fs_fs__pack(svn_fs_t *fs,
struct pack_baton pb = { 0 };
fs_fs_data_t *ffd = fs->fsap_data;
svn_error_t *err;
+ svn_boolean_t fully_packed;
+
+ /* If the repository isn't a new enough format, we don't support packing.
+ Return a friendly error to that effect. */
+ if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT)
+ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("FSFS format (%d) too old to pack; please upgrade the filesystem."),
+ ffd->format);
+
+ /* If we aren't using sharding, we can't do any packing, so quit. */
+ if (!ffd->max_files_per_dir)
+ {
+ if (notify_func)
+ (*notify_func)(notify_baton, -1, svn_fs_pack_notify_noop, pool);
+
+ return SVN_NO_ERROR;
+ }
+
+ /* Is there we even anything to do?. */
+ SVN_ERR(get_pack_status(&fully_packed, fs, pool));
+ 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);
+
+ return SVN_NO_ERROR;
+ }
+ /* Lock the repo and start the pack process. */
pb.fs = fs;
pb.notify_func = notify_func;
pb.notify_baton = notify_baton;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h Mon Nov 30 10:24:16 2015
@@ -51,13 +51,14 @@ svn_fs_fs__get_packed_offset(apr_off_t *
apr_pool_t *pool);
/* Return the svn_dir_entry_t* objects of DIRECTORY in an APR array
- * allocated in POOL with entries added in storage (on-disk) order.
- * FS format will be used to pick the optimal ordering strategy.
+ * allocated in RESULT_POOL with entries added in storage (on-disk) order.
+ * FS' format will be used to pick the optimal ordering strategy. Use
+ * SCRATCH_POOL for temporary allocations.
*/
apr_array_header_t *
svn_fs_fs__order_dir_entries(svn_fs_t *fs,
apr_hash_t *directory,
- apr_pool_t *pool);
-
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
#endif
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/recovery.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/recovery.c Mon Nov 30 10:24:16 2015
@@ -160,6 +160,7 @@ recover_find_max_ids(svn_fs_t *fs,
apr_hash_index_t *hi;
apr_pool_t *iterpool;
node_revision_t *noderev;
+ svn_error_t *err;
baton.stream = rev_file->stream;
SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
@@ -196,16 +197,23 @@ recover_find_max_ids(svn_fs_t *fs,
stored in the representation. Note that this is a directory, i.e.
represented using the hash format on disk and can never have 0 length. */
baton.pool = pool;
- baton.remaining = noderev->data_rep->expanded_size
- ? noderev->data_rep->expanded_size
- : noderev->data_rep->size;
+ baton.remaining = noderev->data_rep->expanded_size;
stream = svn_stream_create(&baton, pool);
svn_stream_set_read2(stream, NULL /* only full read support */,
read_handler_recover);
/* Now read the entries from that stream. */
entries = apr_hash_make(pool);
- SVN_ERR(svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool));
+ err = svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool);
+ if (err)
+ {
+ svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+ err = svn_error_compose_create(err, svn_stream_close(stream));
+ return svn_error_quick_wrapf(err,
+ _("malformed representation for node-revision '%s'"),
+ id_str->data);
+ }
SVN_ERR(svn_stream_close(stream));
/* Now check each of the entries in our directory to find new node and
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache-db.sql Mon Nov 30 10:24:16 2015
@@ -63,3 +63,6 @@ WHERE revision > ?1
-- STMT_LOCK_REP
BEGIN TRANSACTION;
INSERT INTO rep_cache VALUES ('dummy', 0, 0, 0, 0)
+
+-- STMT_UNLOCK_REP
+ROLLBACK TRANSACTION;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c Mon Nov 30 10:24:16 2015
@@ -24,6 +24,7 @@
#include "svn_private_config.h"
+#include "cached_data.h"
#include "fs_fs.h"
#include "fs.h"
#include "rep-cache.h"
@@ -273,6 +274,8 @@ svn_fs_fs__get_rep_reference(representat
(*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);
+
+ SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, *rep, pool));
}
else
*rep = NULL;
@@ -371,9 +374,13 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
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;
@@ -384,3 +391,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));
+}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h Mon Nov 30 10:24:16 2015
@@ -87,10 +87,14 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
apr_pool_t *pool);
/* Start a transaction to take an SQLite reserved lock that prevents
- other writes. */
+ other writes, call BODY, end the transaction, and return what BODY returned.
+ */
svn_error_t *
-svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
- apr_pool_t *pool);
+svn_fs_fs__with_rep_cache_lock(svn_fs_t *fs,
+ svn_error_t *(*body)(void *baton,
+ apr_pool_t *pool),
+ void *baton,
+ apr_pool_t *pool);
#ifdef __cplusplus
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rev_file.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rev_file.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rev_file.c Mon Nov 30 10:24:16 2015
@@ -259,6 +259,7 @@ svn_fs_fs__auto_read_footer(svn_fs_fs__r
SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->l2p_checksum,
&file->p2l_offset, &file->p2l_checksum,
footer, file->start_revision,
+ filesize - footer_length - 1,
file->pool));
file->footer_offset = filesize - footer_length - 1;
}