You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by iv...@apache.org on 2014/11/14 14:18:03 UTC
svn commit: r1639628 [14/23] - in /subversion/branches/svn-auth-x509: ./
build/ build/generator/ notes/ notes/api-errata/1.8/ notes/api-errata/1.9/
notes/wc-ng/ subversion/ subversion/bindings/ctypes-python/
subversion/bindings/cxxhl/ subversion/bindin...
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.c?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.c Fri Nov 14 13:17:55 2014
@@ -43,6 +43,7 @@
#include "index.h"
#include "private/svn_fs_util.h"
+#include "private/svn_fspath.h"
#include "private/svn_sorts_private.h"
#include "private/svn_string_private.h"
#include "private/svn_subr_private.h"
@@ -649,7 +650,7 @@ auto_truncate_proto_rev(svn_fs_t *fs,
if (indexed_length < actual_length)
SVN_ERR(svn_io_file_trunc(proto_rev, indexed_length, pool));
else if (indexed_length > actual_length)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
NULL,
_("p2l proto index offset %s beyond proto"
"rev file size %s for TXN %s"),
@@ -750,7 +751,6 @@ svn_fs_x__put_node_revision(svn_fs_t *fs
svn_boolean_t fresh_txn_root,
apr_pool_t *pool)
{
- fs_x_data_t *ffd = fs->fsap_data;
apr_file_t *noderev_file;
noderev->is_fresh_txn_root = fresh_txn_root;
@@ -767,7 +767,7 @@ svn_fs_x__put_node_revision(svn_fs_t *fs
SVN_ERR(svn_fs_x__write_noderev(svn_stream_from_aprfile2(noderev_file, TRUE,
pool),
- noderev, ffd->format, pool));
+ noderev, pool));
SVN_ERR(svn_io_file_close(noderev_file, pool));
@@ -776,12 +776,12 @@ svn_fs_x__put_node_revision(svn_fs_t *fs
/* For the in-transaction NODEREV within FS, write the sha1->rep mapping
* file in the respective transaction, if rep sharing has been enabled etc.
- * Use POOL for temporary allocations.
+ * Use SCATCH_POOL for temporary allocations.
*/
static svn_error_t *
store_sha1_rep_mapping(svn_fs_t *fs,
node_revision_t *noderev,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
@@ -796,20 +796,21 @@ store_sha1_rep_mapping(svn_fs_t *fs,
= svn_fs_x__get_txn_id(noderev->data_rep->id.change_set);
const char *file_name
= svn_fs_x__path_txn_sha1(fs, txn_id,
- noderev->data_rep->sha1_digest, pool);
+ noderev->data_rep->sha1_digest,
+ scratch_pool);
svn_stringbuf_t *rep_string
= svn_fs_x__unparse_representation(noderev->data_rep,
- ffd->format,
(noderev->kind == svn_node_dir),
- pool);
+ scratch_pool, scratch_pool);
+
SVN_ERR(svn_io_file_open(&rep_file, file_name,
APR_WRITE | APR_CREATE | APR_TRUNCATE
- | APR_BUFFERED, APR_OS_DEFAULT, pool));
+ | APR_BUFFERED, APR_OS_DEFAULT, scratch_pool));
SVN_ERR(svn_io_file_write_full(rep_file, rep_string->data,
- rep_string->len, NULL, pool));
+ rep_string->len, NULL, scratch_pool));
- SVN_ERR(svn_io_file_close(rep_file, pool));
+ SVN_ERR(svn_io_file_close(rep_file, scratch_pool));
}
return SVN_NO_ERROR;
@@ -857,47 +858,37 @@ unparse_dir_entries(apr_array_header_t *
return SVN_NO_ERROR;
}
-/* Copy the contents of NEW_CHANGE into OLD_CHANGE assuming that both
- belong to the same path. Allocate copies in POOL.
+/* Return a deep copy of SOURCE and allocate it in RESULT_POOL.
*/
-static void
-replace_change(svn_fs_path_change2_t *old_change,
- const svn_fs_path_change2_t *new_change,
- apr_pool_t *pool)
-{
- /* An add at this point must be following a previous delete,
- so treat it just like a replace. */
- old_change->node_kind = new_change->node_kind;
- old_change->node_rev_id = svn_fs_x__id_copy(new_change->node_rev_id, pool);
- old_change->text_mod = new_change->text_mod;
- old_change->prop_mod = new_change->prop_mod;
- old_change->mergeinfo_mod = new_change->mergeinfo_mod;
- if (new_change->copyfrom_rev == SVN_INVALID_REVNUM)
- {
- old_change->copyfrom_rev = SVN_INVALID_REVNUM;
- old_change->copyfrom_path = NULL;
- }
- else
- {
- old_change->copyfrom_rev = new_change->copyfrom_rev;
- old_change->copyfrom_path = apr_pstrdup(pool,
- new_change->copyfrom_path);
- }
+static svn_fs_path_change2_t *
+path_change_dup(const svn_fs_path_change2_t *source,
+ apr_pool_t *result_pool)
+{
+ svn_fs_path_change2_t *result = apr_pmemdup(result_pool, source,
+ sizeof(*source));
+ result->node_rev_id = svn_fs_x__id_copy(source->node_rev_id, result_pool);
+ if (source->copyfrom_path)
+ result->copyfrom_path = apr_pstrdup(result_pool, source->copyfrom_path);
+
+ return result;
}
/* Merge the internal-use-only CHANGE into a hash of public-FS
- svn_fs_path_change2_t CHANGES, collapsing multiple changes into a
- single summarical (is that real word?) change per path. */
+ svn_fs_path_change2_t CHANGED_PATHS, collapsing multiple changes into a
+ single summarical (is that real word?) change per path. DELETIONS is
+ also a path->svn_fs_path_change2_t hash and contains all the deletions
+ that got turned into a replacement. */
static svn_error_t *
-fold_change(apr_hash_t *changes,
+fold_change(apr_hash_t *changed_paths,
+ apr_hash_t *deletions,
const change_t *change)
{
- apr_pool_t *pool = apr_hash_pool_get(changes);
+ apr_pool_t *pool = apr_hash_pool_get(changed_paths);
svn_fs_path_change2_t *old_change, *new_change;
const svn_string_t *path = &change->path;
const svn_fs_path_change2_t *info = &change->info;
- if ((old_change = apr_hash_get(changes, path->data, path->len)))
+ if ((old_change = apr_hash_get(changed_paths, path->data, path->len)))
{
/* This path already exists in the hash, so we have to merge
this change into the already existing one. */
@@ -921,7 +912,7 @@ fold_change(apr_hash_t *changes,
_("Invalid change ordering: new node revision ID "
"without delete"));
- /* Sanity check: an add, replacement, move, or reset must be the first
+ /* Sanity check: an add, replacement, or reset must be the first
thing to follow a deletion. */
if ((old_change->change_kind == svn_fs_path_change_delete)
&& (! ((info->change_kind == svn_fs_path_change_replace)
@@ -946,7 +937,7 @@ fold_change(apr_hash_t *changes,
case svn_fs_path_change_reset:
/* A reset here will simply remove the path change from the
hash. */
- old_change = NULL;
+ apr_hash_set(changed_paths, path->data, path->len, NULL);
break;
case svn_fs_path_change_delete:
@@ -954,144 +945,148 @@ fold_change(apr_hash_t *changes,
{
/* If the path was introduced in this transaction via an
add, and we are deleting it, just remove the path
- altogether. */
- old_change = NULL;
+ altogether. (The caller will delete any child paths.) */
+ apr_hash_set(changed_paths, path->data, path->len, NULL);
+ }
+ else if (old_change->change_kind == svn_fs_path_change_replace)
+ {
+ /* A deleting a 'replace' restore the original deletion. */
+ new_change = apr_hash_get(deletions, path->data, path->len);
+ SVN_ERR_ASSERT(new_change);
+ apr_hash_set(changed_paths, path->data, path->len, new_change);
}
else
{
- /* A deletion overrules all previous changes. */
- old_change->change_kind = svn_fs_path_change_delete;
- old_change->text_mod = info->text_mod;
- old_change->prop_mod = info->prop_mod;
- old_change->mergeinfo_mod = info->mergeinfo_mod;
- old_change->copyfrom_rev = SVN_INVALID_REVNUM;
- old_change->copyfrom_path = NULL;
+ /* A deletion overrules a previous change (modify). */
+ new_change = path_change_dup(info, pool);
+ apr_hash_set(changed_paths, path->data, path->len, new_change);
}
break;
case svn_fs_path_change_add:
case svn_fs_path_change_replace:
/* An add at this point must be following a previous delete,
- so treat it just like a replace. */
- replace_change(old_change, info, pool);
- old_change->change_kind = svn_fs_path_change_replace;
+ so treat it just like a replace. Remember the original
+ deletion such that we are able to delete this path again
+ (the replacement may have changed node kind and id). */
+ new_change = path_change_dup(info, pool);
+ new_change->change_kind = svn_fs_path_change_replace;
+
+ apr_hash_set(changed_paths, path->data, path->len, new_change);
+
+ /* Remember the original change.
+ * Make sure to allocate the hash key in a durable pool. */
+ apr_hash_set(deletions,
+ apr_pstrmemdup(apr_hash_pool_get(deletions),
+ path->data, path->len),
+ path->len, old_change);
break;
case svn_fs_path_change_modify:
default:
+ /* If the new change modifies some attribute of the node, set
+ the corresponding flag, whether it already was set or not.
+ Note: We do not reset a flag to FALSE if a change is undone. */
if (info->text_mod)
old_change->text_mod = TRUE;
if (info->prop_mod)
old_change->prop_mod = TRUE;
- if (info->mergeinfo_mod)
+ if (info->mergeinfo_mod == svn_tristate_true)
old_change->mergeinfo_mod = svn_tristate_true;
break;
}
-
- /* remove old_change from the cache if it is no longer needed. */
- if (old_change == NULL)
- apr_hash_set(changes, path->data, path->len, NULL);
}
else
{
- /* This change is new to the hash, so make a new public change
- structure from the internal one (in the hash's pool), and dup
- the path into the hash's pool, too. */
- new_change = apr_pmemdup(pool, info, sizeof(*new_change));
- new_change->node_rev_id = svn_fs_x__id_copy(info->node_rev_id, pool);
- if (info->copyfrom_path)
- new_change->copyfrom_path = apr_pstrdup(pool, info->copyfrom_path);
-
/* Add this path. The API makes no guarantees that this (new) key
- will not be retained. Thus, we copy the key into the target pool
- to ensure a proper lifetime. */
- apr_hash_set(changes,
+ will not be retained. Thus, we copy the key into the target pool
+ to ensure a proper lifetime. */
+ apr_hash_set(changed_paths,
apr_pstrmemdup(pool, path->data, path->len), path->len,
- new_change);
+ path_change_dup(info, pool));
}
return SVN_NO_ERROR;
}
+/* Baton type to be used with process_changes(). */
+typedef struct process_changes_baton_t
+{
+ /* Folded list of path changes. */
+ apr_hash_t *changed_paths;
+
+ /* Path changes that are deletions and have been turned into
+ replacements. If those replacements get deleted again, this
+ container contains the record that we have to revert to. */
+ apr_hash_t *deletions;
+} process_changes_baton_t;
-/* Examine all the changed path entries in CHANGES and store them in
+/* An implementation of svn_fs_x__change_receiver_t.
+ Examine all the changed path entries in CHANGES and store them in
*CHANGED_PATHS. Folding is done to remove redundant or unnecessary
- data. Do all allocations in POOL. */
+ data. Use SCRATCH_POOL for temporary allocations. */
static svn_error_t *
-process_changes(apr_hash_t *changed_paths,
- apr_array_header_t *changes,
- apr_pool_t *pool)
+process_changes(void *baton_p,
+ change_t *change,
+ apr_pool_t *scratch_pool)
{
- apr_pool_t *iterpool = svn_pool_create(pool);
- int i;
+ process_changes_baton_t *baton = baton_p;
- /* Read in the changes one by one, folding them into our local hash
- as necessary. */
+ SVN_ERR(fold_change(baton->changed_paths, baton->deletions, change));
- for (i = 0; i < changes->nelts; ++i)
- {
- /* The ITERPOOL will be cleared at the end of this function
- * since it is only used rarely and for a single hash iterator.
- */
- change_t *change = APR_ARRAY_IDX(changes, i, change_t *);
+ /* Now, if our change was a deletion or replacement, we have to
+ blow away any changes thus far on paths that are (or, were)
+ children of this path.
+ ### i won't bother with another iteration pool here -- at
+ most we talking about a few extra dups of paths into what
+ is already a temporary subpool.
+ */
- SVN_ERR(fold_change(changed_paths, change));
+ if ((change->info.change_kind == svn_fs_path_change_delete)
+ || (change->info.change_kind == svn_fs_path_change_replace))
+ {
+ apr_hash_index_t *hi;
- /* Now, if our change was a deletion or replacement, we have to
- blow away any changes thus far on paths that are (or, were)
- children of this path.
- ### i won't bother with another iteration pool here -- at
- most we talking about a few extra dups of paths into what
- is already a temporary subpool.
+ /* a potential child path must contain at least 2 more chars
+ (the path separator plus at least one char for the name).
+ Also, we should not assume that all paths have been normalized
+ i.e. some might have trailing path separators.
*/
-
- if ((change->info.change_kind == svn_fs_path_change_delete)
- || (change->info.change_kind == svn_fs_path_change_replace))
+ apr_ssize_t path_len = change->path.len;
+ apr_ssize_t min_child_len = path_len == 0
+ ? 1
+ : change->path.data[path_len-1] == '/'
+ ? path_len + 1
+ : path_len + 2;
+
+ /* CAUTION: This is the inner loop of an O(n^2) algorithm.
+ The number of changes to process may be >> 1000.
+ Therefore, keep the inner loop as tight as possible.
+ */
+ for (hi = apr_hash_first(scratch_pool, baton->changed_paths);
+ hi;
+ hi = apr_hash_next(hi))
{
- apr_hash_index_t *hi;
-
- /* a potential child path must contain at least 2 more chars
- (the path separator plus at least one char for the name).
- Also, we should not assume that all paths have been normalized
- i.e. some might have trailing path separators.
- */
- apr_ssize_t path_len = change->path.len;
- apr_ssize_t min_child_len = path_len == 0
- ? 1
- : change->path.data[path_len-1] == '/'
- ? path_len + 1
- : path_len + 2;
-
- /* CAUTION: This is the inner loop of an O(n^2) algorithm.
- The number of changes to process may be >> 1000.
- Therefore, keep the inner loop as tight as possible.
- */
- for (hi = apr_hash_first(iterpool, changed_paths);
- hi;
- hi = apr_hash_next(hi))
+ /* KEY is the path. */
+ const void *path;
+ apr_ssize_t klen;
+ apr_hash_this(hi, &path, &klen, NULL);
+
+ /* If we come across a child of our path, remove it.
+ Call svn_fspath__skip_ancestor only if there is a chance that
+ this is actually a sub-path.
+ */
+ if (klen >= min_child_len)
{
- /* KEY is the path. */
- const void *path;
- apr_ssize_t klen;
- apr_hash_this(hi, &path, &klen, NULL);
-
- /* If we come across a child of our path, remove it.
- Call svn_dirent_is_child only if there is a chance that
- this is actually a sub-path.
- */
- if ( klen >= min_child_len
- && svn_dirent_is_child(change->path.data, path, iterpool))
- apr_hash_set(changed_paths, path, klen, NULL);
- }
+ const char *child;
- /* Clear the per-iteration subpool. */
- svn_pool_clear(iterpool);
+ child = svn_fspath__skip_ancestor(change->path.data, path);
+ if (child && child[0] != '\0')
+ apr_hash_set(baton->changed_paths, path, klen, NULL);
+ }
}
}
- /* Destroy the per-iteration subpool. */
- svn_pool_destroy(iterpool);
-
return SVN_NO_ERROR;
}
@@ -1103,19 +1098,22 @@ svn_fs_x__txn_changes_fetch(apr_hash_t *
{
apr_file_t *file;
apr_hash_t *changed_paths = apr_hash_make(pool);
- apr_array_header_t *changes;
apr_pool_t *scratch_pool = svn_pool_create(pool);
+ process_changes_baton_t baton;
+
+ baton.changed_paths = changed_paths;
+ baton.deletions = apr_hash_make(scratch_pool);
SVN_ERR(svn_io_file_open(&file,
svn_fs_x__path_txn_changes(fs, txn_id, scratch_pool),
APR_READ | APR_BUFFERED, APR_OS_DEFAULT,
scratch_pool));
- SVN_ERR(svn_fs_x__read_changes(&changes,
+ SVN_ERR(svn_fs_x__read_changes_incrementally(
svn_stream_from_aprfile2(file, TRUE,
scratch_pool),
+ process_changes, &baton,
scratch_pool));
- SVN_ERR(process_changes(changed_paths, changes, pool));
svn_pool_destroy(scratch_pool);
*changed_paths_p = changed_paths;
@@ -1160,7 +1158,7 @@ create_new_txn_noderev_from_rev(svn_fs_t
{
node_revision_t *noderev;
- SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, src, pool));
+ SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, src, pool, pool));
/* This must be a root node. */
SVN_ERR_ASSERT( svn_fs_x__id_node_id(noderev->id)->number == 0
@@ -1244,12 +1242,7 @@ create_txn_dir(const char **id_p,
*txn_id = cb.txn_number;
*id_p = svn_fs_x__txn_name(*txn_id, pool);
- txn_dir = svn_dirent_join_many(pool,
- fs->path,
- PATH_TXNS_DIR,
- apr_pstrcat(pool, *id_p, PATH_EXT_TXN,
- SVN_VA_NULL),
- SVN_VA_NULL);
+ txn_dir = svn_fs_x__path_txn_dir(fs, *txn_id, pool);
return svn_io_dir_make(txn_dir, APR_OS_DEFAULT, pool);
}
@@ -1278,7 +1271,7 @@ svn_fs_x__create_txn(svn_fs_txn_t **txn_
*txn_p = txn;
/* Create a new root node for this transaction. */
- SVN_ERR(svn_fs_x__rev_get_root(&root_id, fs, rev, pool));
+ SVN_ERR(svn_fs_x__rev_get_root(&root_id, fs, rev, pool, pool));
SVN_ERR(create_new_txn_noderev_from_rev(fs, ftd->txn_id, root_id, pool));
/* Create an empty rev file. */
@@ -1429,7 +1422,7 @@ svn_fs_x__get_txn(transaction_t **txn_p,
SVN_ERR(get_txn_proplist(txn->proplist, fs, txn_id, pool));
root_id = svn_fs_x__id_txn_create_root(txn_id, pool);
- SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, root_id, pool));
+ SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, root_id, pool, pool));
txn->root_id = svn_fs_x__id_copy(noderev->id, pool);
txn->base_id = svn_fs_x__id_copy(noderev->predecessor_id, pool);
@@ -1513,7 +1506,7 @@ allocate_item_index(apr_uint64_t *item_i
to_write = svn__ui64toa(buffer, *item_index + 1);
/* write it back to disk */
- SVN_ERR(svn_io_file_seek(file, SEEK_SET, &offset, pool));
+ SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
SVN_ERR(svn_io_file_write_full(file, buffer, to_write, NULL, pool));
SVN_ERR(svn_io_file_close(file, pool));
@@ -1825,8 +1818,10 @@ svn_fs_x__add_change(svn_fs_t *fs,
? svn_tristate_true
: svn_tristate_false;
change->node_kind = node_kind;
+ change->copyfrom_known = TRUE;
change->copyfrom_rev = copyfrom_rev;
- change->copyfrom_path = apr_pstrdup(pool, copyfrom_path);
+ if (copyfrom_path)
+ change->copyfrom_path = apr_pstrdup(pool, copyfrom_path);
svn_hash_sets(changes, path, change);
SVN_ERR(svn_fs_x__write_changes(svn_stream_from_aprfile2(file, TRUE, pool),
@@ -1874,9 +1869,11 @@ struct rep_write_baton
/* Receives the low-level checksum when closing REP_STREAM. */
apr_uint32_t fnv1a_checksum;
- apr_pool_t *pool;
+ /* Local / scratch pool, available for temporary allocations. */
+ apr_pool_t *scratch_pool;
- apr_pool_t *parent_pool;
+ /* Outer / result pool. */
+ apr_pool_t *result_pool;
};
/* Handler for the write method of the representation writable stream.
@@ -1907,14 +1904,18 @@ shards_spanned(int *spanned,
apr_pool_t *pool)
{
fs_x_data_t *ffd = fs->fsap_data;
- int shard_size = ffd->max_files_per_dir ? ffd->max_files_per_dir : 1;
+ int shard_size = ffd->max_files_per_dir;
+ apr_pool_t *iterpool;
int count = walk ? 1 : 0; /* The start of a walk already touches a shard. */
svn_revnum_t shard, last_shard = ffd->youngest_rev_cache / shard_size;
+ iterpool = svn_pool_create(pool);
while (walk-- && noderev->predecessor_count)
{
+ svn_pool_clear(iterpool);
SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs,
- noderev->predecessor_id, pool));
+ noderev->predecessor_id, pool,
+ iterpool));
shard = svn_fs_x__id_rev(noderev->id) / shard_size;
if (shard != last_shard)
{
@@ -1922,6 +1923,7 @@ shards_spanned(int *spanned,
last_shard = shard;
}
}
+ svn_pool_destroy(iterpool);
*spanned = count;
return SVN_NO_ERROR;
@@ -1948,6 +1950,7 @@ choose_delta_base(representation_t **rep
int walk;
node_revision_t *base;
fs_x_data_t *ffd = fs->fsap_data;
+ apr_pool_t *iterpool;
/* If we have no predecessors, or that one is empty, then use the empty
* stream as a base. */
@@ -1994,9 +1997,15 @@ choose_delta_base(representation_t **rep
if noderev has ten predecessors and we want the eighth file rev,
walk back two predecessors.) */
base = noderev;
+ iterpool = svn_pool_create(pool);
while ((count++) < noderev->predecessor_count)
- SVN_ERR(svn_fs_x__get_node_revision(&base, fs,
- base->predecessor_id, pool));
+ {
+ svn_pool_clear(iterpool);
+ SVN_ERR(svn_fs_x__get_node_revision(&base, fs,
+ base->predecessor_id, pool,
+ iterpool));
+ }
+ svn_pool_destroy(iterpool);
/* return a suitable base representation */
*rep = props ? base->prop_rep : base->data_rep;
@@ -2054,8 +2063,9 @@ rep_write_cleanup(void *data)
struct rep_write_baton *b = data;
/* Truncate and close the protorevfile. */
- err = svn_io_file_trunc(b->file, b->rep_offset, b->pool);
- err = svn_error_compose_create(err, svn_io_file_close(b->file, b->pool));
+ err = svn_io_file_trunc(b->file, b->rep_offset, b->scratch_pool);
+ err = svn_error_compose_create(err, svn_io_file_close(b->file,
+ b->scratch_pool));
/* Remove our lock regardless of any preceding errors so that the
being_written flag is always removed and stays consistent with the
@@ -2063,8 +2073,8 @@ rep_write_cleanup(void *data)
going away. */
err = svn_error_compose_create(err,
unlock_proto_rev(b->fs,
- svn_fs_x__id_txn_id(b->noderev->id),
- b->lockcookie, b->pool));
+ svn_fs_x__id_txn_id(b->noderev->id),
+ b->lockcookie, b->scratch_pool));
if (err)
{
apr_status_t rc = err->apr_err;
@@ -2101,27 +2111,29 @@ rep_write_get_baton(struct rep_write_bat
b->md5_checksum_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
b->fs = fs;
- b->parent_pool = pool;
- b->pool = svn_pool_create(pool);
+ b->result_pool = pool;
+ b->scratch_pool = svn_pool_create(pool);
b->rep_size = 0;
b->noderev = noderev;
/* Open the prototype rev file and seek to its end. */
SVN_ERR(get_writable_proto_rev(&file, &b->lockcookie,
fs, svn_fs_x__id_txn_id(noderev->id),
- b->pool));
+ b->scratch_pool));
b->file = file;
b->rep_stream = svn_checksum__wrap_write_stream_fnv1a_32x4(
&b->fnv1a_checksum,
- svn_stream_from_aprfile2(file, TRUE, b->pool),
- b->pool);
+ svn_stream_from_aprfile2(file, TRUE,
+ b->scratch_pool),
+ b->scratch_pool);
- SVN_ERR(svn_fs_x__get_file_offset(&b->rep_offset, file, b->pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&b->rep_offset, file, b->scratch_pool));
/* Get the base for this delta. */
- SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->pool));
- SVN_ERR(svn_fs_x__get_contents(&source, fs, base_rep, TRUE, b->pool));
+ SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->scratch_pool));
+ SVN_ERR(svn_fs_x__get_contents(&source, fs, base_rep, TRUE,
+ b->scratch_pool));
/* Write out the rep header. */
if (base_rep)
@@ -2135,24 +2147,27 @@ rep_write_get_baton(struct rep_write_bat
{
header.type = svn_fs_x__rep_self_delta;
}
- SVN_ERR(svn_fs_x__write_rep_header(&header, b->rep_stream, b->pool));
+ SVN_ERR(svn_fs_x__write_rep_header(&header, b->rep_stream,
+ b->scratch_pool));
/* Now determine the offset of the actual svndiff data. */
- SVN_ERR(svn_fs_x__get_file_offset(&b->delta_start, file, b->pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&b->delta_start, file,
+ b->scratch_pool));
/* Cleanup in case something goes wrong. */
- apr_pool_cleanup_register(b->pool, b, rep_write_cleanup,
+ apr_pool_cleanup_register(b->scratch_pool, b, rep_write_cleanup,
apr_pool_cleanup_null);
/* Prepare to write the svndiff data. */
svn_txdelta_to_svndiff3(&wh,
&whb,
- svn_stream_disown(b->rep_stream, b->pool),
+ svn_stream_disown(b->rep_stream, b->result_pool),
diff_version,
ffd->delta_compression_level,
pool);
- b->delta_stream = svn_txdelta_target_push(wh, whb, source, b->pool);
+ b->delta_stream = svn_txdelta_target_push(wh, whb, source,
+ b->result_pool);
*wb_p = b;
@@ -2165,15 +2180,16 @@ rep_write_get_baton(struct rep_write_bat
there may be new duplicate representations within the same uncommitted
revision, those can be passed in REPS_HASH (maps a sha1 digest onto
representation_t*), otherwise pass in NULL for REPS_HASH.
- POOL will be used for allocations. The lifetime of the returned rep is
- limited by both, POOL and REP lifetime.
+ Use RESULT_POOL for *OLD_REP allocations and SCRATCH_POOL for temporaries.
+ The lifetime of *OLD_REP is limited by both, RESULT_POOL and REP lifetime.
*/
static svn_error_t *
get_shared_rep(representation_t **old_rep,
svn_fs_t *fs,
representation_t *rep,
apr_hash_t *reps_hash,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_error_t *err;
fs_x_data_t *ffd = fs->fsap_data;
@@ -2197,12 +2213,12 @@ get_shared_rep(representation_t **old_re
svn_checksum_t checksum;
checksum.digest = rep->sha1_digest;
checksum.kind = svn_checksum_sha1;
- err = svn_fs_x__get_rep_reference(old_rep, fs, &checksum, pool);
+ err = svn_fs_x__get_rep_reference(old_rep, fs, &checksum, result_pool);
/* ### Other error codes that we shouldn't mask out? */
if (err == SVN_NO_ERROR)
{
if (*old_rep)
- SVN_ERR(svn_fs_x__check_rep(*old_rep, fs, pool));
+ SVN_ERR(svn_fs_x__check_rep(*old_rep, fs, scratch_pool));
}
else if (err->apr_err == SVN_ERR_FS_CORRUPT
|| SVN_ERROR_IN_CATEGORY(err->apr_err,
@@ -2237,17 +2253,19 @@ get_shared_rep(representation_t **old_re
const char *file_name
= svn_fs_x__path_txn_sha1(fs,
svn_fs_x__get_txn_id(rep->id.change_set),
- rep->sha1_digest, pool);
+ rep->sha1_digest, scratch_pool);
/* in our txn, is there a rep file named with the wanted SHA1?
If so, read it and use that rep.
*/
- SVN_ERR(svn_io_check_path(file_name, &kind, pool));
+ SVN_ERR(svn_io_check_path(file_name, &kind, scratch_pool));
if (kind == svn_node_file)
{
svn_stringbuf_t *rep_string;
- SVN_ERR(svn_stringbuf_from_file2(&rep_string, file_name, pool));
- SVN_ERR(svn_fs_x__parse_representation(old_rep, rep_string, pool));
+ SVN_ERR(svn_stringbuf_from_file2(&rep_string, file_name,
+ scratch_pool));
+ SVN_ERR(svn_fs_x__parse_representation(old_rep, rep_string,
+ result_pool, scratch_pool));
}
}
@@ -2294,14 +2312,14 @@ rep_write_contents_close(void *baton)
apr_off_t offset;
apr_int64_t txn_id;
- rep = apr_pcalloc(b->parent_pool, sizeof(*rep));
+ rep = apr_pcalloc(b->result_pool, sizeof(*rep));
/* Close our delta stream so the last bits of svndiff are written
out. */
SVN_ERR(svn_stream_close(b->delta_stream));
/* Determine the length of the svndiff data. */
- SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->scratch_pool));
rep->size = offset - b->delta_start;
/* Fill in the rest of the representation field. */
@@ -2311,16 +2329,17 @@ rep_write_contents_close(void *baton)
/* Finalize the checksum. */
SVN_ERR(digests_final(rep, b->md5_checksum_ctx, b->sha1_checksum_ctx,
- b->parent_pool));
+ b->result_pool));
/* Check and see if we already have a representation somewhere that's
identical to the one we just wrote out. */
- SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->parent_pool));
+ SVN_ERR(get_shared_rep(&old_rep, b->fs, rep, NULL, b->result_pool,
+ b->scratch_pool));
if (old_rep)
{
/* We need to erase from the protorev the data we just wrote. */
- SVN_ERR(svn_io_file_trunc(b->file, b->rep_offset, b->pool));
+ SVN_ERR(svn_io_file_trunc(b->file, b->rep_offset, b->scratch_pool));
/* Use the old rep for this content. */
b->noderev->data_rep = old_rep;
@@ -2329,9 +2348,10 @@ rep_write_contents_close(void *baton)
{
/* Write out our cosmetic end marker. */
SVN_ERR(svn_stream_puts(b->rep_stream, "ENDREP\n"));
- SVN_ERR(allocate_item_index(&rep->id.number, b->fs, txn_id, b->pool));
+ SVN_ERR(allocate_item_index(&rep->id.number, b->fs, txn_id,
+ b->scratch_pool));
SVN_ERR(store_l2p_index_entry(b->fs, txn_id, b->rep_offset,
- rep->id.number, b->pool));
+ rep->id.number, b->scratch_pool));
b->noderev->data_rep = rep;
}
@@ -2339,11 +2359,11 @@ rep_write_contents_close(void *baton)
SVN_ERR(svn_stream_close(b->rep_stream));
/* Remove cleanup callback. */
- apr_pool_cleanup_kill(b->pool, b, rep_write_cleanup);
+ apr_pool_cleanup_kill(b->scratch_pool, b, rep_write_cleanup);
/* Write out the new node-rev information. */
SVN_ERR(svn_fs_x__put_node_revision(b->fs, b->noderev->id, b->noderev,
- FALSE, b->pool));
+ FALSE, b->scratch_pool));
if (!old_rep)
{
svn_fs_x__p2l_entry_t entry;
@@ -2352,20 +2372,20 @@ rep_write_contents_close(void *baton)
noderev_id.number = rep->id.number;
entry.offset = b->rep_offset;
- SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->scratch_pool));
entry.size = offset - b->rep_offset;
entry.type = SVN_FS_X__ITEM_TYPE_FILE_REP;
entry.item_count = 1;
entry.items = &noderev_id;
entry.fnv1_checksum = b->fnv1a_checksum;
- SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->pool));
- SVN_ERR(store_p2l_index_entry(b->fs, txn_id, &entry, b->pool));
+ SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->scratch_pool));
+ SVN_ERR(store_p2l_index_entry(b->fs, txn_id, &entry, b->scratch_pool));
}
- SVN_ERR(svn_io_file_close(b->file, b->pool));
- SVN_ERR(unlock_proto_rev(b->fs, txn_id, b->lockcookie, b->pool));
- svn_pool_destroy(b->pool);
+ SVN_ERR(svn_io_file_close(b->file, b->scratch_pool));
+ SVN_ERR(unlock_proto_rev(b->fs, txn_id, b->lockcookie, b->scratch_pool));
+ svn_pool_destroy(b->scratch_pool);
return SVN_NO_ERROR;
}
@@ -2554,7 +2574,8 @@ write_directory_to_stream(svn_stream_t *
If ITEM_TYPE is IS_PROPS equals SVN_FS_FS__ITEM_TYPE_*_PROPS, assume
that we want to a props representation as the base for our delta.
If FINAL_REVISION is not SVN_INVALID_REVNUM, use it to determine whether
- to write to the proto-index files. Perform temporary allocations in POOL.
+ to write to the proto-index files.
+ Perform temporary allocations in SCRATCH_POOL.
*/
static svn_error_t *
write_container_delta_rep(representation_t *rep,
@@ -2565,9 +2586,9 @@ write_container_delta_rep(representation
svn_fs_x__txn_id_t txn_id,
node_revision_t *noderev,
apr_hash_t *reps_hash,
- int item_type,
+ apr_uint32_t item_type,
svn_revnum_t final_revision,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_txdelta_window_handler_t diff_wh;
@@ -2591,10 +2612,10 @@ write_container_delta_rep(representation
|| (item_type == SVN_FS_X__ITEM_TYPE_DIR_PROPS);
/* Get the base for this delta. */
- SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, pool));
- SVN_ERR(svn_fs_x__get_contents(&source, fs, base_rep, FALSE, pool));
+ SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, scratch_pool));
+ SVN_ERR(svn_fs_x__get_contents(&source, fs, base_rep, FALSE, scratch_pool));
- SVN_ERR(svn_fs_x__get_file_offset(&offset, file, pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
/* Write out the rep header. */
if (base_rep)
@@ -2611,45 +2632,48 @@ write_container_delta_rep(representation
file_stream = svn_checksum__wrap_write_stream_fnv1a_32x4(
&entry.fnv1_checksum,
- svn_stream_from_aprfile2(file, TRUE, pool),
- pool);
- SVN_ERR(svn_fs_x__write_rep_header(&header, file_stream, pool));
- SVN_ERR(svn_fs_x__get_file_offset(&delta_start, file, pool));
+ svn_stream_from_aprfile2(file, TRUE,
+ scratch_pool),
+ scratch_pool);
+ SVN_ERR(svn_fs_x__write_rep_header(&header, file_stream, scratch_pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&delta_start, file, scratch_pool));
/* Prepare to write the svndiff data. */
svn_txdelta_to_svndiff3(&diff_wh,
&diff_whb,
- svn_stream_disown(file_stream, pool),
+ svn_stream_disown(file_stream, scratch_pool),
diff_version,
ffd->delta_compression_level,
- pool);
+ scratch_pool);
- whb = apr_pcalloc(pool, sizeof(*whb));
- whb->stream = svn_txdelta_target_push(diff_wh, diff_whb, source, pool);
+ whb = apr_pcalloc(scratch_pool, sizeof(*whb));
+ whb->stream = svn_txdelta_target_push(diff_wh, diff_whb, source,
+ scratch_pool);
whb->size = 0;
- whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, pool);
- whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, pool);
+ whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
+ whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
/* serialize the hash */
- stream = svn_stream_create(whb, pool);
+ stream = svn_stream_create(whb, scratch_pool);
svn_stream_set_write(stream, write_container_handler);
- SVN_ERR(writer(stream, collection, pool));
+ SVN_ERR(writer(stream, collection, scratch_pool));
SVN_ERR(svn_stream_close(whb->stream));
/* Store the results. */
- SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, pool));
+ SVN_ERR(digests_final(rep, whb->md5_ctx, whb->sha1_ctx, scratch_pool));
/* Check and see if we already have a representation somewhere that's
identical to the one we just wrote out. */
- SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, pool));
+ SVN_ERR(get_shared_rep(&old_rep, fs, rep, reps_hash, scratch_pool,
+ scratch_pool));
if (old_rep)
{
SVN_ERR(svn_stream_close(file_stream));
/* We need to erase from the protorev the data we just wrote. */
- SVN_ERR(svn_io_file_trunc(file, offset, pool));
+ SVN_ERR(svn_io_file_trunc(file, offset, scratch_pool));
/* Use the old rep for this content. */
memcpy(rep, old_rep, sizeof (*rep));
@@ -2659,24 +2683,26 @@ write_container_delta_rep(representation
svn_fs_x__id_part_t noderev_id;
/* Write out our cosmetic end marker. */
- SVN_ERR(svn_fs_x__get_file_offset(&rep_end, file, pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&rep_end, file, scratch_pool));
SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
SVN_ERR(svn_stream_close(file_stream));
- SVN_ERR(allocate_item_index(&rep->id.number, fs, txn_id, pool));
- SVN_ERR(store_l2p_index_entry(fs, txn_id, offset, rep->id.number, pool));
+ SVN_ERR(allocate_item_index(&rep->id.number, fs, txn_id,
+ scratch_pool));
+ SVN_ERR(store_l2p_index_entry(fs, txn_id, offset, rep->id.number,
+ scratch_pool));
noderev_id.change_set = SVN_FS_X__INVALID_CHANGE_SET;
noderev_id.number = rep->id.number;
entry.offset = offset;
- SVN_ERR(svn_fs_x__get_file_offset(&offset, file, pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
entry.size = offset - entry.offset;
entry.type = item_type;
entry.item_count = 1;
entry.items = &noderev_id;
- SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, pool));
+ SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, scratch_pool));
/* update the representation */
rep->expanded_size = whb->size;
@@ -2713,7 +2739,7 @@ validate_root_noderev(svn_fs_t *fs,
SVN_ERR(svn_fs_x__revision_root(&head_revision, fs, head_revnum, pool));
SVN_ERR(svn_fs_x__node_id(&head_root_id, head_revision, "/", pool));
SVN_ERR(svn_fs_x__get_node_revision(&head_root_noderev, fs, head_root_id,
- pool));
+ pool, pool));
head_predecessor_count = head_root_noderev->predecessor_count;
}
@@ -2806,6 +2832,7 @@ write_final_rev(const svn_fs_id_t **new_
svn_fs_x__p2l_entry_t entry;
svn_fs_x__change_set_t change_set = svn_fs_x__change_set_by_rev(rev);
svn_stream_t *file_stream;
+ apr_pool_t *subpool;
*new_id_p = NULL;
@@ -2813,16 +2840,15 @@ write_final_rev(const svn_fs_id_t **new_
if (! svn_fs_x__id_is_txn(id))
return SVN_NO_ERROR;
- SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool));
+ subpool = svn_pool_create(pool);
+ SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool, subpool));
if (noderev->kind == svn_node_dir)
{
- apr_pool_t *subpool;
apr_array_header_t *entries;
int i;
/* This is a directory. Write out all the children first. */
- subpool = svn_pool_create(pool);
SVN_ERR(svn_fs_x__rep_contents_dir(&entries, fs, noderev, pool,
subpool));
@@ -2838,7 +2864,6 @@ write_final_rev(const svn_fs_id_t **new_
if (new_id && (svn_fs_x__id_rev(new_id) == rev))
dirent->id = svn_fs_x__id_copy(new_id, pool);
}
- svn_pool_destroy(subpool);
if (noderev->data_rep
&& ! svn_fs_x__is_revision(noderev->data_rep->id.change_set))
@@ -2866,14 +2891,16 @@ write_final_rev(const svn_fs_id_t **new_
}
}
+ svn_pool_destroy(subpool);
+
/* Fix up the property reps. */
if (noderev->prop_rep
&& svn_fs_x__is_txn(noderev->prop_rep->id.change_set))
{
apr_hash_t *proplist;
- int item_type = noderev->kind == svn_node_dir
- ? SVN_FS_X__ITEM_TYPE_DIR_PROPS
- : SVN_FS_X__ITEM_TYPE_FILE_PROPS;
+ apr_uint32_t item_type = noderev->kind == svn_node_dir
+ ? SVN_FS_X__ITEM_TYPE_DIR_PROPS
+ : SVN_FS_X__ITEM_TYPE_FILE_PROPS;
SVN_ERR(svn_fs_x__get_proplist(&proplist, fs, noderev, pool));
noderev->prop_rep->id.change_set = change_set;
@@ -2949,7 +2976,7 @@ write_final_rev(const svn_fs_id_t **new_
&entry.fnv1_checksum,
svn_stream_from_aprfile2(file, TRUE, pool),
pool);
- SVN_ERR(svn_fs_x__write_noderev(file_stream, noderev, ffd->format, pool));
+ SVN_ERR(svn_fs_x__write_noderev(file_stream, noderev, pool));
SVN_ERR(svn_stream_close(file_stream));
/* reference the root noderev from the log-to-phys index */
@@ -3068,36 +3095,37 @@ verify_as_revision_before_current_plus_p
static svn_error_t *
verify_locks(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
+ apr_hash_t *changed_paths,
apr_pool_t *pool)
{
apr_pool_t *subpool = svn_pool_create(pool);
- apr_hash_t *changes;
apr_hash_index_t *hi;
- apr_array_header_t *changed_paths;
+ apr_array_header_t *changed_paths_sorted;
svn_stringbuf_t *last_recursed = NULL;
int i;
- /* Fetch the changes for this transaction. */
- SVN_ERR(svn_fs_x__txn_changes_fetch(&changes, fs, txn_id, pool));
-
/* Make an array of the changed paths, and sort them depth-first-ily. */
- changed_paths = apr_array_make(pool, apr_hash_count(changes) + 1,
- sizeof(const char *));
- for (hi = apr_hash_first(pool, changes); hi; hi = apr_hash_next(hi))
- APR_ARRAY_PUSH(changed_paths, const char *) = apr_hash_this_key(hi);
- svn_sort__array(changed_paths, svn_sort_compare_paths);
+ changed_paths_sorted = apr_array_make(pool,
+ apr_hash_count(changed_paths) + 1,
+ sizeof(const char *));
+ for (hi = apr_hash_first(pool, changed_paths); hi; hi = apr_hash_next(hi))
+ {
+ APR_ARRAY_PUSH(changed_paths_sorted, const char *) =
+ apr_hash_this_key(hi);
+ }
+ svn_sort__array(changed_paths_sorted, 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
over children of that path when we get to them. */
- for (i = 0; i < changed_paths->nelts; i++)
+ for (i = 0; i < changed_paths_sorted->nelts; i++)
{
const char *path;
svn_fs_path_change2_t *change;
svn_boolean_t recurse = TRUE;
svn_pool_clear(subpool);
- path = APR_ARRAY_IDX(changed_paths, i, const char *);
+ path = APR_ARRAY_IDX(changed_paths_sorted, i, const char *);
/* If this path has already been verified as part of a recursive
check of one of its parents, no need to do it again. */
@@ -3106,7 +3134,7 @@ verify_locks(svn_fs_t *fs,
continue;
/* Fetch the change associated with our path. */
- change = svn_hash_gets(changes, path);
+ change = svn_hash_gets(changed_paths, path);
/* What does it mean to succeed at lock verification for a given
path? For an existing file or directory getting modified
@@ -3196,6 +3224,47 @@ write_final_revprop(const char **path,
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__add_index_data(svn_fs_t *fs,
+ apr_file_t *file,
+ const char *l2p_proto_index,
+ const char *p2l_proto_index,
+ svn_revnum_t revision,
+ apr_pool_t *pool)
+{
+ apr_off_t l2p_offset;
+ apr_off_t p2l_offset;
+ svn_stringbuf_t *footer;
+ unsigned char footer_length;
+ svn_checksum_t *l2p_checksum;
+ svn_checksum_t *p2l_checksum;
+
+ /* Append the actual index data to the pack file. */
+ l2p_offset = 0;
+ SVN_ERR(svn_io_file_seek(file, APR_END, &l2p_offset, pool));
+ SVN_ERR(svn_fs_x__l2p_index_append(&l2p_checksum, fs, file,
+ l2p_proto_index, revision,
+ pool, pool));
+
+ p2l_offset = 0;
+ SVN_ERR(svn_io_file_seek(file, APR_END, &p2l_offset, pool));
+ SVN_ERR(svn_fs_x__p2l_index_append(&p2l_checksum, fs, file,
+ p2l_proto_index, revision,
+ pool, pool));
+
+ /* Append footer. */
+ footer = svn_fs_x__unparse_footer(l2p_offset, l2p_checksum,
+ p2l_offset, p2l_checksum, pool, pool);
+ SVN_ERR(svn_io_file_write_full(file, footer->data, footer->len, NULL,
+ pool));
+
+ footer_length = footer->len;
+ SVN_ERR_ASSERT(footer_length == footer->len);
+ SVN_ERR(svn_io_file_write_full(file, &footer_length, 1, NULL, pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Baton used for commit_body below. */
struct commit_baton {
svn_revnum_t *new_rev_p;
@@ -3224,6 +3293,22 @@ commit_body(void *baton, apr_pool_t *poo
svn_fs_x__txn_id_t txn_id = svn_fs_x__txn_get_id(cb->txn);
apr_hash_t *changed_paths;
+ /* Re-Read the current repository format. All our repo upgrade and
+ config evaluation strategies are such that existing information in
+ FS and FFD remains valid.
+
+ Although we don't recommend upgrading hot repositories, people may
+ still do it and we must make sure to either handle them gracefully
+ or to error out.
+
+ Committing pre-format 3 txns will fail after upgrade to format 3+
+ because the proto-rev cannot be found; no further action needed.
+ Upgrades from pre-f7 to f7+ means a potential change in addressing
+ mode for the final rev. We must be sure to detect that cause because
+ the failure would only manifest once the new revision got committed.
+ */
+ SVN_ERR(svn_fs_x__read_format_file(cb->fs, pool));
+
/* Get the current youngest revision. */
SVN_ERR(svn_fs_x__youngest_rev(&old_rev, cb->fs, pool));
@@ -3233,16 +3318,16 @@ commit_body(void *baton, apr_pool_t *poo
return svn_error_create(SVN_ERR_FS_TXN_OUT_OF_DATE, NULL,
_("Transaction out of date"));
+ /* We need the changes list for verification as well as for writing it
+ to the final rev file. */
+ SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
+ pool));
+
/* Locks may have been added (or stolen) between the calling of
previous svn_fs.h functions and svn_fs_commit_txn(), so we need
to re-examine every changed-path in the txn and re-verify all
discovered locks. */
- SVN_ERR(verify_locks(cb->fs, txn_id, pool));
-
- /* we need the changes list for verification as well as for writing it
- to the final rev file */
- SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, cb->fs, txn_id,
- pool));
+ SVN_ERR(verify_locks(cb->fs, txn_id, changed_paths, pool));
/* We are going to be one better than this puny old revision. */
new_rev = old_rev + 1;
@@ -3263,6 +3348,12 @@ commit_body(void *baton, apr_pool_t *poo
cb->fs, txn_id, changed_paths,
new_rev, pool));
+ /* Append the index data to the rev file. */
+ SVN_ERR(svn_fs_x__add_index_data(cb->fs, proto_file,
+ svn_fs_x__path_l2p_proto_index(cb->fs, txn_id, pool),
+ svn_fs_x__path_p2l_proto_index(cb->fs, txn_id, pool),
+ new_rev, pool));
+
SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
SVN_ERR(svn_io_file_close(proto_file, pool));
@@ -3305,17 +3396,6 @@ commit_body(void *baton, apr_pool_t *poo
}
}
- /* Convert the index files from the proto format into their form
- in their final location */
- SVN_ERR(svn_fs_x__l2p_index_create(cb->fs,
- svn_fs_x__path_l2p_index(cb->fs, new_rev, pool),
- svn_fs_x__path_l2p_proto_index(cb->fs, txn_id, pool),
- new_rev, pool));
- SVN_ERR(svn_fs_x__p2l_index_create(cb->fs,
- svn_fs_x__path_p2l_index(cb->fs, new_rev, pool),
- svn_fs_x__path_p2l_proto_index(cb->fs, txn_id, pool),
- new_rev, pool));
-
/* Move the finished rev file into place.
### This "breaks" the transaction by removing the protorev file
@@ -3447,7 +3527,7 @@ svn_fs_x__list_transactions(apr_array_he
names = apr_array_make(pool, 1, sizeof(const char *));
/* Get the transactions directory. */
- txn_dir = svn_dirent_join(fs->path, PATH_TXNS_DIR, pool);
+ txn_dir = svn_fs_x__path_txns_dir(fs, pool);
/* Now find a listing of this directory. */
SVN_ERR(svn_io_get_dirents3(&dirents, txn_dir, TRUE, pool, pool));
@@ -3537,7 +3617,7 @@ svn_fs_x__delete_node_revision(svn_fs_t
{
node_revision_t *noderev;
- SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool));
+ SVN_ERR(svn_fs_x__get_node_revision(&noderev, fs, id, pool, pool));
/* Delete any mutable property representation. */
if (noderev->prop_rep
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.h?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.h (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/transaction.h Fri Nov 14 13:17:55 2014
@@ -240,6 +240,18 @@ svn_fs_x__set_proplist(svn_fs_t *fs,
apr_hash_t *proplist,
apr_pool_t *pool);
+/* Append the L2P and P2L indexes given by their proto index file names
+ * L2P_PROTO_INDEX and P2L_PROTO_INDEX to the revision / pack FILE.
+ * The latter contains revision(s) starting at REVISION in FS.
+ * Use POOL for temporary allocations. */
+svn_error_t *
+svn_fs_x__add_index_data(svn_fs_t *fs,
+ apr_file_t *file,
+ const char *l2p_proto_index,
+ const char *p2l_proto_index,
+ svn_revnum_t revision,
+ apr_pool_t *pool);
+
/* Commit the transaction TXN in filesystem FS and return its new
revision number in *REV. If the transaction is out of date, return
the error SVN_ERR_FS_TXN_OUT_OF_DATE. Use POOL for temporary
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/tree.c?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/tree.c Fri Nov 14 13:17:55 2014
@@ -395,7 +395,9 @@ cache_lookup( fs_x_dag_cache_t *cache
/* 2nd level cache */
/* Find and return the DAG node cache for ROOT and the key that
- should be used for PATH. */
+ should be used for PATH.
+
+ Pool will only be used for allocating a new keys if necessary */
static void
locate_cache(svn_cache__t **cache,
const char **key,
@@ -406,15 +408,20 @@ locate_cache(svn_cache__t **cache,
if (root->is_txn_root)
{
fs_txn_root_data_t *frd = root->fsap_data;
- if (cache) *cache = frd->txn_node_cache;
- if (key && path) *key = path;
+
+ if (cache)
+ *cache = frd->txn_node_cache;
+ if (key && path)
+ *key = path;
}
else
{
fs_x_data_t *ffd = root->fs->fsap_data;
- if (cache) *cache = ffd->rev_node_cache;
- if (key && path) *key
- = svn_fs_x__combine_number_and_string(root->rev, path, pool);
+
+ if (cache)
+ *cache = ffd->rev_node_cache;
+ if (key && path)
+ *key = svn_fs_x__combine_number_and_string(root->rev, path, pool);
}
}
@@ -1044,7 +1051,7 @@ open_path(parent_path_t **parent_path_p,
if (flags & open_path_node_only)
{
- /* Shortcut: the caller only wan'ts the final DAG node. */
+ /* Shortcut: the caller only wants the final DAG node. */
parent_path->node = child;
}
else
@@ -1509,7 +1516,7 @@ x_change_node_prop(svn_fs_root_t *root,
parent_path_t *parent_path;
apr_hash_t *proplist;
svn_fs_x__txn_id_t txn_id;
- svn_boolean_t modeinfo_mod = FALSE;
+ svn_boolean_t mergeinfo_mod = FALSE;
if (! root->is_txn_root)
return SVN_FS__NOT_TXN(root);
@@ -1553,7 +1560,7 @@ x_change_node_prop(svn_fs_root_t *root,
(value != NULL), pool));
}
- modeinfo_mod = TRUE;
+ mergeinfo_mod = TRUE;
}
/* Set the property. */
@@ -1566,7 +1573,7 @@ x_change_node_prop(svn_fs_root_t *root,
/* Make a record of this modification in the changes table. */
return add_change(root->fs, txn_id, path,
svn_fs_x__dag_get_id(parent_path->node),
- svn_fs_path_change_modify, FALSE, TRUE, modeinfo_mod,
+ svn_fs_path_change_modify, FALSE, TRUE, mergeinfo_mod,
svn_fs_x__dag_node_kind(parent_path->node),
SVN_INVALID_REVNUM, NULL, pool);
}
@@ -1826,11 +1833,19 @@ merge(svn_stringbuf_t *conflict_p,
{
node_revision_t *tgt_nr, *anc_nr, *src_nr;
svn_boolean_t same;
+ apr_pool_t *scratch_pool;
/* Get node revisions for our id's. */
- SVN_ERR(svn_fs_x__get_node_revision(&tgt_nr, fs, target_id, pool));
- SVN_ERR(svn_fs_x__get_node_revision(&anc_nr, fs, ancestor_id, pool));
- SVN_ERR(svn_fs_x__get_node_revision(&src_nr, fs, source_id, pool));
+ scratch_pool = svn_pool_create(pool);
+ SVN_ERR(svn_fs_x__get_node_revision(&tgt_nr, fs, target_id, pool,
+ scratch_pool));
+ svn_pool_clear(scratch_pool);
+ SVN_ERR(svn_fs_x__get_node_revision(&anc_nr, fs, ancestor_id, pool,
+ scratch_pool));
+ svn_pool_clear(scratch_pool);
+ SVN_ERR(svn_fs_x__get_node_revision(&src_nr, fs, source_id, pool,
+ scratch_pool));
+ svn_pool_destroy(scratch_pool);
/* Now compare the prop-keys of the skels. Note that just because
the keys are different -doesn't- mean the proplists have
@@ -2452,27 +2467,15 @@ x_same_p(svn_boolean_t *same_p,
return SVN_NO_ERROR;
}
-/* Type to select the various behavioral modes of copy_helper.
- */
-typedef enum copy_type_t
-{
- /* add without history */
- copy_type_plain_add,
-
- /* add with history */
- copy_type_add_with_history,
-} copy_type_t;
-
/* Copy the node at FROM_PATH under FROM_ROOT to TO_PATH under
- TO_ROOT. COPY_TYPE determines whether then the copy is recorded in
- the copies table and whether it is being marked as a move.
- Perform temporary allocations in POOL. */
+ TO_ROOT. If PRESERVE_HISTORY is set, then the copy is recorded in
+ the copies table. Perform temporary allocations in POOL. */
static svn_error_t *
copy_helper(svn_fs_root_t *from_root,
const char *from_path,
svn_fs_root_t *to_root,
const char *to_path,
- copy_type_t copy_type,
+ svn_boolean_t preserve_history,
apr_pool_t *pool)
{
dag_node_t *from_node;
@@ -2558,7 +2561,7 @@ copy_helper(svn_fs_root_t *from_root,
SVN_ERR(svn_fs_x__dag_copy(to_parent_path->parent->node,
to_parent_path->entry,
from_node,
- copy_type != copy_type_plain_add,
+ preserve_history,
from_root->rev,
from_canonpath,
txn_id, pool));
@@ -2617,7 +2620,7 @@ x_copy(svn_fs_root_t *from_root,
to_root,
svn_fs__canonicalize_abspath(to_path,
pool),
- copy_type_add_with_history, pool));
+ TRUE, pool));
}
@@ -2635,7 +2638,7 @@ x_revision_link(svn_fs_root_t *from_root
path = svn_fs__canonicalize_abspath(path, pool);
return svn_error_trace(copy_helper(from_root, path, to_root, path,
- copy_type_plain_add, pool));
+ FALSE, pool));
}
@@ -4100,10 +4103,12 @@ stringify_node(dag_node_t *node,
/* Check metadata sanity on NODE, and on its children. Manually verify
information for DAG nodes in revision REV, and trust the metadata
- accuracy for nodes belonging to older revisions. */
+ accuracy for nodes belonging to older revisions. To detect cycles,
+ provide all parent dag_node_t * in PARENT_NODES. */
static svn_error_t *
verify_node(dag_node_t *node,
svn_revnum_t rev,
+ apr_array_header_t *parent_nodes,
apr_pool_t *pool)
{
svn_boolean_t has_mergeinfo;
@@ -4113,6 +4118,18 @@ verify_node(dag_node_t *node,
int pred_count;
svn_node_kind_t kind;
apr_pool_t *iterpool = svn_pool_create(pool);
+ int i;
+
+ /* Detect (non-)DAG cycles. */
+ for (i = 0; i < parent_nodes->nelts; ++i)
+ {
+ dag_node_t *parent = APR_ARRAY_IDX(parent_nodes, i, dag_node_t *);
+ if (svn_fs_x__id_eq(svn_fs_x__dag_get_id(parent),
+ svn_fs_x__dag_get_id(node)))
+ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+ "Node is its own direct or indirect parent '%s'",
+ stringify_node(node, iterpool));
+ }
/* Fetch some data. */
SVN_ERR(svn_fs_x__dag_has_mergeinfo(&has_mergeinfo, node));
@@ -4164,8 +4181,8 @@ verify_node(dag_node_t *node,
if (kind == svn_node_dir)
{
apr_array_header_t *entries;
- int i;
apr_int64_t children_mergeinfo = 0;
+ APR_ARRAY_PUSH(parent_nodes, dag_node_t*) = node;
SVN_ERR(svn_fs_x__dag_dir_entries(&entries, node, pool));
@@ -4184,7 +4201,7 @@ verify_node(dag_node_t *node,
{
SVN_ERR(svn_fs_x__dag_get_node(&child, fs, dirent->id,
iterpool));
- SVN_ERR(verify_node(child, rev, iterpool));
+ SVN_ERR(verify_node(child, rev, parent_nodes, iterpool));
SVN_ERR(svn_fs_x__dag_get_mergeinfo_count(&child_mergeinfo,
child));
}
@@ -4206,6 +4223,10 @@ verify_node(dag_node_t *node,
stringify_node(node, iterpool),
mergeinfo_count, has_mergeinfo,
children_mergeinfo);
+
+ /* If we don't make it here, there was an error / corruption.
+ * In that case, nobody will need PARENT_NODES anymore. */
+ apr_array_pop(parent_nodes);
}
svn_pool_destroy(iterpool);
@@ -4218,6 +4239,7 @@ svn_fs_x__verify_root(svn_fs_root_t *roo
{
svn_fs_t *fs = root->fs;
dag_node_t *root_dir;
+ apr_array_header_t *parent_nodes;
/* Issue #4129: bogus pred-counts and minfo-cnt's on the root node-rev
(and elsewhere). This code makes more thorough checks than the
@@ -4241,7 +4263,8 @@ svn_fs_x__verify_root(svn_fs_root_t *roo
}
/* Recursively verify ROOT_DIR. */
- SVN_ERR(verify_node(root_dir, root->rev, pool));
+ parent_nodes = apr_array_make(pool, 16, sizeof(dag_node_t *));
+ SVN_ERR(verify_node(root_dir, root->rev, parent_nodes, pool));
/* Verify explicitly the predecessor of the root. */
{
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.c?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.c Fri Nov 14 13:17:55 2014
@@ -172,24 +172,6 @@ svn_fs_x__path_rev(svn_fs_t *fs, svn_rev
}
const char *
-svn_fs_x__path_l2p_index(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool)
-{
- return apr_psprintf(pool, "%s" PATH_EXT_L2P_INDEX,
- svn_fs_x__path_rev_absolute(fs, rev, pool));
-}
-
-const char *
-svn_fs_x__path_p2l_index(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool)
-{
- return apr_psprintf(pool, "%s" PATH_EXT_P2L_INDEX,
- svn_fs_x__path_rev_absolute(fs, rev, pool));
-}
-
-const char *
svn_fs_x__path_rev_absolute(svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *pool)
@@ -270,11 +252,18 @@ combine_txn_id_string(svn_fs_x__txn_id_t
}
const char *
+svn_fs_x__path_txns_dir(svn_fs_t *fs,
+ apr_pool_t *pool)
+{
+ return svn_dirent_join(fs->path, PATH_TXNS_DIR, pool);
+}
+
+const char *
svn_fs_x__path_txn_dir(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
apr_pool_t *pool)
{
- return svn_dirent_join_many(pool, fs->path, PATH_TXNS_DIR,
+ return svn_dirent_join_many(pool, svn_fs_x__path_txns_dir(fs, pool),
combine_txn_id_string(txn_id, PATH_EXT_TXN,
pool),
SVN_VA_NULL);
@@ -359,6 +348,13 @@ svn_fs_x__path_min_unpacked_rev(svn_fs_t
}
const char *
+svn_fs_x__path_txn_proto_revs(svn_fs_t *fs,
+ apr_pool_t *pool)
+{
+ return svn_dirent_join(fs->path, PATH_TXN_PROTOS_DIR, pool);
+}
+
+const char *
svn_fs_x__path_txn_item_index(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
apr_pool_t *pool)
@@ -372,7 +368,7 @@ svn_fs_x__path_txn_proto_rev(svn_fs_t *f
svn_fs_x__txn_id_t txn_id,
apr_pool_t *pool)
{
- return svn_dirent_join_many(pool, fs->path, PATH_TXN_PROTOS_DIR,
+ return svn_dirent_join_many(pool, svn_fs_x__path_txn_proto_revs(fs, pool),
combine_txn_id_string(txn_id, PATH_EXT_REV,
pool),
SVN_VA_NULL);
@@ -383,7 +379,7 @@ svn_fs_x__path_txn_proto_rev_lock(svn_fs
svn_fs_x__txn_id_t txn_id,
apr_pool_t *pool)
{
- return svn_dirent_join_many(pool, fs->path, PATH_TXN_PROTOS_DIR,
+ return svn_dirent_join_many(pool, svn_fs_x__path_txn_proto_revs(fs, pool),
combine_txn_id_string(txn_id,
PATH_EXT_REV_LOCK,
pool),
@@ -462,7 +458,7 @@ svn_fs_x__read_min_unpacked_rev(svn_revn
SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
SVN_ERR(svn_io_file_close(file, pool));
- *min_unpacked_rev = SVN_STR_TO_REV(buf);
+ SVN_ERR(svn_revnum_parse(min_unpacked_rev, buf, NULL));
return SVN_NO_ERROR;
}
@@ -496,6 +492,24 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__read_current(svn_revnum_t *rev,
+ svn_fs_t *fs,
+ apr_pool_t *pool)
+{
+ const char *str;
+ svn_stringbuf_t *content;
+ SVN_ERR(svn_fs_x__read_content(&content,
+ svn_fs_x__path_current(fs, pool),
+ pool));
+ SVN_ERR(svn_revnum_parse(rev, content->data, &str));
+ if (*str != '\n')
+ return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+ _("Corrupt 'current' file"));
+
+ return SVN_NO_ERROR;
+}
+
/* Atomically update the 'current' file to hold the specifed REV.
Perform temporary allocations in POOL. */
svn_error_t *
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.h?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.h (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/util.h Fri Nov 14 13:17:55 2014
@@ -78,9 +78,11 @@ svn_boolean_t
svn_fs_x__is_packed_revprop(svn_fs_t *fs,
svn_revnum_t rev);
-/* Return the revision number of the pack / rev file in FS containing REV. */
+/* Return the first revision in the pack / rev file containing REVISION in
+ * filesystem FS. For non-packed revs, this will simply be REVISION. */
svn_revnum_t
-svn_fs_x__packed_base_rev(svn_fs_t *fs, svn_revnum_t rev);
+svn_fs_x__packed_base_rev(svn_fs_t *fs,
+ svn_revnum_t rev);
/* Return the number of revisions in the pack / rev file in FS that contains
* revision REV. */
@@ -135,16 +137,6 @@ svn_fs_x__path_rev(svn_fs_t *fs,
apr_pool_t *pool);
const char *
-svn_fs_x__path_l2p_index(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool);
-
-const char *
-svn_fs_x__path_p2l_index(svn_fs_t *fs,
- svn_revnum_t rev,
- apr_pool_t *pool);
-
-const char *
svn_fs_x__path_revprops_shard(svn_fs_t *fs,
svn_revnum_t rev,
apr_pool_t *pool);
@@ -167,11 +159,21 @@ svn_error_t *
svn_fs_x__txn_by_name(svn_fs_x__txn_id_t *txn_id,
const char *txn_name);
+/* Return the path of the directory containing the transaction TXN_ID in FS.
+ * The result will be allocated in POOL.
+ */
const char *
svn_fs_x__path_txn_dir(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
apr_pool_t *pool);
+/* Return the path of the 'transactions' directory in FS.
+ * The result will be allocated in POOL.
+ */
+const char *
+svn_fs_x__path_txns_dir(svn_fs_t *fs,
+ apr_pool_t *pool);
+
/* Return the name of the sha1->rep mapping file in transaction TXN_ID
* within FS for the given SHA1 checksum. Use POOL for allocations.
*/
@@ -181,6 +183,16 @@ svn_fs_x__path_txn_sha1(svn_fs_t *fs,
const unsigned char *sha1,
apr_pool_t *pool);
+/* Return the path of the 'txn-protorevs' directory in FS, even if that
+ * folder may not exist in FS. The result will be allocated in POOL.
+ */
+const char *
+svn_fs_x__path_txn_proto_revs(svn_fs_t *fs,
+ apr_pool_t *pool);
+
+/* Return the path of the proto-revision file for transaction TXN_ID in FS.
+ * The result will be allocated in POOL.
+ */
const char *
svn_fs_x__path_txn_changes(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
@@ -276,6 +288,14 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
svn_revnum_t revnum,
apr_pool_t *scratch_pool);
+/* Set *REV to the value read from the 'current' file. Perform temporary
+ * allocations in POOL.
+ */
+svn_error_t *
+svn_fs_x__read_current(svn_revnum_t *rev,
+ svn_fs_t *fs,
+ apr_pool_t *pool);
+
/* Atomically update the 'current' file to hold the specifed REV.
Perform temporary allocations in POOL. */
svn_error_t *
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/verify.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/verify.c?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/verify.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_fs_x/verify.c Fri Nov 14 13:17:55 2014
@@ -133,6 +133,93 @@ verify_rep_cache(svn_fs_t *fs,
return SVN_NO_ERROR;
}
+/* Verify that the MD5 checksum of the data between offsets START and END
+ * in FILE matches the EXPECTED checksum. If there is a mismatch use the
+ * indedx NAME in the error message. Supports cancellation with CANCEL_FUNC
+ * and CANCEL_BATON. SCRATCH_POOL is for temporary allocations. */
+static svn_error_t *
+verify_index_checksum(apr_file_t *file,
+ const char *name,
+ apr_off_t start,
+ apr_off_t end,
+ svn_checksum_t *expected,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ unsigned char buffer[SVN__STREAM_CHUNK_SIZE];
+ apr_off_t size = end - start;
+ svn_checksum_t *actual;
+ svn_checksum_ctx_t *context
+ = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
+
+ /* Calculate the index checksum. */
+ SVN_ERR(svn_io_file_seek(file, APR_SET, &start, scratch_pool));
+ while (size > 0)
+ {
+ apr_size_t to_read = size > sizeof(buffer)
+ ? sizeof(buffer)
+ : (apr_size_t)size;
+ SVN_ERR(svn_io_file_read_full2(file, buffer, to_read, NULL, NULL,
+ scratch_pool));
+ SVN_ERR(svn_checksum_update(context, buffer, to_read));
+ size -= to_read;
+
+ if (cancel_func)
+ SVN_ERR(cancel_func(cancel_baton));
+ }
+
+ SVN_ERR(svn_checksum_final(&actual, context, scratch_pool));
+
+ /* Verify that it matches the expected checksum. */
+ if (!svn_checksum_match(expected, actual))
+ {
+ const char *file_name;
+
+ SVN_ERR(svn_io_file_name_get(&file_name, file, scratch_pool));
+ SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool,
+ _("%s checksum mismatch in file %s"),
+ name, file_name));
+ }
+
+ return SVN_NO_ERROR;
+}
+
+/* Verify the MD5 checksums of the index data in the rev / pack file
+ * containing revision START in FS. If given, invoke CANCEL_FUNC with
+ * CANCEL_BATON at regular intervals. Use SCRATCH_POOL for temporary
+ * allocations.
+ */
+static svn_error_t *
+verify_index_checksums(svn_fs_t *fs,
+ svn_revnum_t start,
+ svn_cancel_func_t cancel_func,
+ void *cancel_baton,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_x__revision_file_t *rev_file;
+
+ /* Open the rev / pack file and read the footer */
+ SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start,
+ scratch_pool, scratch_pool));
+ SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
+
+ /* Verify the index contents against the checksum from the footer. */
+ SVN_ERR(verify_index_checksum(rev_file->file, "L2P index",
+ rev_file->l2p_offset, rev_file->p2l_offset,
+ rev_file->l2p_checksum,
+ cancel_func, cancel_baton, scratch_pool));
+ SVN_ERR(verify_index_checksum(rev_file->file, "P2L index",
+ rev_file->p2l_offset, rev_file->footer_offset,
+ rev_file->p2l_checksum,
+ cancel_func, cancel_baton, scratch_pool));
+
+ /* Done. */
+ SVN_ERR(svn_fs_x__close_revision_file(rev_file));
+
+ return SVN_NO_ERROR;
+}
+
/* Verify that for all log-to-phys index entries for revisions START to
* START + COUNT-1 in FS there is a consistent entry in the phys-to-log
* index. If given, invoke CANCEL_FUNC with CANCEL_BATON at regular
@@ -150,8 +237,14 @@ compare_l2p_to_p2l_index(svn_fs_t *fs,
apr_pool_t *iterpool = svn_pool_create(pool);
apr_array_header_t *max_ids;
+ /* common file access structure */
+ svn_fs_x__revision_file_t *rev_file;
+ SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start, pool,
+ iterpool));
+
/* determine the range of items to check for each revision */
- SVN_ERR(svn_fs_x__l2p_get_max_ids(&max_ids, fs, start, count, pool));
+ SVN_ERR(svn_fs_x__l2p_get_max_ids(&max_ids, fs, start, count, pool,
+ iterpool));
/* check all items in all revisions if the given range */
for (i = 0; i < max_ids->nelts; ++i)
@@ -171,17 +264,18 @@ compare_l2p_to_p2l_index(svn_fs_t *fs,
l2p_item.number = k;
/* get L2P entry. Ignore unused entries. */
- SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &l2p_item,
- iterpool));
+ SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, rev_file,
+ &l2p_item, iterpool));
if (offset == -1)
continue;
/* find the corresponding P2L entry */
- SVN_ERR(svn_fs_x__p2l_item_lookup(&p2l_item, fs, start,
- offset, sub_item, iterpool));
+ SVN_ERR(svn_fs_x__p2l_item_lookup(&p2l_item, fs, rev_file,
+ revision, offset, sub_item,
+ iterpool, iterpool));
if (p2l_item == NULL)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
NULL,
_("p2l index entry not found for "
"PHYS o%s:s%ld returned by "
@@ -190,7 +284,7 @@ compare_l2p_to_p2l_index(svn_fs_t *fs,
(long)sub_item, revision, (long)k);
if (!svn_fs_x__id_part_eq(&l2p_item, p2l_item))
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
NULL,
_("p2l index info LOG r%ld:i%ld"
" does not match "
@@ -208,6 +302,8 @@ compare_l2p_to_p2l_index(svn_fs_t *fs,
svn_pool_destroy(iterpool);
+ SVN_ERR(svn_fs_x__close_revision_file(rev_file));
+
return SVN_NO_ERROR;
}
@@ -232,8 +328,14 @@ compare_p2l_to_l2p_index(svn_fs_t *fs,
apr_off_t max_offset;
apr_off_t offset = 0;
+ /* common file access structure */
+ svn_fs_x__revision_file_t *rev_file;
+ SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start, pool,
+ iterpool));
+
/* get the size of the rev / pack file as covered by the P2L index */
- SVN_ERR(svn_fs_x__p2l_get_max_offset(&max_offset, fs, start, pool));
+ SVN_ERR(svn_fs_x__p2l_get_max_offset(&max_offset, fs, rev_file, start,
+ pool));
/* for all offsets in the file, get the P2L index entries and check
them against the L2P index */
@@ -244,10 +346,11 @@ compare_p2l_to_l2p_index(svn_fs_t *fs,
int i;
/* get all entries for the current block */
- SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, start, offset,
- ffd->p2l_page_size, iterpool));
+ SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, rev_file, start,
+ offset, ffd->p2l_page_size,
+ iterpool, iterpool));
if (entries->nelts == 0)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_CORRUPTION,
+ return svn_error_createf(SVN_ERR_FS_INDEX_CORRUPTION,
NULL,
_("p2l does not cover offset %s"
" for revision %ld"),
@@ -257,7 +360,7 @@ compare_p2l_to_l2p_index(svn_fs_t *fs,
last_entry
= &APR_ARRAY_IDX(entries, entries->nelts-1, svn_fs_x__p2l_entry_t);
offset = last_entry->offset + last_entry->size;
-
+
for (i = 0; i < entries->nelts; ++i)
{
apr_uint32_t k;
@@ -274,10 +377,10 @@ compare_p2l_to_l2p_index(svn_fs_t *fs,
= svn_fs_x__get_revnum(p2l_item->change_set);
SVN_ERR(svn_fs_x__item_offset(&l2p_offset, &sub_item, fs,
- p2l_item, iterpool));
+ rev_file, p2l_item, iterpool));
if (sub_item != k || l2p_offset != entry->offset)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
NULL,
_("l2p index entry PHYS o%s:s%ld "
"does not match p2l index value "
@@ -297,6 +400,8 @@ compare_p2l_to_l2p_index(svn_fs_t *fs,
svn_pool_destroy(iterpool);
+ SVN_ERR(svn_fs_x__close_revision_file(rev_file));
+
return SVN_NO_ERROR;
}
@@ -385,7 +490,7 @@ expected_checksum(apr_file_t *file,
SVN_ERR(svn_io_file_name_get(&file_name, file, pool));
SVN_ERR(svn_io_file_name_get(&file_name, file, pool));
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
- _("Checksum mismatch item at offset %s of "
+ _("Checksum mismatch in item at offset %s of "
"length %s bytes in file %s"),
apr_off_t_toa(pool, entry->offset),
apr_off_t_toa(pool, entry->size), file_name);
@@ -468,23 +573,26 @@ compare_p2l_to_rev(svn_fs_t *fs,
apr_pool_t *iterpool = svn_pool_create(pool);
apr_off_t max_offset;
apr_off_t offset = 0;
- apr_file_t *rev_file;
+ svn_fs_x__revision_file_t *rev_file;
/* open the pack / rev file that is covered by the p2l index */
- SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start, pool));
+ SVN_ERR(svn_fs_x__open_pack_or_rev_file(&rev_file, fs, start, pool,
+ iterpool));
/* check file size vs. range covered by index */
- SVN_ERR(svn_io_file_seek(rev_file, APR_END, &offset, pool));
- SVN_ERR(svn_fs_x__p2l_get_max_offset(&max_offset, fs, start, pool));
+ SVN_ERR(svn_fs_x__auto_read_footer(rev_file));
+ SVN_ERR(svn_fs_x__p2l_get_max_offset(&max_offset, fs, rev_file, start,
+ pool));
- if (offset != max_offset)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT, NULL,
+ if (rev_file->l2p_offset != max_offset)
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT, NULL,
_("File size of %s for revision r%ld does "
"not match p2l index size of %s"),
- apr_off_t_toa(pool, offset), start,
+ apr_off_t_toa(pool, rev_file->l2p_offset), start,
apr_off_t_toa(pool, max_offset));
- SVN_ERR(svn_io_file_aligned_seek(rev_file, ffd->block_size, NULL, 0, pool));
+ SVN_ERR(svn_io_file_aligned_seek(rev_file->file, ffd->block_size, NULL, 0,
+ pool));
/* for all offsets in the file, get the P2L index entries and check
them against the L2P index */
@@ -496,8 +604,14 @@ compare_p2l_to_rev(svn_fs_t *fs,
svn_pool_clear(iterpool);
/* get all entries for the current block */
- SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, start, offset,
- ffd->p2l_page_size, iterpool));
+ SVN_ERR(svn_fs_x__p2l_index_lookup(&entries, fs, rev_file, start,
+ offset, ffd->p2l_page_size,
+ iterpool, iterpool));
+
+ /* The above might have moved the file pointer.
+ * Ensure we actually start reading at OFFSET. */
+ SVN_ERR(svn_io_file_aligned_seek(rev_file->file, ffd->block_size,
+ NULL, offset, iterpool));
/* process all entries (and later continue with the next block) */
for (i = 0; i < entries->nelts; ++i)
@@ -515,7 +629,7 @@ compare_p2l_to_rev(svn_fs_t *fs,
/* p2l index must cover all rev / pack file offsets exactly once */
if (entry->offset != offset)
- return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+ return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
NULL,
_("p2l index entry for revision r%ld"
" is non-contiguous between offsets "
@@ -529,14 +643,16 @@ compare_p2l_to_rev(svn_fs_t *fs,
{
/* skip filler entry at the end of the p2l index */
if (entry->offset != max_offset)
- SVN_ERR(read_all_nul(rev_file, entry->size, pool));
+ SVN_ERR(read_all_nul(rev_file->file, entry->size, pool));
}
- else if (entry->fnv1_checksum)
+ else
{
if (entry->size < STREAM_THRESHOLD)
- SVN_ERR(expected_buffered_checksum(rev_file, entry, pool));
+ SVN_ERR(expected_buffered_checksum(rev_file->file, entry,
+ pool));
else
- SVN_ERR(expected_streamed_checksum(rev_file, entry, pool));
+ SVN_ERR(expected_streamed_checksum(rev_file->file, entry,
+ pool));
}
/* advance offset */
@@ -569,29 +685,59 @@ verify_index_consistency(svn_fs_t *fs,
void *cancel_baton,
apr_pool_t *pool)
{
+ svn_error_t *err;
fs_x_data_t *ffd = fs->fsap_data;
- svn_revnum_t revision, pack_start, pack_end;
+ svn_revnum_t revision, next_revision;
apr_pool_t *iterpool = svn_pool_create(pool);
- for (revision = start; revision <= end; revision = pack_end)
+ for (revision = start; revision <= end; revision = next_revision)
{
- pack_start = svn_fs_x__packed_base_rev(fs, revision);
- pack_end = pack_start + svn_fs_x__pack_size(fs, revision);
+ svn_revnum_t count = svn_fs_x__packed_base_rev(fs, revision);
+ svn_revnum_t pack_start = count;
+ svn_revnum_t pack_end = pack_start + svn_fs_x__pack_size(fs, revision);
+
+ svn_pool_clear(iterpool);
if (notify_func && (pack_start % ffd->max_files_per_dir == 0))
notify_func(pack_start, notify_baton, iterpool);
+ /* Check for external corruption to the indexes. */
+ err = verify_index_checksums(fs, pack_start, cancel_func,
+ cancel_baton, iterpool);
+
/* two-way index check */
- SVN_ERR(compare_l2p_to_p2l_index(fs, pack_start, pack_end - pack_start,
- cancel_func, cancel_baton, iterpool));
- SVN_ERR(compare_p2l_to_l2p_index(fs, pack_start, pack_end - pack_start,
- cancel_func, cancel_baton, iterpool));
+ if (!err)
+ err = compare_l2p_to_p2l_index(fs, pack_start, pack_end - pack_start,
+ cancel_func, cancel_baton, iterpool);
+ if (!err)
+ err = compare_p2l_to_l2p_index(fs, pack_start, pack_end - pack_start,
+ cancel_func, cancel_baton, iterpool);
/* verify in-index checksums and types vs. actual rev / pack files */
- SVN_ERR(compare_p2l_to_rev(fs, pack_start, pack_end - pack_start,
- cancel_func, cancel_baton, iterpool));
+ if (!err)
+ err = compare_p2l_to_rev(fs, pack_start, pack_end - pack_start,
+ cancel_func, cancel_baton, iterpool);
+
+ /* concurrent packing is one of the reasons why verification may fail.
+ Make sure, we operate on up-to-date information. */
+ if (err)
+ SVN_ERR(svn_fs_x__read_min_unpacked_rev(&ffd->min_unpacked_rev,
+ fs, pool));
- svn_pool_clear(iterpool);
+ /* retry the whole shard if it got packed in the meantime */
+ if (err && count != svn_fs_x__pack_size(fs, revision))
+ {
+ svn_error_clear(err);
+
+ /* We could simply assign revision here but the code below is
+ more intuitive to maintainers. */
+ next_revision = svn_fs_x__packed_base_rev(fs, revision);
+ }
+ else
+ {
+ SVN_ERR(err);
+ next_revision = pack_end;
+ }
}
svn_pool_destroy(iterpool);
Modified: subversion/branches/svn-auth-x509/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-auth-x509/subversion/libsvn_ra_serf/blame.c?rev=1639628&r1=1639627&r2=1639628&view=diff
==============================================================================
--- subversion/branches/svn-auth-x509/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/svn-auth-x509/subversion/libsvn_ra_serf/blame.c Fri Nov 14 13:17:55 2014
@@ -302,9 +302,8 @@ create_file_revs_body(serf_bucket_t **bo
if (blame_ctx->include_merged_revisions)
{
- svn_ra_serf__add_tag_buckets(buckets,
- "S:include-merged-revisions", NULL,
- alloc);
+ svn_ra_serf__add_empty_tag_buckets(buckets, alloc,
+ "S:include-merged-revisions", SVN_VA_NULL);
}
svn_ra_serf__add_tag_buckets(buckets,