Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/lock.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/lock.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/lock.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/lock.c Mon Feb 9 11:23:39 2015 @@ -103,8 +103,7 @@ hash_store(apr_hash_t *hash, of that value (if it exists). */ static const char * hash_fetch(apr_hash_t *hash, - const char *key, - apr_pool_t *pool) + const char *key) { svn_string_t *str = svn_hash_gets(hash, key); return str ? str->data : NULL; @@ -284,7 +283,7 @@ read_digest_file(apr_hash_t **children_p /* If our caller cares, see if we have a lock path in our hash. If so, we'll assume we have a lock here. */ - val = hash_fetch(hash, PATH_KEY, pool); + val = hash_fetch(hash, PATH_KEY); if (val && lock_p) { const char *path = val; @@ -293,30 +292,30 @@ read_digest_file(apr_hash_t **children_p lock = svn_lock_create(pool); lock->path = path; - if (! ((lock->token = hash_fetch(hash, TOKEN_KEY, pool)))) + if (! ((lock->token = hash_fetch(hash, TOKEN_KEY)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); - if (! ((lock->owner = hash_fetch(hash, OWNER_KEY, pool)))) + if (! ((lock->owner = hash_fetch(hash, OWNER_KEY)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); - if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY, pool)))) + if (! ((val = hash_fetch(hash, IS_DAV_COMMENT_KEY)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); lock->is_dav_comment = (val[0] == '1'); - if (! ((val = hash_fetch(hash, CREATION_DATE_KEY, pool)))) + if (! ((val = hash_fetch(hash, CREATION_DATE_KEY)))) return svn_error_trace(err_corrupt_lockfile(fs_path, path)); SVN_ERR(svn_time_from_cstring(&(lock->creation_date), val, pool)); - if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY, pool))) + if ((val = hash_fetch(hash, EXPIRATION_DATE_KEY))) SVN_ERR(svn_time_from_cstring(&(lock->expiration_date), val, pool)); - lock->comment = hash_fetch(hash, COMMENT_KEY, pool); + lock->comment = hash_fetch(hash, COMMENT_KEY); *lock_p = lock; } /* If our caller cares, see if we have any children for this path. */ - val = hash_fetch(hash, CHILDREN_KEY, pool); + val = hash_fetch(hash, CHILDREN_KEY); if (val && children_p) { apr_array_header_t *kiddos = svn_cstring_split(val, "\n", FALSE, pool); @@ -854,9 +853,6 @@ lock_body(void *baton, apr_pool_t *pool) int i, outstanding = 0; apr_pool_t *iterpool = svn_pool_create(pool); - lb->infos = apr_array_make(lb->result_pool, lb->targets->nelts, - sizeof(struct lock_info_t)); - /* Until we implement directory locks someday, we only allow locks on files or non-existent paths. */ /* Use fs->vtable->foo instead of svn_fs_foo to avoid circular @@ -1057,9 +1053,6 @@ unlock_body(void *baton, apr_pool_t *poo int i, max_components = 0, outstanding = 0; apr_pool_t *iterpool = svn_pool_create(pool); - ub->infos = apr_array_make(ub->result_pool, ub->targets->nelts, - sizeof(struct unlock_info_t)); - SVN_ERR(ub->fs->vtable->youngest_rev(&youngest, ub->fs, pool)); SVN_ERR(ub->fs->vtable->revision_root(&root, ub->fs, youngest, pool)); @@ -1181,6 +1174,8 @@ unlock_single(svn_fs_t *fs, ub.fs = fs; ub.targets = targets; + ub.infos = apr_array_make(pool, targets->nelts, + sizeof(struct unlock_info_t)); ub.skip_check = TRUE; ub.result_pool = pool; @@ -1241,6 +1236,8 @@ svn_fs_fs__lock(svn_fs_t *fs, lb.fs = fs; lb.targets = sorted_targets; + lb.infos = apr_array_make(result_pool, sorted_targets->nelts, + sizeof(struct lock_info_t)); lb.comment = comment; lb.is_dav_comment = is_dav_comment; lb.expiration_date = expiration_date; @@ -1331,6 +1328,8 @@ svn_fs_fs__unlock(svn_fs_t *fs, ub.fs = fs; ub.targets = sorted_targets; + ub.infos = apr_array_make(result_pool, sorted_targets->nelts, + sizeof(struct unlock_info_t)); ub.skip_check = FALSE; ub.break_lock = break_lock; ub.result_pool = result_pool;
Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c Mon Feb 9 11:23:39 2015 @@ -208,7 +208,9 @@ parse_revprop(apr_hash_t **properties, svn_stream_t *stream = svn_stream_from_string(content, scratch_pool); *properties = apr_hash_make(pool); - SVN_ERR(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR, pool)); + SVN_ERR_W(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR, pool), + apr_psprintf(scratch_pool, "Failed to parse revprops for r%ld.", + revision)); return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c Mon Feb 9 11:23:39 2015 @@ -249,8 +249,8 @@ add_to_histogram(svn_fs_fs__histogram_t */ static void add_change(svn_fs_fs__stats_t *stats, - apr_int64_t rep_size, - apr_int64_t expanded_size, + apr_uint64_t rep_size, + apr_uint64_t expanded_size, svn_revnum_t revision, const char *path, rep_kind_t kind, @@ -293,29 +293,25 @@ add_change(svn_fs_fs__stats_t *stats, /* specific histograms by type */ switch (kind) { - case unused_rep: add_to_histogram(&stats->unused_rep_histogram, - rep_size); - break; - case dir_property_rep: add_to_histogram(&stats->dir_prop_rep_histogram, - rep_size); - add_to_histogram(&stats->dir_prop_histogram, - expanded_size); - break; - case file_property_rep: add_to_histogram(&stats->file_prop_rep_histogram, - rep_size); - add_to_histogram(&stats->file_prop_histogram, - expanded_size); - break; - case dir_rep: add_to_histogram(&stats->dir_rep_histogram, - rep_size); - add_to_histogram(&stats->dir_histogram, - expanded_size); - break; - case file_rep: add_to_histogram(&stats->file_rep_histogram, - rep_size); - add_to_histogram(&stats->file_histogram, - expanded_size); - break; + case unused_rep: + add_to_histogram(&stats->unused_rep_histogram, rep_size); + break; + case dir_property_rep: + add_to_histogram(&stats->dir_prop_rep_histogram, rep_size); + add_to_histogram(&stats->dir_prop_histogram, expanded_size); + break; + case file_property_rep: + add_to_histogram(&stats->file_prop_rep_histogram, rep_size); + add_to_histogram(&stats->file_prop_histogram, expanded_size); + break; + case dir_rep: + add_to_histogram(&stats->dir_rep_histogram, rep_size); + add_to_histogram(&stats->dir_histogram, expanded_size); + break; + case file_rep: + add_to_histogram(&stats->file_rep_histogram, rep_size); + add_to_histogram(&stats->file_histogram, expanded_size); + break; } /* by extension */ @@ -615,13 +611,12 @@ read_noderev(query_t *query, /* record largest changes */ if (text && text->ref_count == 1) - add_change(query->stats, (apr_int64_t)text->size, - (apr_int64_t)text->expanded_size, text->revision, + add_change(query->stats, text->size, text->expanded_size, text->revision, noderev->created_path, text->kind, !noderev->predecessor_id); if (props && props->ref_count == 1) - add_change(query->stats, (apr_int64_t)props->size, - (apr_int64_t)props->expanded_size, props->revision, - noderev->created_path, props->kind, !noderev->predecessor_id); + add_change(query->stats, props->size, props->expanded_size, + props->revision, noderev->created_path, props->kind, + !noderev->predecessor_id); /* if this is a directory and has not been processed, yet, read and * process it recursively */ @@ -1033,7 +1028,7 @@ svn_fs_fs__get_stats(svn_fs_fs__stats_t query_t *query; *stats = create_stats(result_pool); - SVN_ERR(create_query(&query, fs, *stats, progress_func, progress_func, + SVN_ERR(create_query(&query, fs, *stats, progress_func, progress_baton, cancel_func, cancel_baton, scratch_pool, scratch_pool)); SVN_ERR(read_revisions(query, scratch_pool, scratch_pool)); Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/structure URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/structure?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/structure (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/structure Mon Feb 9 11:23:39 2015 @@ -560,8 +560,7 @@ defined: props "<rev> <item_index> <length> <size> <digest>" for props rep <rev> and <item_index> give location of rep <length> gives length of rep, sans header and trailer - <size> gives size of expanded rep; for props only, it may be 0 - if equal to the length + <size> gives size of expanded rep (*) <digest> gives hex MD5 digest of expanded rep ### in formats >=4, also present: <sha1-digest> gives hex SHA1 digest of expanded rep @@ -573,6 +572,15 @@ defined: which have svn:mergeinfo. minfo-here Exists if this node itself has svn:mergeinfo. +(*) Earlier versions of this document would state that <size> may be 0 + if the actual value matches <length>. This is only true for property + and directory representations and should be avoided in general. File + representations may not be handled correctly by SVN before 1.7.20, + 1.8.12 and 1.9.0, if they have 0 <size> fields for non-empty contents. + Releases 1.8.0 through 1.8.11 may have falsely created instances of + that (see issue #4554). Finally, 0 <size> fields are NEVER legal for + DELTA representations. + The predecessor of a node-rev crosses both soft and true copies; together with the count field, it allows efficient determination of the base for skip-deltas. The first node-rev of a node contains no Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/transaction.c Mon Feb 9 11:23:39 2015 @@ -1991,10 +1991,21 @@ get_shared_rep(representation_t **old_re } } - /* Add information that is missing in the cached data. */ - if (*old_rep) + if (!*old_rep) + return SVN_NO_ERROR; + + /* We don't want 0-length PLAIN representations to replace non-0-length + ones (see issue #4554). Also, this doubles as a simple guard against + general rep-cache induced corruption. */ + if ( ((*old_rep)->expanded_size != rep->expanded_size) + || ((*old_rep)->size != rep->size)) { - /* Use the old rep for this content. */ + *old_rep = NULL; + } + else + { + /* Add information that is missing in the cached data. + Use the old rep for this content. */ memcpy((*old_rep)->md5_digest, rep->md5_digest, sizeof(rep->md5_digest)); (*old_rep)->uniquifier = rep->uniquifier; } @@ -2860,44 +2871,41 @@ verify_locks(svn_fs_t *fs, apr_hash_t *changed_paths, apr_pool_t *pool) { - apr_pool_t *subpool = svn_pool_create(pool); - apr_hash_index_t *hi; + apr_pool_t *iterpool; apr_array_header_t *changed_paths_sorted; svn_stringbuf_t *last_recursed = NULL; int i; /* Make an array of the changed paths, and sort them depth-first-ily. */ - 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); + changed_paths_sorted = svn_sort__hash(changed_paths, + svn_sort_compare_items_as_paths, + pool); /* 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. */ + iterpool = svn_pool_create(pool); for (i = 0; i < changed_paths_sorted->nelts; i++) { + const svn_sort__item_t *item; const char *path; svn_fs_path_change2_t *change; svn_boolean_t recurse = TRUE; - svn_pool_clear(subpool); - path = APR_ARRAY_IDX(changed_paths_sorted, i, const char *); + svn_pool_clear(iterpool); + + item = &APR_ARRAY_IDX(changed_paths_sorted, i, svn_sort__item_t); + + /* Fetch the change associated with our path. */ + path = item->key; + change = item->value; /* If this path has already been verified as part of a recursive check of one of its parents, no need to do it again. */ if (last_recursed - && svn_dirent_is_child(last_recursed->data, path, subpool)) + && svn_fspath__skip_ancestor(last_recursed->data, path)) continue; - /* Fetch the change associated with our 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 (text, props), it means we hold the lock on the file or @@ -2910,7 +2918,7 @@ verify_locks(svn_fs_t *fs, if (change->change_kind == svn_fs_path_change_modify) recurse = FALSE; SVN_ERR(svn_fs_fs__allow_locked_operation(path, fs, recurse, TRUE, - subpool)); + iterpool)); /* If we just did a recursive check, remember the path we checked (so children can be skipped). */ @@ -2922,7 +2930,7 @@ verify_locks(svn_fs_t *fs, svn_stringbuf_set(last_recursed, path); } } - svn_pool_destroy(subpool); + svn_pool_destroy(iterpool); return SVN_NO_ERROR; } Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/tree.c Mon Feb 9 11:23:39 2015 @@ -100,7 +100,6 @@ typedef struct fs_txn_root_data_t static svn_error_t * get_dag(dag_node_t **dag_node_p, svn_fs_root_t *root, const char *path, - svn_boolean_t needs_lock_cache, apr_pool_t *pool); static svn_fs_root_t *make_revision_root(svn_fs_t *fs, svn_revnum_t rev, @@ -159,34 +158,10 @@ typedef struct cache_entry_t */ enum { BUCKET_COUNT = 256 }; -/* Each pool that has received a DAG node, will hold at least on lock on - our cache to ensure that the node remains valid despite being allocated - in the cache's pool. This is the structure to represent the lock. - */ -typedef struct cache_lock_t -{ - /* pool holding the lock */ - apr_pool_t *pool; - - /* cache being locked */ - fs_fs_dag_cache_t *cache; - - /* next lock. NULL at EOL */ - struct cache_lock_t *next; - - /* previous lock. NULL at list head. Only then this==cache->first_lock */ - struct cache_lock_t *prev; -} cache_lock_t; - /* The actual cache structure. All nodes will be allocated in POOL. When the number of INSERTIONS (i.e. objects created form that pool) exceeds a certain threshold, the pool will be cleared and the cache with it. - - To ensure that nodes returned from this structure remain valid, the - cache will get locked for the lifetime of the _receiving_ pools (i.e. - those in which we would allocate the node if there was no cache.). - The cache will only be cleared FIRST_LOCK is 0. */ struct fs_fs_dag_cache_t { @@ -203,109 +178,29 @@ struct fs_fs_dag_cache_t Thus, remember the last hit location for optimistic lookup. */ apr_size_t last_hit; - /* List of receiving pools that are still alive. */ - cache_lock_t *first_lock; + /* Position of the last bucket hit that actually had a DAG node in it. + LAST_HIT may refer to a bucket that matches path@rev but has not + its NODE element set, yet. + This value is a mere hint for optimistic lookup and any value is + valid (as long as it is < BUCKET_COUNT). */ + apr_size_t last_non_empty; }; -/* Cleanup function to be called when a receiving pool gets cleared. - Unlocks the cache once. - */ -static apr_status_t -unlock_cache(void *baton_void) -{ - cache_lock_t *lock = baton_void; - - /* remove lock from chain. Update the head */ - if (lock->next) - lock->next->prev = lock->prev; - if (lock->prev) - lock->prev->next = lock->next; - else - lock->cache->first_lock = lock->next; - - return APR_SUCCESS; -} - -/* Cleanup function to be called when the cache itself gets destroyed. - In that case, we must unregister all unlock requests. - */ -static apr_status_t -unregister_locks(void *baton_void) -{ - fs_fs_dag_cache_t *cache = baton_void; - cache_lock_t *lock; - - for (lock = cache->first_lock; lock; lock = lock->next) - apr_pool_cleanup_kill(lock->pool, - lock, - unlock_cache); - - return APR_SUCCESS; -} - fs_fs_dag_cache_t* svn_fs_fs__create_dag_cache(apr_pool_t *pool) { fs_fs_dag_cache_t *result = apr_pcalloc(pool, sizeof(*result)); result->pool = svn_pool_create(pool); - apr_pool_cleanup_register(pool, - result, - unregister_locks, - apr_pool_cleanup_null); - return result; } -/* Prevent the entries in CACHE from being destroyed, for as long as the - POOL lives. - */ -static void -lock_cache(fs_fs_dag_cache_t* cache, apr_pool_t *pool) -{ - /* we only need to lock / unlock once per pool. Since we will often ask - for multiple nodes with the same pool, we can reduce the overhead. - However, if e.g. pools are being used in an alternating pattern, - we may lock the cache more than once for the same pool (and register - just as many cleanup actions). - */ - cache_lock_t *lock = cache->first_lock; - - /* try to find an existing lock for POOL. - But limit the time spent on chasing pointers. */ - int limiter = 8; - while (lock && --limiter) - { - if (lock->pool == pool) - return; - - lock = lock->next; - } - - /* create a new lock and put it at the beginning of the lock chain */ - lock = apr_palloc(pool, sizeof(*lock)); - lock->cache = cache; - lock->pool = pool; - lock->next = cache->first_lock; - lock->prev = NULL; - - if (cache->first_lock) - cache->first_lock->prev = lock; - cache->first_lock = lock; - - /* instruct POOL to remove the look upon cleanup */ - apr_pool_cleanup_register(pool, - lock, - unlock_cache, - apr_pool_cleanup_null); -} - /* Clears the CACHE at regular intervals (destroying all cached nodes) */ static void auto_clear_dag_cache(fs_fs_dag_cache_t* cache) { - if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT) + if (cache->insertions > BUCKET_COUNT) { svn_pool_clear(cache->pool); @@ -338,6 +233,10 @@ cache_lookup( fs_fs_dag_cache_t *cache && (result->path_len == path_len) && !memcmp(result->path, path, path_len)) { + /* Remember the position of the last node we found in this cache. */ + if (result->node) + cache->last_non_empty = cache->last_hit; + return result; } @@ -409,10 +308,38 @@ cache_lookup( fs_fs_dag_cache_t *cache cache->insertions++; } + else if (result->node) + { + /* This bucket is valid & has a suitable DAG node in it. + Remember its location. */ + cache->last_non_empty = bucket_index; + } return result; } +/* Optimistic lookup using the last seen non-empty location in CACHE. + Return the node of that entry, if it is still in use and matches PATH. + Return NULL otherwise. Since the caller usually already knows the path + length, provide it in PATH_LEN. */ +static dag_node_t * +cache_lookup_last_path(fs_fs_dag_cache_t *cache, + const char *path, + apr_size_t path_len) +{ + cache_entry_t *result = &cache->buckets[cache->last_non_empty]; + assert(strlen(path) == path_len); + + if ( result->node + && (result->path_len == path_len) + && !memcmp(result->path, path, path_len)) + { + return result->node; + } + + return NULL; +} + /* 2nd level cache */ /* Find and return the DAG node cache for ROOT and the key that @@ -446,18 +373,12 @@ locate_cache(svn_cache__t **cache, } } -/* Return NODE for PATH from ROOT's node cache, or NULL if the node - isn't cached; read it from the FS. *NODE remains valid until either - POOL or the FS gets cleared or destroyed (whichever comes first). - - Since locking can be expensive and POOL may be long-living, for - nodes that will not need to survive the next call to this function, - set NEEDS_LOCK_CACHE to FALSE. */ +/* In *NODE_P, return the DAG node for PATH from ROOT's node cache, or NULL + if the node isn't cached. *NODE_P is allocated in POOL. */ static svn_error_t * dag_node_cache_get(dag_node_t **node_p, svn_fs_root_t *root, const char *path, - svn_boolean_t needs_lock_cache, apr_pool_t *pool) { svn_boolean_t found; @@ -479,25 +400,23 @@ dag_node_cache_get(dag_node_t **node_p, if (bucket->node == NULL) { locate_cache(&cache, &key, root, path, pool); - SVN_ERR(svn_cache__get((void **)&node, &found, cache, key, - ffd->dag_node_cache->pool)); + SVN_ERR(svn_cache__get((void **)&node, &found, cache, key, pool)); if (found && node) { /* Patch up the FS, since this might have come from an old FS - * object. */ + * object. */ svn_fs_fs__dag_set_fs(node, root->fs); - bucket->node = node; + + /* Retain the DAG node in L1 cache. */ + bucket->node = svn_fs_fs__dag_dup(node, + ffd->dag_node_cache->pool); } } else { - node = bucket->node; + /* Copy the node from L1 cache into the passed-in POOL. */ + node = svn_fs_fs__dag_dup(bucket->node, pool); } - - /* if we found a node, make sure it remains valid at least as long - as it would when allocated in POOL. */ - if (node && needs_lock_cache) - lock_cache(ffd->dag_node_cache, pool); } else { @@ -509,7 +428,7 @@ dag_node_cache_get(dag_node_t **node_p, if (found && node) { /* Patch up the FS, since this might have come from an old FS - * object. */ + * object. */ svn_fs_fs__dag_set_fs(node, root->fs); } } @@ -532,11 +451,7 @@ dag_node_cache_set(svn_fs_root_t *root, SVN_ERR_ASSERT(*path == '/'); - /* Do *not* attempt to dup and put the node into L1. - * dup() is twice as expensive as an L2 lookup (which will set also L1). - */ locate_cache(&cache, &key, root, path, pool); - return svn_cache__set(cache, key, node, pool); } @@ -848,7 +763,7 @@ get_copy_inheritance(copy_id_inherit_t * SVN_ERR(svn_fs_fs__dag_get_copyroot(©root_rev, ©root_path, child->node)); SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev, pool)); - SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, FALSE, pool)); + SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool)); copyroot_id = svn_fs_fs__dag_get_id(copyroot_node); if (svn_fs_fs__id_compare(copyroot_id, child_id) == svn_fs_node_unrelated) @@ -912,6 +827,56 @@ typedef enum open_path_flags_t { open_path_allow_null = 8 } open_path_flags_t; +/* Try a short-cut for the open_path() function using the last node accessed. + * If that ROOT is that nodes's "created rev" and PATH of PATH_LEN chars is + * its "created path", return the node in *NODE_P. Set it to NULL otherwise. + * + * This function is used to support ra_serf-style access patterns where we + * are first asked for path@rev and then for path@c_rev of the same node. + * The shortcut works by ignoring the "rev" part of the cache key and then + * checking whether we got lucky. Lookup and verification are both quick + * plus there are many early outs for common types of mismatch. + */ +static svn_error_t * +try_match_last_node(dag_node_t **node_p, + svn_fs_root_t *root, + const char *path, + apr_size_t path_len, + apr_pool_t *scratch_pool) +{ + fs_fs_data_t *ffd = root->fs->fsap_data; + + /* Optimistic lookup: if the last node returned from the cache applied to + the same PATH, return it in NODE. */ + dag_node_t *node + = cache_lookup_last_path(ffd->dag_node_cache, path, path_len); + + /* Did we get a bucket with a committed node? */ + if (node && !svn_fs_fs__dag_check_mutable(node)) + { + /* Get the path&rev pair at which this node was created. + This is repository location for which this node is _known_ to be + the right lookup result irrespective of how we found it. */ + const char *created_path + = svn_fs_fs__dag_get_created_path(node); + svn_revnum_t revision; + SVN_ERR(svn_fs_fs__dag_get_revision(&revision, node, scratch_pool)); + + /* Is it an exact match? */ + if (revision == root->rev && strcmp(created_path, path) == 0) + { + /* Cache it under its full path@rev access path. */ + SVN_ERR(dag_node_cache_set(root, path, node, scratch_pool)); + + *node_p = node; + return SVN_NO_ERROR; + } + } + + *node_p = NULL; + return SVN_NO_ERROR; +} + /* Open the node identified by PATH in ROOT, allocating in POOL. Set *PARENT_PATH_P to a path from the node up to ROOT. The resulting @@ -959,20 +924,55 @@ open_path(parent_path_t **parent_path_p, at the respective position and replacing that with a '/' in the next iteration. This is correct as we assert() PATH to be canonical. */ svn_stringbuf_t *path_so_far = svn_stringbuf_create(path, pool); + apr_size_t path_len = path_so_far->len; - /* callers often traverse the tree in some path-based order. That means - a sibling of PATH has been presently accessed. Try to start the lookup - directly at the parent node, if the caller did not requested the full - parent chain. */ + /* Callers often traverse the DAG in some path-based order or along the + history segments. That allows us to try a few guesses about where to + find the next item. This is only useful if the caller didn't request + the full parent chain. */ assert(svn_fs__is_canonical_abspath(path)); path_so_far->len = 0; /* "" */ if (flags & open_path_node_only) { - const char *directory = svn_dirent_dirname(path, pool); + const char *directory; + + /* First attempt: Assume that we access the DAG for the same path as + in the last lookup but for a different revision that happens to be + the last revision that touched the respective node. This is a + common pattern when e.g. checking out over ra_serf. Note that this + will only work for committed data as the revision info for nodes in + txns is bogus. + + This shortcut is quick and will exit this function upon success. + So, try it first. */ + if (!root->is_txn_root) + { + dag_node_t *node; + SVN_ERR(try_match_last_node(&node, root, path, path_len, iterpool)); + + /* Did the shortcut work? */ + if (node) + { + /* Construct and return the result. */ + svn_pool_destroy(iterpool); + + parent_path = make_parent_path(node, 0, 0, pool); + parent_path->copy_inherit = copy_id_inherit_self; + *parent_path_p = parent_path; + + return SVN_NO_ERROR; + } + } + + /* Second attempt: Try starting the lookup immediately at the parent + node. We will often have recently accessed either a sibling or + said parent DIRECTORY itself for the same revision. */ + directory = svn_dirent_dirname(path, pool); if (directory[1] != 0) /* root nodes are covered anyway */ { - SVN_ERR(dag_node_cache_get(&here, root, directory, TRUE, pool)); - /* did the shortcut work? */ + SVN_ERR(dag_node_cache_get(&here, root, directory, pool)); + + /* Did the shortcut work? */ if (here) { apr_size_t dirname_len = strlen(directory); @@ -1037,7 +1037,7 @@ open_path(parent_path_t **parent_path_p, complete path. */ if (next || !(flags & open_path_uncached)) SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far->data, - TRUE, pool)); + pool)); if (cached_node) child = cached_node; else @@ -1176,8 +1176,7 @@ make_path_mutable(svn_fs_root_t *root, parent_path->node)); SVN_ERR(svn_fs_fs__revision_root(©root_root, root->fs, copyroot_rev, pool)); - SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, - FALSE, pool)); + SVN_ERR(get_dag(©root_node, copyroot_root, copyroot_path, pool)); child_id = svn_fs_fs__dag_get_id(parent_path->node); copyroot_id = svn_fs_fs__dag_get_id(copyroot_node); @@ -1214,16 +1213,11 @@ make_path_mutable(svn_fs_root_t *root, /* Open the node identified by PATH in ROOT. Set DAG_NODE_P to the node we find, allocated in POOL. Return the error - SVN_ERR_FS_NOT_FOUND if this node doesn't exist. - - Since locking can be expensive and POOL may be long-living, for - nodes that will not need to survive the next call to this function, - set NEEDS_LOCK_CACHE to FALSE. */ + SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */ static svn_error_t * get_dag(dag_node_t **dag_node_p, svn_fs_root_t *root, const char *path, - svn_boolean_t needs_lock_cache, apr_pool_t *pool) { parent_path_t *parent_path; @@ -1232,7 +1226,7 @@ get_dag(dag_node_t **dag_node_p, /* First we look for the DAG in our cache (if the path may be canonical). */ if (*path == '/') - SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache, pool)); + SVN_ERR(dag_node_cache_get(&node, root, path, pool)); if (! node) { @@ -1242,8 +1236,7 @@ get_dag(dag_node_t **dag_node_p, * performance benefit over previously checking path for being * canonical. */ path = svn_fs__canonicalize_abspath(path, pool); - SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache, - pool)); + SVN_ERR(dag_node_cache_get(&node, root, path, pool)); if (! node) { @@ -1322,7 +1315,7 @@ svn_fs_fs__node_id(const svn_fs_id_t **i { dag_node_t *node; - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); *id_p = svn_fs_fs__id_copy(svn_fs_fs__dag_get_id(node), pool); } return SVN_NO_ERROR; @@ -1371,12 +1364,12 @@ fs_node_relation(svn_fs_node_relation_t /* We checked for all separations between ID spaces (repos, txn). * Now, we can simply test for the ID values themselves. */ - SVN_ERR(get_dag(&node, root_a, path_a, FALSE, pool)); + SVN_ERR(get_dag(&node, root_a, path_a, pool)); id = svn_fs_fs__dag_get_id(node); rev_item_a = *svn_fs_fs__id_rev_item(id); node_id_a = *svn_fs_fs__id_node_id(id); - SVN_ERR(get_dag(&node, root_b, path_b, FALSE, pool)); + SVN_ERR(get_dag(&node, root_b, path_b, pool)); id = svn_fs_fs__dag_get_id(node); rev_item_b = *svn_fs_fs__id_rev_item(id); node_id_b = *svn_fs_fs__id_node_id(id); @@ -1399,7 +1392,7 @@ svn_fs_fs__node_created_rev(svn_revnum_t { dag_node_t *node; - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); return svn_fs_fs__dag_get_revision(revision, node, pool); } @@ -1414,7 +1407,7 @@ fs_node_created_path(const char **create { dag_node_t *node; - SVN_ERR(get_dag(&node, root, path, TRUE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); *created_path = svn_fs_fs__dag_get_created_path(node); return SVN_NO_ERROR; @@ -1478,7 +1471,7 @@ fs_node_prop(svn_string_t **value_p, dag_node_t *node; apr_hash_t *proplist; - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, node, pool)); *value_p = NULL; if (proplist) @@ -1501,7 +1494,7 @@ fs_node_proplist(apr_hash_t **table_p, apr_hash_t *table; dag_node_t *node; - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); SVN_ERR(svn_fs_fs__dag_get_proplist(&table, node, pool)); *table_p = table ? table : apr_hash_make(pool); @@ -1622,8 +1615,8 @@ fs_props_changed(svn_boolean_t *changed_ (SVN_ERR_FS_GENERAL, NULL, _("Cannot compare property value between two different filesystems")); - SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool)); - SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool)); + SVN_ERR(get_dag(&node1, root1, path1, pool)); + SVN_ERR(get_dag(&node2, root2, path2, pool)); return svn_fs_fs__dag_things_different(changed_p, NULL, node1, node2, strict, pool); } @@ -1636,7 +1629,7 @@ fs_props_changed(svn_boolean_t *changed_ static svn_error_t * get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool) { - return get_dag(node, root, "/", TRUE, pool); + return get_dag(node, root, "/", pool); } @@ -2367,7 +2360,7 @@ fs_dir_entries(apr_hash_t **table_p, int i; /* Get the entries for this path in the caller's pool. */ - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); SVN_ERR(svn_fs_fs__dag_dir_entries(&table, node, pool)); /* Convert directory array to hash. */ @@ -2567,7 +2560,7 @@ copy_helper(svn_fs_root_t *from_root, _("Copy immutable tree not supported")); /* Get the NODE for FROM_PATH in FROM_ROOT.*/ - SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool)); + SVN_ERR(get_dag(&from_node, from_root, from_path, pool)); /* Build up the parent path from TO_PATH in TO_ROOT. If the last component does not exist, it's not that big a deal. We'll just @@ -2644,7 +2637,7 @@ copy_helper(svn_fs_root_t *from_root, pool)); /* Make a record of this modification in the changes table. */ - SVN_ERR(get_dag(&new_node, to_root, to_path, TRUE, pool)); + SVN_ERR(get_dag(&new_node, to_root, to_path, pool)); SVN_ERR(add_change(to_root->fs, txn_id, to_path, svn_fs_fs__dag_get_id(new_node), kind, FALSE, FALSE, FALSE, svn_fs_fs__dag_node_kind(from_node), @@ -2725,7 +2718,7 @@ fs_copied_from(svn_revnum_t *rev_p, /* There is no cached entry, look it up the old-fashioned way. */ - SVN_ERR(get_dag(&node, root, path, TRUE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(rev_p, node)); SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(path_p, node)); @@ -2796,7 +2789,7 @@ fs_file_length(svn_filesize_t *length_p, dag_node_t *file; /* First create a dag_node_t from the root/path pair. */ - SVN_ERR(get_dag(&file, root, path, FALSE, pool)); + SVN_ERR(get_dag(&file, root, path, pool)); /* Now fetch its length */ return svn_fs_fs__dag_file_length(length_p, file, pool); @@ -2815,7 +2808,7 @@ fs_file_checksum(svn_checksum_t **checks { dag_node_t *file; - SVN_ERR(get_dag(&file, root, path, FALSE, pool)); + SVN_ERR(get_dag(&file, root, path, pool)); return svn_fs_fs__dag_file_checksum(checksum, file, kind, pool); } @@ -2834,7 +2827,7 @@ fs_file_contents(svn_stream_t **contents svn_stream_t *file_stream; /* First create a dag_node_t from the root/path pair. */ - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); /* Then create a readable stream from the dag_node_t. */ SVN_ERR(svn_fs_fs__dag_get_contents(&file_stream, node, pool)); @@ -2857,7 +2850,7 @@ fs_try_process_file_contents(svn_boolean apr_pool_t *pool) { dag_node_t *node; - SVN_ERR(get_dag(&node, root, path, FALSE, pool)); + SVN_ERR(get_dag(&node, root, path, pool)); return svn_fs_fs__dag_try_process_file_contents(success, node, processor, baton, pool); @@ -3181,8 +3174,8 @@ fs_contents_changed(svn_boolean_t *chang (SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path2); } - SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool)); - SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool)); + SVN_ERR(get_dag(&node1, root1, path1, pool)); + SVN_ERR(get_dag(&node2, root2, path2, pool)); return svn_fs_fs__dag_things_different(NULL, changed_p, node1, node2, strict, pool); } @@ -3202,10 +3195,10 @@ fs_get_file_delta_stream(svn_txdelta_str dag_node_t *source_node, *target_node; if (source_root && source_path) - SVN_ERR(get_dag(&source_node, source_root, source_path, TRUE, pool)); + SVN_ERR(get_dag(&source_node, source_root, source_path, pool)); else source_node = NULL; - SVN_ERR(get_dag(&target_node, target_root, target_path, TRUE, pool)); + SVN_ERR(get_dag(&target_node, target_root, target_path, pool)); /* Create a delta stream that turns the source into the target. */ return svn_fs_fs__dag_get_file_delta_stream(stream_p, source_node, @@ -3669,7 +3662,7 @@ history_prev(svn_fs_history_t **prev_his SVN_ERR(svn_fs_fs__revision_root(©root_root, fs, copyroot_rev, scratch_pool)); - SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, FALSE, scratch_pool)); + SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, scratch_pool)); copy_dst = svn_fs_fs__dag_get_created_path(node); /* If our current path was the very destination of the copy, @@ -3753,12 +3746,14 @@ fs_history_prev(svn_fs_history_t **prev_ } else { + apr_pool_t *iterpool = svn_pool_create(scratch_pool); prev_history = history; while (1) { + svn_pool_clear(iterpool); SVN_ERR(history_prev(&prev_history, prev_history, cross_copies, - result_pool, scratch_pool)); + result_pool, iterpool)); if (! prev_history) break; @@ -3766,6 +3761,8 @@ fs_history_prev(svn_fs_history_t **prev_ if (fhd->is_interesting) break; } + + svn_pool_destroy(iterpool); } *prev_history_p = prev_history; @@ -3859,7 +3856,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs svn_pool_clear(iterpool); kid_path = svn_fspath__join(this_path, dirent->name, iterpool); - SVN_ERR(get_dag(&kid_dag, root, kid_path, TRUE, iterpool)); + SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool)); SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag)); SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag)); @@ -4105,7 +4102,7 @@ add_descendant_mergeinfo(svn_mergeinfo_c dag_node_t *this_dag; svn_boolean_t go_down; - SVN_ERR(get_dag(&this_dag, root, path, TRUE, scratch_pool)); + SVN_ERR(get_dag(&this_dag, root, path, scratch_pool)); SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, this_dag)); if (go_down) Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_util/fs-util.c URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_util/fs-util.c?rev=1658362&r1=1658361&r2=1658362&view=diff ============================================================================== --- subversion/branches/remove-log-addressing/subversion/libsvn_fs_util/fs-util.c (original) +++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_util/fs-util.c Mon Feb 9 11:23:39 2015 @@ -38,6 +38,14 @@ #include "private/svn_subr_private.h" #include "../libsvn_fs/fs-loader.h" + +const svn_version_t * +svn_fs_util__version(void) +{ + SVN_VERSION_BODY; +} + + /* Return TRUE, if PATH of PATH_LEN > 0 chars starts with a '/' and does * not end with a '/' and does not contain duplicate '/'. */ Propchange: subversion/branches/remove-log-addressing/subversion/libsvn_fs_x/ ------------------------------------------------------------------------------ --- svn:mergeinfo (original) +++ svn:mergeinfo Mon Feb 9 11:23:39 2015 @@ -10,6 +10,7 @@ /subversion/branches/diff-optimizations-bytes/subversion/libsvn_fs_x:1037353-1067789 /subversion/branches/dont-save-plaintext-passwords-by-default/subversion/libsvn_fs_x:870728-871118 /subversion/branches/double-delete/subversion/libsvn_fs_x:870511-872970 +/subversion/branches/dump-load-cross-check/subversion/libsvn_fs_x:1654853-1657295 /subversion/branches/ev2-export/subversion/libsvn_fs_x:1325914,1332738,1413107 /subversion/branches/explore-wc/subversion/libsvn_fs_x:875486,875493,875497,875507,875511,875514,875559,875580-875581,875584,875587,875611,875627,875647,875667-875668,875711-875712,875733-875734,875736,875744-875748,875751,875758,875782,875795-875796,875830,875836,875838,875842,875852,875855,875864,875870,875873,875880,875885-875888,875890,875897-875898,875905,875907-875909,875935,875943-875944,875946,875979,875982-875983,875985-875986,875990,875997 /subversion/branches/file-externals/subversion/libsvn_fs_x:871779-873302 @@ -20,6 +21,7 @@ /subversion/branches/fsfs-lock-many/subversion/libsvn_fs_x:1571740-1577217 /subversion/branches/fsfs-pack/subversion/libsvn_fs_x:873717-874575 /subversion/branches/fsx/subversion/libsvn_fs_x:1507845-1508040 +/subversion/branches/fsx-id/subversion/libsvn_fs_x:1645603-1649011 /subversion/branches/gnome-keyring/subversion/libsvn_fs_x:870558-871410 /subversion/branches/gpg-agent-password-store/subversion/libsvn_fs_x:1005036-1150766 /subversion/branches/gtest_addition/subversion/libsvn_fs_x:1452117-1502138 @@ -67,6 +69,7 @@ /subversion/branches/revprop-caching-ng/subversion/libsvn_fs_x:1620597 /subversion/branches/revprop-packing/subversion/libsvn_fs_x:1143907,1143971,1143997,1144017,1144499,1144568,1146145 /subversion/branches/subtree-mergeinfo/subversion/libsvn_fs_x:876734-878766 +/subversion/branches/svn-auth-x509/subversion/libsvn_fs_x:1603509-1655900 /subversion/branches/svn-mergeinfo-enhancements/subversion/libsvn_fs_x:870119-870195,870197-870288 /subversion/branches/svn-patch-improvements/subversion/libsvn_fs_x:918519-934609 /subversion/branches/svn_mutex/subversion/libsvn_fs_x:1141683-1182099 @@ -85,5 +88,5 @@ /subversion/branches/verify-at-commit/subversion/libsvn_fs_x:1462039-1462408 /subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110 /subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384 -/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162 4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629 -/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1603891-1641359 +/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162 4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1653608 +/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1603891-1658357
