You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2016/10/11 09:11:54 UTC
svn commit: r1764214 [8/21] - in /subversion/branches/ra-git: ./ build/
build/ac-macros/ build/generator/ build/win32/ contrib/client-side/
contrib/client-side/svnmerge/ contrib/hook-scripts/ contrib/server-side/
contrib/server-side/fsfsfixer/fixer/ co...
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c Tue Oct 11 09:11:50 2016
@@ -381,16 +381,9 @@ typedef struct packed_revprops_t
/* sum of values in SIZES */
apr_size_t total_size;
- /* size of the revprops in PACKED_REVPROPS */
- apr_array_header_t *sizes;
-
- /* offset of the revprops in PACKED_REVPROPS */
- apr_array_header_t *offsets;
-
-
- /* concatenation of the serialized representation of all revprops
- * in the pack, i.e. the pack content without header and compression */
- svn_stringbuf_t *packed_revprops;
+ /* Array of svn_string_t, containing the serialized revprops for
+ * REVISION * I. */
+ apr_array_header_t *revprops;
/* content of the manifest.
* Sorted list of manifest_entry_t. */
@@ -409,7 +402,7 @@ static svn_error_t *
parse_revprop(apr_hash_t **properties,
svn_fs_t *fs,
svn_revnum_t revision,
- svn_string_t *content,
+ const svn_string_t *content,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
@@ -433,6 +426,35 @@ parse_revprop(apr_hash_t **properties,
return SVN_NO_ERROR;
}
+/* Verify the checksum attached to CONTENT and remove it.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+verify_checksum(svn_stringbuf_t *content,
+ apr_pool_t *scratch_pool)
+{
+ const apr_byte_t *digest;
+ svn_checksum_t *actual, *expected;
+
+ /* Verify the checksum. */
+ if (content->len < sizeof(apr_uint32_t))
+ return svn_error_create(SVN_ERR_CORRUPT_PACKED_DATA, NULL,
+ "File too short");
+
+ content->len -= sizeof(apr_uint32_t);
+ digest = (apr_byte_t *)content->data + content->len;
+
+ expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
+ SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
+ content->len, scratch_pool));
+
+ if (!svn_checksum_match(actual, expected))
+ SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool,
+ "checksum mismatch"));
+
+ return SVN_NO_ERROR;
+}
+
/* Read the non-packed revprops for revision REV in FS, put them into the
* revprop cache if activated and return them in *PROPERTIES.
*
@@ -467,10 +489,17 @@ read_non_packed_revprop(apr_hash_t **pro
if (content)
{
+ svn_string_t *as_string;
+
+ /* Consistency check. */
+ SVN_ERR_W(verify_checksum(content, scratch_pool),
+ apr_psprintf(scratch_pool,
+ "Revprop file for r%ld is corrupt",
+ rev));
+
/* The contents string becomes part of the *PROPERTIES structure, i.e.
* we must make sure it lives at least as long as the latter. */
- svn_string_t *as_string = svn_string_create_from_buf(content,
- result_pool);
+ as_string = svn_string_create_from_buf(content, result_pool);
SVN_ERR(parse_revprop(properties, fs, rev, as_string,
result_pool, iterpool));
}
@@ -480,6 +509,32 @@ read_non_packed_revprop(apr_hash_t **pro
return SVN_NO_ERROR;
}
+/* Serialize ROOT into FILE and append a checksum to it.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+write_packed_data_checksummed(svn_packed__data_root_t *root,
+ apr_file_t *file,
+ apr_pool_t *scratch_pool)
+{
+ svn_checksum_t *checksum;
+ svn_stream_t *stream;
+
+ stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+ stream = svn_checksum__wrap_write_stream(&checksum, stream,
+ svn_checksum_fnv1a_32x4,
+ scratch_pool);
+ SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+
+ /* Append the checksum */
+ SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+ svn_checksum_size(checksum), NULL,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Serialize the packed revprops MANIFEST into FILE.
* Use SCRATCH_POOL for temporary allocations.
*/
@@ -489,8 +544,6 @@ write_manifest(apr_file_t *file,
apr_pool_t *scratch_pool)
{
int i;
- svn_checksum_t *checksum;
- svn_stream_t *stream;
svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
/* one top-level stream per struct element */
@@ -508,17 +561,26 @@ write_manifest(apr_file_t *file,
}
/* Write to file and calculate the checksum. */
- stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
- stream = svn_checksum__wrap_write_stream(&checksum, stream,
- svn_checksum_fnv1a_32x4,
- scratch_pool);
- SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(write_packed_data_checksummed(root, file, scratch_pool));
- /* Append the checksum */
- SVN_ERR(svn_io_file_write_full(file, checksum->digest,
- svn_checksum_size(checksum), NULL,
- scratch_pool));
+ return SVN_NO_ERROR;
+}
+
+/* Read *ROOT from CONTENT and verify its checksum. Allocate *ROOT in
+ * RESULT_POOL and use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+read_packed_data_checksummed(svn_packed__data_root_t **root,
+ svn_stringbuf_t *content,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_stream_t *stream;
+
+ SVN_ERR(verify_checksum(content, scratch_pool));
+
+ stream = svn_stream_from_stringbuf(content, scratch_pool);
+ SVN_ERR(svn_packed__data_read(root, stream, result_pool, scratch_pool));
return SVN_NO_ERROR;
}
@@ -534,39 +596,19 @@ read_manifest(apr_array_header_t **manif
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_size_t data_len;
apr_size_t i;
apr_size_t count;
- svn_stream_t *stream;
svn_packed__data_root_t *root;
svn_packed__int_stream_t *start_rev_stream;
svn_packed__int_stream_t *tag_stream;
- const apr_byte_t *digest;
- svn_checksum_t *actual, *expected;
-
- /* Verify the checksum. */
- if (content->len < sizeof(apr_uint32_t))
- return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
- "Revprop manifest too short for revision r%ld",
- revision);
-
- data_len = content->len - sizeof(apr_uint32_t);
- digest = (apr_byte_t *)content->data + data_len;
- expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
- SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
- data_len, scratch_pool));
-
- if (!svn_checksum_match(actual, expected))
- SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool,
- _("checksum mismatch in revprop "
- "manifest for revision r%ld"),
- revision));
-
- /* read everything from the buffer */
- stream = svn_stream_from_stringbuf(content, scratch_pool);
- SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool));
+ /* Verify the checksum and decode packed data. */
+ SVN_ERR_W(read_packed_data_checksummed(&root, content, result_pool,
+ scratch_pool),
+ apr_psprintf(scratch_pool,
+ "Revprop manifest file for r%ld is corrupt",
+ revision));
/* get streams */
start_rev_stream = svn_packed__first_int_stream(root);
@@ -716,9 +758,9 @@ same_shard(svn_fs_t *fs,
return (r1 / ffd->max_files_per_dir) == (r2 / ffd->max_files_per_dir);
}
-/* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS
- * and make PACKED_REVPROPS point to the first serialized revprop. If
- * READ_ALL is set, initialize the SIZES and OFFSETS members as well.
+/* Given FS and the full packed file content in CONTENT and make
+ * PACKED_REVPROPS point to the first serialized revprop. If READ_ALL
+ * is set, initialize the SIZES and OFFSETS members as well.
*
* Parse the revprops for REVPROPS->REVISION and set the PROPERTIES as
* well as the SERIALIZED_SIZE member. If revprop caching has been
@@ -727,33 +769,31 @@ same_shard(svn_fs_t *fs,
static svn_error_t *
parse_packed_revprops(svn_fs_t *fs,
packed_revprops_t *revprops,
+ svn_stringbuf_t *content,
svn_boolean_t read_all,
apr_pool_t *result_pool,
apr_pool_t *scratch_pool)
{
- apr_uint64_t first_rev, count, i;
- apr_size_t offset;
+ apr_size_t count, i;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_boolean_t cache_all = has_revprop_cache(fs, scratch_pool);
- const apr_byte_t *p, *end;
+ svn_packed__data_root_t *root;
+ svn_packed__byte_stream_t *revprops_stream;
+ svn_revnum_t first_rev = revprops->entry.start_rev;
- /* decompress (even if the data is only "stored", there is still a
- * length header to remove) */
- svn_stringbuf_t *compressed = revprops->packed_revprops;
- svn_stringbuf_t *uncompressed = svn_stringbuf_create_empty(result_pool);
- SVN_ERR(svn__decompress(compressed->data, compressed->len,
- uncompressed, APR_SIZE_MAX));
-
- /* read first revision number and number of revisions in the pack */
- p = (apr_byte_t *)uncompressed->data;
- end = p + uncompressed->len;
- p = svn__decode_uint(&first_rev, p, end);
- p = svn__decode_uint(&count, p, end);
+ /* Verify the checksum and decode packed data. */
+ SVN_ERR_W(read_packed_data_checksummed(&root, content, result_pool,
+ scratch_pool),
+ apr_psprintf(scratch_pool,
+ "Revprop pack file for r%ld is corrupt",
+ first_rev));
+
+ /* get streams */
+ revprops_stream = svn_packed__first_byte_stream(root);
+ count = svn_packed__byte_block_count(revprops_stream);
/* Check revision range for validity. */
- if ( !same_shard(fs, revprops->revision, first_rev)
- || !same_shard(fs, revprops->revision, first_rev + count - 1)
- || count < 1)
+ if (!same_shard(fs, first_rev, first_rev + count - 1) || count < 1)
return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
_("Revprop pack for revision r%ld"
" contains revprops for r%ld .. r%ld"),
@@ -770,71 +810,35 @@ parse_packed_revprops(svn_fs_t *fs,
" starts at non-packed revisions r%ld"),
revprops->revision, (svn_revnum_t)first_rev);
- /* Read the item sizes from the header. */
- revprops->sizes = apr_array_make(result_pool, (int)count, sizeof(offset));
- revprops->offsets = apr_array_make(result_pool, (int)count, sizeof(offset));
-
- for (i = 0, offset = 0, revprops->total_size = 0; i < count; ++i)
+ /* Request all data (just references to data already expanded in ROOT) */
+ revprops->revprops = apr_array_make(result_pool, (int)count,
+ sizeof(svn_string_t));
+ for (i = 0, revprops->total_size = 0; i < count; ++i)
{
- apr_uint64_t size64;
- apr_size_t size;
-
- /* read & check the serialized size */
- p = svn__decode_uint(&size64, p, end);
- if (size64 > uncompressed->len - offset)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- "Packed revprop size exceeds pack file size");
-
- size = (apr_size_t)size64;
+ svn_string_t *props = apr_array_push(revprops->revprops);
+ props->data = svn_packed__get_bytes(revprops_stream, &props->len);
- /* fill REVPROPS data structures */
- APR_ARRAY_PUSH(revprops->sizes, apr_size_t) = size;
- APR_ARRAY_PUSH(revprops->offsets, apr_size_t) = offset;
- revprops->total_size += size;
-
- offset += size;
+ revprops->total_size += props->len;
}
- /* make PACKED_REVPROPS point to the first char after the header.
- * This is where the serialized revprops are. */
- offset = p - (apr_byte_t *)uncompressed->data;
-
- revprops->packed_revprops = svn_stringbuf_create_empty(result_pool);
- revprops->packed_revprops->data = uncompressed->data + offset;
- revprops->packed_revprops->len = uncompressed->len - offset;
- revprops->packed_revprops->blocksize = uncompressed->blocksize - offset;
-
- /* Verify that the last offset size does not extend beyond file sans
- * header (we only checked against the full file contents). */
- if (revprops->total_size > revprops->packed_revprops->len)
- return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
- "Packed revprop size exceeds pack file size");
-
- /* STREAM still points to the first entry in the sizes list. */
- SVN_ERR_ASSERT(revprops->entry.start_rev = (svn_revnum_t)first_rev);
-
- /* Now parse, revision by revision, the size and content of each
- * revisions' revprops. */
- for (i = 0, offset = 0; i < count; ++i)
+ /* Now parse the serialized revprops. */
+ for (i = 0; i < count; ++i)
{
- svn_string_t serialized;
-
- svn_revnum_t revision = (svn_revnum_t)(first_rev + i);
- apr_size_t size = APR_ARRAY_IDX(revprops->sizes, (int)i, apr_size_t);
- offset = APR_ARRAY_IDX(revprops->offsets, (int)i, apr_size_t);
+ const svn_string_t *serialized;
+ svn_revnum_t revision;
svn_pool_clear(iterpool);
- serialized.data = revprops->packed_revprops->data + offset;
- serialized.len = size;
+ serialized = &APR_ARRAY_IDX(revprops->revprops, (int)i, svn_string_t);
+ revision = first_rev + (long)i;
/* Parse this revprops list, if necessary */
if (revision == revprops->revision)
{
/* Parse (and possibly cache) the one revprop list we care about. */
SVN_ERR(parse_revprop(&revprops->properties, fs, revision,
- &serialized, result_pool, iterpool));
- revprops->serialized_size = serialized.len;
+ serialized, result_pool, iterpool));
+ revprops->serialized_size = serialized->len;
/* If we only wanted the revprops for REVISION then we are done. */
if (!read_all && !cache_all)
@@ -844,7 +848,7 @@ parse_packed_revprops(svn_fs_t *fs,
{
/* Parse and cache all other revprop lists. */
apr_hash_t *properties;
- SVN_ERR(parse_revprop(&properties, fs, revision, &serialized,
+ SVN_ERR(parse_revprop(&properties, fs, revision, serialized,
iterpool, iterpool));
}
}
@@ -871,7 +875,6 @@ read_pack_revprop(packed_revprops_t **re
{
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
svn_boolean_t missing = FALSE;
- svn_error_t *err;
packed_revprops_t *result;
int i;
@@ -889,11 +892,11 @@ read_pack_revprop(packed_revprops_t **re
/* try to read the packed revprops. This may require retries if we have
* concurrent writers. */
- for (i = 0;
- i < SVN_FS_X__RECOVERABLE_RETRY_COUNT && !result->packed_revprops;
- ++i)
+ for (i = 0; i < SVN_FS_X__RECOVERABLE_RETRY_COUNT; ++i)
{
const char *file_path;
+ svn_stringbuf_t *contents = NULL;
+
svn_pool_clear(iterpool);
/* there might have been concurrent writes.
@@ -902,11 +905,21 @@ read_pack_revprop(packed_revprops_t **re
SVN_ERR(get_revprop_packname(fs, result, result_pool, iterpool));
file_path = get_revprop_pack_filepath(result, &result->entry,
iterpool);
- SVN_ERR(svn_fs_x__try_stringbuf_from_file(&result->packed_revprops,
+ SVN_ERR(svn_fs_x__try_stringbuf_from_file(&contents,
&missing,
file_path,
i + 1 < SVN_FS_X__RECOVERABLE_RETRY_COUNT,
- result_pool));
+ iterpool));
+
+ if (contents)
+ {
+ SVN_ERR_W(parse_packed_revprops(fs, result, contents, read_all,
+ result_pool, iterpool),
+ apr_psprintf(iterpool,
+ "Revprop pack file for r%ld is corrupt",
+ rev));
+ break;
+ }
/* If we could not find the file, there was a write.
* So, we should refresh our revprop generation info as well such
@@ -918,17 +931,10 @@ read_pack_revprop(packed_revprops_t **re
}
/* the file content should be available now */
- if (!result->packed_revprops)
+ if (!result->revprops)
return svn_error_createf(SVN_ERR_FS_PACKED_REVPROP_READ_FAILURE, NULL,
_("Failed to read revprop pack file for r%ld"), rev);
- /* parse it. RESULT will be complete afterwards. */
- err = parse_packed_revprops(fs, result, read_all, result_pool, iterpool);
- svn_pool_destroy(iterpool);
- if (err)
- return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
- _("Revprop pack file for r%ld is corrupt"), rev);
-
*revprops = result;
return SVN_NO_ERROR;
@@ -1006,6 +1012,29 @@ svn_fs_x__get_revision_proplist(apr_hash
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_fs_x__write_non_packed_revprops(apr_file_t *file,
+ apr_hash_t *proplist,
+ apr_pool_t *scratch_pool)
+{
+ svn_stream_t *stream;
+ svn_checksum_t *checksum;
+
+ stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+ stream = svn_checksum__wrap_write_stream(&checksum, stream,
+ svn_checksum_fnv1a_32x4,
+ scratch_pool);
+ SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
+ SVN_ERR(svn_stream_close(stream));
+
+ /* Append the checksum */
+ SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+ svn_checksum_size(checksum), NULL,
+ scratch_pool));
+
+ return SVN_NO_ERROR;
+}
+
/* Serialize the revision property list PROPLIST of revision REV in
* filesystem FS to a non-packed file. Return the name of that temporary
* file in *TMP_PATH and the file path that it must be moved to in
@@ -1025,16 +1054,13 @@ write_non_packed_revprop(const char **fi
apr_pool_t *scratch_pool)
{
apr_file_t *file;
- svn_stream_t *stream;
*final_path = svn_fs_x__path_revprops(fs, rev, result_pool);
*tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
scratch_pool));
- stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
- SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_fs_x__write_non_packed_revprops(file, proplist, scratch_pool));
return SVN_NO_ERROR;
}
@@ -1096,51 +1122,8 @@ switch_to_new_revprop(svn_fs_t *fs,
return SVN_NO_ERROR;
}
-/* Write VALUE to STREAM using 7/8b encoding. */
-static svn_error_t *
-write_encoded_uint(svn_stream_t *stream,
- apr_uint64_t value)
-{
- apr_byte_t buffer[SVN__MAX_ENCODED_UINT_LEN];
- apr_size_t len;
-
- len = svn__encode_uint(buffer, value) - buffer;
- SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len));
-
- return SVN_NO_ERROR;
-}
-
-/* Write a pack file header to STREAM that starts at revision START_REVISION
- * and contains the indexes [START,END) of SIZES.
- */
-static svn_error_t *
-serialize_revprops_header(svn_stream_t *stream,
- svn_revnum_t start_revision,
- apr_array_header_t *sizes,
- int start,
- int end,
- apr_pool_t *scratch_pool)
-{
- int i;
- SVN_ERR_ASSERT(start < end);
-
- /* start revision and entry count */
- SVN_ERR(write_encoded_uint(stream, start_revision));
- SVN_ERR(write_encoded_uint(stream, end - start));
-
- /* the sizes array */
- for (i = start; i < end; ++i)
- SVN_ERR(write_encoded_uint(stream, APR_ARRAY_IDX(sizes, i, apr_size_t)));
-
- return SVN_NO_ERROR;
-}
-
/* Writes the a pack file to FILE. It copies the serialized data
- * from REVPROPS for the indexes [START,END) except for index CHANGED_INDEX.
- *
- * The data for the latter is taken from NEW_SERIALIZED. Note, that
- * CHANGED_INDEX may be outside the [START,END) range, i.e. no new data is
- * taken in that case but only a subset of the old data will be copied.
+ * from REVPROPS for the indexes [START,END).
*
* NEW_TOTAL_SIZE is a hint for pre-allocating buffers of appropriate size.
* SCRATCH_POOL is used for temporary allocations.
@@ -1150,60 +1133,27 @@ repack_revprops(svn_fs_t *fs,
packed_revprops_t *revprops,
int start,
int end,
- int changed_index,
- svn_stringbuf_t *new_serialized,
apr_size_t new_total_size,
apr_file_t *file,
apr_pool_t *scratch_pool)
{
- svn_fs_x__data_t *ffd = fs->fsap_data;
- svn_stream_t *stream;
int i;
- /* create data empty buffers and the stream object */
- svn_stringbuf_t *uncompressed
- = svn_stringbuf_create_ensure((apr_size_t)new_total_size, scratch_pool);
- svn_stringbuf_t *compressed
- = svn_stringbuf_create_empty(scratch_pool);
- stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
-
- /* write the header*/
- SVN_ERR(serialize_revprops_header(stream,
- revprops->entry.start_rev + start,
- revprops->sizes, start, end,
- scratch_pool));
+ svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
+ svn_packed__byte_stream_t *revprops_stream
+ = svn_packed__create_bytes_stream(root);
/* append the serialized revprops */
for (i = start; i < end; ++i)
- if (i == changed_index)
- {
- SVN_ERR(svn_stream_write(stream,
- new_serialized->data,
- &new_serialized->len));
- }
- else
- {
- apr_size_t size = APR_ARRAY_IDX(revprops->sizes, i, apr_size_t);
- apr_size_t offset = APR_ARRAY_IDX(revprops->offsets, i, apr_size_t);
-
- SVN_ERR(svn_stream_write(stream,
- revprops->packed_revprops->data + offset,
- &size));
- }
+ {
+ const svn_string_t *props
+ = &APR_ARRAY_IDX(revprops->revprops, i, svn_string_t);
- /* flush the stream buffer (if any) to our underlying data buffer */
- SVN_ERR(svn_stream_close(stream));
+ svn_packed__add_bytes(revprops_stream, props->data, props->len);
+ }
- /* compress / store the data */
- SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
- compressed,
- ffd->compress_packed_revprops
- ? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT
- : SVN_DELTA_COMPRESSION_LEVEL_NONE));
-
- /* finally, write the content to the target file, flush and close it */
- SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
- NULL, scratch_pool));
+ /* Write to file. */
+ SVN_ERR(write_packed_data_checksummed(root, file, scratch_pool));
return SVN_NO_ERROR;
}
@@ -1263,6 +1213,14 @@ repack_file_open(apr_file_t **file,
return SVN_NO_ERROR;
}
+/* Return the length of the serialized reprop list of index I in REVPROPS. */
+static apr_size_t
+props_len(packed_revprops_t *revprops,
+ int i)
+{
+ return APR_ARRAY_IDX(revprops->revprops, i, svn_string_t).len;
+}
+
/* For revision REV in filesystem FS, set the revision properties to
* PROPLIST. Return a new file in *TMP_PATH that the caller shall move
* to *FINAL_PATH to make the change visible. Files to be deleted will
@@ -1289,6 +1247,7 @@ write_packed_revprop(const char **final_
svn_stringbuf_t *serialized;
apr_size_t new_total_size;
int changed_index;
+ int count;
/* read the current revprop generation. This value will not change
* while we hold the global write lock to this FS. */
@@ -1305,17 +1264,18 @@ write_packed_revprop(const char **final_
SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
SVN_ERR(svn_stream_close(stream));
- /* calculate the size of the new data */
+ /* estimate the size of the new data */
+ count = revprops->revprops->nelts;
changed_index = (int)(rev - revprops->entry.start_rev);
new_total_size = revprops->total_size - revprops->serialized_size
+ serialized->len
- + (revprops->offsets->nelts + 2) * SVN_INT64_BUFFER_SIZE;
+ + (count + 2) * SVN_INT64_BUFFER_SIZE;
- APR_ARRAY_IDX(revprops->sizes, changed_index, apr_size_t) = serialized->len;
+ APR_ARRAY_IDX(revprops->revprops, changed_index, svn_string_t)
+ = *svn_stringbuf__morph_into_string(serialized);
/* can we put the new data into the same pack as the before? */
- if ( new_total_size < ffd->revprop_pack_size
- || revprops->sizes->nelts == 1)
+ if (new_total_size < ffd->revprop_pack_size || count == 1)
{
/* simply replace the old pack file with new content as we do it
* in the non-packed case */
@@ -1325,9 +1285,8 @@ write_packed_revprop(const char **final_
*tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
scratch_pool));
- SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
- changed_index, serialized, new_total_size,
- file, scratch_pool));
+ SVN_ERR(repack_revprops(fs, revprops, 0, count,
+ new_total_size, file, scratch_pool));
}
else
{
@@ -1335,31 +1294,29 @@ write_packed_revprop(const char **final_
int right_count, left_count;
int left = 0;
- int right = revprops->sizes->nelts - 1;
+ int right = count - 1;
apr_size_t left_size = 2 * SVN_INT64_BUFFER_SIZE;
apr_size_t right_size = 2 * SVN_INT64_BUFFER_SIZE;
/* let left and right side grow such that their size difference
* is minimal after each step. */
while (left <= right)
- if ( left_size + APR_ARRAY_IDX(revprops->sizes, left, apr_size_t)
- < right_size + APR_ARRAY_IDX(revprops->sizes, right, apr_size_t))
+ if ( left_size + props_len(revprops, left)
+ < right_size + props_len(revprops, right))
{
- left_size += APR_ARRAY_IDX(revprops->sizes, left, apr_size_t)
- + SVN_INT64_BUFFER_SIZE;
+ left_size += props_len(revprops, left) + SVN_INT64_BUFFER_SIZE;
++left;
}
else
{
- right_size += APR_ARRAY_IDX(revprops->sizes, right, apr_size_t)
- + SVN_INT64_BUFFER_SIZE;
+ right_size += props_len(revprops, right) + SVN_INT64_BUFFER_SIZE;
--right;
}
/* since the items need much less than SVN_INT64_BUFFER_SIZE
* bytes to represent their length, the split may not be optimal */
left_count = left;
- right_count = revprops->sizes->nelts - left;
+ right_count = count - left;
/* if new_size is large, one side may exceed the pack size limit.
* In that case, split before and after the modified revprop.*/
@@ -1367,7 +1324,7 @@ write_packed_revprop(const char **final_
|| right_size > ffd->revprop_pack_size)
{
left_count = changed_index;
- right_count = revprops->sizes->nelts - left_count - 1;
+ right_count = count - left_count - 1;
}
/* Allocate this here such that we can call the repack functions with
@@ -1384,19 +1341,17 @@ write_packed_revprop(const char **final_
files_to_delete, batch,
scratch_pool, scratch_pool));
SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
- changed_index, serialized, new_total_size,
- file, scratch_pool));
+ new_total_size, file, scratch_pool));
}
- if (left_count + right_count < revprops->sizes->nelts)
+ if (left_count + right_count < count)
{
SVN_ERR(repack_file_open(&file, fs, revprops, rev,
files_to_delete, batch,
scratch_pool, scratch_pool));
SVN_ERR(repack_revprops(fs, revprops, changed_index,
changed_index + 1,
- changed_index, serialized, new_total_size,
- file, scratch_pool));
+ new_total_size, file, scratch_pool));
}
if (right_count)
@@ -1404,11 +1359,8 @@ write_packed_revprop(const char **final_
SVN_ERR(repack_file_open(&file, fs, revprops, rev + 1,
files_to_delete, batch,
scratch_pool, scratch_pool));
- SVN_ERR(repack_revprops(fs, revprops,
- revprops->sizes->nelts - right_count,
- revprops->sizes->nelts, changed_index,
- serialized, new_total_size, file,
- scratch_pool));
+ SVN_ERR(repack_revprops(fs, revprops, count - right_count, count,
+ new_total_size, file, scratch_pool));
}
/* write the new manifest */
@@ -1438,11 +1390,13 @@ svn_fs_x__set_revision_proplist(svn_fs_t
const char *perms_reference;
apr_array_header_t *files_to_delete = NULL;
svn_fs_x__batch_fsync_t *batch;
+ svn_fs_x__data_t *ffd = fs->fsap_data;
SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
/* Perform all fsyncs through this instance. */
- SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
+ SVN_ERR(svn_fs_x__batch_fsync_create(&batch, ffd->flush_to_disk,
+ scratch_pool));
/* this info will not change while we hold the global FS write lock */
is_packed = svn_fs_x__is_packed_revprop(fs, rev);
@@ -1564,34 +1518,19 @@ copy_revprops(svn_fs_t *fs,
void *cancel_baton,
apr_pool_t *scratch_pool)
{
- svn_stream_t *pack_stream;
apr_file_t *pack_file;
svn_revnum_t rev;
apr_pool_t *iterpool = svn_pool_create(scratch_pool);
- /* create empty data buffer and a write stream on top of it */
- svn_stringbuf_t *uncompressed
- = svn_stringbuf_create_ensure(total_size, scratch_pool);
- svn_stringbuf_t *compressed
- = svn_stringbuf_create_empty(scratch_pool);
- pack_stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
-
- /* write the pack file header */
- SVN_ERR(serialize_revprops_header(pack_stream, start_rev, sizes, 0,
- sizes->nelts, iterpool));
-
- /* Create the auto-fsync'ing pack file. */
- SVN_ERR(svn_fs_x__batch_fsync_open_file(&pack_file, batch,
- svn_dirent_join(pack_file_dir,
- pack_filename,
- scratch_pool),
- scratch_pool));
+ svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
+ svn_packed__byte_stream_t *stream
+ = svn_packed__create_bytes_stream(root);
/* Iterate over the revisions in this shard, squashing them together. */
for (rev = start_rev; rev <= end_rev; rev++)
{
const char *path;
- svn_stream_t *stream;
+ svn_stringbuf_t *props;
svn_pool_clear(iterpool);
@@ -1600,21 +1539,24 @@ copy_revprops(svn_fs_t *fs,
/* Copy all the bits from the non-packed revprop file to the end of
* the pack file. */
- SVN_ERR(svn_stream_open_readonly(&stream, path, iterpool, iterpool));
- SVN_ERR(svn_stream_copy3(stream, pack_stream,
- cancel_func, cancel_baton, iterpool));
+ SVN_ERR(svn_stringbuf_from_file2(&props, path, iterpool));
+ SVN_ERR_W(verify_checksum(props, iterpool),
+ apr_psprintf(iterpool, "Failed to read revprops for r%ld.",
+ rev));
+
+ svn_packed__add_bytes(stream, props->data, props->len);
}
- /* flush stream buffers to content buffer */
- SVN_ERR(svn_stream_close(pack_stream));
+ /* Create the auto-fsync'ing pack file. */
+ SVN_ERR(svn_fs_x__batch_fsync_open_file(&pack_file, batch,
+ svn_dirent_join(pack_file_dir,
+ pack_filename,
+ scratch_pool),
+ scratch_pool));
- /* compress the content (or just store it for COMPRESSION_LEVEL 0) */
- SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
- compressed, compression_level));
+ /* write all to disk */
+ SVN_ERR(write_packed_data_checksummed(root, pack_file, scratch_pool));
- /* write the pack file content to disk */
- SVN_ERR(svn_io_file_write_full(pack_file, compressed->data, compressed->len,
- NULL, scratch_pool));
svn_pool_destroy(iterpool);
return SVN_NO_ERROR;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h Tue Oct 11 09:11:50 2016
@@ -46,6 +46,17 @@ svn_fs_x__reset_revprop_generation_file(
void
svn_fs_x__invalidate_revprop_generation(svn_fs_t *fs);
+/* Utility function serializing PROPLIST into FILE and adding the checksum.
+ * Use SCRATCH_POOL for temporary allocations.
+ *
+ * Call this only when creating initial revprop file contents.
+ * For modifications use svn_fs_x__set_revision_proplist.
+ */
+svn_error_t *
+svn_fs_x__write_non_packed_revprops(apr_file_t *file,
+ apr_hash_t *proplist,
+ apr_pool_t *scratch_pool);
+
/* Read the revprops for revision REV in FS and return them in *PROPLIST_P.
* If BYPASS_CACHE is set, don't consult the disks but always read from disk.
* If REFRESH is set, update the revprop generation info; otherwise access
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c Tue Oct 11 09:11:50 2016
@@ -259,6 +259,9 @@ serialize_dir(svn_fs_x__dir_data_t *dir,
* sizeof(svn_fs_x__dirent_t*);
apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
+ /* Estimate the size of a directory entry + its name. */
+ enum { ENTRY_SIZE = sizeof(svn_fs_x__dirent_t) + 32 };
+
/* copy the hash entries to an auxiliary struct of known layout */
dir_data.count = count;
dir_data.txn_filesize = dir->txn_filesize;
@@ -274,7 +277,8 @@ serialize_dir(svn_fs_x__dir_data_t *dir,
* estimate for the size of the buffer that we will need. */
context = svn_temp_serializer__init(&dir_data,
sizeof(dir_data),
- 50 + count * 200 + entries_len,
+ 50 + count * ENTRY_SIZE
+ + entries_len + lengths_len,
scratch_pool);
/* serialize entries references */
@@ -675,16 +679,18 @@ svn_fs_x__deserialize_node_revision(void
}
/* Utility function that returns the directory serialized inside CONTEXT
- * to DATA and DATA_LEN. */
+ * to DATA and DATA_LEN. If OVERPROVISION is set, allocate some extra
+ * room for future in-place changes by svn_fs_x__replace_dir_entry. */
static svn_error_t *
return_serialized_dir_context(svn_temp_serializer__context_t *context,
void **data,
- apr_size_t *data_len)
+ apr_size_t *data_len,
+ svn_boolean_t overprovision)
{
svn_stringbuf_t *serialized = svn_temp_serializer__get(context);
*data = serialized->data;
- *data_len = serialized->blocksize;
+ *data_len = overprovision ? serialized->blocksize : serialized->len;
((dir_data_t *)serialized->data)->len = serialized->len;
return SVN_NO_ERROR;
@@ -702,7 +708,8 @@ svn_fs_x__serialize_dir_entries(void **d
* and return the serialized data */
return return_serialized_dir_context(serialize_dir(dir, pool),
data,
- data_len);
+ data_len,
+ FALSE);
}
svn_error_t *
@@ -832,6 +839,10 @@ svn_fs_x__extract_dir_entry(void **out,
const apr_uint32_t *lengths =
svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
+ /* Before we return, make sure we tell the caller this data is even still
+ relevant. */
+ b->out_of_date = dir_data->txn_filesize != b->txn_filesize;
+
/* Special case: Early out for empty directories.
That simplifies tests further down the road. */
*out = NULL;
@@ -860,7 +871,7 @@ svn_fs_x__extract_dir_entry(void **out,
/* de-serialize that entry or return NULL, if no match has been found.
* Be sure to check that the directory contents is still up-to-date. */
- if (found && dir_data->txn_filesize == b->txn_filesize)
+ if (found && !b->out_of_date)
{
const svn_fs_x__dirent_t *source =
svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
@@ -1020,9 +1031,7 @@ svn_fs_x__replace_dir_entry(void **data,
serialize_dir_entry(context, &entries[pos], &length);
/* return the updated serialized data */
- SVN_ERR (return_serialized_dir_context(context,
- data,
- data_len));
+ SVN_ERR(return_serialized_dir_context(context, data, data_len, TRUE));
/* since the previous call may have re-allocated the buffer, the lengths
* pointer may no longer point to the entry in that buffer. Therefore,
@@ -1117,47 +1126,29 @@ deserialize_change(void *buffer,
svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path);
}
-/* Auxiliary structure representing the content of a svn_fs_x__change_t array.
- This structure is much easier to (de-)serialize than an APR array.
- */
-typedef struct changes_data_t
-{
- /* number of entries in the array */
- int count;
-
- /* reference to the changes */
- svn_fs_x__change_t **changes;
-} changes_data_t;
-
svn_error_t *
svn_fs_x__serialize_changes(void **data,
apr_size_t *data_len,
void *in,
apr_pool_t *pool)
{
- apr_array_header_t *array = in;
- changes_data_t changes;
+ svn_fs_x__changes_list_t *changes = in;
svn_temp_serializer__context_t *context;
svn_stringbuf_t *serialized;
int i;
- /* initialize our auxiliary data structure and link it to the
- * array elements */
- changes.count = array->nelts;
- changes.changes = (svn_fs_x__change_t **)array->elts;
-
/* serialize it and all its elements */
- context = svn_temp_serializer__init(&changes,
- sizeof(changes),
- changes.count * 250,
+ context = svn_temp_serializer__init(changes,
+ sizeof(*changes),
+ changes->count * 250,
pool);
svn_temp_serializer__push(context,
- (const void * const *)&changes.changes,
- changes.count * sizeof(**changes.changes));
+ (const void * const *)&changes->changes,
+ changes->count * sizeof(*changes->changes));
- for (i = 0; i < changes.count; ++i)
- serialize_change(context, &changes.changes[i]);
+ for (i = 0; i < changes->count; ++i)
+ serialize_change(context, &changes->changes[i]);
svn_temp_serializer__pop(context);
@@ -1177,9 +1168,7 @@ svn_fs_x__deserialize_changes(void **out
apr_pool_t *result_pool)
{
int i;
- changes_data_t *changes = (changes_data_t *)data;
- apr_array_header_t *array = apr_array_make(result_pool, 0,
- sizeof(svn_fs_x__change_t *));
+ svn_fs_x__changes_list_t *changes = (svn_fs_x__changes_list_t *)data;
/* de-serialize our auxiliary data structure */
svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
@@ -1189,15 +1178,8 @@ svn_fs_x__deserialize_changes(void **out
deserialize_change(changes->changes,
(svn_fs_x__change_t **)&changes->changes[i]);
- /* Use the changes buffer as the array's data buffer
- * (DATA remains valid for at least as long as POOL). */
- array->elts = (char *)changes->changes;
- array->nelts = changes->count;
- array->nalloc = changes->count;
-
/* done */
- *out = array;
+ *out = changes;
return SVN_NO_ERROR;
}
-
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h Tue Oct 11 09:11:50 2016
@@ -182,6 +182,12 @@ typedef struct svn_fs_x__ede_baton_t
/** Current length of the in-txn in-disk representation of the directory.
* SVN_INVALID_FILESIZE if unknown. */
svn_filesize_t txn_filesize;
+
+ /** Will be set by the callback. If FALSE, the cached data is out of date.
+ * We need this indicator because the svn_cache__t interface will always
+ * report the lookup as a success (FOUND==TRUE) if the generic lookup was
+ * successful -- regardless of what the entry extraction callback does. */
+ svn_boolean_t out_of_date;
} svn_fs_x__ede_baton_t;
/**
@@ -260,9 +266,34 @@ svn_fs_x__deserialize_rep_header(void **
apr_size_t data_len,
apr_pool_t *result_pool);
+/*** Block of changes in a changed paths list. */
+typedef struct svn_fs_x__changes_list_t
+{
+ /* Offset of the first element in CHANGES within the changed paths list
+ on disk. */
+ apr_off_t start_offset;
+
+ /* Offset of the first element behind CHANGES within the changed paths
+ list on disk. */
+ apr_off_t end_offset;
+
+ /* End of list reached? This may have false negatives in case the number
+ of elements in the list is a multiple of our block / range size. */
+ svn_boolean_t eol;
+
+ /* Array of #svn_fs_x__change_t * representing a consecutive sub-range of
+ elements in a changed paths list. */
+
+ /* number of entries in the array */
+ int count;
+
+ /* reference to the changes */
+ svn_fs_x__change_t **changes;
+
+} svn_fs_x__changes_list_t;
+
/**
- * Implements #svn_cache__serialize_func_t for an #apr_array_header_t of
- * #svn_fs_x__change_t *.
+ * Implements #svn_cache__serialize_func_t for a #svn_fs_x__changes_list_t.
*/
svn_error_t *
svn_fs_x__serialize_changes(void **data,
@@ -271,8 +302,7 @@ svn_fs_x__serialize_changes(void **data,
apr_pool_t *pool);
/**
- * Implements #svn_cache__deserialize_func_t for an #apr_array_header_t of
- * #svn_fs_x__change_t *.
+ * Implements #svn_cache__deserialize_func_t for a #svn_fs_x__changes_list_t.
*/
svn_error_t *
svn_fs_x__deserialize_changes(void **out,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c Tue Oct 11 09:11:50 2016
@@ -43,6 +43,7 @@
#include "rep-cache.h"
#include "index.h"
#include "batch_fsync.h"
+#include "revprops.h"
#include "private/svn_fs_util.h"
#include "private/svn_fspath.h"
@@ -973,16 +974,6 @@ fold_change(apr_hash_t *changed_paths,
/* This path already exists in the hash, so we have to merge
this change into the already existing one. */
- /* Sanity check: we should be talking about the same node
- revision ID as our last change except where the last change
- was a deletion. */
- if (!svn_fs_x__id_eq(&old_change->noderev_id, &change->noderev_id)
- && (old_change->change_kind != svn_fs_path_change_delete))
- return svn_error_create
- (SVN_ERR_FS_CORRUPT, NULL,
- _("Invalid change ordering: new node revision ID "
- "without delete"));
-
/* 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)
@@ -1941,7 +1932,6 @@ svn_error_t *
svn_fs_x__add_change(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
const char *path,
- const svn_fs_x__id_t *id,
svn_fs_path_change_kind_t change_kind,
svn_boolean_t text_mod,
svn_boolean_t prop_mod,
@@ -1964,7 +1954,6 @@ svn_fs_x__add_change(svn_fs_t *fs,
change.path.data = path;
change.path.len = strlen(path);
- change.noderev_id = *id;
change.change_kind = change_kind;
change.text_mod = text_mod;
change.prop_mod = prop_mod;
@@ -2289,7 +2278,7 @@ rep_write_get_baton(rep_write_baton_t **
b->local_pool),
b->local_pool);
- SVN_ERR(svn_fs_x__get_file_offset(&b->rep_offset, file, b->local_pool));
+ SVN_ERR(svn_io_file_get_offset(&b->rep_offset, file, b->local_pool));
/* Get the base for this delta. */
SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->local_pool));
@@ -2312,8 +2301,7 @@ rep_write_get_baton(rep_write_baton_t **
b->local_pool));
/* Now determine the offset of the actual svndiff data. */
- SVN_ERR(svn_fs_x__get_file_offset(&b->delta_start, file,
- b->local_pool));
+ SVN_ERR(svn_io_file_get_offset(&b->delta_start, file, b->local_pool));
/* Cleanup in case something goes wrong. */
apr_pool_cleanup_register(b->local_pool, b, rep_write_cleanup,
@@ -2525,7 +2513,7 @@ rep_write_contents_close(void *baton)
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->local_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->local_pool));
rep->size = offset - b->delta_start;
/* Fill in the rest of the representation field. */
@@ -2577,7 +2565,7 @@ 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->local_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->local_pool));
entry.size = offset - b->rep_offset;
entry.type = SVN_FS_X__ITEM_TYPE_FILE_REP;
entry.item_count = 1;
@@ -2816,7 +2804,7 @@ write_container_delta_rep(svn_fs_x__repr
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, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
/* Write out the rep header. */
if (base_rep)
@@ -2837,7 +2825,7 @@ write_container_delta_rep(svn_fs_x__repr
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));
+ SVN_ERR(svn_io_file_get_offset(&delta_start, file, scratch_pool));
/* Prepare to write the svndiff data. */
svn_txdelta_to_svndiff3(&diff_wh,
@@ -2886,7 +2874,7 @@ write_container_delta_rep(svn_fs_x__repr
svn_fs_x__id_t noderev_id;
/* Write out our cosmetic end marker. */
- SVN_ERR(svn_fs_x__get_file_offset(&rep_end, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
SVN_ERR(svn_stream_close(file_stream));
@@ -2899,7 +2887,7 @@ write_container_delta_rep(svn_fs_x__repr
noderev_id.number = rep->id.number;
entry.offset = offset;
- SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
entry.size = offset - entry.offset;
entry.type = item_type;
entry.item_count = 1;
@@ -3042,7 +3030,6 @@ write_final_rev(svn_fs_x__id_t *new_id_p
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;
- svn_fs_x__change_t *change;
/* Check to see if this is a transaction node. */
if (txn_id == SVN_FS_X__INVALID_TXN_ID)
@@ -3153,7 +3140,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
if (noderev->copyroot_rev == SVN_INVALID_REVNUM)
noderev->copyroot_rev = rev;
- SVN_ERR(svn_fs_x__get_file_offset(&my_offset, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&my_offset, file, scratch_pool));
SVN_ERR(store_l2p_index_entry(fs, txn_id, my_offset,
noderev->noderev_id.number, scratch_pool));
@@ -3212,7 +3199,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
noderev_id.change_set = SVN_FS_X__INVALID_CHANGE_SET;
entry.offset = my_offset;
- SVN_ERR(svn_fs_x__get_file_offset(&my_offset, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&my_offset, file, scratch_pool));
entry.size = my_offset - entry.offset;
entry.type = SVN_FS_X__ITEM_TYPE_NODEREV;
entry.item_count = 1;
@@ -3220,38 +3207,12 @@ write_final_rev(svn_fs_x__id_t *new_id_p
SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, scratch_pool));
- /* Update the ID within the changed paths list. */
- change = svn_hash_gets(changed_paths, noderev->created_path);
- if (change)
- change->noderev_id = noderev->noderev_id;
-
/* Return our ID that references the revision file. */
*new_id_p = new_id;
return SVN_NO_ERROR;
}
-/* Reset all in-transaction noderev-IDs in CHANGED_PATHS. They should
- belong to deleted nodes only. At any rate, these IDs become invalid
- as soon as transaction got committed.
- Perform temporary allocations in SCRATCH_POOL. */
-static svn_error_t *
-sanitize_changed_path_info(apr_hash_t *changed_paths,
- apr_pool_t *scratch_pool)
-{
- apr_hash_index_t *hi;
- for (hi = apr_hash_first(scratch_pool, changed_paths);
- hi;
- hi = apr_hash_next(hi))
- {
- svn_fs_x__change_t *change = apr_hash_this_val(hi);
- if (svn_fs_x__is_txn(change->noderev_id.change_set))
- svn_fs_x__id_reset(&change->noderev_id);
- }
-
- return SVN_NO_ERROR;
-}
-
/* Write the changed path info CHANGED_PATHS from transaction TXN_ID to the
permanent rev-file FILE representing NEW_REV in filesystem FS. *OFFSET_P
is set the to offset in the file of the beginning of this information.
@@ -3272,7 +3233,7 @@ write_final_changed_path_info(apr_off_t
svn_fs_x__id_t rev_item
= {SVN_INVALID_REVNUM, SVN_FS_X__ITEM_INDEX_CHANGES};
- SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
/* write to target file & calculate checksum */
stream = svn_checksum__wrap_write_stream_fnv1a_32x4(&entry.fnv1_checksum,
@@ -3286,7 +3247,7 @@ write_final_changed_path_info(apr_off_t
/* reference changes from the indexes */
entry.offset = offset;
- SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+ SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
entry.size = offset - entry.offset;
entry.type = SVN_FS_X__ITEM_TYPE_CHANGES;
entry.item_count = 1;
@@ -3434,7 +3395,6 @@ write_final_revprop(const char **path,
svn_string_t date;
svn_string_t *client_date;
apr_file_t *file;
- svn_stream_t *stream;
SVN_ERR(svn_fs_x__txn_proplist(&props, txn, scratch_pool));
@@ -3463,9 +3423,7 @@ write_final_revprop(const char **path,
SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *path, scratch_pool));
/* Write the new contents to the final revprops file. */
- stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
- SVN_ERR(svn_fs_x__write_properties(stream, props, scratch_pool));
- SVN_ERR(svn_stream_close(stream));
+ SVN_ERR(svn_fs_x__write_non_packed_revprops(file, props, scratch_pool));
return SVN_NO_ERROR;
}
@@ -3636,36 +3594,30 @@ write_next_file(svn_fs_t *fs,
return SVN_NO_ERROR;
}
-/* Baton type to be used with bump_ids. */
-typedef struct bump_ids_baton_t
-{
- svn_fs_t *fs;
- svn_revnum_t new_rev;
- svn_fs_x__batch_fsync_t *batch;
-} bump_ids_baton_t;
-
-/* Bump the 'current' and 'txn-current' files in BATON->FS. */
+/* Bump the 'current' file in FS to NEW_REV. Schedule fsyncs in BATCH.
+ * Use SCRATCH_POOL for temporary allocations. */
static svn_error_t *
-bump_ids(void *baton,
- apr_pool_t *scratch_pool)
+bump_current(svn_fs_t *fs,
+ svn_revnum_t new_rev,
+ svn_fs_x__batch_fsync_t *batch,
+ apr_pool_t *scratch_pool)
{
- bump_ids_baton_t *b = baton;
const char *current_filename;
/* Write the 'next' file. */
- SVN_ERR(write_next_file(b->fs, b->new_rev, b->batch, scratch_pool));
+ SVN_ERR(write_next_file(fs, new_rev, batch, scratch_pool));
/* Commit all changes to disk. */
- SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
+ SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
/* Make the revision visible to all processes and threads. */
- current_filename = svn_fs_x__path_current(b->fs, scratch_pool);
- SVN_ERR(svn_fs_x__move_into_place(svn_fs_x__path_next(b->fs, scratch_pool),
+ current_filename = svn_fs_x__path_current(fs, scratch_pool);
+ SVN_ERR(svn_fs_x__move_into_place(svn_fs_x__path_next(fs, scratch_pool),
current_filename, current_filename,
- b->batch, scratch_pool));
+ batch, scratch_pool));
/* Make the new revision permanently visible. */
- SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
+ SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
return SVN_NO_ERROR;
}
@@ -3733,7 +3685,6 @@ commit_body(void *baton,
svn_fs_x__txn_id_t txn_id = svn_fs_x__txn_get_id(cb->txn);
apr_hash_t *changed_paths;
svn_fs_x__batch_fsync_t *batch;
- bump_ids_baton_t bump_ids_baton;
apr_array_header_t *directory_ids
= apr_array_make(scratch_pool, 4, sizeof(svn_fs_x__pair_cache_key_t));
@@ -3779,7 +3730,8 @@ commit_body(void *baton,
/* Use this to force all data to be flushed to physical storage
(to the degree our environment will allow). */
- SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
+ SVN_ERR(svn_fs_x__batch_fsync_create(&batch, ffd->flush_to_disk,
+ scratch_pool));
/* Set up the target directory. */
SVN_ERR(auto_create_shard(cb->fs, new_rev, batch, subpool));
@@ -3791,7 +3743,7 @@ commit_body(void *baton,
### not complete for any reason the transaction will be lost. */
SVN_ERR(get_writable_final_rev(&proto_file, cb->fs, txn_id, new_rev,
batch, subpool));
- SVN_ERR(svn_fs_x__get_file_offset(&initial_offset, proto_file, subpool));
+ SVN_ERR(svn_io_file_get_offset(&initial_offset, proto_file, subpool));
svn_pool_clear(subpool);
/* Write out all the node-revisions and directory contents. */
@@ -3803,7 +3755,6 @@ commit_body(void *baton,
svn_pool_clear(subpool);
/* Write the changed-path information. */
- SVN_ERR(sanitize_changed_path_info(changed_paths, subpool));
SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
cb->fs, txn_id, changed_paths,
new_rev, subpool));
@@ -3833,16 +3784,8 @@ commit_body(void *baton,
SVN_ERR(verify_as_revision_before_current_plus_plus(cb->fs, new_rev,
subpool));
- /* Bump 'current' and 'txn-current'.
- The latter is a piggy-back allocation of a new txn ID such that
- reusing this FS for multiple commits does not involve additional
- fsync latencies. If that txn ID goes to waste, it's not a big loss
- because we've got 18 quintillion of them ... */
- bump_ids_baton.fs = cb->fs;
- bump_ids_baton.new_rev = new_rev;
- bump_ids_baton.batch = batch;
- SVN_ERR(svn_fs_x__with_txn_current_lock(cb->fs, bump_ids, &bump_ids_baton,
- subpool));
+ /* Bump 'current'. */
+ SVN_ERR(bump_current(cb->fs, new_rev, batch, subpool));
/* At this point the new revision is committed and globally visible
so let the caller know it succeeded by giving it the new revision
@@ -3920,6 +3863,8 @@ svn_fs_x__commit(svn_revnum_t *new_rev_p
if (ffd->rep_sharing_allowed)
{
+ svn_error_t *err;
+
SVN_ERR(svn_fs_x__open_rep_cache(fs, scratch_pool));
/* Write new entries to the rep-sharing database.
@@ -3930,9 +3875,21 @@ svn_fs_x__commit(svn_revnum_t *new_rev_p
/* ### A commit that touches thousands of files will starve other
(reader/writer) commits for the duration of the below call.
Maybe write in batches? */
- SVN_SQLITE__WITH_TXN(
- write_reps_to_cache(fs, cb.reps_to_cache, scratch_pool),
- ffd->rep_cache_db);
+ SVN_ERR(svn_sqlite__begin_transaction(ffd->rep_cache_db));
+ err = write_reps_to_cache(fs, cb.reps_to_cache, scratch_pool);
+ err = svn_sqlite__finish_transaction(ffd->rep_cache_db, err);
+
+ if (svn_error_find_cause(err, SVN_ERR_SQLITE_ROLLBACK_FAILED))
+ {
+ /* Failed rollback means that our db connection is unusable, and
+ the only thing we can do is close it. The connection will be
+ reopened during the next operation with rep-cache.db. */
+ return svn_error_trace(
+ svn_error_compose_create(err,
+ svn_fs_x__close_rep_cache(fs)));
+ }
+ else if (err)
+ return svn_error_trace(err);
}
return SVN_NO_ERROR;
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h Tue Oct 11 09:11:50 2016
@@ -64,8 +64,8 @@ svn_fs_x__with_txn_current_lock(svn_fs_t
call BODY with BATON and that subpool, destroy the subpool (releasing
the locks) and return what BODY returned.
- This combines svn_fs_fs__with_write_lock, svn_fs_fs__with_pack_lock,
- and svn_fs_fs__with_txn_current_lock, ensuring correct lock ordering. */
+ This combines svn_fs_x__with_write_lock, svn_fs_x__with_pack_lock,
+ and svn_fs_x__with_txn_current_lock, ensuring correct lock ordering. */
svn_error_t *
svn_fs_x__with_all_locks(svn_fs_t *fs,
svn_error_t *(*body)(void *baton,
@@ -167,9 +167,9 @@ svn_fs_x__set_entry(svn_fs_t *fs,
apr_pool_t *scratch_pool);
/* Add a change to the changes record for filesystem FS in transaction
- TXN_ID. Mark path PATH, having noderev-id ID, as changed according to
- the type in CHANGE_KIND. If the text representation was changed set
- TEXT_MOD to TRUE, and likewise for PROP_MOD as well as MERGEINFO_MOD.
+ TXN_ID. Mark path PATH as changed according to the type in
+ CHANGE_KIND. If the text representation was changed set TEXT_MOD
+ to TRUE, and likewise for PROP_MOD as well as MERGEINFO_MOD.
If this change was the result of a copy, set COPYFROM_REV and
COPYFROM_PATH to the revision and path of the copy source, otherwise
they should be set to SVN_INVALID_REVNUM and NULL. Perform any
@@ -178,7 +178,6 @@ svn_error_t *
svn_fs_x__add_change(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
const char *path,
- const svn_fs_x__id_t *id,
svn_fs_path_change_kind_t change_kind,
svn_boolean_t text_mod,
svn_boolean_t prop_mod,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c Tue Oct 11 09:11:50 2016
@@ -224,18 +224,16 @@ parent_path_relpath(svn_fs_x__dag_path_t
/* Add a change to the changes table in FS, keyed on transaction id
TXN_ID, and indicated that a change of kind CHANGE_KIND occurred on
- PATH (whose node revision id is--or was, in the case of a
- deletion--NODEREV_ID), and optionally that TEXT_MODs, PROP_MODs or
- MERGEINFO_MODs occurred. If the change resulted from a copy,
- COPYFROM_REV and COPYFROM_PATH specify under which revision and path
- the node was copied from. If this was not part of a copy, COPYFROM_REV
- should be SVN_INVALID_REVNUM. Use SCRATCH_POOL for temporary allocations.
+ PATH, and optionally that TEXT_MODs, PROP_MODs or MERGEINFO_MODs
+ occurred. If the change resulted from a copy, COPYFROM_REV and
+ COPYFROM_PATH specify under which revision and path the node was
+ copied from. If this was not part of a copy, COPYFROM_REV should
+ be SVN_INVALID_REVNUM. Use SCRATCH_POOL for temporary allocations.
*/
static svn_error_t *
add_change(svn_fs_t *fs,
svn_fs_x__txn_id_t txn_id,
const char *path,
- const svn_fs_x__id_t *noderev_id,
svn_fs_path_change_kind_t change_kind,
svn_boolean_t text_mod,
svn_boolean_t prop_mod,
@@ -248,8 +246,7 @@ add_change(svn_fs_t *fs,
return svn_fs_x__add_change(fs, txn_id,
svn_fs__canonicalize_abspath(path,
scratch_pool),
- noderev_id, change_kind,
- text_mod, prop_mod, mergeinfo_mod,
+ change_kind, text_mod, prop_mod, mergeinfo_mod,
node_kind, copyfrom_rev, copyfrom_path,
scratch_pool);
}
@@ -388,26 +385,6 @@ x_node_created_path(const char **created
}
-/* Set *KIND_P to the type of node located at PATH under ROOT.
- Perform temporary allocations in SCRATCH_POOL. */
-static svn_error_t *
-node_kind(svn_node_kind_t *kind_p,
- svn_fs_root_t *root,
- const char *path,
- apr_pool_t *scratch_pool)
-{
- dag_node_t *node;
-
- /* Get the node id. */
- SVN_ERR(svn_fs_x__get_temp_dag_node(&node, root, path, scratch_pool));
-
- /* Use the node id to get the real kind. */
- *kind_p = svn_fs_x__dag_node_kind(node);
-
- return SVN_NO_ERROR;
-}
-
-
/* Set *KIND_P to the type of node present at PATH under ROOT. If
PATH does not exist under ROOT, set *KIND_P to svn_node_none. Use
SCRATCH_POOL for temporary allocation. */
@@ -417,7 +394,16 @@ svn_fs_x__check_path(svn_node_kind_t *ki
const char *path,
apr_pool_t *scratch_pool)
{
- svn_error_t *err = node_kind(kind_p, root, path, scratch_pool);
+ dag_node_t *node;
+
+ /* Get the node id. */
+ svn_error_t *err = svn_fs_x__get_temp_dag_node(&node, root, path,
+ scratch_pool);
+
+ /* Use the node id to get the real kind. */
+ if (!err)
+ *kind_p = svn_fs_x__dag_node_kind(node);
+
if (err &&
((err->apr_err == SVN_ERR_FS_NOT_FOUND)
|| (err->apr_err == SVN_ERR_FS_NOT_DIRECTORY)))
@@ -584,7 +570,6 @@ x_change_node_prop(svn_fs_root_t *root,
/* Make a record of this modification in the changes table. */
SVN_ERR(add_change(root->fs, txn_id, path,
- svn_fs_x__dag_get_id(dag_path->node),
svn_fs_path_change_modify, FALSE, TRUE, mergeinfo_mod,
svn_fs_x__dag_node_kind(dag_path->node),
SVN_INVALID_REVNUM, NULL, subpool));
@@ -1457,7 +1442,7 @@ x_make_dir(svn_fs_root_t *root,
svn_fs_x__update_dag_cache(sub_dir);
/* Make a record of this modification in the changes table. */
- SVN_ERR(add_change(root->fs, txn_id, path, svn_fs_x__dag_get_id(sub_dir),
+ SVN_ERR(add_change(root->fs, txn_id, path,
svn_fs_path_change_add, FALSE, FALSE, FALSE,
svn_node_dir, SVN_INVALID_REVNUM, NULL, subpool));
@@ -1517,7 +1502,6 @@ x_delete_node(svn_fs_root_t *root,
/* Make a record of this modification in the changes table. */
SVN_ERR(add_change(root->fs, txn_id, path,
- svn_fs_x__dag_get_id(dag_path->node),
svn_fs_path_change_delete, FALSE, FALSE, FALSE, kind,
SVN_INVALID_REVNUM, NULL, subpool));
@@ -1654,8 +1638,7 @@ copy_helper(svn_fs_root_t *from_root,
/* Make a record of this modification in the changes table. */
SVN_ERR(svn_fs_x__get_dag_node(&new_node, to_root, to_path,
scratch_pool, scratch_pool));
- SVN_ERR(add_change(to_root->fs, txn_id, to_path,
- svn_fs_x__dag_get_id(new_node), kind, FALSE,
+ SVN_ERR(add_change(to_root->fs, txn_id, to_path, kind, FALSE,
FALSE, FALSE, svn_fs_x__dag_node_kind(from_node),
from_root->rev, from_canonpath, scratch_pool));
}
@@ -1795,7 +1778,7 @@ x_make_file(svn_fs_root_t *root,
svn_fs_x__update_dag_cache(child);
/* Make a record of this modification in the changes table. */
- SVN_ERR(add_change(root->fs, txn_id, path, svn_fs_x__dag_get_id(child),
+ SVN_ERR(add_change(root->fs, txn_id, path,
svn_fs_path_change_add, TRUE, FALSE, FALSE,
svn_node_file, SVN_INVALID_REVNUM, NULL, subpool));
@@ -2003,7 +1986,6 @@ apply_textdelta(void *baton,
/* Make a record of this modification in the changes table. */
return add_change(tb->root->fs, txn_id, tb->path,
- svn_fs_x__dag_get_id(tb->node),
svn_fs_path_change_modify, TRUE, FALSE, FALSE,
svn_node_file, SVN_INVALID_REVNUM, NULL, scratch_pool);
}
@@ -2144,7 +2126,6 @@ apply_text(void *baton,
/* Make a record of this modification in the changes table. */
return add_change(tb->root->fs, txn_id, tb->path,
- svn_fs_x__dag_get_id(tb->node),
svn_fs_path_change_modify, TRUE, FALSE, FALSE,
svn_node_file, SVN_INVALID_REVNUM, NULL, scratch_pool);
}
@@ -2255,92 +2236,142 @@ x_get_file_delta_stream(svn_txdelta_stre
/* Finding Changes */
-/* Copy CHANGE into a FS API object allocated in RESULT_POOL and return
- it in *RESULT_P. Pass CONTEXT to the ID API object being created. */
+/* Implement changes_iterator_vtable_t.get for in-txn change lists.
+ There is no specific FSAP data type, a simple APR hash iterator
+ to the underlying collection is sufficient. */
+static svn_error_t *
+x_txn_changes_iterator_get(svn_fs_path_change3_t **change,
+ svn_fs_path_change_iterator_t *iterator)
+{
+ apr_hash_index_t *hi = iterator->fsap_data;
+
+ if (hi)
+ {
+ *change = apr_hash_this_val(hi);
+ iterator->fsap_data = apr_hash_next(hi);
+ }
+ else
+ {
+ *change = NULL;
+ }
+
+ return SVN_NO_ERROR;
+}
+
+static changes_iterator_vtable_t txn_changes_iterator_vtable =
+{
+ x_txn_changes_iterator_get
+};
+
+/* FSAP data structure for in-revision changes list iterators. */
+typedef struct fs_revision_changes_iterator_data_t
+{
+ /* Context that tells the lower layers from where to fetch the next
+ block of changes. */
+ svn_fs_x__changes_context_t *context;
+
+ /* Changes to send. */
+ apr_array_header_t *changes;
+
+ /* Current indexes within CHANGES. */
+ int idx;
+
+ /* A cleanable scratch pool in case we need one.
+ No further sub-pool creation necessary. */
+ apr_pool_t *scratch_pool;
+} fs_revision_changes_iterator_data_t;
+
static svn_error_t *
-construct_fs_path_change(svn_fs_path_change2_t **result_p,
- svn_fs_x__id_context_t *context,
- svn_fs_x__change_t *change,
- apr_pool_t *result_pool)
+x_revision_changes_iterator_get(svn_fs_path_change3_t **change,
+ svn_fs_path_change_iterator_t *iterator)
{
- const svn_fs_id_t *id
- = svn_fs_x__id_create(context, &change->noderev_id, result_pool);
- svn_fs_path_change2_t *result
- = svn_fs__path_change_create_internal(id, change->change_kind,
- result_pool);
+ fs_revision_changes_iterator_data_t *data = iterator->fsap_data;
- result->text_mod = change->text_mod;
- result->prop_mod = change->prop_mod;
- result->node_kind = change->node_kind;
+ /* If we exhausted our block of changes and did not reach the end of the
+ list, yet, fetch the next block. Note that that block may be empty. */
+ if ((data->idx >= data->changes->nelts) && !data->context->eol)
+ {
+ apr_pool_t *changes_pool = data->changes->pool;
- result->copyfrom_known = change->copyfrom_known;
- result->copyfrom_rev = change->copyfrom_rev;
- result->copyfrom_path = change->copyfrom_path;
+ /* Drop old changes block, read new block. */
+ svn_pool_clear(changes_pool);
+ SVN_ERR(svn_fs_x__get_changes(&data->changes, data->context,
+ changes_pool, data->scratch_pool));
+ data->idx = 0;
- result->mergeinfo_mod = change->mergeinfo_mod;
+ /* Immediately release any temporary data. */
+ svn_pool_clear(data->scratch_pool);
+ }
- *result_p = result;
+ if (data->idx < data->changes->nelts)
+ {
+ *change = APR_ARRAY_IDX(data->changes, data->idx,
+ svn_fs_x__change_t *);
+ ++data->idx;
+ }
+ else
+ {
+ *change = NULL;
+ }
return SVN_NO_ERROR;
}
-/* Set *CHANGED_PATHS_P to a newly allocated hash containing
- descriptions of the paths changed under ROOT. The hash is keyed
- with const char * paths and has svn_fs_path_change2_t * values. Use
- POOL for all allocations. */
-static svn_error_t *
-x_paths_changed(apr_hash_t **changed_paths_p,
- svn_fs_root_t *root,
- apr_pool_t *pool)
+static changes_iterator_vtable_t rev_changes_iterator_vtable =
{
- apr_hash_t *changed_paths;
- svn_fs_path_change2_t *path_change;
- svn_fs_x__id_context_t *context
- = svn_fs_x__id_create_context(root->fs, pool);
+ x_revision_changes_iterator_get
+};
+static svn_error_t *
+x_report_changes(svn_fs_path_change_iterator_t **iterator,
+ svn_fs_root_t *root,
+ apr_pool_t *result_pool,
+ apr_pool_t *scratch_pool)
+{
+ svn_fs_path_change_iterator_t *result = apr_pcalloc(result_pool,
+ sizeof(*result));
if (root->is_txn_root)
{
- apr_hash_index_t *hi;
+ apr_hash_t *changed_paths;
SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, root->fs,
svn_fs_x__root_txn_id(root),
- pool));
- for (hi = apr_hash_first(pool, changed_paths);
- hi;
- hi = apr_hash_next(hi))
- {
- svn_fs_x__change_t *change = apr_hash_this_val(hi);
- SVN_ERR(construct_fs_path_change(&path_change, context, change,
- pool));
- apr_hash_set(changed_paths,
- apr_hash_this_key(hi), apr_hash_this_key_len(hi),
- path_change);
- }
+ result_pool));
+
+ result->fsap_data = apr_hash_first(result_pool, changed_paths);
+ result->vtable = &txn_changes_iterator_vtable;
}
else
{
- apr_array_header_t *changes;
- int i;
-
- SVN_ERR(svn_fs_x__get_changes(&changes, root->fs, root->rev, pool));
-
- changed_paths = svn_hash__make(pool);
- for (i = 0; i < changes->nelts; ++i)
- {
- svn_fs_x__change_t *change = APR_ARRAY_IDX(changes, i,
- svn_fs_x__change_t *);
- SVN_ERR(construct_fs_path_change(&path_change, context, change,
- pool));
- apr_hash_set(changed_paths, change->path.data, change->path.len,
- path_change);
- }
+ /* The block of changes that we retrieve need to live in a separately
+ cleanable pool. */
+ apr_pool_t *changes_pool = svn_pool_create(result_pool);
+
+ /* Our iteration context info. */
+ fs_revision_changes_iterator_data_t *data = apr_pcalloc(result_pool,
+ sizeof(*data));
+
+ /* This pool must remain valid as long as ITERATOR lives but will
+ be used only for temporary allocations and will be cleaned up
+ frequently. So, this must be a sub-pool of RESULT_POOL. */
+ data->scratch_pool = svn_pool_create(result_pool);
+
+ /* Fetch the first block of data. */
+ SVN_ERR(svn_fs_x__create_changes_context(&data->context,
+ root->fs, root->rev,
+ result_pool, scratch_pool));
+ SVN_ERR(svn_fs_x__get_changes(&data->changes, data->context,
+ changes_pool, scratch_pool));
+
+ /* Return the fully initialized object. */
+ result->fsap_data = data;
+ result->vtable = &rev_changes_iterator_vtable;
}
- *changed_paths_p = changed_paths;
+ *iterator = result;
return SVN_NO_ERROR;
}
-
/* Our coolio opaque history object. */
typedef struct fs_history_data_t
@@ -3169,7 +3200,8 @@ x_get_mergeinfo(svn_mergeinfo_catalog_t
/* The vtable associated with root objects. */
static root_vtable_t root_vtable = {
- x_paths_changed,
+ NULL,
+ x_report_changes,
svn_fs_x__check_path,
x_node_history,
x_node_id,
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/util.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/util.c Tue Oct 11 09:11:50 2016
@@ -535,6 +535,7 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
svn_revnum_t revnum,
apr_pool_t *scratch_pool)
{
+ svn_fs_x__data_t *ffd = fs->fsap_data;
const char *final_path;
char buf[SVN_INT64_BUFFER_SIZE];
apr_size_t len = svn__i64toa(buf, revnum);
@@ -543,8 +544,8 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
final_path = svn_fs_x__path_min_unpacked_rev(fs, scratch_pool);
SVN_ERR(svn_io_write_atomic2(final_path, buf, len + 1,
- final_path /* copy_perms */, TRUE,
- scratch_pool));
+ final_path /* copy_perms */,
+ ffd->flush_to_disk, scratch_pool));
return SVN_NO_ERROR;
}
@@ -567,7 +568,7 @@ svn_fs_x__read_current(svn_revnum_t *rev
return SVN_NO_ERROR;
}
-/* Atomically update the 'current' file to hold the specifed REV.
+/* Atomically update the 'current' file to hold the specified REV.
Perform temporary allocations in SCRATCH_POOL. */
svn_error_t *
svn_fs_x__write_current(svn_fs_t *fs,
@@ -644,22 +645,6 @@ svn_fs_x__try_stringbuf_from_file(svn_st
/* Fetch the current offset of FILE into *OFFSET_P. */
svn_error_t *
-svn_fs_x__get_file_offset(apr_off_t *offset_p,
- apr_file_t *file,
- apr_pool_t *scratch_pool)
-{
- apr_off_t offset;
-
- /* Note that, for buffered files, one (possibly surprising) side-effect
- of this call is to flush any unwritten data to disk. */
- offset = 0;
- SVN_ERR(svn_io_file_seek(file, APR_CUR, &offset, scratch_pool));
- *offset_p = offset;
-
- return SVN_NO_ERROR;
-}
-
-svn_error_t *
svn_fs_x__read_content(svn_stringbuf_t **content,
const char *fname,
apr_pool_t *result_pool)
Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/util.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/util.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/util.h Tue Oct 11 09:11:50 2016
@@ -369,7 +369,7 @@ svn_fs_x__check_file_buffer_numeric(cons
apr_pool_t *scratch_pool);
/* Set *MIN_UNPACKED_REV to the integer value read from the file returned
- * by #svn_fs_fs__path_min_unpacked_rev() for FS.
+ * by #svn_fs_x__path_min_unpacked_rev() for FS.
* Use SCRATCH_POOL for temporary allocations.
*/
svn_error_t *
@@ -422,13 +422,6 @@ svn_fs_x__try_stringbuf_from_file(svn_st
svn_boolean_t last_attempt,
apr_pool_t *result_pool);
-/* Fetch the current offset of FILE into *OFFSET_P.
- * Perform temporary allocations in SCRATCH_POOL. */
-svn_error_t *
-svn_fs_x__get_file_offset(apr_off_t *offset_p,
- apr_file_t *file,
- apr_pool_t *scratch_pool);
-
/* Read the file FNAME and store the contents in *BUF.
Allocations are performed in RESULT_POOL. */
svn_error_t *
@@ -456,7 +449,7 @@ svn_fs_x__read_number_from_stream(apr_in
Temporary allocations are from SCRATCH_POOL.
This function almost duplicates svn_io_file_move(), but it tries to
- guarantee a flush. */
+ guarantee a flush if BATCH->FLUSH_TO_DISK is non-zero. */
svn_error_t *
svn_fs_x__move_into_place(const char *old_filename,
const char *new_filename,
Modified: subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c Tue Oct 11 09:11:50 2016
@@ -1134,19 +1134,19 @@ svn_ra_local__get_log(svn_ra_session_t *
receiver = log_receiver_wrapper;
receiver_baton = &lb;
- return svn_repos_get_logs4(sess->repos,
- abs_paths,
- start,
- end,
- limit,
- discover_changed_paths,
- strict_node_history,
- include_merged_revisions,
- revprops,
- NULL, NULL,
- receiver,
- receiver_baton,
- pool);
+ return svn_repos__get_logs_compat(sess->repos,
+ abs_paths,
+ start,
+ end,
+ limit,
+ discover_changed_paths,
+ strict_node_history,
+ include_merged_revisions,
+ revprops,
+ NULL, NULL,
+ receiver,
+ receiver_baton,
+ pool);
}
@@ -1362,7 +1362,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
if (dirent_fields & SVN_DIRENT_SIZE)
{
/* size */
- if (entry->kind == svn_node_dir)
+ if (fs_entry->kind == svn_node_dir)
entry->size = 0;
else
SVN_ERR(svn_fs_file_length(&(entry->size), root,