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,