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 [14/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_base/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/dag.c Mon Nov 30 10:24:16 2015
@@ -1657,8 +1657,14 @@ svn_fs_base__things_different(svn_boolea
/* Compare contents keys and their (optional) uniquifiers. */
if (contents_changed != NULL)
- *contents_changed = (! svn_fs_base__same_keys(noderev1->data_key,
- noderev2->data_key));
+ *contents_changed =
+ (! (svn_fs_base__same_keys(noderev1->data_key,
+ noderev2->data_key)
+ /* Technically, these uniquifiers aren't used and "keys",
+ but keys are base-36 stringified numbers, so we'll take
+ this liberty. */
+ && (svn_fs_base__same_keys(noderev1->data_key_uniquifier,
+ noderev2->data_key_uniquifier))));
return SVN_NO_ERROR;
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/fs.c Mon Nov 30 10:24:16 2015
@@ -471,6 +471,13 @@ bdb_write_config(svn_fs_t *fs)
}
static svn_error_t *
+base_bdb_refresh_revision(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
+{
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
base_bdb_info_format(int *fs_format,
svn_version_t **supports_version,
svn_fs_t *fs,
@@ -545,6 +552,7 @@ base_bdb_freeze(svn_fs_t *fs,
static fs_vtable_t fs_vtable = {
svn_fs_base__youngest_rev,
+ base_bdb_refresh_revision,
svn_fs_base__revision_prop,
svn_fs_base__revision_proplist,
svn_fs_base__change_rev_prop,
@@ -572,13 +580,12 @@ static fs_vtable_t fs_vtable = {
#define FORMAT_FILE "format"
/* Depending on CREATE, create or open the environment and databases
- for filesystem FS in PATH. Use POOL for temporary allocations. */
+ for filesystem FS in PATH. */
static svn_error_t *
open_databases(svn_fs_t *fs,
svn_boolean_t create,
int format,
- const char *path,
- apr_pool_t *pool)
+ const char *path)
{
base_fs_data_t *bfd;
@@ -732,7 +739,7 @@ static svn_error_t *
base_create(svn_fs_t *fs,
const char *path,
svn_mutex__t *common_pool_lock,
- apr_pool_t *pool,
+ apr_pool_t *scratch_pool,
apr_pool_t *common_pool)
{
int format = SVN_FS_BASE__FORMAT_NUMBER;
@@ -743,7 +750,7 @@ base_create(svn_fs_t *fs,
{
svn_version_t *compatible_version;
SVN_ERR(svn_fs__compatible_version(&compatible_version, fs->config,
- pool));
+ scratch_pool));
/* select format number */
switch(compatible_version->minor)
@@ -765,7 +772,7 @@ base_create(svn_fs_t *fs,
}
/* Create the environment and databases. */
- svn_err = open_databases(fs, TRUE, format, path, pool);
+ svn_err = open_databases(fs, TRUE, format, path);
if (svn_err) goto error;
/* Initialize the DAG subsystem. */
@@ -773,14 +780,15 @@ base_create(svn_fs_t *fs,
if (svn_err) goto error;
/* This filesystem is ready. Stamp it with a format number. */
- svn_err = svn_io_write_version_file(
- svn_dirent_join(fs->path, FORMAT_FILE, pool), format, pool);
+ svn_err = svn_io_write_version_file(svn_dirent_join(fs->path, FORMAT_FILE,
+ scratch_pool),
+ format, scratch_pool);
if (svn_err) goto error;
((base_fs_data_t *) fs->fsap_data)->format = format;
- SVN_ERR(populate_opened_fs(fs, pool));
- return SVN_NO_ERROR;;
+ SVN_ERR(populate_opened_fs(fs, scratch_pool));
+ return SVN_NO_ERROR;
error:
return svn_error_compose_create(svn_err,
@@ -826,7 +834,7 @@ static svn_error_t *
base_open(svn_fs_t *fs,
const char *path,
svn_mutex__t *common_pool_lock,
- apr_pool_t *pool,
+ apr_pool_t *scratch_pool,
apr_pool_t *common_pool)
{
int format;
@@ -835,8 +843,9 @@ base_open(svn_fs_t *fs,
/* Read the FS format number. */
svn_err = svn_io_read_version_file(&format,
- svn_dirent_join(path, FORMAT_FILE, pool),
- pool);
+ svn_dirent_join(path, FORMAT_FILE,
+ scratch_pool),
+ scratch_pool);
if (svn_err && APR_STATUS_IS_ENOENT(svn_err->apr_err))
{
/* Pre-1.2 filesystems did not have a format file (you could say
@@ -852,7 +861,7 @@ base_open(svn_fs_t *fs,
goto error;
/* Create the environment and databases. */
- svn_err = open_databases(fs, FALSE, format, path, pool);
+ svn_err = open_databases(fs, FALSE, format, path);
if (svn_err) goto error;
((base_fs_data_t *) fs->fsap_data)->format = format;
@@ -862,12 +871,12 @@ base_open(svn_fs_t *fs,
if (write_format_file)
{
svn_err = svn_io_write_version_file(svn_dirent_join(path, FORMAT_FILE,
- pool),
- format, pool);
+ scratch_pool),
+ format, scratch_pool);
if (svn_err) goto error;
}
- SVN_ERR(populate_opened_fs(fs, pool));
+ SVN_ERR(populate_opened_fs(fs, scratch_pool));
return SVN_NO_ERROR;
error:
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/fs.h Mon Nov 30 10:24:16 2015
@@ -195,11 +195,7 @@ typedef struct node_revision_t
only because one or both of us decided to pick up a shared
representation after-the-fact." May be NULL (if this node
revision isn't using a shared rep, or isn't the original
- "assignee" of a shared rep).
-
- This is no longer used by the 1.9 code but we have to keep
- reading and writing it to remain compatible with 1.8, and
- earlier, that require it. */
+ "assignee" of a shared rep). */
const char *data_key_uniquifier;
/* representation key for this node's text-data-in-progess (files
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/id.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/id.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/id.c Mon Nov 30 10:24:16 2015
@@ -113,7 +113,7 @@ svn_fs_base__id_compare(const svn_fs_id_
const svn_fs_id_t *b)
{
if (svn_fs_base__id_eq(a, b))
- return svn_fs_node_same;
+ return svn_fs_node_unchanged;
return (svn_fs_base__id_check_related(a, b) ? svn_fs_node_common_ancestor
: svn_fs_node_unrelated);
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/lock.c Mon Nov 30 10:24:16 2015
@@ -39,6 +39,7 @@
#include "private/svn_fs_util.h"
#include "private/svn_subr_private.h"
#include "private/svn_dep_compat.h"
+#include "revs-txns.h"
/* Add LOCK and its associated LOCK_TOKEN (associated with PATH) as
@@ -107,7 +108,7 @@ txn_body_lock(void *baton, trail_t *trai
SVN_ERR(svn_fs_base__get_path_kind(&kind, args->path, trail, trail->pool));
/* Until we implement directory locks someday, we only allow locks
- on files or non-existent paths. */
+ on files. */
if (kind == svn_node_dir)
return SVN_FS__ERR_NOT_FILE(trail->fs, args->path);
@@ -241,8 +242,11 @@ svn_fs_base__lock(svn_fs_t *fs,
{
apr_hash_index_t *hi;
svn_error_t *cb_err = SVN_NO_ERROR;
+ svn_revnum_t youngest_rev = SVN_INVALID_REVNUM;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_fs__check_fs(fs, TRUE));
+ SVN_ERR(svn_fs_base__youngest_rev(&youngest_rev, fs, scratch_pool));
for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
{
@@ -250,8 +254,9 @@ svn_fs_base__lock(svn_fs_t *fs,
const char *path = apr_hash_this_key(hi);
const svn_fs_lock_target_t *target = apr_hash_this_val(hi);
svn_lock_t *lock;
- svn_error_t *err;
+ svn_error_t *err = NULL;
+ svn_pool_clear(iterpool);
args.lock_p = &lock;
args.path = svn_fs__canonicalize_abspath(path, result_pool);
args.token = target->token;
@@ -262,12 +267,22 @@ svn_fs_base__lock(svn_fs_t *fs,
args.current_rev = target->current_rev;
args.result_pool = result_pool;
- err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, TRUE,
- scratch_pool);
+ if (SVN_IS_VALID_REVNUM(target->current_rev))
+ {
+ if (target->current_rev > youngest_rev)
+ err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+ _("No such revision %ld"),
+ target->current_rev);
+ }
+
+ if (!err)
+ err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, TRUE,
+ iterpool);
if (!cb_err && lock_callback)
- cb_err = lock_callback(lock_baton, args.path, lock, err, scratch_pool);
+ cb_err = lock_callback(lock_baton, args.path, lock, err, iterpool);
svn_error_clear(err);
}
+ svn_pool_destroy(iterpool);
return svn_error_trace(cb_err);
}
@@ -356,6 +371,7 @@ svn_fs_base__unlock(svn_fs_t *fs,
{
apr_hash_index_t *hi;
svn_error_t *cb_err = SVN_NO_ERROR;
+ apr_pool_t *iterpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_fs__check_fs(fs, TRUE));
@@ -366,16 +382,18 @@ svn_fs_base__unlock(svn_fs_t *fs,
const char *token = apr_hash_this_val(hi);
svn_error_t *err;
+ svn_pool_clear(iterpool);
args.path = svn_fs__canonicalize_abspath(path, result_pool);
args.token = token;
args.break_lock = break_lock;
err = svn_fs_base__retry_txn(fs, txn_body_unlock, &args, TRUE,
- scratch_pool);
+ iterpool);
if (!cb_err && lock_callback)
- cb_err = lock_callback(lock_baton, path, NULL, err, scratch_pool);
+ cb_err = lock_callback(lock_baton, path, NULL, err, iterpool);
svn_error_clear(err);
}
+ svn_pool_destroy(iterpool);
return svn_error_trace(cb_err);
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.c Mon Nov 30 10:24:16 2015
@@ -194,7 +194,9 @@ svn_error_t *
svn_fs_base__revision_proplist(apr_hash_t **table_p,
svn_fs_t *fs,
svn_revnum_t rev,
- apr_pool_t *pool)
+ svn_boolean_t refresh,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
struct revision_proplist_args args;
apr_hash_t *table;
@@ -204,9 +206,9 @@ svn_fs_base__revision_proplist(apr_hash_
args.table_p = &table;
args.rev = rev;
SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_revision_proplist, &args,
- FALSE, pool));
+ FALSE, result_pool));
- *table_p = table ? table : apr_hash_make(pool);
+ *table_p = table ? table : apr_hash_make(result_pool);
return SVN_NO_ERROR;
}
@@ -216,7 +218,9 @@ svn_fs_base__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)
{
struct revision_proplist_args args;
apr_hash_t *table;
@@ -227,7 +231,7 @@ svn_fs_base__revision_prop(svn_string_t
args.table_p = &table;
args.rev = rev;
SVN_ERR(svn_fs_base__retry_txn(fs, txn_body_revision_proplist, &args,
- FALSE, pool));
+ FALSE, result_pool));
/* And then the prop from that list (if there was a list). */
*value_p = svn_hash_gets(table, propname);
@@ -247,8 +251,10 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
{
transaction_t *txn;
const char *txn_id;
+ const svn_string_t *present_value;
SVN_ERR(get_rev_txn(&txn, &txn_id, fs, rev, trail, pool));
+ present_value = svn_hash_gets(txn->proplist, name);
/* If there's no proplist, but we're just deleting a property, exit now. */
if ((! txn->proplist) && (! value))
@@ -262,7 +268,6 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
if (old_value_p)
{
const svn_string_t *wanted_value = *old_value_p;
- const svn_string_t *present_value = svn_hash_gets(txn->proplist, name);
if ((!wanted_value != !present_value)
|| (wanted_value && present_value
&& !svn_string_compare(wanted_value, present_value)))
@@ -275,6 +280,13 @@ svn_fs_base__set_rev_prop(svn_fs_t *fs,
}
/* Fall through. */
}
+
+ /* If the prop-set is a no-op, skip the actual write. */
+ if ((!present_value && !value)
+ || (present_value && value
+ && svn_string_compare(present_value, value)))
+ return SVN_NO_ERROR;
+
svn_hash_sets(txn->proplist, name, value);
/* Overwrite the revision. */
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/revs-txns.h Mon Nov 30 10:24:16 2015
@@ -172,12 +172,16 @@ svn_error_t *svn_fs_base__youngest_rev(s
svn_error_t *svn_fs_base__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);
svn_error_t *svn_fs_base__revision_proplist(apr_hash_t **table_p,
svn_fs_t *fs,
svn_revnum_t rev,
- apr_pool_t *pool);
+ svn_boolean_t refresh,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool);
svn_error_t *svn_fs_base__change_rev_prop(svn_fs_t *fs, svn_revnum_t rev,
const char *name,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_base/tree.c Mon Nov 30 10:24:16 2015
@@ -68,6 +68,7 @@
#include "private/svn_fspath.h"
#include "private/svn_fs_util.h"
#include "private/svn_mergeinfo_private.h"
+#include "private/svn_sorts_private.h"
/* ### I believe this constant will become internal to reps-strings.c.
@@ -1285,6 +1286,21 @@ base_node_proplist(apr_hash_t **table_p,
return SVN_NO_ERROR;
}
+static svn_error_t *
+base_node_has_props(svn_boolean_t *has_props,
+ svn_fs_root_t *root,
+ const char *path,
+ apr_pool_t *scratch_pool)
+{
+ apr_hash_t *props;
+
+ SVN_ERR(base_node_proplist(&props, root, path, scratch_pool));
+
+ *has_props = (0 < apr_hash_count(props));
+
+ return SVN_NO_ERROR;
+}
+
struct change_node_prop_args {
svn_fs_root_t *root;
@@ -1608,13 +1624,15 @@ static svn_error_t *
base_dir_optimal_order(apr_array_header_t **ordered_p,
svn_fs_root_t *root,
apr_hash_t *entries,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
/* 1:1 copy of entries with no differnce in ordering */
apr_hash_index_t *hi;
- apr_array_header_t *result = apr_array_make(pool, apr_hash_count(entries),
- sizeof(svn_fs_dirent_t *));
- for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
+ apr_array_header_t *result
+ = apr_array_make(result_pool, apr_hash_count(entries),
+ sizeof(svn_fs_dirent_t *));
+ for (hi = apr_hash_first(scratch_pool, entries); hi; hi = apr_hash_next(hi))
APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = apr_hash_this_val(hi);
*ordered_p = result;
@@ -2563,8 +2581,7 @@ verify_locks(const char *txn_name,
apr_hash_this(hi, &key, NULL, NULL);
APR_ARRAY_PUSH(changed_paths, const char *) = key;
}
- qsort(changed_paths->elts, changed_paths->nelts,
- changed_paths->elt_size, svn_sort_compare_paths);
+ svn_sort__array(changed_paths, svn_sort_compare_paths);
/* Now, traverse the array of changed paths, verify locks. Note
that if we need to do a recursive verification a path, we'll skip
@@ -3164,7 +3181,8 @@ txn_body_copy(void *baton,
if ((to_parent_path->node)
&& (svn_fs_base__id_compare(svn_fs_base__dag_get_id(from_node),
svn_fs_base__dag_get_id
- (to_parent_path->node)) == svn_fs_node_same))
+ (to_parent_path->node))
+ == svn_fs_node_unchanged))
return SVN_NO_ERROR;
if (! from_root->is_txn_root)
@@ -5489,6 +5507,7 @@ static root_vtable_t root_vtable = {
base_closest_copy,
base_node_prop,
base_node_proplist,
+ base_node_has_props,
base_change_node_prop,
base_props_changed,
base_dir_entries,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.c Mon Nov 30 10:24:16 2015
@@ -57,7 +57,7 @@ block_read(void **result,
apr_pool_t *scratch_pool);
-/* Defined this to enable access logging via dgb__log_access
+/* Define this to enable access logging via dbg_log_access
#define SVN_FS_FS__LOG_ACCESS
*/
@@ -91,7 +91,7 @@ dbg_log_access(svn_fs_t *fs,
svn_fs_fs__revision_file_t *rev_file;
SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, revision,
- scratch_pool));
+ scratch_pool, scratch_pool));
/* determine rev / pack file offset */
SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, revision, NULL,
@@ -158,7 +158,8 @@ dbg_log_access(svn_fs_t *fs,
{
/* reverse index lookup: get item description in ENTRY */
SVN_ERR(svn_fs_fs__p2l_entry_lookup(&entry, fs, rev_file, revision,
- offset, scratch_pool));
+ offset, scratch_pool,
+ scratch_pool));
if (entry)
{
/* more details */
@@ -183,6 +184,10 @@ dbg_log_access(svn_fs_t *fs,
description);
}
+ /* We don't know when SCRATCH_POOL will be cleared, so close the rev file
+ explicitly. */
+ SVN_ERR(svn_fs_fs__close_revision_file(rev_file));
+
#endif
return SVN_NO_ERROR;
@@ -286,6 +291,114 @@ use_block_read(svn_fs_t *fs)
return svn_fs_fs__use_log_addressing(fs) && ffd->use_block_read;
}
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+ representation_t *rep,
+ apr_pool_t *scratch_pool)
+{
+ svn_checksum_t checksum;
+ svn_checksum_t *empty_md5;
+ svn_fs_fs__revision_file_t *revision_file;
+ svn_fs_fs__rep_header_t *rep_header;
+
+ /* Anything to do at all?
+ *
+ * Note that a 0 SIZE is only possible for PLAIN reps due to the SVN\1
+ * magic prefix in any DELTA rep. */
+ if (!rep || rep->expanded_size != 0 || rep->size == 0)
+ return SVN_NO_ERROR;
+
+ /* This function may only be called for committed data. */
+ assert(!svn_fs_fs__id_txn_used(&rep->txn_id));
+
+ /* EXPANDED_SIZE is 0. If the MD5 does not match the one for empty
+ * contents, we know that EXPANDED_SIZE == 0 is wrong and needs to
+ * be set to the actual value given by SIZE.
+ *
+ * Using svn_checksum_match() will also accept all-zero values for
+ * the MD5 digest and only report a mismatch if the MD5 has actually
+ * been given. */
+ empty_md5 = svn_checksum_empty_checksum(svn_checksum_md5, scratch_pool);
+
+ checksum.digest = rep->md5_digest;
+ checksum.kind = svn_checksum_md5;
+ if (!svn_checksum_match(empty_md5, &checksum))
+ {
+ rep->expanded_size = rep->size;
+ return SVN_NO_ERROR;
+ }
+
+ /* Data in the rep-cache.db does not have MD5 checksums (all zero) on it.
+ * Compare SHA1 instead. */
+ if (rep->has_sha1)
+ {
+ svn_checksum_t *empty_sha1
+ = svn_checksum_empty_checksum(svn_checksum_sha1, scratch_pool);
+
+ checksum.digest = rep->sha1_digest;
+ checksum.kind = svn_checksum_sha1;
+ if (!svn_checksum_match(empty_sha1, &checksum))
+ {
+ rep->expanded_size = rep->size;
+ return SVN_NO_ERROR;
+ }
+ }
+
+ /* Only two cases are left here.
+ * (1) A non-empty PLAIN rep with a MD5 collision on EMPTY_MD5.
+ * (2) A DELTA rep with zero-length output. */
+
+ /* SVN always stores a DELTA rep with zero-length output as an empty
+ * sequence of txdelta windows, i.e. as "SVN\1". In that case, SIZE is
+ * 4 bytes. There is no other possible DELTA rep of that size and any
+ * PLAIN rep of 4 bytes would produce a different MD5. Hence, if SIZE is
+ * actually 4 here, we know that this is an empty DELTA rep.
+ *
+ * Note that it is technically legal to have DELTA reps with a 0 length
+ * output window. Their on-disk size would be longer. We handle that
+ * case later together with the equally unlikely MD5 collision. */
+ if (rep->size == 4)
+ {
+ /* EXPANDED_SIZE is already 0. */
+ return SVN_NO_ERROR;
+ }
+
+ /* We still have the two options, PLAIN or DELTA rep. At this point, we
+ * are in an extremely unlikely case and can spend some time to figure it
+ * out. So, let's just look at the representation header. */
+ SVN_ERR(open_and_seek_revision(&revision_file, fs, rep->revision,
+ rep->item_index, scratch_pool));
+ SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, revision_file->stream,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+
+ /* Only for PLAIN reps do we have to correct EXPANDED_SIZE. */
+ if (rep_header->type == svn_fs_fs__rep_plain)
+ rep->expanded_size = rep->size;
+
+ return SVN_NO_ERROR;
+}
+
+/* Correct known issues with committed NODEREV in FS.
+ * Uses SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+fixup_node_revision(svn_fs_t *fs,
+ node_revision_t *noderev,
+ apr_pool_t *scratch_pool)
+{
+ /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+ noderev->is_fresh_txn_root = FALSE;
+
+ /* Make sure EXPANDED_SIZE has the correct value for every rep. */
+ SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->data_rep,
+ scratch_pool));
+ SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->prop_rep,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Get the node-revision for the node ID in FS.
Set *NODEREV_P to the new node-revision structure, allocated in POOL.
See svn_fs_fs__get_node_revision, which wraps this and adds another
@@ -312,14 +425,13 @@ get_node_revision_body(node_revision_t *
scratch_pool),
APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
scratch_pool);
- if (err)
+ if (err && APR_STATUS_IS_ENOENT(err->apr_err))
+ {
+ svn_error_clear(err);
+ return svn_error_trace(err_dangling_id(fs, id));
+ }
+ else if (err)
{
- if (APR_STATUS_IS_ENOENT(err->apr_err))
- {
- svn_error_clear(err);
- return svn_error_trace(err_dangling_id(fs, id));
- }
-
return svn_error_trace(err);
}
@@ -376,9 +488,7 @@ get_node_revision_body(node_revision_t *
revision_file->stream,
result_pool,
scratch_pool));
-
- /* Workaround issue #4031: is-fresh-txn-root in revision files. */
- (*noderev_p)->is_fresh_txn_root = FALSE;
+ SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
/* The noderev is not in cache, yet. Add it, if caching has been enabled. */
if (ffd->node_revision_cache)
@@ -765,9 +875,7 @@ create_rep_state_body(rep_state_t **rep_
Since we don't know the depth of the delta chain, let's assume, the
whole contents get rewritten 3 times.
*/
- estimated_window_storage
- = 4 * ( (rep->expanded_size ? rep->expanded_size : rep->size)
- + SVN_DELTA_WINDOW_SIZE);
+ estimated_window_storage = 4 * (rep->expanded_size + SVN_DELTA_WINDOW_SIZE);
estimated_window_storage = MIN(estimated_window_storage, APR_SIZE_MAX);
rs->window_cache = ffd->txdelta_window_cache
@@ -952,7 +1060,7 @@ svn_fs_fs__check_rep(representation_t *r
if ( entry == NULL
|| entry->type < SVN_FS_FS__ITEM_TYPE_FILE_REP
|| entry->type > SVN_FS_FS__ITEM_TYPE_DIR_PROPS)
- return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
_("No representation found at offset %s "
"for item %s in revision %ld"),
apr_off_t_toa(scratch_pool, offset),
@@ -1322,15 +1430,11 @@ set_cached_combined_window(svn_stringbuf
ID, and representation REP.
Also, set *WINDOW_P to the base window content for *LIST, if it
could be found in cache. Otherwise, *LIST will contain the base
- representation for the whole delta chain.
- Finally, return the expanded size of the representation in
- *EXPANDED_SIZE. It will take care of cases where only the on-disk
- size is known. */
+ representation for the whole delta chain. */
static svn_error_t *
build_rep_list(apr_array_header_t **list,
svn_stringbuf_t **window_p,
rep_state_t **src_state,
- svn_filesize_t *expanded_size,
svn_fs_t *fs,
representation_t *first_rep,
apr_pool_t *pool)
@@ -1345,24 +1449,9 @@ build_rep_list(apr_array_header_t **list
*list = apr_array_make(pool, 1, sizeof(rep_state_t *));
rep = *first_rep;
- /* The value as stored in the data struct.
- 0 is either for unknown length or actually zero length. */
- *expanded_size = first_rep->expanded_size;
-
/* for the top-level rep, we need the rep_args */
SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file, &rep, fs, pool,
iterpool));
-
- /* Unknown size or empty representation?
- That implies the this being the first iteration.
- Usually size equals on-disk size, except for empty,
- compressed representations (delta, size = 4).
- Please note that for all non-empty deltas have
- a 4-byte header _plus_ some data. */
- if (*expanded_size == 0)
- if (rep_header->type == svn_fs_fs__rep_plain || first_rep->size != 4)
- *expanded_size = first_rep->size;
-
while (1)
{
svn_pool_clear(iterpool);
@@ -1624,9 +1713,11 @@ get_combined_window(svn_stringbuf_t **re
/* Maybe, we've got a PLAIN start representation. If we do, read
as much data from it as the needed for the txdelta window's source
view.
- Note that BUF / SOURCE may only be NULL in the first iteration. */
+ Note that BUF / SOURCE may only be NULL in the first iteration.
+ Also note that we may have short-cut reading the delta chain --
+ in which case SRC_OPS is 0 and it might not be a PLAIN rep. */
source = buf;
- if (source == NULL && rb->src_state != NULL)
+ if (source == NULL && rb->src_state != NULL && window->src_ops)
SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
pool, iterpool));
@@ -1664,7 +1755,7 @@ get_combined_window(svn_stringbuf_t **re
}
/* Returns whether or not the expanded fulltext of the file is cachable
- * based on its size SIZE. The decision depends on the cache used by RB.
+ * based on its size SIZE. The decision depends on the cache used by FFD.
*/
static svn_boolean_t
fulltext_size_is_cachable(fs_fs_data_t *ffd, svn_filesize_t size)
@@ -1997,8 +2088,9 @@ rep_read_contents(void *baton,
if (!rb->rs_list)
{
/* Window stream not initialized, yet. Do it now. */
+ rb->len = rb->rep.expanded_size;
SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window,
- &rb->src_state, &rb->len, rb->fs, &rb->rep,
+ &rb->src_state, rb->fs, &rb->rep,
rb->filehandle_pool));
/* In case we did read from the fulltext cache before, make the
@@ -2065,7 +2157,6 @@ svn_fs_fs__get_contents(svn_stream_t **c
else
{
fs_fs_data_t *ffd = fs->fsap_data;
- svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
struct rep_read_baton *rb;
pair_cache_key_t fulltext_cache_key = { 0 };
@@ -2081,7 +2172,7 @@ svn_fs_fs__get_contents(svn_stream_t **c
* cache it. */
if (ffd->fulltext_cache && cache_fulltext
&& SVN_IS_VALID_REVNUM(rep->revision)
- && fulltext_size_is_cachable(ffd, len))
+ && fulltext_size_is_cachable(ffd, rep->expanded_size))
{
rb->fulltext_cache = ffd->fulltext_cache;
}
@@ -2330,12 +2421,12 @@ compare_dirent_name(const void *a, const
return strcmp(lhs->name, rhs);
}
-/* Into ENTRIES, read all directories entries from the key-value text in
+/* Into *ENTRIES_P, read all directories entries from the key-value text in
* STREAM. If INCREMENTAL is TRUE, read until the end of the STREAM and
* update the data. ID is provided for nicer error messages.
*/
static svn_error_t *
-read_dir_entries(apr_array_header_t *entries,
+read_dir_entries(apr_array_header_t **entries_p,
svn_stream_t *stream,
svn_boolean_t incremental,
const svn_fs_id_t *id,
@@ -2343,8 +2434,14 @@ read_dir_entries(apr_array_header_t *ent
apr_pool_t *scratch_pool)
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- apr_hash_t *hash = incremental ? svn_hash__make(scratch_pool) : NULL;
+ apr_hash_t *hash = NULL;
const char *terminator = SVN_HASH_TERMINATOR;
+ apr_array_header_t *entries = NULL;
+
+ if (incremental)
+ hash = svn_hash__make(scratch_pool);
+ else
+ entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
/* Read until the terminator (non-incremental) or the end of STREAM
(incremental mode). In the latter mode, we use a temporary HASH
@@ -2425,6 +2522,9 @@ read_dir_entries(apr_array_header_t *ent
if (incremental)
{
apr_hash_index_t *hi;
+
+ entries = apr_array_make(result_pool, apr_hash_count(hash),
+ sizeof(svn_fs_dirent_t *));
for (hi = apr_hash_first(iterpool, hash); hi; hi = apr_hash_next(hi))
APR_ARRAY_PUSH(entries, svn_fs_dirent_t *) = apr_hash_this_val(hi);
}
@@ -2434,14 +2534,45 @@ read_dir_entries(apr_array_header_t *ent
svn_pool_destroy(iterpool);
+ *entries_p = entries;
return SVN_NO_ERROR;
}
-/* Fetch the contents of a directory into ENTRIES. Values are stored
+/* For directory NODEREV in FS, return the *FILESIZE of its in-txn
+ * representation. If the directory representation is comitted data,
+ * set *FILESIZE to SVN_INVALID_FILESIZE. Use SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+get_txn_dir_info(svn_filesize_t *filesize,
+ svn_fs_t *fs,
+ node_revision_t *noderev,
+ apr_pool_t *scratch_pool)
+{
+ if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
+ {
+ const svn_io_dirent2_t *dirent;
+ const char *filename;
+
+ filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+ scratch_pool);
+
+ SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+ scratch_pool, scratch_pool));
+ *filesize = dirent->filesize;
+ }
+ else
+ {
+ *filesize = SVN_INVALID_FILESIZE;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Fetch the contents of a directory into DIR. Values are stored
as filename to string mappings; further conversion is necessary to
convert them into svn_fs_dirent_t values. */
static svn_error_t *
-get_dir_contents(apr_array_header_t **entries,
+get_dir_contents(svn_fs_fs__dir_data_t *dir,
svn_fs_t *fs,
node_revision_t *noderev,
apr_pool_t *result_pool,
@@ -2449,18 +2580,30 @@ get_dir_contents(apr_array_header_t **en
{
svn_stream_t *contents;
- *entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
+ /* Initialize the result. */
+ dir->txn_filesize = SVN_INVALID_FILESIZE;
+
+ /* Read dir contents - unless there is none in which case we are done. */
if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
{
- const char *filename
- = svn_fs_fs__path_txn_node_children(fs, noderev->id, scratch_pool);
+ /* Get location & current size of the directory representation. */
+ const char *filename;
+ apr_file_t *file;
+
+ filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+ scratch_pool);
/* The representation is mutable. Read the old directory
contents from the mutable children file, followed by the
changes we've made in this transaction. */
- SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool,
- scratch_pool));
- SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id,
+ SVN_ERR(svn_io_file_open(&file, filename, APR_READ | APR_BUFFERED,
+ APR_OS_DEFAULT, scratch_pool));
+
+ /* Obtain txn children file size. */
+ SVN_ERR(svn_io_file_size_get(&dir->txn_filesize, file, scratch_pool));
+
+ contents = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+ SVN_ERR(read_dir_entries(&dir->entries, contents, TRUE, noderev->id,
result_pool, scratch_pool));
SVN_ERR(svn_stream_close(contents));
}
@@ -2469,9 +2612,7 @@ get_dir_contents(apr_array_header_t **en
/* Undeltify content before parsing it. Otherwise, we could only
* parse it byte-by-byte.
*/
- apr_size_t len = noderev->data_rep->expanded_size
- ? (apr_size_t)noderev->data_rep->expanded_size
- : (apr_size_t)noderev->data_rep->size;
+ apr_size_t len = noderev->data_rep->expanded_size;
svn_stringbuf_t *text;
/* The representation is immutable. Read it normally. */
@@ -2482,9 +2623,13 @@ get_dir_contents(apr_array_header_t **en
/* de-serialize hash */
contents = svn_stream_from_stringbuf(text, scratch_pool);
- SVN_ERR(read_dir_entries(*entries, contents, FALSE, noderev->id,
+ SVN_ERR(read_dir_entries(&dir->entries, contents, FALSE, noderev->id,
result_pool, scratch_pool));
}
+ else
+ {
+ dir->entries = apr_array_make(result_pool, 0, sizeof(svn_fs_dirent_t *));
+ }
return SVN_NO_ERROR;
}
@@ -2503,27 +2648,27 @@ locate_dir_cache(svn_fs_t *fs,
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
- if (svn_fs_fs__id_is_txn(noderev->id))
+ if (!noderev->data_rep)
+ {
+ /* no data rep -> empty directory.
+ A NULL key causes a cache miss. */
+ *key = NULL;
+ return ffd->dir_cache;
+ }
+
+ if (svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
{
/* data in txns requires the expensive fs_id-based addressing mode */
*key = svn_fs_fs__id_unparse(noderev->id, pool)->data;
+
return ffd->txn_dir_cache;
}
else
{
/* committed data can use simple rev,item pairs */
- if (noderev->data_rep)
- {
- pair_key->revision = noderev->data_rep->revision;
- pair_key->second = noderev->data_rep->item_index;
- *key = pair_key;
- }
- else
- {
- /* no data rep -> empty directory.
- A NULL key causes a cache miss. */
- *key = NULL;
- }
+ pair_key->revision = noderev->data_rep->revision;
+ pair_key->second = noderev->data_rep->item_index;
+ *key = pair_key;
return ffd->dir_cache;
}
@@ -2538,6 +2683,7 @@ svn_fs_fs__rep_contents_dir(apr_array_he
{
pair_cache_key_t pair_key = { 0 };
const void *key;
+ svn_fs_fs__dir_data_t *dir;
/* find the cache we may use */
svn_cache__t *cache = locate_dir_cache(fs, &key, &pair_key, noderev,
@@ -2546,19 +2692,32 @@ svn_fs_fs__rep_contents_dir(apr_array_he
{
svn_boolean_t found;
- SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, key,
+ SVN_ERR(svn_cache__get((void **)&dir, &found, cache, key,
result_pool));
if (found)
- return SVN_NO_ERROR;
+ {
+ /* Verify that the cached dir info is not stale
+ * (no-op for committed data). */
+ svn_filesize_t filesize;
+ SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
+ if (filesize == dir->txn_filesize)
+ {
+ /* Still valid. Done. */
+ *entries_p = dir->entries;
+ return SVN_NO_ERROR;
+ }
+ }
}
/* Read in the directory contents. */
- SVN_ERR(get_dir_contents(entries_p, fs, noderev, result_pool,
- scratch_pool));
+ dir = apr_pcalloc(scratch_pool, sizeof(*dir));
+ SVN_ERR(get_dir_contents(dir, fs, noderev, result_pool, scratch_pool));
+ *entries_p = dir->entries;
/* Update the cache, if we are to use one. */
if (cache)
- SVN_ERR(svn_cache__set(cache, key, *entries_p, scratch_pool));
+ SVN_ERR(svn_cache__set(cache, key, dir, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2590,30 +2749,40 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
scratch_pool);
if (cache)
{
+ extract_dir_entry_baton_t baton;
+
+ svn_filesize_t filesize;
+ SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
/* Cache lookup. */
+ baton.txn_filesize = filesize;
+ baton.name = name;
SVN_ERR(svn_cache__get_partial((void **)dirent,
&found,
cache,
key,
svn_fs_fs__extract_dir_entry,
- (void*)name,
+ &baton,
result_pool));
}
/* fetch data from disk if we did not find it in the cache */
if (! found)
{
- apr_array_header_t *entries;
svn_fs_dirent_t *entry;
svn_fs_dirent_t *entry_copy = NULL;
+ svn_fs_fs__dir_data_t dir;
- /* read the dir from the file system. It will probably be put it
- into the cache for faster lookup in future calls. */
- SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev,
- scratch_pool, scratch_pool));
+ /* Read in the directory contents. */
+ SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool,
+ scratch_pool));
+
+ /* Update the cache, if we are to use one. */
+ if (cache)
+ SVN_ERR(svn_cache__set(cache, key, &dir, scratch_pool));
/* find desired entry and return a copy in POOL, if found */
- entry = svn_fs_fs__find_dir_entry(entries, name, NULL);
+ entry = svn_fs_fs__find_dir_entry(dir.entries, name, NULL);
if (entry)
{
entry_copy = apr_palloc(result_pool, sizeof(*entry_copy));
@@ -2639,16 +2808,27 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
if (noderev->prop_rep && svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
{
+ svn_error_t *err;
const char *filename
= svn_fs_fs__path_txn_node_props(fs, noderev->id, pool);
proplist = apr_hash_make(pool);
SVN_ERR(svn_stream_open_readonly(&stream, filename, pool, pool));
- SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+ err = svn_hash_read2(proplist, 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 property list for node-revision '%s' in '%s'"),
+ id_str->data, filename);
+ }
SVN_ERR(svn_stream_close(stream));
}
else if (noderev->prop_rep)
{
+ svn_error_t *err;
fs_fs_data_t *ffd = fs->fsap_data;
representation_t *rep = noderev->prop_rep;
pair_cache_key_t key = { 0 };
@@ -2667,7 +2847,16 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
proplist = apr_hash_make(pool);
SVN_ERR(svn_fs_fs__get_contents(&stream, fs, noderev->prop_rep, FALSE,
pool));
- SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+ err = svn_hash_read2(proplist, 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 property list for node-revision '%s'"),
+ id_str->data);
+ }
SVN_ERR(svn_stream_close(stream));
if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
@@ -2690,7 +2879,7 @@ svn_fs_fs__get_changes(apr_array_header_
svn_revnum_t rev,
apr_pool_t *result_pool)
{
- apr_off_t changes_offset = SVN_FS_FS__ITEM_INDEX_CHANGES;
+ apr_off_t item_index = SVN_FS_FS__ITEM_INDEX_CHANGES;
svn_fs_fs__revision_file_t *revision_file;
svn_boolean_t found;
fs_fs_data_t *ffd = fs->fsap_data;
@@ -2725,17 +2914,26 @@ svn_fs_fs__get_changes(apr_array_header_
}
else
{
+ apr_off_t changes_offset;
+
/* Addressing is very different for old formats
* (needs to read the revision trailer). */
if (svn_fs_fs__use_log_addressing(fs))
- SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs,
- revision_file, rev, NULL,
- SVN_FS_FS__ITEM_INDEX_CHANGES,
- scratch_pool));
+ {
+ SVN_ERR(svn_fs_fs__item_offset(&changes_offset, fs,
+ revision_file, rev, NULL,
+ SVN_FS_FS__ITEM_INDEX_CHANGES,
+ scratch_pool));
+ }
else
- SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
- revision_file, fs, rev,
- scratch_pool));
+ {
+ SVN_ERR(get_root_changes_offset(NULL, &changes_offset,
+ revision_file, fs, rev,
+ scratch_pool));
+
+ /* This variable will be used for debug logging only. */
+ item_index = changes_offset;
+ }
/* Actual reading and parsing are the same, though. */
SVN_ERR(aligned_seek(fs, revision_file->file, NULL, changes_offset,
@@ -2763,7 +2961,7 @@ svn_fs_fs__get_changes(apr_array_header_
SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
}
- SVN_ERR(dbg_log_access(fs, rev, changes_offset, *changes,
+ SVN_ERR(dbg_log_access(fs, rev, item_index, *changes,
SVN_FS_FS__ITEM_TYPE_CHANGES, scratch_pool));
svn_pool_destroy(scratch_pool);
@@ -3200,9 +3398,7 @@ block_read_noderev(node_revision_t **nod
/* read node rev from revision file */
SVN_ERR(svn_fs_fs__read_noderev(noderev_p, stream,
result_pool, scratch_pool));
-
- /* Workaround issue #4031: is-fresh-txn-root in revision files. */
- (*noderev_p)->is_fresh_txn_root = FALSE;
+ SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
if (ffd->node_revision_cache)
SVN_ERR(svn_cache__set(ffd->node_revision_cache, &key, *noderev_p,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/cached_data.h Mon Nov 30 10:24:16 2015
@@ -30,6 +30,18 @@
+/* Resolve a FSFS quirk: if REP in FS is a "PLAIN" representation, its
+ * EXPANDED_SIZE element may be 0, in which case its value has to be taken
+ * from SIZE.
+ *
+ * This function ensures that EXPANDED_SIZE in REP always contains the
+ * actual value. No-op if REP is NULL. Uses SCRATCH_POOL for temporaries.
+ */
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+ representation_t *rep,
+ apr_pool_t *scratch_pool);
+
/* Set *NODEREV_P to the node-revision for the node ID in FS. Do any
allocations in POOL. */
svn_error_t *
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/caching.c Mon Nov 30 10:24:16 2015
@@ -274,7 +274,8 @@ init_callbacks(svn_cache__t *cache,
* MEMBUFFER is not NULL. Fallbacks to inprocess cache if MEMCACHE and
* MEMBUFFER are NULL and pages is non-zero. Sets *CACHE_P to NULL
* otherwise. Use the given PRIORITY class for the new cache. If it
- * is 0, then use the default priority class.
+ * is 0, then use the default priority class. HAS_NAMESPACE indicates
+ * whether we prefixed this cache instance with a namespace.
*
* Unless NO_HANDLER is true, register an error handler that reports errors
* as warnings to the FS warning callback.
@@ -292,6 +293,7 @@ create_cache(svn_cache__t **cache_p,
apr_ssize_t klen,
const char *prefix,
apr_uint32_t priority,
+ svn_boolean_t has_namespace,
svn_fs_t *fs,
svn_boolean_t no_handler,
apr_pool_t *result_pool,
@@ -314,9 +316,12 @@ create_cache(svn_cache__t **cache_p,
}
else if (membuffer)
{
+ /* We assume caches with namespaces to be relatively short-lived,
+ * i.e. their data will not be needed after a while. */
SVN_ERR(svn_cache__create_membuffer_cache(
cache_p, membuffer, serializer, deserializer,
- klen, prefix, priority, FALSE, result_pool, scratch_pool));
+ klen, prefix, priority, FALSE, has_namespace,
+ result_pool, scratch_pool));
}
else if (pages)
{
@@ -349,6 +354,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
svn_boolean_t cache_txdeltas;
svn_boolean_t cache_fulltexts;
const char *cache_namespace;
+ svn_boolean_t has_namespace;
/* Evaluating the cache configuration. */
SVN_ERR(read_config(&cache_namespace,
@@ -358,6 +364,7 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
pool));
prefix = apr_pstrcat(pool, "ns:", cache_namespace, ":", prefix, SVN_VA_NULL);
+ has_namespace = strlen(cache_namespace) > 0;
membuffer = svn_cache__get_global_membuffer_cache();
@@ -386,34 +393,35 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
* commands, this is only going to contain a few entries (svnadmin
* dump/verify is an exception here), so to reduce overhead let's
* try to keep it to just one page. I estimate each entry has about
- * 72 bytes of overhead (svn_revnum_t key, svn_fs_id_t +
- * id_private_t + 3 strings for value, and the cache_entry); the
- * default pool size is 8192, so about a hundred should fit
- * comfortably. */
+ * 130 bytes of overhead (svn_revnum_t key, ID struct, and the cache_entry);
+ * the default pool size is 8192, so about a fifty should fit comfortably.
+ */
SVN_ERR(create_cache(&(ffd->rev_root_id_cache),
NULL,
membuffer,
- 1, 100,
+ 1, 50,
svn_fs_fs__serialize_id,
svn_fs_fs__deserialize_id,
sizeof(svn_revnum_t),
apr_pstrcat(pool, prefix, "RRI", SVN_VA_NULL),
0,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
- /* Rough estimate: revision DAG nodes have size around 320 bytes, so
- * let's put 16 on a page. */
+ /* Rough estimate: revision DAG nodes have size around 1kBytes, so
+ * let's put 8 on a page. */
SVN_ERR(create_cache(&(ffd->rev_node_cache),
NULL,
membuffer,
- 1024, 16,
+ 1, 8,
svn_fs_fs__dag_serialize,
svn_fs_fs__dag_deserialize,
APR_HASH_KEY_STRING,
apr_pstrcat(pool, prefix, "DAG", SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -425,28 +433,30 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->dir_cache),
NULL,
membuffer,
- 1024, 8,
+ 1, 8,
svn_fs_fs__serialize_dir_entries,
svn_fs_fs__deserialize_dir_entries,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "DIR", SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
- /* Only 16 bytes per entry (a revision number + the corresponding offset).
- Since we want ~8k pages, that means 512 entries per page. */
+ /* 8 kBytes per entry (1000 revs / shared, one file offset per rev).
+ Covering about 8 pack files gives us an "o.k." hit rate. */
SVN_ERR(create_cache(&(ffd->packed_offset_cache),
NULL,
membuffer,
- 32, 1,
+ 8, 1,
svn_fs_fs__serialize_manifest,
svn_fs_fs__deserialize_manifest,
sizeof(svn_revnum_t),
apr_pstrcat(pool, prefix, "PACK-MANIFEST",
SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -455,12 +465,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->node_revision_cache),
NULL,
membuffer,
- 32, 32, /* ~200 byte / entry; 1k entries total */
+ 2, 16, /* ~500 byte / entry; 32 entries total */
svn_fs_fs__serialize_node_revision,
svn_fs_fs__deserialize_node_revision,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "NODEREVS", SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -469,12 +480,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->rep_header_cache),
NULL,
membuffer,
- 1, 1000, /* ~8 bytes / entry; 1k entries total */
+ 1, 200, /* ~40 bytes / entry; 200 entries total */
svn_fs_fs__serialize_rep_header,
svn_fs_fs__deserialize_rep_header,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "REPHEADER", SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -489,6 +501,22 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
sizeof(svn_revnum_t),
apr_pstrcat(pool, prefix, "CHANGES", SVN_VA_NULL),
0,
+ has_namespace,
+ fs,
+ no_handler,
+ fs->pool, pool));
+
+ /* if enabled, cache revprops */
+ SVN_ERR(create_cache(&(ffd->revprop_cache),
+ NULL,
+ membuffer,
+ 0, 0, /* Do not use inprocess cache */
+ svn_fs_fs__serialize_revprops,
+ svn_fs_fs__deserialize_revprops,
+ sizeof(pair_cache_key_t),
+ apr_pstrcat(pool, prefix, "REVPROP", SVN_VA_NULL),
+ SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ TRUE, /* contents is short-lived */
fs,
no_handler,
fs->pool, pool));
@@ -499,12 +527,13 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->fulltext_cache),
ffd->memcache,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
/* Values are svn_stringbuf_t */
NULL, NULL,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "TEXT", SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -512,13 +541,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->properties_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
svn_fs_fs__serialize_properties,
svn_fs_fs__deserialize_properties,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "PROP",
SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_DEFAULT_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -526,13 +556,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->mergeinfo_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
svn_fs_fs__serialize_mergeinfo,
svn_fs_fs__deserialize_mergeinfo,
APR_HASH_KEY_STRING,
apr_pstrcat(pool, prefix, "MERGEINFO",
SVN_VA_NULL),
0,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -540,13 +571,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->mergeinfo_existence_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
/* Values are svn_stringbuf_t */
NULL, NULL,
APR_HASH_KEY_STRING,
apr_pstrcat(pool, prefix, "HAS_MERGEINFO",
SVN_VA_NULL),
0,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -565,13 +597,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->raw_window_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
svn_fs_fs__serialize_raw_window,
svn_fs_fs__deserialize_raw_window,
sizeof(window_cache_key_t),
apr_pstrcat(pool, prefix, "RAW_WINDOW",
SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -579,13 +612,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->txdelta_window_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
svn_fs_fs__serialize_txdelta_window,
svn_fs_fs__deserialize_txdelta_window,
sizeof(window_cache_key_t),
apr_pstrcat(pool, prefix, "TXDELTA_WINDOW",
SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -593,13 +627,14 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->combined_window_cache),
NULL,
membuffer,
- 0, 0, /* Do not use inprocess cache */
+ 0, 0, /* Do not use the inprocess cache */
/* Values are svn_stringbuf_t */
NULL, NULL,
sizeof(window_cache_key_t),
apr_pstrcat(pool, prefix, "COMBINED_WINDOW",
SVN_VA_NULL),
SVN_CACHE__MEMBUFFER_LOW_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -613,28 +648,34 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
SVN_ERR(create_cache(&(ffd->l2p_header_cache),
NULL,
membuffer,
- 64, 16, /* entry size varies but we must cover
- a reasonable number of revisions (1k) */
+ 8, 16, /* entry size varies but we must cover a
+ reasonable number of rev / pack files
+ to allow for delta chains to be walked
+ efficiently etc. */
svn_fs_fs__serialize_l2p_header,
svn_fs_fs__deserialize_l2p_header,
sizeof(pair_cache_key_t),
apr_pstrcat(pool, prefix, "L2P_HEADER",
(char *)NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
SVN_ERR(create_cache(&(ffd->l2p_page_cache),
NULL,
membuffer,
- 64, 16, /* entry size varies but we must cover
- a reasonable number of revisions (1k) */
+ 8, 16, /* entry size varies but we must cover a
+ reasonable number of rev / pack files
+ to allow for delta chains to be walked
+ efficiently etc. */
svn_fs_fs__serialize_l2p_page,
svn_fs_fs__deserialize_l2p_page,
sizeof(svn_fs_fs__page_cache_key_t),
apr_pstrcat(pool, prefix, "L2P_PAGE",
(char *)NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -648,19 +689,21 @@ svn_fs_fs__initialize_caches(svn_fs_t *f
apr_pstrcat(pool, prefix, "P2L_HEADER",
(char *)NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
SVN_ERR(create_cache(&(ffd->p2l_page_cache),
NULL,
membuffer,
- 4, 16, /* Variably sized entries. Rarely used. */
+ 4, 1, /* Variably sized entries. Rarely used. */
svn_fs_fs__serialize_p2l_page,
svn_fs_fs__deserialize_p2l_page,
sizeof(svn_fs_fs__page_cache_key_t),
apr_pstrcat(pool, prefix, "P2L_PAGE",
(char *)NULL),
SVN_CACHE__MEMBUFFER_HIGH_PRIORITY,
+ has_namespace,
fs,
no_handler,
fs->pool, pool));
@@ -773,18 +816,7 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
apr_pool_t *pool)
{
fs_fs_data_t *ffd = fs->fsap_data;
-
- /* Transaction content needs to be carefully prefixed to virtually
- eliminate any chance for conflicts. The (repo, txn_id) pair
- should be unique but if a transaction fails, it might be possible
- to start a new transaction later that receives the same id.
- Therefore, throw in a uuid as well - just to be sure. */
- const char *prefix = apr_pstrcat(pool,
- "fsfs:", fs->uuid,
- "/", fs->path,
- ":", txn_id,
- ":", svn_uuid_generate(pool), ":",
- SVN_VA_NULL);
+ const char *prefix;
/* We don't support caching for concurrent transactions in the SAME
* FSFS session. Maybe, you forgot to clean POOL. */
@@ -796,6 +828,19 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
return SVN_NO_ERROR;
}
+ /* Transaction content needs to be carefully prefixed to virtually
+ eliminate any chance for conflicts. The (repo, txn_id) pair
+ should be unique but if a transaction fails, it might be possible
+ to start a new transaction later that receives the same id.
+ Therefore, throw in a uuid as well - just to be sure. */
+ prefix = apr_pstrcat(pool,
+ "fsfs:", fs->uuid,
+ "/", fs->path,
+ ":", txn_id,
+ ":", svn_uuid_generate(pool),
+ ":", "TXNDIR",
+ SVN_VA_NULL);
+
/* create a txn-local directory cache */
SVN_ERR(create_cache(&ffd->txn_dir_cache,
NULL,
@@ -804,9 +849,9 @@ svn_fs_fs__initialize_txn_caches(svn_fs_
svn_fs_fs__serialize_dir_entries,
svn_fs_fs__deserialize_dir_entries,
APR_HASH_KEY_STRING,
- apr_pstrcat(pool, prefix, "TXNDIR",
- SVN_VA_NULL),
+ prefix,
0,
+ TRUE, /* The TXN-ID is our namespace. */
fs,
TRUE,
pool, pool));
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.c Mon Nov 30 10:24:16 2015
@@ -498,6 +498,40 @@ svn_fs_fs__dag_get_proplist(apr_hash_t *
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+ dag_node_t *node,
+ apr_pool_t *scratch_pool)
+{
+ node_revision_t *noderev;
+
+ SVN_ERR(get_node_revision(&noderev, node));
+
+ if (! noderev->prop_rep)
+ {
+ *has_props = FALSE; /* Easy out */
+ return SVN_NO_ERROR;
+ }
+
+ if (svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
+ {
+ /* We are in a commit or something. Check actual properties */
+ apr_hash_t *proplist;
+
+ SVN_ERR(svn_fs_fs__get_proplist(&proplist, node->fs,
+ noderev, scratch_pool));
+
+ *has_props = proplist ? (0 < apr_hash_count(proplist)) : FALSE;
+ }
+ else
+ {
+ /* Properties are stored as a standard hash stream,
+ always ending with "END\n" (4 bytes) */
+ *has_props = noderev->prop_rep->expanded_size > 4;
+ }
+
+ return SVN_NO_ERROR;
+}
svn_error_t *
svn_fs_fs__dag_set_proplist(dag_node_t *node,
@@ -1271,34 +1305,58 @@ svn_fs_fs__dag_things_different(svn_bool
apr_pool_t *pool)
{
node_revision_t *noderev1, *noderev2;
- svn_fs_t *fs;
- svn_boolean_t same;
/* If we have no place to store our results, don't bother doing
anything. */
if (! props_changed && ! contents_changed)
return SVN_NO_ERROR;
- fs = svn_fs_fs__dag_get_fs(node1);
-
/* The node revision skels for these two nodes. */
SVN_ERR(get_node_revision(&noderev1, node1));
SVN_ERR(get_node_revision(&noderev2, node2));
- /* Compare property keys. */
- if (props_changed != NULL)
+ if (strict)
{
- SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, noderev1, noderev2,
- strict, pool));
- *props_changed = !same;
- }
+ /* In strict mode, compare text and property representations in the
+ svn_fs_contents_different() / svn_fs_props_different() manner.
- /* Compare contents keys. */
- if (contents_changed != NULL)
+ See the "No-op changes no longer dumped by 'svnadmin dump' in 1.9"
+ discussion (http://svn.haxx.se/dev/archive-2015-09/0269.shtml) and
+ issue #4598 (https://issues.apache.org/jira/browse/SVN-4598). */
+ svn_fs_t *fs = svn_fs_fs__dag_get_fs(node1);
+ svn_boolean_t same;
+
+ /* Compare property keys. */
+ if (props_changed != NULL)
+ {
+ SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, noderev1,
+ noderev2, pool));
+ *props_changed = !same;
+ }
+
+ /* Compare contents keys. */
+ if (contents_changed != NULL)
+ {
+ SVN_ERR(svn_fs_fs__file_text_rep_equal(&same, fs, noderev1,
+ noderev2, pool));
+ *contents_changed = !same;
+ }
+ }
+ else
{
- SVN_ERR(svn_fs_fs__file_text_rep_equal(&same, fs, noderev1, noderev2,
- strict, pool));
- *contents_changed = !same;
+ /* Otherwise, compare representation keys -- as in Subversion 1.8. */
+
+ /* Compare property keys. */
+ if (props_changed != NULL)
+ *props_changed =
+ !svn_fs_fs__noderev_same_rep_key(noderev1->prop_rep,
+ noderev2->prop_rep);
+
+ /* Compare contents keys. */
+ if (contents_changed != NULL)
+ *contents_changed =
+ !svn_fs_fs__noderev_same_rep_key(noderev1->data_rep,
+ noderev2->data_rep);
}
return SVN_NO_ERROR;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/dag.h Mon Nov 30 10:24:16 2015
@@ -177,6 +177,12 @@ svn_error_t *svn_fs_fs__dag_get_proplist
dag_node_t *node,
apr_pool_t *pool);
+/* Set *HAS_PROPS to TRUE if NODE has properties. Use SCRATCH_POOL
+ for temporary allocations */
+svn_error_t *svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+ dag_node_t *node,
+ apr_pool_t *scratch_pool);
+
/* Set the property list of NODE to PROPLIST, allocating from POOL.
The node being changed must be mutable.
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.c Mon Nov 30 10:24:16 2015
@@ -27,7 +27,6 @@
#include <apr_general.h>
#include <apr_pools.h>
#include <apr_file_io.h>
-#include <apr_thread_mutex.h>
#include "svn_fs.h"
#include "svn_delta.h"
@@ -135,8 +134,29 @@ fs_serialized_init(svn_fs_t *fs, apr_poo
return SVN_NO_ERROR;
}
+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)
+{
+ SVN_MUTEX__WITH_LOCK(common_pool_lock,
+ fs_serialized_init(fs, common_pool, pool));
+
+ return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+fs_refresh_revprops(svn_fs_t *fs,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_fs__reset_revprop_cache(fs);
+
+ return SVN_NO_ERROR;
+}
+
/* This function is provided for Subversion 1.0.x compatibility. It
has no effect for fsfs backed Subversion filesystems. It conforms
to the fs_library_vtable_t.bdb_set_errcall() API. */
@@ -163,9 +183,11 @@ fs_freeze_body(void *baton,
SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
if (exists)
- SVN_ERR(svn_fs_fs__lock_rep_cache(b->fs, pool));
-
- SVN_ERR(b->freeze_func(b->freeze_baton, pool));
+ SVN_ERR(svn_fs_fs__with_rep_cache_lock(b->fs,
+ b->freeze_func, b->freeze_baton,
+ pool));
+ else
+ SVN_ERR(b->freeze_func(b->freeze_baton, pool));
return SVN_NO_ERROR;
}
@@ -236,6 +258,7 @@ fs_set_uuid(svn_fs_t *fs,
/* The vtable associated with a specific open filesystem. */
static fs_vtable_t fs_vtable = {
svn_fs_fs__youngest_rev,
+ fs_refresh_revprops,
svn_fs_fs__revision_prop,
svn_fs_fs__get_revision_proplist,
svn_fs_fs__change_rev_prop,
@@ -268,6 +291,7 @@ initialize_fs_struct(svn_fs_t *fs)
{
fs_fs_data_t *ffd = apr_pcalloc(fs->pool, sizeof(*ffd));
ffd->use_log_addressing = FALSE;
+ ffd->revprop_prefix = 0;
fs->vtable = &fs_vtable;
fs->fsap_data = ffd;
@@ -291,18 +315,18 @@ static svn_error_t *
fs_create(svn_fs_t *fs,
const char *path,
svn_mutex__t *common_pool_lock,
- apr_pool_t *pool,
+ apr_pool_t *scratch_pool,
apr_pool_t *common_pool)
{
SVN_ERR(svn_fs__check_fs(fs, FALSE));
SVN_ERR(initialize_fs_struct(fs));
- SVN_ERR(svn_fs_fs__create(fs, path, pool));
+ SVN_ERR(svn_fs_fs__create(fs, path, scratch_pool));
- SVN_ERR(svn_fs_fs__initialize_caches(fs, pool));
+ SVN_ERR(svn_fs_fs__initialize_caches(fs, scratch_pool));
SVN_MUTEX__WITH_LOCK(common_pool_lock,
- fs_serialized_init(fs, common_pool, pool));
+ fs_serialized_init(fs, common_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -320,10 +344,10 @@ static svn_error_t *
fs_open(svn_fs_t *fs,
const char *path,
svn_mutex__t *common_pool_lock,
- apr_pool_t *pool,
+ apr_pool_t *scratch_pool,
apr_pool_t *common_pool)
{
- apr_pool_t *subpool = svn_pool_create(pool);
+ apr_pool_t *subpool = svn_pool_create(scratch_pool);
SVN_ERR(svn_fs__check_fs(fs, FALSE));
@@ -479,28 +503,19 @@ fs_hotcopy(svn_fs_t *src_fs,
apr_pool_t *pool,
apr_pool_t *common_pool)
{
- /* Open the source repo as usual. */
SVN_ERR(fs_open(src_fs, src_path, common_pool_lock, pool, common_pool));
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
- /* Test target repo when in INCREMENTAL mode, initialize it when not.
- * For this, we need our FS internal data structures to be temporarily
- * available. */
+ SVN_ERR(svn_fs__check_fs(dst_fs, FALSE));
SVN_ERR(initialize_fs_struct(dst_fs));
- SVN_ERR(svn_fs_fs__hotcopy_prepare_target(src_fs, dst_fs, dst_path,
- incremental, pool));
- uninitialize_fs_struct(dst_fs);
-
- /* Now, the destination repo should open just fine. */
- SVN_ERR(fs_open(dst_fs, dst_path, common_pool_lock, pool, common_pool));
- if (cancel_func)
- SVN_ERR(cancel_func(cancel_baton));
-
- /* Now, we may copy data as needed ... */
- return svn_fs_fs__hotcopy(src_fs, dst_fs, incremental,
- notify_func, notify_baton,
- cancel_func, cancel_baton, pool);
+
+ /* In INCREMENTAL mode, svn_fs_fs__hotcopy() will open DST_FS.
+ Otherwise, it's not an FS yet --- possibly just an empty dir --- so
+ can't be opened.
+ */
+ return svn_fs_fs__hotcopy(src_fs, dst_fs, src_path, dst_path,
+ incremental, notify_func, notify_baton,
+ cancel_func, cancel_baton, common_pool_lock,
+ pool, common_pool);
}
Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/fs.h Mon Nov 30 10:24:16 2015
@@ -82,8 +82,6 @@ extern "C" {
/* Names of special files and file extensions for transactions */
#define PATH_CHANGES "changes" /* Records changes made so far */
#define PATH_TXN_PROPS "props" /* Transaction properties */
-#define PATH_TXN_PROPS_FINAL "props-final" /* Final transaction properties
- before moving to revprops */
#define PATH_NEXT_IDS "next-ids" /* Next temporary ID assignments */
#define PATH_PREFIX_NODE "node." /* Prefix for node filename */
#define PATH_EXT_TXN ".txn" /* Extension of txn dir */
@@ -353,6 +351,15 @@ typedef struct fs_fs_data_t
rep key (revision/offset) to svn_stringbuf_t. */
svn_cache__t *fulltext_cache;
+ /* The current prefix to be used for revprop cache entries.
+ If this is 0, a new unique prefix must be chosen. */
+ apr_uint64_t revprop_prefix;
+
+ /* Revision property cache. Maps from (rev,prefix) to apr_hash_t.
+ Unparsed svn_string_t representations of the serialized hash
+ will be written to the cache but the getter returns apr_hash_t. */
+ svn_cache__t *revprop_cache;
+
/* Node properties cache. Maps from rep key to apr_hash_t. */
svn_cache__t *properties_cache;
@@ -478,10 +485,6 @@ typedef struct fs_fs_data_t
/*** Filesystem Transaction ***/
typedef struct transaction_t
{
- /* property list (const char * name, svn_string_t * value).
- may be NULL if there are no properties. */
- apr_hash_t *proplist;
-
/* node revision id of the root node. */
const svn_fs_id_t *root_id;
@@ -527,7 +530,14 @@ typedef struct representation_t
svn_filesize_t size;
/* The size of the fulltext of the representation. If this is 0,
- * the fulltext size is equal to representation size in the rev file, */
+ * for a plain rep, the real fulltext size is equal to the SIZE field.
+ * For a delta rep, this field is always the real fulltext size.
+ *
+ * Note that svn_fs_fs__fixup_expanded_size() checks for these special
+ * cases and ensures that this field contains the actual value. We call
+ * it early after reading a representation struct, so most code does not
+ * have to worry about it.
+ */
svn_filesize_t expanded_size;
/* Is this a representation (still) within a transaction? */
@@ -536,13 +546,7 @@ typedef struct representation_t
/* For rep-sharing, we need a way of uniquifying node-revs which share the
same representation (see svn_fs_fs__noderev_same_rep_key() ). So, we
store the original txn of the node rev (not the rep!), along with some
- intra-node uniqification content.
-
- This is no longer used by the 1.9 code but we have to keep
- reading and writing it for old formats to remain compatible with
- 1.8, and earlier, that require it. We also read/write it in
- format 7 even though it is not currently required by any code
- that handles that format. */
+ intra-node uniqification content. */
struct
{
/* unique context, i.e. txn ID, in which the noderev (!) got created */
@@ -616,6 +620,18 @@ typedef struct change_t
svn_fs_path_change2_t info;
} change_t;
+
+/*** Directory (only used at the cache interface) ***/
+typedef struct svn_fs_fs__dir_data_t
+{
+ /* Contents, i.e. all directory entries, sorted by name. */
+ apr_array_header_t *entries;
+
+ /* SVN_INVALID_FILESIZE for committed data, otherwise the length of the
+ * in-txn on-disk representation of that directory. */
+ svn_filesize_t txn_filesize;
+} svn_fs_fs__dir_data_t;
+
#ifdef __cplusplus
}