You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2014/10/29 12:39:15 UTC
svn commit: r1635101 - in /subversion/trunk/subversion/libsvn_fs_x: ./
cached_data.c low_level.c low_level.h transaction.c
Author: stefan2
Date: Wed Oct 29 11:39:14 2014
New Revision: 1635101
URL: http://svn.apache.org/r1635101
Log:
Sync FSX with FSFS:
Merge and adapt revisions r1604188, r1604413, r1604442, r1604700, r1604726
r1604755 and r1604844 from libsvn_fs_fs. Various conflicts were caused by
reordered code and renamed functions in FSX.
This ports memory / pool usage improvements in the parser and lower data
access layers.
Modified:
subversion/trunk/subversion/libsvn_fs_x/ (props changed)
subversion/trunk/subversion/libsvn_fs_x/cached_data.c
subversion/trunk/subversion/libsvn_fs_x/low_level.c
subversion/trunk/subversion/libsvn_fs_x/low_level.h
subversion/trunk/subversion/libsvn_fs_x/transaction.c
Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
Merged /subversion/trunk/subversion/libsvn_fs_fs:r1604188,1604413,1604442,1604700,1604726,1604755,1604844
Modified: subversion/trunk/subversion/libsvn_fs_x/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/cached_data.c?rev=1635101&r1=1635100&r2=1635101&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/cached_data.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/cached_data.c Wed Oct 29 11:39:14 2014
@@ -1306,6 +1306,8 @@ read_delta_window(svn_txdelta_window_t *
svn_boolean_t is_cached;
apr_off_t start_offset;
apr_off_t end_offset;
+ apr_pool_t *iterpool;
+
SVN_ERR_ASSERT(rs->chunk_index <= this_chunk);
SVN_ERR(dgb__log_access(rs->file->fs, &rs->rep_id, NULL,
@@ -1348,12 +1350,15 @@ read_delta_window(svn_txdelta_window_t *
pool));
/* Skip windows to reach the current chunk if we aren't there yet. */
+ iterpool = svn_pool_create(pool);
while (rs->chunk_index < this_chunk)
{
+ svn_pool_clear(iterpool);
SVN_ERR(svn_txdelta_skip_svndiff_window(rs->file->file, rs->ver,
- pool));
+ iterpool));
rs->chunk_index++;
- SVN_ERR(svn_fs_x__get_file_offset(&start_offset, rs->file->file, pool));
+ SVN_ERR(svn_fs_x__get_file_offset(&start_offset, rs->file->file,
+ iterpool));
rs->current = start_offset - rs->start;
if (rs->current >= rs->size)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
@@ -1361,6 +1366,7 @@ read_delta_window(svn_txdelta_window_t *
"beyond the end of the "
"representation"));
}
+ svn_pool_destroy(iterpool);
/* Actually read the next window. */
SVN_ERR(svn_txdelta_read_svndiff_window(nwin, rs->file->stream, rs->ver,
@@ -2715,11 +2721,12 @@ svn_error_t *
svn_fs_x__get_changes(apr_array_header_t **changes,
svn_fs_t *fs,
svn_revnum_t rev,
- apr_pool_t *pool)
+ apr_pool_t *result_pool)
{
apr_file_t *revision_file;
svn_boolean_t found;
fs_x_data_t *ffd = fs->fsap_data;
+ apr_pool_t *scratch_pool = svn_pool_create(result_pool);
svn_fs_x__id_part_t id;
id.change_set = svn_fs_x__change_set_by_rev(rev);
@@ -2733,19 +2740,20 @@ svn_fs_x__get_changes(apr_array_header_t
apr_uint32_t sub_item;
pair_cache_key_t key;
- SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &id, pool));
+ SVN_ERR(svn_fs_x__item_offset(&offset, &sub_item, fs, &id,
+ scratch_pool));
key.revision = svn_fs_x__packed_base_rev(fs, rev);
key.second = offset;
SVN_ERR(svn_cache__get_partial((void **)changes, &found,
ffd->changes_container_cache, &key,
svn_fs_x__changes_get_list_func,
- &sub_item, pool));
+ &sub_item, result_pool));
}
else if (ffd->changes_cache)
{
SVN_ERR(svn_cache__get((void **) changes, &found, ffd->changes_cache,
- &rev, pool));
+ &rev, result_pool));
}
else
{
@@ -2756,20 +2764,21 @@ svn_fs_x__get_changes(apr_array_header_t
{
/* read changes from revision file */
- SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, pool));
+ SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
SVN_ERR(svn_fs_x__open_pack_or_rev_file(&revision_file, fs, rev,
- pool));
+ scratch_pool));
/* 'block-read' will also provide us with the desired data */
SVN_ERR(block_read((void **)changes, fs, &id, revision_file,
- pool, pool));
+ result_pool, scratch_pool));
- SVN_ERR(svn_io_file_close(revision_file, pool));
+ SVN_ERR(svn_io_file_close(revision_file, scratch_pool));
}
SVN_ERR(dgb__log_access(fs, &id, *changes, SVN_FS_X__ITEM_TYPE_CHANGES,
- pool));
+ scratch_pool));
+ svn_pool_destroy(scratch_pool);
return SVN_NO_ERROR;
}
@@ -2777,7 +2786,7 @@ svn_fs_x__get_changes(apr_array_header_t
* addressed by ENTRY->ITEM in FS and cache it if caches are enabled.
* Read the data from the already open FILE and the wrapping
* STREAM object. If MAX_OFFSET is not -1, don't read windows that start
- * at or beyond that offset. Use POOL for allocations.
+ * at or beyond that offset. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
block_read_contents(svn_fs_t *fs,
@@ -2786,7 +2795,7 @@ block_read_contents(svn_fs_t *fs,
svn_fs_x__p2l_entry_t* entry,
pair_cache_key_t *key,
apr_off_t max_offset,
- apr_pool_t *pool)
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
representation_cache_key_t header_key = { 0 };
@@ -2801,9 +2810,11 @@ block_read_contents(svn_fs_t *fs,
header_key.is_packed = svn_fs_x__is_packed_rev(fs, header_key.revision);
header_key.item_index = key->second;
- SVN_ERR(read_rep_header(&rep_header, fs, stream, &header_key, pool));
- SVN_ERR(init_rep_state(&rs, rep_header, fs, file, stream, entry, pool));
- SVN_ERR(cache_windows(&fulltext_len, fs, &rs, max_offset, pool));
+ SVN_ERR(read_rep_header(&rep_header, fs, stream, &header_key,
+ scratch_pool));
+ SVN_ERR(init_rep_state(&rs, rep_header, fs, file, stream, entry,
+ scratch_pool));
+ SVN_ERR(cache_windows(&fulltext_len, fs, &rs, max_offset, scratch_pool));
return SVN_NO_ERROR;
}
@@ -2835,6 +2846,12 @@ auto_select_stream(svn_stream_t **stream
return SVN_NO_ERROR;
}
+/* Read all txdelta / plain windows following REP_HEADER in FS as described
+ * by ENTRY. Read the data from the already open FILE and the wrapping
+ * STREAM object. If MAX_OFFSET is not -1, don't read windows that start
+ * at or beyond that offset. Use SCRATCH_POOL for temporary allocations.
+ * If caching is not enabled, this is a no-op.
+ */
static svn_error_t *
block_read_changes(apr_array_header_t **changes,
svn_fs_t *fs,
@@ -2842,7 +2859,8 @@ block_read_changes(apr_array_header_t **
svn_stream_t *file_stream,
svn_fs_x__p2l_entry_t* entry,
svn_boolean_t must_read,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_stream_t *stream;
@@ -2858,21 +2876,23 @@ block_read_changes(apr_array_header_t **
{
svn_boolean_t is_cached = FALSE;
SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache, &revision,
- pool));
+ scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
}
- SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry, pool));
+ SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
+ scratch_pool));
/* read changes from revision file */
- SVN_ERR(svn_fs_x__read_changes(changes, stream, pool));
+ SVN_ERR(svn_fs_x__read_changes(changes, stream, result_pool));
/* cache for future reference */
if (ffd->changes_cache)
- SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes, pool));
+ SVN_ERR(svn_cache__set(ffd->changes_cache, &revision, *changes,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -2885,7 +2905,8 @@ block_read_changes_container(apr_array_h
svn_fs_x__p2l_entry_t* entry,
apr_uint32_t sub_item,
svn_boolean_t must_read,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_fs_x__changes_t *container;
@@ -2901,25 +2922,28 @@ block_read_changes_container(apr_array_h
{
svn_boolean_t is_cached = FALSE;
SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_container_cache,
- &key, pool));
+ &key, scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
}
- SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry, pool));
+ SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
+ scratch_pool));
/* read changes from revision file */
- SVN_ERR(svn_fs_x__read_changes_container(&container, stream, pool, pool));
+ SVN_ERR(svn_fs_x__read_changes_container(&container, stream, scratch_pool,
+ scratch_pool));
/* extract requested data */
if (must_read)
- SVN_ERR(svn_fs_x__changes_get_list(changes, container, sub_item, pool));
+ SVN_ERR(svn_fs_x__changes_get_list(changes, container, sub_item,
+ result_pool));
if (ffd->changes_container_cache)
SVN_ERR(svn_cache__set(ffd->changes_container_cache, &key, container,
- pool));
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -2932,7 +2956,8 @@ block_read_noderev(node_revision_t **nod
svn_fs_x__p2l_entry_t* entry,
pair_cache_key_t *key,
svn_boolean_t must_read,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_stream_t *stream;
@@ -2947,22 +2972,24 @@ block_read_noderev(node_revision_t **nod
{
svn_boolean_t is_cached = FALSE;
SVN_ERR(svn_cache__has_key(&is_cached, ffd->node_revision_cache, key,
- pool));
+ scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
}
- SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry, pool));
+ SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
+ scratch_pool));
/* read node rev from revision file */
- SVN_ERR(svn_fs_x__read_noderev(noderev_p, stream, pool));
+ SVN_ERR(svn_fs_x__read_noderev(noderev_p, stream, result_pool));
/* Workaround issue #4031: is-fresh-txn-root in revision files. */
(*noderev_p)->is_fresh_txn_root = FALSE;
if (ffd->node_revision_cache)
- SVN_ERR(svn_cache__set(ffd->node_revision_cache, key, *noderev_p, pool));
+ SVN_ERR(svn_cache__set(ffd->node_revision_cache, key, *noderev_p,
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -2975,7 +3002,8 @@ block_read_noderevs_container(node_revis
svn_fs_x__p2l_entry_t* entry,
apr_uint32_t sub_item,
svn_boolean_t must_read,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_fs_x__noderevs_t *container;
@@ -2991,25 +3019,28 @@ block_read_noderevs_container(node_revis
{
svn_boolean_t is_cached = FALSE;
SVN_ERR(svn_cache__has_key(&is_cached, ffd->noderevs_container_cache,
- &key, pool));
+ &key, scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
}
- SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry, pool));
+ SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
+ scratch_pool));
/* read noderevs from revision file */
- SVN_ERR(svn_fs_x__read_noderevs_container(&container, stream, pool, pool));
+ SVN_ERR(svn_fs_x__read_noderevs_container(&container, stream, scratch_pool,
+ scratch_pool));
/* extract requested data */
if (must_read)
- SVN_ERR(svn_fs_x__noderevs_get(noderev_p, container, sub_item, pool));
+ SVN_ERR(svn_fs_x__noderevs_get(noderev_p, container, sub_item,
+ result_pool));
if (ffd->noderevs_container_cache)
SVN_ERR(svn_cache__set(ffd->noderevs_container_cache, &key, container,
- pool));
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -3022,7 +3053,8 @@ block_read_reps_container(svn_fs_x__rep_
svn_fs_x__p2l_entry_t* entry,
apr_uint32_t sub_item,
svn_boolean_t must_read,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
fs_x_data_t *ffd = fs->fsap_data;
svn_fs_x__reps_t *container;
@@ -3038,25 +3070,28 @@ block_read_reps_container(svn_fs_x__rep_
{
svn_boolean_t is_cached = FALSE;
SVN_ERR(svn_cache__has_key(&is_cached, ffd->reps_container_cache,
- &key, pool));
+ &key, scratch_pool));
if (is_cached)
return SVN_NO_ERROR;
}
- SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry, pool));
+ SVN_ERR(auto_select_stream(&stream, fs, file, file_stream, entry,
+ scratch_pool));
/* read noderevs from revision file */
- SVN_ERR(svn_fs_x__read_reps_container(&container, stream, pool, pool));
+ SVN_ERR(svn_fs_x__read_reps_container(&container, stream, result_pool,
+ scratch_pool));
/* extract requested data */
if (must_read)
- SVN_ERR(svn_fs_x__reps_get(extractor, fs, container, sub_item, pool));
+ SVN_ERR(svn_fs_x__reps_get(extractor, fs, container, sub_item,
+ result_pool));
if (ffd->noderevs_container_cache)
SVN_ERR(svn_cache__set(ffd->reps_container_cache, &key, container,
- pool));
+ scratch_pool));
return SVN_NO_ERROR;
}
@@ -3144,7 +3179,7 @@ block_read(void **result,
is_wanted
? -1
: block_start + ffd->block_size,
- pool));
+ iterpool));
break;
case SVN_FS_X__ITEM_TYPE_NODEREV:
@@ -3152,13 +3187,14 @@ block_read(void **result,
SVN_ERR(block_read_noderev((node_revision_t **)&item,
fs, revision_file, stream,
entry, &key, is_result,
- pool));
+ pool, iterpool));
break;
case SVN_FS_X__ITEM_TYPE_CHANGES:
SVN_ERR(block_read_changes((apr_array_header_t **)&item,
fs, revision_file, stream,
- entry, is_result, pool));
+ entry, is_result,
+ pool, iterpool));
break;
case SVN_FS_X__ITEM_TYPE_CHANGES_CONT:
@@ -3166,7 +3202,7 @@ block_read(void **result,
((apr_array_header_t **)&item,
fs, revision_file, stream,
entry, wanted_sub_item,
- is_result, pool));
+ is_result, pool, iterpool));
break;
case SVN_FS_X__ITEM_TYPE_NODEREVS_CONT:
@@ -3174,7 +3210,7 @@ block_read(void **result,
((node_revision_t **)&item,
fs, revision_file, stream,
entry, wanted_sub_item,
- is_result, pool));
+ is_result, pool, iterpool));
break;
case SVN_FS_X__ITEM_TYPE_REPS_CONT:
@@ -3182,7 +3218,7 @@ block_read(void **result,
((svn_fs_x__rep_extractor_t **)&item,
fs, revision_file, stream,
entry, wanted_sub_item,
- is_result, pool));
+ is_result, pool, iterpool));
break;
default:
Modified: subversion/trunk/subversion/libsvn_fs_x/low_level.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/low_level.c?rev=1635101&r1=1635100&r2=1635101&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/low_level.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/low_level.c Wed Oct 29 11:39:14 2014
@@ -730,7 +730,8 @@ svn_fs_x__write_rep_header(svn_fs_x__rep
static svn_error_t *
read_change(change_t **change_p,
svn_stream_t *stream,
- apr_pool_t *pool)
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
{
svn_stringbuf_t *line;
svn_boolean_t eof = TRUE;
@@ -741,13 +742,13 @@ read_change(change_t **change_p,
/* Default return value. */
*change_p = NULL;
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool));
+ SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool));
/* Check for a blank line. */
if (eof || (line->len == 0))
return SVN_NO_ERROR;
- change = apr_pcalloc(pool, sizeof(*change));
+ change = apr_pcalloc(result_pool, sizeof(*change));
info = &change->info;
last_str = line->data;
@@ -757,7 +758,7 @@ read_change(change_t **change_p,
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid changes line in rev-file"));
- info->node_rev_id = svn_fs_x__id_parse(str, strlen(str), pool);
+ info->node_rev_id = svn_fs_x__id_parse(str, strlen(str), result_pool);
if (info->node_rev_id == NULL)
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid changes line in rev-file"));
@@ -873,13 +874,14 @@ read_change(change_t **change_p,
}
/* Get the changed path. */
- change->path.data = auto_unescape_path(apr_pstrmemdup(pool, last_str,
+ change->path.data = auto_unescape_path(apr_pstrmemdup(result_pool,
+ last_str,
strlen(last_str)),
- pool);
+ result_pool);
change->path.len = strlen(change->path.data);
/* Read the next line, the copyfrom line. */
- SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool));
+ SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool));
info->copyfrom_known = TRUE;
if (eof || line->len == 0)
{
@@ -899,7 +901,7 @@ read_change(change_t **change_p,
return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
_("Invalid changes line in rev-file"));
- info->copyfrom_path = auto_unescape_path(last_str, pool);
+ info->copyfrom_path = auto_unescape_path(last_str, result_pool);
}
*change_p = change;
@@ -913,24 +915,51 @@ svn_fs_x__read_changes(apr_array_header_
apr_pool_t *pool)
{
change_t *change;
+ apr_pool_t *iterpool = svn_pool_create(pool);
/* pre-allocate enough room for most change lists
(will be auto-expanded as necessary) */
*changes = apr_array_make(pool, 30, sizeof(change_t *));
-
- SVN_ERR(read_change(&change, stream, pool));
+
+ SVN_ERR(read_change(&change, stream, pool, iterpool));
while (change)
{
APR_ARRAY_PUSH(*changes, change_t*) = change;
- SVN_ERR(read_change(&change, stream, pool));
+ SVN_ERR(read_change(&change, stream, pool, iterpool));
+ svn_pool_clear(iterpool);
}
+ svn_pool_destroy(iterpool);
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_x__read_changes_incrementally(svn_stream_t *stream,
+ svn_fs_x__change_receiver_t
+ change_receiver,
+ void *change_receiver_baton,
+ apr_pool_t *pool)
+{
+ change_t *change;
+ apr_pool_t *iterpool;
+ iterpool = svn_pool_create(pool);
+ do
+ {
+ svn_pool_clear(iterpool);
+
+ SVN_ERR(read_change(&change, stream, iterpool, iterpool));
+ if (change)
+ SVN_ERR(change_receiver(change_receiver_baton, change, iterpool));
+ }
+ while (change);
+ svn_pool_destroy(iterpool);
+
return SVN_NO_ERROR;
}
/* Write a single change entry, path PATH, change CHANGE, and copyfrom
- string COPYFROM, into the file specified by FILE. Only include the
- node kind field if INCLUDE_NODE_KIND is true. All temporary
+ string COPYFROM, into the file specified by FILE. All temporary
allocations are in POOL. */
static svn_error_t *
write_change_entry(svn_stream_t *stream,
Modified: subversion/trunk/subversion/libsvn_fs_x/low_level.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/low_level.h?rev=1635101&r1=1635100&r2=1635101&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/low_level.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/low_level.h Wed Oct 29 11:39:14 2014
@@ -153,6 +153,20 @@ svn_fs_x__read_changes(apr_array_header_
svn_stream_t *stream,
apr_pool_t *pool);
+typedef svn_error_t *(*svn_fs_x__change_receiver_t)(
+ void *baton,
+ change_t *change,
+ apr_pool_t *scratch_pool);
+
+/* Read all the changes from STREAM and invoke CHANGE_RECEIVER on each change.
+ Do all allocations in POOL. */
+svn_error_t *
+svn_fs_x__read_changes_incrementally(svn_stream_t *stream,
+ svn_fs_x__change_receiver_t
+ change_receiver,
+ void *change_receiver_baton,
+ apr_pool_t *scratch_pool);
+
/* Write the changed path info from CHANGES in filesystem FS to the
output stream STREAM. You may call this function multiple time on
the same stream but the last call should set TERMINATE_LIST to write
Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.c?rev=1635101&r1=1635100&r2=1635101&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.c Wed Oct 29 11:39:14 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"
@@ -1008,86 +1009,84 @@ fold_change(apr_hash_t *changed_paths,
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;
-/* Examine all the changed path entries in CHANGES and store them in
+ /* 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;
+
+/* 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. Use SCRATCH_POOL for temporary allocations. */
static svn_error_t *
-process_changes(apr_hash_t *changed_paths,
- apr_array_header_t *changes,
+process_changes(void *baton_p,
+ change_t *change,
apr_pool_t *scratch_pool)
{
- apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- apr_hash_t *deletions = svn_hash__make(scratch_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 *);
-
- SVN_ERR(fold_change(changed_paths, deletions, change));
-
- /* 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.
+ /* 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.
+ */
+
+ if ((change->info.change_kind == svn_fs_path_change_delete)
+ || (change->info.change_kind == svn_fs_path_change_replace))
+ {
+ 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.
*/
-
- 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;
}
@@ -1099,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;
@@ -3064,36 +3066,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. */
@@ -3102,7 +3105,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
@@ -3229,16 +3232,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;