Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/index.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/index.h?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_fs_x/index.h (original) +++ subversion/branches/authzperf/subversion/libsvn_fs_x/index.h Sat Jan 3 14:00:41 2015 @@ -24,6 +24,7 @@ #define SVN_LIBSVN_FS__INDEX_H #include "fs.h" +#include "rev_file.h" /* Per-defined item index values. They are used to identify empty or * mandatory items. @@ -65,7 +66,7 @@ typedef struct svn_fs_x__p2l_entry_t apr_off_t size; /* type of the item (see SVN_FS_X__ITEM_TYPE_*) defines */ - unsigned type; + apr_uint32_t type; /* modified FNV-1a checksum. 0 if unknown checksum */ apr_uint32_t fnv1_checksum; @@ -76,7 +77,7 @@ typedef struct svn_fs_x__p2l_entry_t apr_uint32_t item_count; /* List of items in that block / container */ - svn_fs_x__id_part_t *items; + svn_fs_x__id_t *items; } svn_fs_x__p2l_entry_t; /* Return a (deep) copy of ENTRY, allocated in POOL. @@ -86,20 +87,21 @@ svn_fs_x__p2l_entry_dup(const svn_fs_x__ apr_pool_t *pool); /* Open / create a log-to-phys index file with the full file path name - * FILE_NAME. Return the open file in *PROTO_INDEX and use POOL for - * allocations. + * FILE_NAME. Return the open file in *PROTO_INDEX allocated in + * RESULT_POOL. */ svn_error_t * svn_fs_x__l2p_proto_index_open(apr_file_t **proto_index, const char *file_name, - apr_pool_t *pool); + apr_pool_t *result_pool); /* Call this function before adding entries for the next revision to the - * log-to-phys index file in PROTO_INDEX. Use POOL for allocations. + * log-to-phys index file in PROTO_INDEX. Use SCRATCH_POOL for temporary + * allocations. */ svn_error_t * svn_fs_x__l2p_proto_index_add_revision(apr_file_t *proto_index, - apr_pool_t *pool); + apr_pool_t *scratch_pool); /* Add a new mapping, ITEM_INDEX to the (OFFSET, SUB_ITEM) pair, to log-to- * phys index file in PROTO_INDEX. Please note that mappings may be added @@ -109,72 +111,84 @@ svn_fs_x__l2p_proto_index_add_revision(a * that is already implied for all item indexes not explicitly given a * mapping. * - * Use POOL for allocations. + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__l2p_proto_index_add_entry(apr_file_t *proto_index, apr_off_t offset, apr_uint32_t sub_item, apr_uint64_t item_index, - apr_pool_t *pool); + apr_pool_t *scratch_pool); -/* Use the proto index file stored at PROTO_FILE_NAME and construct the - * final log-to-phys index file at FILE_NAME. The first revision will +/* Use the proto index file stored at PROTO_FILE_NAME, construct the final + * log-to-phys index and append it to INDEX_FILE. The first revision will * be REVISION, entries to the next revision will be assigned to REVISION+1 - * and so forth. Use POOL for allocations. + * and so forth. + * + * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated + * in RESULT_POOL. Use SCRATCH_POOL for temporary allocations. */ svn_error_t * -svn_fs_x__l2p_index_create(svn_fs_t *fs, - const char *file_name, +svn_fs_x__l2p_index_append(svn_checksum_t **checksum, + svn_fs_t *fs, + apr_file_t *index_file, const char *proto_file_name, svn_revnum_t revision, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Open / create a phys-to-log index file with the full file path name - * FILE_NAME. Return the open file in *PROTO_INDEX and use POOL for - * allocations. + * FILE_NAME. Return the open file in *PROTO_INDEX allocated in + * RESULT_POOL. */ svn_error_t * svn_fs_x__p2l_proto_index_open(apr_file_t **proto_index, const char *file_name, - apr_pool_t *pool); + apr_pool_t *result_pool); /* Add a new mapping ENTRY to the phys-to-log index file in PROTO_INDEX. * The entries must be added in ascending offset order and must not leave * intermittent ranges uncovered. The revision value in ENTRY may be - * SVN_INVALID_REVISION. Use POOL for allocations. + * SVN_INVALID_REVISION. Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__p2l_proto_index_add_entry(apr_file_t *proto_index, - svn_fs_x__p2l_entry_t *entry, - apr_pool_t *pool); + const svn_fs_x__p2l_entry_t *entry, + apr_pool_t *scratch_pool); /* Set *NEXT_OFFSET to the first offset behind the last entry in the * phys-to-log proto index file PROTO_INDEX. This will be 0 for empty - * index files. Use POOL for temporary allocations. + * index files. Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__p2l_proto_index_next_offset(apr_off_t *next_offset, apr_file_t *proto_index, - apr_pool_t *pool); + apr_pool_t *scratch_pool); -/* Use the proto index file stored at PROTO_FILE_NAME and construct the - * final phys-to-log index file at FILE_NAME. Entries without a valid +/* Use the proto index file stored at PROTO_FILE_NAME, construct the final + * phys-to-log index and append it to INDEX_FILE. Entries without a valid * revision will be assigned to the REVISION given here. - * Use POOL for allocations. + * + * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated + * in RESULT_POOL. Use SCRATCH_POOL for temporary allocations. */ svn_error_t * -svn_fs_x__p2l_index_create(svn_fs_t *fs, - const char *file_name, +svn_fs_x__p2l_index_append(svn_checksum_t **checksum, + svn_fs_t *fs, + apr_file_t *index_file, const char *proto_file_name, svn_revnum_t revision, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Use the phys-to-log mapping files in FS to build a list of entries * that (at least partly) overlap with the range given by BLOCK_START * offset and BLOCK_SIZE in the rep / pack file containing REVISION. - * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements. - * Use POOL for allocations. + * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements, + * allocated in RESULT_POOL. REV_FILE determines whether to access single + * rev or pack file data. If that is not available anymore (neither in + * cache nor on disk), return an error. Use SCRATCH_POOL for temporary + * allocations. * * Note that (only) the first and the last mapping may cross a cluster * boundary. @@ -182,69 +196,122 @@ svn_fs_x__p2l_index_create(svn_fs_t *fs, svn_error_t * svn_fs_x__p2l_index_lookup(apr_array_header_t **entries, svn_fs_t *fs, + svn_fs_x__revision_file_t *rev_file, svn_revnum_t revision, apr_off_t block_start, apr_off_t block_size, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Use the phys-to-log mapping files in FS to return the entry for the * container or single item starting at global OFFSET in the rep file - * containing REVISION in *ENTRY. Sets *ENTRY to NULL if no item starts - * at exactly that offset. Use POOL for allocations. + * containing REVISION in*ENTRY, allocated in RESULT_POOL. Sets *ENTRY + * to NULL if no item starts at exactly that offset. REV_FILE determines + * whether to access single rev or pack file data. If that is not available + * anymore (neither in cache nor on disk), return an error. + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__p2l_entry_lookup(svn_fs_x__p2l_entry_t **entry, svn_fs_t *fs, + svn_fs_x__revision_file_t *rev_file, svn_revnum_t revision, apr_off_t offset, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Use the phys-to-log mapping files in FS to return the svn_fs_x__id_part_t +/* Use the phys-to-log mapping files in FS to return the svn_fs_x__id_t * for the SUB_ITEM of the container starting at global OFFSET in the rep / - * pack file containing REVISION in *ITEM. Sets *ITEM to NULL if no element - * starts at exactly that offset or if it contains no more than SUB_ITEM - * sub-items. Use POOL for allocations. + * pack file containing REVISION in *ITEM, allocated in RESULT_POOL. Sets + * *ITEM to NULL if no element starts at exactly that offset or if it + * contains no more than SUB_ITEM sub-items. + * + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * -svn_fs_x__p2l_item_lookup(svn_fs_x__id_part_t **item, +svn_fs_x__p2l_item_lookup(svn_fs_x__id_t **item, svn_fs_t *fs, + svn_fs_x__revision_file_t *rev_file, svn_revnum_t revision, apr_off_t offset, apr_uint32_t sub_item, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Use the log-to-phys mapping files in FS to find the packed / non-packed / - * proto-rev file offset and container sub-item of ITEM_ID. *SUB_ITEM will - * be 0 for non-container items. Use POOL for allocations. +/* For ITEM_ID in FS, return the position in the respective rev or pack file + * in *ABSOLUTE_POSITION and the *SUB_ITEM number within the object at that + * location. *SUB_ITEM will be 0 for non-container items. + * + * REV_FILE determines whether to access single rev or pack file data. + * If that is not available anymore (neither in cache nor on disk), re-open + * the rev / pack file and retry to open the index file. For transaction + * content, REV_FILE may be NULL. + * + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * -svn_fs_x__item_offset(apr_off_t *offset, +svn_fs_x__item_offset(apr_off_t *absolute_position, apr_uint32_t *sub_item, svn_fs_t *fs, - const svn_fs_x__id_part_t *item_id, - apr_pool_t *pool); + svn_fs_x__revision_file_t *rev_file, + const svn_fs_x__id_t *item_id, + apr_pool_t *scratch_pool); /* Use the log-to-phys indexes in FS to determine the maximum item indexes * assigned to revision START_REV to START_REV + COUNT - 1. That is a * close upper limit to the actual number of items in the respective revs. - * Return the results in *MAX_IDS, allocated in POOL. + * Return the results in *MAX_IDS, allocated in RESULT_POOL. + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__l2p_get_max_ids(apr_array_header_t **max_ids, svn_fs_t *fs, svn_revnum_t start_rev, apr_size_t count, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* In *OFFSET, return the first OFFSET in the pack / rev file containing * REVISION in FS not covered by the log-to-phys index. - * Use POOL for allocations. + * Use SCRATCH_POOL for temporary allocations. */ svn_error_t * svn_fs_x__p2l_get_max_offset(apr_off_t *offset, svn_fs_t *fs, + svn_fs_x__revision_file_t *rev_file, svn_revnum_t revision, - apr_pool_t *pool); + apr_pool_t *scratch_pool); + +/* Index (re-)creation utilities. + */ + +/* For FS, create a new L2P auto-deleting proto index file in POOL and return + * its name in *PROTONAME. All entries to write are given in ENTRIES and + * entries are of type svn_fs_fs__p2l_entry_t* (sic!). The ENTRIES array + * will be reordered. Give the proto index file the lifetime of RESULT_POOL + * and use SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_x__l2p_index_from_p2l_entries(const char **protoname, + svn_fs_t *fs, + apr_array_header_t *entries, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* For FS, create a new P2L auto-deleting proto index file in POOL and return + * its name in *PROTONAME. All entries to write are given in ENTRIES and + * of type svn_fs_fs__p2l_entry_t*. The FVN1 checksums are not taken from + * ENTRIES but are begin calculated from the current contents of REV_FILE + * as we go. Give the proto index file the lifetime of RESULT_POOL and use + * SCRATCH_POOL for temporary allocations. + */ +svn_error_t * +svn_fs_x__p2l_index_from_p2l_entries(const char **protoname, + svn_fs_t *fs, + svn_fs_x__revision_file_t *rev_file, + apr_array_header_t *entries, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Serialization and caching interface */
Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/lock.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/lock.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_fs_x/lock.c (original) +++ subversion/branches/authzperf/subversion/libsvn_fs_x/lock.c Sat Jan 3 14:00:41 2015 @@ -386,7 +386,8 @@ add_to_digest(const char *fs_path, const char *index_digest_path; apr_hash_t *children; svn_lock_t *lock; - int i, original_count; + int i; + unsigned int original_count; SVN_ERR(digest_path_from_path(&index_digest_path, fs_path, index_path, pool)); Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.c (original) +++ subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.c Sat Jan 3 14:00:41 2015 @@ -27,6 +27,7 @@ #include "private/svn_sorts_private.h" #include "private/svn_string_private.h" #include "private/svn_subr_private.h" +#include "private/svn_fspath.h" #include "../libsvn_fs/fs-loader.h" @@ -37,6 +38,8 @@ /* Headers used to describe node-revision in the revision file. */ #define HEADER_ID "id" +#define HEADER_NODE "node" +#define HEADER_COPY "copy" #define HEADER_TYPE "type" #define HEADER_COUNT "count" #define HEADER_PROPS "props" @@ -71,115 +74,126 @@ * various flags. */ #define MAX_CHANGE_LINE_LEN FSX_MAX_PATH_LEN + 256 -svn_error_t * -svn_fs_x__parse_revision_trailer(apr_off_t *root_offset, - apr_off_t *changes_offset, - svn_stringbuf_t *trailer, - svn_revnum_t rev) -{ - int i, num_bytes; - const char *str; - - /* This cast should be safe since the maximum amount read, 64, will - never be bigger than the size of an int. */ - num_bytes = (int) trailer->len; - - /* The last byte should be a newline. */ - if (trailer->len == 0 || trailer->data[trailer->len - 1] != '\n') +/* Convert the C string in *TEXT to a revision number and return it in *REV. + * Overflows, negative values other than -1 and terminating characters other + * than 0x20 or 0x0 will cause an error. Set *TEXT to the first char after + * the initial separator or to EOS. + */ +static svn_error_t * +parse_revnum(svn_revnum_t *rev, + const char **text) +{ + const char *string = *text; + if ((string[0] == '-') && (string[1] == '1')) { - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - _("Revision file (r%ld) lacks trailing newline"), - rev); + *rev = SVN_INVALID_REVNUM; + string += 2; } - - /* Look for the next previous newline. */ - for (i = num_bytes - 2; i >= 0; i--) + else { - if (trailer->data[i] == '\n') - break; + SVN_ERR(svn_revnum_parse(rev, string, &string)); } - if (i < 0) - { - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - _("Final line in revision file (r%ld) longer " - "than 64 characters"), - rev); - } + if (*string == ' ') + ++string; + else if (*string != '\0') + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid character in revision number")); - i++; - str = &trailer->data[i]; + *text = string; + return SVN_NO_ERROR; +} - /* find the next space */ - for ( ; i < (num_bytes - 2) ; i++) - if (trailer->data[i] == ' ') - break; +svn_error_t * +svn_fs_x__parse_footer(apr_off_t *l2p_offset, + svn_checksum_t **l2p_checksum, + apr_off_t *p2l_offset, + svn_checksum_t **p2l_checksum, + svn_stringbuf_t *footer, + svn_revnum_t rev, + apr_pool_t *result_pool) +{ + apr_int64_t val; + char *last_str = footer->data; - if (i == (num_bytes - 2)) - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - _("Final line in revision file r%ld missing space"), - rev); + /* Get the L2P offset. */ + const char *str = svn_cstring_tokenize(" ", &last_str); + if (str == NULL) + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid revision footer")); - if (root_offset) - { - apr_int64_t val; + SVN_ERR(svn_cstring_atoi64(&val, str)); + *l2p_offset = (apr_off_t)val; - trailer->data[i] = '\0'; - SVN_ERR(svn_cstring_atoi64(&val, str)); - *root_offset = (apr_off_t)val; - } + /* Get the L2P checksum. */ + str = svn_cstring_tokenize(" ", &last_str); + if (str == NULL) + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid revision footer")); - i++; - str = &trailer->data[i]; + SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str, + result_pool)); - /* find the next newline */ - for ( ; i < num_bytes; i++) - if (trailer->data[i] == '\n') - break; + /* Get the P2L offset. */ + str = svn_cstring_tokenize(" ", &last_str); + if (str == NULL) + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid revision footer")); - if (changes_offset) - { - apr_int64_t val; + SVN_ERR(svn_cstring_atoi64(&val, str)); + *p2l_offset = (apr_off_t)val; - trailer->data[i] = '\0'; - SVN_ERR(svn_cstring_atoi64(&val, str)); - *changes_offset = (apr_off_t)val; - } + /* Get the P2L checksum. */ + str = svn_cstring_tokenize(" ", &last_str); + if (str == NULL) + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid revision footer")); + + SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str, + result_pool)); return SVN_NO_ERROR; } svn_stringbuf_t * -svn_fs_x__unparse_revision_trailer(apr_off_t root_offset, - apr_off_t changes_offset, - apr_pool_t *pool) -{ - return svn_stringbuf_createf(pool, - "%" APR_OFF_T_FMT " %" APR_OFF_T_FMT "\n", - root_offset, - changes_offset); +svn_fs_x__unparse_footer(apr_off_t l2p_offset, + svn_checksum_t *l2p_checksum, + apr_off_t p2l_offset, + svn_checksum_t *p2l_checksum, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) +{ + return svn_stringbuf_createf(result_pool, + "%" APR_OFF_T_FMT " %s %" APR_OFF_T_FMT " %s", + l2p_offset, + svn_checksum_to_cstring(l2p_checksum, + scratch_pool), + p2l_offset, + svn_checksum_to_cstring(p2l_checksum, + scratch_pool)); } /* Given a revision file FILE that has been pre-positioned at the beginning of a Node-Rev header block, read in that header block and store it in the apr_hash_t HEADERS. All allocations will be from - POOL. */ + RESULT_POOL. */ static svn_error_t * read_header_block(apr_hash_t **headers, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *result_pool) { - *headers = svn_hash__make(pool); + *headers = svn_hash__make(result_pool); while (1) { svn_stringbuf_t *header_str; const char *name, *value; - apr_ssize_t i = 0; - apr_ssize_t name_len; + apr_size_t i = 0; + apr_size_t name_len; svn_boolean_t eof; - SVN_ERR(svn_stream_readline(stream, &header_str, "\n", &eof, pool)); + SVN_ERR(svn_stream_readline(stream, &header_str, "\n", &eof, + result_pool)); if (eof || header_str->len == 0) break; /* end of header block */ @@ -199,13 +213,10 @@ read_header_block(apr_hash_t **headers, name = header_str->data; name_len = i; - /* Skip over the NULL byte and the space following it. */ - i += 2; - - if (i > header_str->len) + /* Check if we have enough data to parse. */ + if (i + 2 > header_str->len) { /* Restore the original line for the error. */ - i -= 2; header_str->data[i] = ':'; return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Found malformed header '%s' in " @@ -213,6 +224,9 @@ read_header_block(apr_hash_t **headers, header_str->data); } + /* Skip over the NULL byte and the space following it. */ + i += 2; + value = header_str->data + i; /* header_str is safely in our pool, so we can use bits of it as @@ -224,17 +238,18 @@ read_header_block(apr_hash_t **headers, } svn_error_t * -svn_fs_x__parse_representation(representation_t **rep_p, +svn_fs_x__parse_representation(svn_fs_x__representation_t **rep_p, svn_stringbuf_t *text, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - representation_t *rep; + svn_fs_x__representation_t *rep; char *str; apr_int64_t val; char *string = text->data; svn_checksum_t *checksum; - rep = apr_pcalloc(pool, sizeof(*rep)); + rep = apr_pcalloc(result_pool, sizeof(*rep)); *rep_p = rep; str = svn_cstring_tokenize(" ", &string); @@ -283,7 +298,8 @@ svn_fs_x__parse_representation(represent return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); - SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str, pool)); + SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_md5, str, + scratch_pool)); if (checksum) memcpy(rep->md5_digest, checksum->digest, sizeof(rep->md5_digest)); @@ -297,7 +313,8 @@ svn_fs_x__parse_representation(represent return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Malformed text representation offset line in node-rev")); - SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str, pool)); + SVN_ERR(svn_checksum_parse_hex(&checksum, svn_checksum_sha1, str, + scratch_pool)); rep->has_sha1 = checksum != NULL; if (checksum) memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest)); @@ -308,23 +325,28 @@ svn_fs_x__parse_representation(represent /* Wrap read_rep_offsets_body(), extracting its TXN_ID from our NODEREV_ID, and adding an error message. */ static svn_error_t * -read_rep_offsets(representation_t **rep_p, +read_rep_offsets(svn_fs_x__representation_t **rep_p, char *string, - const svn_fs_id_t *noderev_id, - apr_pool_t *pool) + const svn_fs_x__id_t *noderev_id, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_error_t *err = svn_fs_x__parse_representation(rep_p, - svn_stringbuf_create_wrap(string, pool), - pool); + svn_stringbuf_create_wrap(string, + scratch_pool), + result_pool, + scratch_pool); if (err) { - const svn_string_t *id_unparsed = svn_fs_x__id_unparse(noderev_id, pool); + const svn_string_t *id_unparsed; const char *where; - where = apr_psprintf(pool, + + id_unparsed = svn_fs_x__id_unparse(noderev_id, scratch_pool); + where = apr_psprintf(scratch_pool, _("While reading representation offsets " "for node-revision '%s':"), - noderev_id ? id_unparsed->data : "(null)"); + id_unparsed->data); return svn_error_quick_wrap(err, where); } @@ -384,31 +406,45 @@ auto_unescape_path(const char *path, return path; } +/* Find entry HEADER_NAME in HEADERS and parse its value into *ID. */ +static svn_error_t * +read_id_part(svn_fs_x__id_t *id, + apr_hash_t *headers, + const char *header_name) +{ + const char *value = svn_hash_gets(headers, header_name); + if (value == NULL) + return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, + _("Missing %s field in node-rev"), + header_name); + + SVN_ERR(svn_fs_x__id_parse(id, value)); + return SVN_NO_ERROR; +} + svn_error_t * -svn_fs_x__read_noderev(node_revision_t **noderev_p, +svn_fs_x__read_noderev(svn_fs_x__noderev_t **noderev_p, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { apr_hash_t *headers; - node_revision_t *noderev; + svn_fs_x__noderev_t *noderev; char *value; const char *noderev_id; - SVN_ERR(read_header_block(&headers, stream, pool)); + SVN_ERR(read_header_block(&headers, stream, scratch_pool)); + SVN_ERR(svn_stream_close(stream)); - noderev = apr_pcalloc(pool, sizeof(*noderev)); + noderev = apr_pcalloc(result_pool, sizeof(*noderev)); - /* Read the node-rev id. */ - value = svn_hash_gets(headers, HEADER_ID); - if (value == NULL) - /* ### More information: filename/offset coordinates */ - return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, - _("Missing id field in node-rev")); + /* for error messages later */ + noderev_id = svn_hash_gets(headers, HEADER_ID); - SVN_ERR(svn_stream_close(stream)); - - noderev->id = svn_fs_x__id_parse(value, strlen(value), pool); - noderev_id = value; /* for error messages later */ + /* Read the node-rev id. */ + SVN_ERR(read_id_part(&noderev->noderev_id, headers, HEADER_ID)); + SVN_ERR(read_id_part(&noderev->node_id, headers, HEADER_NODE)); + SVN_ERR(read_id_part(&noderev->copy_id, headers, HEADER_COPY)); /* Read the type. */ value = svn_hash_gets(headers, HEADER_TYPE); @@ -437,7 +473,8 @@ svn_fs_x__read_noderev(node_revision_t * if (value) { SVN_ERR(read_rep_offsets(&noderev->prop_rep, value, - noderev->id, pool)); + &noderev->noderev_id, result_pool, + scratch_pool)); } /* Get the data location. */ @@ -445,7 +482,8 @@ svn_fs_x__read_noderev(node_revision_t * if (value) { SVN_ERR(read_rep_offsets(&noderev->data_rep, value, - noderev->id, pool)); + &noderev->noderev_id, result_pool, + scratch_pool)); } /* Get the created path. */ @@ -458,38 +496,42 @@ svn_fs_x__read_noderev(node_revision_t * } else { - noderev->created_path = auto_unescape_path(value, pool); + if (!svn_fspath__is_canonical(value)) + return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, + _("Non-canonical cpath field in node-rev '%s'"), + noderev_id); + + noderev->created_path = auto_unescape_path(apr_pstrdup(result_pool, + value), + result_pool); } /* Get the predecessor ID. */ value = svn_hash_gets(headers, HEADER_PRED); if (value) - noderev->predecessor_id = svn_fs_x__id_parse(value, strlen(value), pool); + SVN_ERR(svn_fs_x__id_parse(&noderev->predecessor_id, value)); + else + svn_fs_x__id_reset(&noderev->predecessor_id); /* Get the copyroot. */ value = svn_hash_gets(headers, HEADER_COPYROOT); if (value == NULL) { noderev->copyroot_path = noderev->created_path; - noderev->copyroot_rev = svn_fs_x__id_rev(noderev->id); + noderev->copyroot_rev + = svn_fs_x__get_revnum(noderev->noderev_id.change_set); } else { - char *str; - - str = svn_cstring_tokenize(" ", &value); - if (str == NULL) - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - _("Malformed copyroot line in node-rev '%s'"), - noderev_id); + SVN_ERR(parse_revnum(&noderev->copyroot_rev, (const char **)&value)); - noderev->copyroot_rev = SVN_STR_TO_REV(str); - - if (*value == '\0') + if (!svn_fspath__is_canonical(value)) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Malformed copyroot line in node-rev '%s'"), noderev_id); - noderev->copyroot_path = auto_unescape_path(value, pool); + noderev->copyroot_path = auto_unescape_path(apr_pstrdup(result_pool, + value), + result_pool); } /* Get the copyfrom. */ @@ -501,19 +543,15 @@ svn_fs_x__read_noderev(node_revision_t * } else { - char *str = svn_cstring_tokenize(" ", &value); - if (str == NULL) - return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, - _("Malformed copyfrom line in node-rev '%s'"), - noderev_id); - - noderev->copyfrom_rev = SVN_STR_TO_REV(str); + SVN_ERR(parse_revnum(&noderev->copyfrom_rev, (const char **)&value)); if (*value == 0) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Malformed copyfrom line in node-rev '%s'"), noderev_id); - noderev->copyfrom_path = auto_unescape_path(value, pool); + noderev->copyfrom_path = auto_unescape_path(apr_pstrdup(result_pool, + value), + result_pool); } /* Get whether this is a fresh txn root. */ @@ -538,13 +576,13 @@ svn_fs_x__read_noderev(node_revision_t * /* Return a textual representation of the DIGEST of given KIND. * If IS_NULL is TRUE, no digest is available. - * Use POOL for allocations. + * Allocate the result in RESULT_POOL. */ static const char * format_digest(const unsigned char *digest, svn_checksum_kind_t kind, svn_boolean_t is_null, - apr_pool_t *pool) + apr_pool_t *result_pool) { svn_checksum_t checksum; checksum.digest = digest; @@ -553,92 +591,105 @@ format_digest(const unsigned char *diges if (is_null) return "(null)"; - return svn_checksum_to_cstring_display(&checksum, pool); + return svn_checksum_to_cstring_display(&checksum, result_pool); } svn_stringbuf_t * -svn_fs_x__unparse_representation(representation_t *rep, - int format, +svn_fs_x__unparse_representation(svn_fs_x__representation_t *rep, svn_boolean_t mutable_rep_truncated, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { if (!rep->has_sha1) return svn_stringbuf_createf - (pool, + (result_pool, "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT " %" SVN_FILESIZE_T_FMT " %s", rep->id.change_set, rep->id.number, rep->size, rep->expanded_size, - format_digest(rep->md5_digest, svn_checksum_md5, FALSE, pool)); + format_digest(rep->md5_digest, svn_checksum_md5, FALSE, + scratch_pool)); return svn_stringbuf_createf - (pool, + (result_pool, "%" APR_INT64_T_FMT " %" APR_UINT64_T_FMT " %" SVN_FILESIZE_T_FMT " %" SVN_FILESIZE_T_FMT " %s %s", rep->id.change_set, rep->id.number, rep->size, rep->expanded_size, - format_digest(rep->md5_digest, svn_checksum_md5, FALSE, pool), + format_digest(rep->md5_digest, svn_checksum_md5, + FALSE, scratch_pool), format_digest(rep->sha1_digest, svn_checksum_sha1, - !rep->has_sha1, pool)); + !rep->has_sha1, scratch_pool)); } svn_error_t * svn_fs_x__write_noderev(svn_stream_t *outfile, - node_revision_t *noderev, - int format, - apr_pool_t *pool) + svn_fs_x__noderev_t *noderev, + apr_pool_t *scratch_pool) { - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_ID ": %s\n", - svn_fs_x__id_unparse(noderev->id, pool)->data)); + svn_string_t *str_id; + + str_id = svn_fs_x__id_unparse(&noderev->noderev_id, scratch_pool); + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_ID ": %s\n", + str_id->data)); + str_id = svn_fs_x__id_unparse(&noderev->node_id, scratch_pool); + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_NODE ": %s\n", + str_id->data)); + str_id = svn_fs_x__id_unparse(&noderev->copy_id, scratch_pool); + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COPY ": %s\n", + str_id->data)); - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_TYPE ": %s\n", + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_TYPE ": %s\n", (noderev->kind == svn_node_file) ? SVN_FS_X__KIND_FILE : SVN_FS_X__KIND_DIR)); - if (noderev->predecessor_id) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_PRED ": %s\n", - svn_fs_x__id_unparse(noderev->predecessor_id, - pool)->data)); + if (svn_fs_x__id_used(&noderev->predecessor_id)) + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_PRED ": %s\n", + svn_fs_x__id_unparse(&noderev->predecessor_id, + scratch_pool)->data)); - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COUNT ": %d\n", + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COUNT ": %d\n", noderev->predecessor_count)); if (noderev->data_rep) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_TEXT ": %s\n", + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_TEXT ": %s\n", svn_fs_x__unparse_representation (noderev->data_rep, - format, noderev->kind == svn_node_dir, - pool)->data)); + scratch_pool, scratch_pool)->data)); if (noderev->prop_rep) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_PROPS ": %s\n", + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_PROPS ": %s\n", svn_fs_x__unparse_representation - (noderev->prop_rep, format, - TRUE, pool)->data)); + (noderev->prop_rep, + TRUE, scratch_pool, scratch_pool)->data)); - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_CPATH ": %s\n", - auto_escape_path(noderev->created_path, pool))); + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_CPATH ": %s\n", + auto_escape_path(noderev->created_path, + scratch_pool))); if (noderev->copyfrom_path) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COPYFROM ": %ld" + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COPYFROM ": %ld" " %s\n", noderev->copyfrom_rev, - auto_escape_path(noderev->copyfrom_path, pool))); + auto_escape_path(noderev->copyfrom_path, + scratch_pool))); - if ((noderev->copyroot_rev != svn_fs_x__id_rev(noderev->id)) || - (strcmp(noderev->copyroot_path, noderev->created_path) != 0)) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_COPYROOT ": %ld" + if ( ( noderev->copyroot_rev + != svn_fs_x__get_revnum(noderev->noderev_id.change_set)) + || (strcmp(noderev->copyroot_path, noderev->created_path) != 0)) + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_COPYROOT ": %ld" " %s\n", noderev->copyroot_rev, - auto_escape_path(noderev->copyroot_path, pool))); + auto_escape_path(noderev->copyroot_path, + scratch_pool))); if (noderev->is_fresh_txn_root) SVN_ERR(svn_stream_puts(outfile, HEADER_FRESHTXNRT ": y\n")); if (noderev->mergeinfo_count > 0) - SVN_ERR(svn_stream_printf(outfile, pool, HEADER_MINFO_CNT ": %" + SVN_ERR(svn_stream_printf(outfile, scratch_pool, HEADER_MINFO_CNT ": %" APR_INT64_T_FMT "\n", noderev->mergeinfo_count)); @@ -651,16 +702,17 @@ svn_fs_x__write_noderev(svn_stream_t *ou svn_error_t * svn_fs_x__read_rep_header(svn_fs_x__rep_header_t **header, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_stringbuf_t *buffer; char *str, *last_str; apr_int64_t val; svn_boolean_t eol = FALSE; - SVN_ERR(svn_stream_readline(stream, &buffer, "\n", &eol, pool)); + SVN_ERR(svn_stream_readline(stream, &buffer, "\n", &eol, scratch_pool)); - *header = apr_pcalloc(pool, sizeof(**header)); + *header = apr_pcalloc(result_pool, sizeof(**header)); (*header)->header_size = buffer->len + 1; if (strcmp(buffer->data, REP_DELTA) == 0) { @@ -677,10 +729,7 @@ svn_fs_x__read_rep_header(svn_fs_x__rep_ if (! str || (strcmp(str, REP_DELTA) != 0)) goto error; - str = svn_cstring_tokenize(" ", &last_str); - if (! str) - goto error; - (*header)->base_revision = SVN_STR_TO_REV(str); + SVN_ERR(parse_revnum(&(*header)->base_revision, (const char **)&last_str)); str = svn_cstring_tokenize(" ", &last_str); if (! str) @@ -704,7 +753,7 @@ svn_fs_x__read_rep_header(svn_fs_x__rep_ svn_error_t * svn_fs_x__write_rep_header(svn_fs_x__rep_header_t *header, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { const char *text; @@ -715,8 +764,8 @@ svn_fs_x__write_rep_header(svn_fs_x__rep break; default: - text = apr_psprintf(pool, REP_DELTA " %ld %" APR_OFF_T_FMT " %" - SVN_FILESIZE_T_FMT "\n", + text = apr_psprintf(scratch_pool, REP_DELTA " %ld %" APR_OFF_T_FMT + " %" SVN_FILESIZE_T_FMT "\n", header->base_revision, header->base_item_index, header->base_length); } @@ -728,27 +777,26 @@ svn_fs_x__write_rep_header(svn_fs_x__rep the resulting change in *CHANGE_P. If there is no next record, store NULL there. Perform all allocations from POOL. */ static svn_error_t * -read_change(change_t **change_p, +read_change(svn_fs_x__change_t **change_p, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { svn_stringbuf_t *line; svn_boolean_t eof = TRUE; - change_t *change; + svn_fs_x__change_t *change; char *str, *last_str, *kind_str; - svn_fs_path_change2_t *info; /* Default return value. */ *change_p = NULL; - SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool)); + SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); /* Check for a blank line. */ if (eof || (line->len == 0)) return SVN_NO_ERROR; - change = apr_pcalloc(pool, sizeof(*change)); - info = &change->info; + change = apr_pcalloc(result_pool, sizeof(*change)); last_str = line->data; /* Get the node-id of the change. */ @@ -757,10 +805,7 @@ read_change(change_t **change_p, return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); - info->node_rev_id = svn_fs_x__id_parse(str, strlen(str), pool); - if (info->node_rev_id == NULL) - return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, - _("Invalid changes line in rev-file")); + SVN_ERR(svn_fs_x__id_parse(&change->noderev_id, str)); /* Get the change type. */ str = svn_cstring_tokenize(" ", &last_str); @@ -770,7 +815,7 @@ read_change(change_t **change_p, /* Don't bother to check the format number before looking for * node-kinds: just read them if you find them. */ - info->node_kind = svn_node_unknown; + change->node_kind = svn_node_unknown; kind_str = strchr(str, '-'); if (kind_str) { @@ -778,9 +823,9 @@ read_change(change_t **change_p, *kind_str = '\0'; kind_str++; if (strcmp(kind_str, SVN_FS_X__KIND_FILE) == 0) - info->node_kind = svn_node_file; + change->node_kind = svn_node_file; else if (strcmp(kind_str, SVN_FS_X__KIND_DIR) == 0) - info->node_kind = svn_node_dir; + change->node_kind = svn_node_dir; else return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); @@ -788,23 +833,23 @@ read_change(change_t **change_p, if (strcmp(str, ACTION_MODIFY) == 0) { - info->change_kind = svn_fs_path_change_modify; + change->change_kind = svn_fs_path_change_modify; } else if (strcmp(str, ACTION_ADD) == 0) { - info->change_kind = svn_fs_path_change_add; + change->change_kind = svn_fs_path_change_add; } else if (strcmp(str, ACTION_DELETE) == 0) { - info->change_kind = svn_fs_path_change_delete; + change->change_kind = svn_fs_path_change_delete; } else if (strcmp(str, ACTION_REPLACE) == 0) { - info->change_kind = svn_fs_path_change_replace; + change->change_kind = svn_fs_path_change_replace; } else if (strcmp(str, ACTION_RESET) == 0) { - info->change_kind = svn_fs_path_change_reset; + change->change_kind = svn_fs_path_change_reset; } else { @@ -820,11 +865,11 @@ read_change(change_t **change_p, if (strcmp(str, FLAG_TRUE) == 0) { - info->text_mod = TRUE; + change->text_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { - info->text_mod = FALSE; + change->text_mod = FALSE; } else { @@ -840,11 +885,11 @@ read_change(change_t **change_p, if (strcmp(str, FLAG_TRUE) == 0) { - info->prop_mod = TRUE; + change->prop_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { - info->prop_mod = FALSE; + change->prop_mod = FALSE; } else { @@ -860,11 +905,11 @@ read_change(change_t **change_p, if (strcmp(str, FLAG_TRUE) == 0) { - info->mergeinfo_mod = svn_tristate_true; + change->mergeinfo_mod = svn_tristate_true; } else if (strcmp(str, FLAG_FALSE) == 0) { - info->mergeinfo_mod = svn_tristate_false; + change->mergeinfo_mod = svn_tristate_false; } else { @@ -873,33 +918,34 @@ read_change(change_t **change_p, } /* Get the changed path. */ - change->path.data = auto_unescape_path(apr_pstrmemdup(pool, last_str, + if (!svn_fspath__is_canonical(last_str)) + return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, + _("Invalid path in changes line")); + + change->path.data = auto_unescape_path(apr_pstrmemdup(result_pool, + last_str, strlen(last_str)), - pool); + result_pool); change->path.len = strlen(change->path.data); /* Read the next line, the copyfrom line. */ - SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, pool)); - info->copyfrom_known = TRUE; + SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool)); + change->copyfrom_known = TRUE; if (eof || line->len == 0) { - info->copyfrom_rev = SVN_INVALID_REVNUM; - info->copyfrom_path = NULL; + change->copyfrom_rev = SVN_INVALID_REVNUM; + change->copyfrom_path = NULL; } else { last_str = line->data; - str = svn_cstring_tokenize(" ", &last_str); - if (! str) - return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, - _("Invalid changes line in rev-file")); - info->copyfrom_rev = SVN_STR_TO_REV(str); + SVN_ERR(parse_revnum(&change->copyfrom_rev, (const char **)&last_str)); - if (! last_str) + if (!svn_fspath__is_canonical(last_str)) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, - _("Invalid changes line in rev-file")); + _("Invalid copy-from path in changes line")); - info->copyfrom_path = auto_unescape_path(last_str, pool); + change->copyfrom_path = auto_unescape_path(last_str, result_pool); } *change_p = change; @@ -910,33 +956,67 @@ read_change(change_t **change_p, svn_error_t * svn_fs_x__read_changes(apr_array_header_t **changes, svn_stream_t *stream, - apr_pool_t *pool) + apr_pool_t *result_pool, + apr_pool_t *scratch_pool) { - change_t *change; + svn_fs_x__change_t *change; + apr_pool_t *iterpool; - /* pre-allocate enough room for most change lists - (will be auto-expanded as necessary) */ - *changes = apr_array_make(pool, 30, sizeof(change_t *)); - - SVN_ERR(read_change(&change, stream, pool)); + /* Pre-allocate enough room for most change lists. + (will be auto-expanded as necessary). + + Chose the default to just below 2^N such that the doubling reallocs + will request roughly 2^M bytes from the OS without exceeding the + respective two-power by just a few bytes (leaves room array and APR + node overhead for large enough M). + */ + *changes = apr_array_make(result_pool, 63, sizeof(svn_fs_x__change_t *)); + + SVN_ERR(read_change(&change, stream, result_pool, scratch_pool)); + iterpool = svn_pool_create(scratch_pool); while (change) { - APR_ARRAY_PUSH(*changes, change_t*) = change; - SVN_ERR(read_change(&change, stream, pool)); + APR_ARRAY_PUSH(*changes, svn_fs_x__change_t*) = change; + SVN_ERR(read_change(&change, stream, result_pool, iterpool)); + svn_pool_clear(iterpool); } + svn_pool_destroy(iterpool); return SVN_NO_ERROR; } -/* Write a single change entry, path PATH, change CHANGE, and copyfrom - string COPYFROM, into the file specified by FILE. Only include the - node kind field if INCLUDE_NODE_KIND is true. All temporary - allocations are in POOL. */ +svn_error_t * +svn_fs_x__read_changes_incrementally(svn_stream_t *stream, + svn_fs_x__change_receiver_t + change_receiver, + void *change_receiver_baton, + apr_pool_t *scratch_pool) +{ + svn_fs_x__change_t *change; + apr_pool_t *iterpool; + + iterpool = svn_pool_create(scratch_pool); + do + { + svn_pool_clear(iterpool); + + SVN_ERR(read_change(&change, stream, iterpool, iterpool)); + if (change) + SVN_ERR(change_receiver(change_receiver_baton, change, iterpool)); + } + while (change); + svn_pool_destroy(iterpool); + + return SVN_NO_ERROR; +} + +/* Write a single change entry, path PATH, change CHANGE, to STREAM. + + All temporary allocations are in SCRATCH_POOL. */ static svn_error_t * write_change_entry(svn_stream_t *stream, - const char *path, - svn_fs_path_change2_t *change, - apr_pool_t *pool) + svn_fs_x__change_t *change, + apr_pool_t *scratch_pool) { const char *idstr; const char *change_string = NULL; @@ -967,30 +1047,29 @@ write_change_entry(svn_stream_t *stream, change->change_kind); } - if (change->node_rev_id) - idstr = svn_fs_x__id_unparse(change->node_rev_id, pool)->data; - else - idstr = ACTION_RESET; + idstr = svn_fs_x__id_unparse(&change->noderev_id, scratch_pool)->data; SVN_ERR_ASSERT(change->node_kind == svn_node_dir - || change->node_kind == svn_node_file); - kind_string = apr_psprintf(pool, "-%s", - change->node_kind == svn_node_dir - ? SVN_FS_X__KIND_DIR - : SVN_FS_X__KIND_FILE); - buf = svn_stringbuf_createf(pool, "%s %s%s %s %s %s %s\n", + || change->node_kind == svn_node_file); + kind_string = apr_psprintf(scratch_pool, "-%s", + change->node_kind == svn_node_dir + ? SVN_FS_X__KIND_DIR + : SVN_FS_X__KIND_FILE); + + buf = svn_stringbuf_createf(scratch_pool, "%s %s%s %s %s %s %s\n", idstr, change_string, kind_string, change->text_mod ? FLAG_TRUE : FLAG_FALSE, change->prop_mod ? FLAG_TRUE : FLAG_FALSE, change->mergeinfo_mod == svn_tristate_true ? FLAG_TRUE : FLAG_FALSE, - auto_escape_path(path, pool)); + auto_escape_path(change->path.data, scratch_pool)); if (SVN_IS_VALID_REVNUM(change->copyfrom_rev)) { - svn_stringbuf_appendcstr(buf, apr_psprintf(pool, "%ld %s", - change->copyfrom_rev, - auto_escape_path(change->copyfrom_path, pool))); + svn_stringbuf_appendcstr(buf, apr_psprintf(scratch_pool, "%ld %s", + change->copyfrom_rev, + auto_escape_path(change->copyfrom_path, + scratch_pool))); } svn_stringbuf_appendbyte(buf, '\n'); @@ -1005,36 +1084,40 @@ svn_fs_x__write_changes(svn_stream_t *st svn_fs_t *fs, apr_hash_t *changes, svn_boolean_t terminate_list, - apr_pool_t *pool) + apr_pool_t *scratch_pool) { - apr_pool_t *iterpool = svn_pool_create(pool); + apr_pool_t *iterpool = svn_pool_create(scratch_pool); apr_array_header_t *sorted_changed_paths; int i; /* For the sake of the repository administrator sort the changes so that the final file is deterministic and repeatable, however the - rest of the FSX code doesn't require any particular order here. */ + rest of the FSX code doesn't require any particular order here. + + Also, this sorting is only effective in writing all entries with + a single call as write_final_changed_path_info() does. For the + list being written incrementally during transaction, we actually + *must not* change the order of entries from different calls. + */ sorted_changed_paths = svn_sort__hash(changes, - svn_sort_compare_items_lexically, pool); + svn_sort_compare_items_lexically, + scratch_pool); /* Write all items to disk in the new order. */ for (i = 0; i < sorted_changed_paths->nelts; ++i) { - svn_fs_path_change2_t *change; - const char *path; + svn_fs_x__change_t *change; svn_pool_clear(iterpool); - change = APR_ARRAY_IDX(sorted_changed_paths, i, svn_sort__item_t).value; - path = APR_ARRAY_IDX(sorted_changed_paths, i, svn_sort__item_t).key; /* Write out the new entry into the final rev-file. */ - SVN_ERR(write_change_entry(stream, path, change, iterpool)); + SVN_ERR(write_change_entry(stream, change, iterpool)); } if (terminate_list) svn_stream_puts(stream, "\n"); - + svn_pool_destroy(iterpool); return SVN_NO_ERROR; Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.h URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.h?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.h (original) +++ subversion/branches/authzperf/subversion/libsvn_fs_x/low_level.h Sat Jan 3 14:00:41 2015 @@ -36,62 +36,81 @@ extern "C" { #define SVN_FS_X__KIND_FILE "file" #define SVN_FS_X__KIND_DIR "dir" -/* Given the last "few" bytes (should be at least 40) of revision REV in - * TRAILER, parse the last line and return the offset of the root noderev - * in *ROOT_OFFSET and the offset of the changed paths list in - * *CHANGES_OFFSET. Offsets are relative to the revision's start offset. - * ROOT_OFFSET and / or CHANGES_OFFSET may be NULL. +/* The functions are grouped as follows: + * + * - revision footer + * - representation (as in "text:" and "props:" lines) + * - node revision + * - representation header ("DELTA" lines) + * - changed path list + */ + +/* Given the FSX revision / pack FOOTER, parse it destructively + * and return the start offsets of the index data in *L2P_OFFSET and + * *P2L_OFFSET, respectively. Also, return the expected checksums in + * in *L2P_CHECKSUM and *P2L_CHECKSUM. * - * Note that REV is only used to construct nicer error objects. + * Note that REV is only used to construct nicer error objects that + * mention this revision. Allocate the checksums in RESULT_POOL. */ svn_error_t * -svn_fs_x__parse_revision_trailer(apr_off_t *root_offset, - apr_off_t *changes_offset, - svn_stringbuf_t *trailer, - svn_revnum_t rev); - -/* Given the offset of the root noderev in ROOT_OFFSET and the offset of - * the changed paths list in CHANGES_OFFSET, return the corresponding - * revision's trailer. Allocate it in POOL. +svn_fs_x__parse_footer(apr_off_t *l2p_offset, + svn_checksum_t **l2p_checksum, + apr_off_t *p2l_offset, + svn_checksum_t **p2l_checksum, + svn_stringbuf_t *footer, + svn_revnum_t rev, + apr_pool_t *result_pool); + +/* Given the offset of the L2P index data in L2P_OFFSET, the content + * checksum in L2P_CHECKSUM and the offset plus checksum of the P2L + * index data in P2L_OFFSET and P2L_CHECKSUM. + * + * Return the corresponding format 7+ revision / pack file footer. + * Allocate it in RESULT_POOL and use SCRATCH_POOL for temporary. */ svn_stringbuf_t * -svn_fs_x__unparse_revision_trailer(apr_off_t root_offset, - apr_off_t changes_offset, - apr_pool_t *pool); +svn_fs_x__unparse_footer(apr_off_t l2p_offset, + svn_checksum_t *l2p_checksum, + apr_off_t p2l_offset, + svn_checksum_t *p2l_checksum, + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Parse the description of a representation from TEXT and store it - into *REP_P. Allocate *REP_P in POOL. */ + into *REP_P. TEXT will be invalidated by this call. Allocate *REP_P in + RESULT_POOL and use SCRATCH_POOL for temporaries. */ svn_error_t * -svn_fs_x__parse_representation(representation_t **rep_p, +svn_fs_x__parse_representation(svn_fs_x__representation_t **rep_p, svn_stringbuf_t *text, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Return a formatted string, compatible with filesystem format FORMAT, - that represents the location of representation REP. If - MUTABLE_REP_TRUNCATED is given, the rep is for props or dir contents, - and only a "-1" revision number will be given for a mutable rep. - If MAY_BE_CORRUPT is true, guard for NULL when constructing the string. - Perform the allocation from POOL. */ +/* Return a formatted string that represents the location of representation + * REP. If MUTABLE_REP_TRUNCATED is given, the rep is for props or dir + * contents, and only a "-1" revision number will be given for a mutable rep. + * If MAY_BE_CORRUPT is true, guard for NULL when constructing the string. + * Allocate the result in RESULT_POOL and temporaries in SCRATCH_POOL. */ svn_stringbuf_t * -svn_fs_x__unparse_representation(representation_t *rep, - int format, +svn_fs_x__unparse_representation(svn_fs_x__representation_t *rep, svn_boolean_t mutable_rep_truncated, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); /* Read a node-revision from STREAM. Set *NODEREV to the new structure, - allocated in POOL. */ + allocated in RESULT_POOL. */ svn_error_t * -svn_fs_x__read_noderev(node_revision_t **noderev, +svn_fs_x__read_noderev(svn_fs_x__noderev_t **noderev, svn_stream_t *stream, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Write the node-revision NODEREV into the stream OUTFILE, compatible with - filesystem format FORMAT. Temporary allocations are from POOL. */ +/* Write the node-revision NODEREV into the stream OUTFILE. + Temporary allocations are from SCRATCH_POOL. */ svn_error_t * svn_fs_x__write_noderev(svn_stream_t *outfile, - node_revision_t *noderev, - int format, - apr_pool_t *pool); + svn_fs_x__noderev_t *noderev, + apr_pool_t *scratch_pool); /* This type enumerates all forms of representations that we support. */ typedef enum svn_fs_x__rep_type_t @@ -132,39 +151,61 @@ typedef struct svn_fs_x__rep_header_t apr_size_t header_size; } svn_fs_x__rep_header_t; -/* Read the next line from file FILE and parse it as a text - representation entry. Return the parsed entry in *REP_ARGS_P. - Perform all allocations in POOL. */ +/* Read the next line from STREAM and parse it as a text + representation header. Return the parsed entry in *HEADER, allocated + in RESULT_POOL. Perform temporary allocations in SCRATCH_POOL. */ svn_error_t * svn_fs_x__read_rep_header(svn_fs_x__rep_header_t **header, svn_stream_t *stream, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); -/* Write the representation HEADER to STREAM. Use POOL for allocations. */ +/* Write the representation HEADER to STREAM. + * Use SCRATCH_POOL for allocations. */ svn_error_t * svn_fs_x__write_rep_header(svn_fs_x__rep_header_t *header, svn_stream_t *stream, - apr_pool_t *pool); + apr_pool_t *scratch_pool); -/* Read all the changes from STREAM and store them in *CHANGES. Do all - allocations in POOL. */ +/* Read all the changes from STREAM and store them in *CHANGES, + allocated in RESULT_POOL. Do temporary allocations in SCRATCH_POOL. */ svn_error_t * svn_fs_x__read_changes(apr_array_header_t **changes, svn_stream_t *stream, - apr_pool_t *pool); + apr_pool_t *result_pool, + apr_pool_t *scratch_pool); + +/* Callback function used by svn_fs_fs__read_changes_incrementally(), + * asking the receiver to process to process CHANGE using BATON. CHANGE + * and SCRATCH_POOL will not be valid beyond the current callback invocation. + */ +typedef svn_error_t *(*svn_fs_x__change_receiver_t)( + void *baton, + svn_fs_x__change_t *change, + apr_pool_t *scratch_pool); + +/* Read all the changes from STREAM and invoke CHANGE_RECEIVER on each change. + Do all allocations in SCRATCH_POOL. */ +svn_error_t * +svn_fs_x__read_changes_incrementally(svn_stream_t *stream, + svn_fs_x__change_receiver_t + change_receiver, + void *change_receiver_baton, + apr_pool_t *scratch_pool); /* Write the changed path info from CHANGES in filesystem FS to the output stream STREAM. You may call this function multiple time on - the same stream but the last call should set TERMINATE_LIST to write - an extra empty line that marks the end of the changed paths list. - Perform temporary allocations in POOL. + the same stream. If you are writing to a (proto-)revision file, + the last call must set TERMINATE_LIST to write an extra empty line + that marks the end of the changed paths list. + Perform temporary allocations in SCRATCH_POOL. */ svn_error_t * svn_fs_x__write_changes(svn_stream_t *stream, svn_fs_t *fs, apr_hash_t *changes, svn_boolean_t terminate_list, - apr_pool_t *pool); + apr_pool_t *scratch_pool); #ifdef __cplusplus } Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/noderevs.c URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/noderevs.c?rev=1649205&r1=1649204&r2=1649205&view=diff ============================================================================== --- subversion/branches/authzperf/subversion/libsvn_fs_x/noderevs.c (original) +++ subversion/branches/authzperf/subversion/libsvn_fs_x/noderevs.c Sat Jan 3 14:00:41 2015 @@ -49,19 +49,7 @@ /* the noderev has copy-root path and revision */ #define NODEREV_HAS_CPATH 0x00040 -/* Our internal representation of an id - * (basically, strip off the txn_id and the fs-agnostic header) - */ -typedef struct binary_id_t -{ - svn_fs_x__id_part_t node_id; - svn_fs_x__id_part_t copy_id; - svn_fs_x__id_part_t noderev_id; -} binary_id_t; - /* Our internal representation of an representation. - * We simply omit the uniquifier, which allows us to share instances of - * binary_representation_t and uniquify them in a shared_representation_t. */ typedef struct binary_representation_t { @@ -72,7 +60,7 @@ typedef struct binary_representation_t unsigned char md5_digest[APR_MD5_DIGESTSIZE]; /* Location of this representation. */ - svn_fs_x__id_part_t id; + svn_fs_x__id_t id; /* The size of the representation in bytes as seen in the revision file. */ @@ -83,7 +71,7 @@ typedef struct binary_representation_t svn_filesize_t expanded_size; } binary_representation_t; -/* Our internal representation of a node_revision_t. +/* Our internal representation of a svn_fs_x__noderev_t. * * We will store path strings in a string container and reference them * from here. Similarly, IDs and representations are being stored in @@ -95,9 +83,15 @@ typedef struct binary_noderev_t /* node type and presence indicators */ apr_uint32_t flags; - /* Index+1 of the node-id for this node-rev. */ + /* Index+1 of the noderev-id for this node-rev. */ int id; + /* Index+1 of the node-id for this node-rev. */ + int node_id; + + /* Index+1 of the copy-id for this node-rev. */ + int copy_id; + /* Index+1 of the predecessor node revision id, or 0 if there is no predecessor for this node revision */ int predecessor_id; @@ -158,19 +152,14 @@ struct svn_fs_x__noderevs_t apr_hash_t *ids_dict; /* During construction, maps a full binary_representation_t to an index - * into DATA_REPS. */ - apr_hash_t *data_reps_dict; - - /* During construction, maps a full binary_representation_t to an index - * into PROP_REPS. */ - apr_hash_t *prop_reps_dict; + * into REPS. */ + apr_hash_t *reps_dict; /* array of binary_id_t */ apr_array_header_t *ids; - /* arrays of binary_representation_t */ - apr_array_header_t *data_reps; - apr_array_header_t *prop_reps; + /* array of binary_representation_t */ + apr_array_header_t *reps; /* array of binary_noderev_t. */ apr_array_header_t *noderevs; @@ -184,16 +173,13 @@ svn_fs_x__noderevs_create(int initial_co noderevs->builder = svn_fs_x__string_table_builder_create(pool); noderevs->ids_dict = svn_hash__make(pool); - noderevs->data_reps_dict = svn_hash__make(pool); - noderevs->prop_reps_dict = svn_hash__make(pool); + noderevs->reps_dict = svn_hash__make(pool); noderevs->paths = NULL; noderevs->ids - = apr_array_make(pool, initial_count, sizeof(binary_id_t)); - noderevs->data_reps - = apr_array_make(pool, initial_count, sizeof(binary_representation_t)); - noderevs->prop_reps - = apr_array_make(pool, initial_count, sizeof(binary_representation_t)); + = apr_array_make(pool, 2 * initial_count, sizeof(svn_fs_x__id_t)); + noderevs->reps + = apr_array_make(pool, 2 * initial_count, sizeof(binary_representation_t)); noderevs->noderevs = apr_array_make(pool, initial_count, sizeof(binary_noderev_t)); @@ -206,24 +192,19 @@ svn_fs_x__noderevs_create(int initial_co static int store_id(apr_array_header_t *ids, apr_hash_t *dict, - const svn_fs_id_t *id) + const svn_fs_x__id_t *id) { - binary_id_t bin_id = { { 0 } }; int idx; void *idx_void; - if (id == NULL) + if (!svn_fs_x__id_used(id)) return 0; - - bin_id.node_id = *svn_fs_x__id_node_id(id); - bin_id.copy_id = *svn_fs_x__id_copy_id(id); - bin_id.noderev_id = *svn_fs_x__id_noderev_id(id); - idx_void = apr_hash_get(dict, &bin_id, sizeof(bin_id)); + idx_void = apr_hash_get(dict, &id, sizeof(id)); idx = (int)(apr_uintptr_t)idx_void; if (idx == 0) { - APR_ARRAY_PUSH(ids, binary_id_t) = bin_id; + APR_ARRAY_PUSH(ids, svn_fs_x__id_t) = *id; idx = ids->nelts; apr_hash_set(dict, ids->elts + (idx-1) * ids->elt_size, ids->elt_size, (void*)(apr_uintptr_t)idx); @@ -238,7 +219,7 @@ store_id(apr_array_header_t *ids, static int store_representation(apr_array_header_t *reps, apr_hash_t *dict, - const representation_t *rep) + const svn_fs_x__representation_t *rep) { binary_representation_t binary_rep = { 0 }; int idx; @@ -269,7 +250,7 @@ store_representation(apr_array_header_t apr_size_t svn_fs_x__noderevs_add(svn_fs_x__noderevs_t *container, - node_revision_t *noderev) + svn_fs_x__noderev_t *noderev) { binary_noderev_t binary_noderev = { 0 }; @@ -280,9 +261,13 @@ svn_fs_x__noderevs_add(svn_fs_x__noderev | (int)noderev->kind; binary_noderev.id - = store_id(container->ids, container->ids_dict, noderev->id); + = store_id(container->ids, container->ids_dict, &noderev->noderev_id); + binary_noderev.node_id + = store_id(container->ids, container->ids_dict, &noderev->node_id); + binary_noderev.copy_id + = store_id(container->ids, container->ids_dict, &noderev->copy_id); binary_noderev.predecessor_id - = store_id(container->ids, container->ids_dict, noderev->predecessor_id); + = store_id(container->ids, container->ids_dict, &noderev->predecessor_id); if (noderev->copyfrom_path) { @@ -303,19 +288,18 @@ svn_fs_x__noderevs_add(svn_fs_x__noderev } binary_noderev.predecessor_count = noderev->predecessor_count; - binary_noderev.prop_rep = store_representation(container->prop_reps, - container->prop_reps_dict, + binary_noderev.prop_rep = store_representation(container->reps, + container->reps_dict, noderev->prop_rep); - if (noderev->data_rep) - binary_noderev.data_rep = store_representation(container->data_reps, - container->data_reps_dict, - noderev->data_rep); + binary_noderev.data_rep = store_representation(container->reps, + container->reps_dict, + noderev->data_rep); if (noderev->created_path) binary_noderev.created_path = svn_fs_x__string_table_builder_add(container->builder, - noderev->created_path, - 0); + noderev->created_path, + 0); binary_noderev.mergeinfo_count = noderev->mergeinfo_count; @@ -333,58 +317,48 @@ svn_fs_x__noderevs_estimate_size(const s /* string table code makes its own prediction, * noderevs should be < 16 bytes each, - * ids < 10 bytes each, + * id parts < 4 bytes each, * data representations < 40 bytes each, * property representations < 30 bytes each, * some static overhead should be assumed */ return svn_fs_x__string_table_builder_estimate_size(container->builder) + container->noderevs->nelts * 16 - + container->ids->nelts * 10 - + container->data_reps->nelts * 40 - + container->prop_reps->nelts * 30 + + container->ids->nelts * 4 + + container->reps->nelts * 40 + 100; } -/* Create an svn_fs_id_t in *ID, allocated in POOL based on the id stored - * at index IDX in IDS. +/* Set *ID to the ID part stored at index IDX in IDS. */ static svn_error_t * -get_id(const svn_fs_id_t **id, +get_id(svn_fs_x__id_t *id, const apr_array_header_t *ids, - int idx, - apr_pool_t *pool) + int idx) { - binary_id_t *binary_id; - /* handle NULL IDs */ if (idx == 0) { - *id = NULL; + svn_fs_x__id_reset(id); return SVN_NO_ERROR; } /* check for corrupted data */ if (idx < 0 || idx > ids->nelts) return svn_error_createf(SVN_ERR_FS_CONTAINER_INDEX, NULL, - _("Node revision ID index %d" - " exceeds container size %d"), + _("ID part index %d exceeds container size %d"), idx, ids->nelts); - /* create a svn_fs_id_t from stored info */ - binary_id = &APR_ARRAY_IDX(ids, idx - 1, binary_id_t); - *id = svn_fs_x__id_create(&binary_id->node_id, - &binary_id->copy_id, - &binary_id->noderev_id, - pool); + /* Return the requested ID. */ + *id = APR_ARRAY_IDX(ids, idx - 1, svn_fs_x__id_t); return SVN_NO_ERROR; } -/* Create a representation_t in *REP, allocated in POOL based on the +/* Create a svn_fs_x__representation_t in *REP, allocated in POOL based on the * representation stored at index IDX in REPS. */ static svn_error_t * -get_representation(representation_t **rep, +get_representation(svn_fs_x__representation_t **rep, const apr_array_header_t *reps, int idx, apr_pool_t *pool) @@ -422,14 +396,14 @@ get_representation(representation_t **re } svn_error_t * -svn_fs_x__noderevs_get(node_revision_t **noderev_p, +svn_fs_x__noderevs_get(svn_fs_x__noderev_t **noderev_p, const svn_fs_x__noderevs_t *container, apr_size_t idx, apr_pool_t *pool) { - node_revision_t *noderev; + svn_fs_x__noderev_t *noderev; binary_noderev_t *binary_noderev; - + /* CONTAINER must be in 'finalized' mode */ SVN_ERR_ASSERT(container->builder == NULL); SVN_ERR_ASSERT(container->paths); @@ -446,11 +420,15 @@ svn_fs_x__noderevs_get(node_revision_t * /* allocate result struct and fill it field by field */ noderev = apr_pcalloc(pool, sizeof(*noderev)); binary_noderev = &APR_ARRAY_IDX(container->noderevs, idx, binary_noderev_t); - + noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK); - SVN_ERR(get_id(&noderev->id, container->ids, binary_noderev->id, pool)); + SVN_ERR(get_id(&noderev->noderev_id, container->ids, binary_noderev->id)); + SVN_ERR(get_id(&noderev->node_id, container->ids, + binary_noderev->node_id)); + SVN_ERR(get_id(&noderev->copy_id, container->ids, + binary_noderev->copy_id)); SVN_ERR(get_id(&noderev->predecessor_id, container->ids, - binary_noderev->predecessor_id, pool)); + binary_noderev->predecessor_id)); if (binary_noderev->flags & NODEREV_HAS_COPYFROM) { @@ -484,9 +462,9 @@ svn_fs_x__noderevs_get(node_revision_t * noderev->predecessor_count = binary_noderev->predecessor_count; - SVN_ERR(get_representation(&noderev->prop_rep, container->prop_reps, + SVN_ERR(get_representation(&noderev->prop_rep, container->reps, binary_noderev->prop_rep, pool)); - SVN_ERR(get_representation(&noderev->data_rep, container->data_reps, + SVN_ERR(get_representation(&noderev->data_rep, container->reps, binary_noderev->data_rep, pool)); if (binary_noderev->flags & NODEREV_HAS_CPATH) @@ -576,40 +554,34 @@ svn_fs_x__write_noderevs_container(svn_s = svn_packed__create_int_stream(root, FALSE, FALSE); svn_packed__int_stream_t *ids_stream = svn_packed__create_int_substream(structs_stream, FALSE, FALSE); - svn_packed__int_stream_t *data_reps_stream - = create_rep_stream(structs_stream); - svn_packed__int_stream_t *prop_reps_stream + svn_packed__int_stream_t *reps_stream = create_rep_stream(structs_stream); svn_packed__int_stream_t *noderevs_stream = svn_packed__create_int_substream(structs_stream, FALSE, FALSE); svn_packed__byte_stream_t *digests_stream = svn_packed__create_bytes_stream(root); - /* structure the CHANGES_STREAM such we can extract much of the redundancy - * from the binary_change_t structs */ - for (i = 0; i < 3 * 2; ++i) + /* structure the IDS_STREAM such we can extract much of the redundancy + * from the svn_fs_x__ip_part_t structs */ + for (i = 0; i < 2; ++i) svn_packed__create_int_substream(ids_stream, TRUE, FALSE); + /* Same storing binary_noderev_t in the NODEREVS_STREAM */ svn_packed__create_int_substream(noderevs_stream, FALSE, FALSE); - for (i = 0; i < 11; ++i) + for (i = 0; i < 13; ++i) svn_packed__create_int_substream(noderevs_stream, TRUE, FALSE); /* serialize ids array */ for (i = 0; i < container->ids->nelts; ++i) { - binary_id_t *id = &APR_ARRAY_IDX(container->ids, i, binary_id_t); + svn_fs_x__id_t *id = &APR_ARRAY_IDX(container->ids, i, svn_fs_x__id_t); - svn_packed__add_int(ids_stream, id->node_id.change_set); - svn_packed__add_uint(ids_stream, id->node_id.number); - svn_packed__add_int(ids_stream, id->copy_id.change_set); - svn_packed__add_uint(ids_stream, id->copy_id.number); - svn_packed__add_int(ids_stream, id->noderev_id.change_set); - svn_packed__add_uint(ids_stream, id->noderev_id.number); + svn_packed__add_int(ids_stream, id->change_set); + svn_packed__add_uint(ids_stream, id->number); } /* serialize rep arrays */ - write_reps(data_reps_stream, digests_stream, container->data_reps); - write_reps(prop_reps_stream, digests_stream, container->prop_reps); + write_reps(reps_stream, digests_stream, container->reps); /* serialize noderevs array */ for (i = 0; i < container->noderevs->nelts; ++i) @@ -620,6 +592,8 @@ svn_fs_x__write_noderevs_container(svn_s svn_packed__add_uint(noderevs_stream, noderev->flags); svn_packed__add_uint(noderevs_stream, noderev->id); + svn_packed__add_uint(noderevs_stream, noderev->node_id); + svn_packed__add_uint(noderevs_stream, noderev->copy_id); svn_packed__add_uint(noderevs_stream, noderev->predecessor_id); svn_packed__add_uint(noderevs_stream, noderev->predecessor_count); @@ -642,9 +616,9 @@ svn_fs_x__write_noderevs_container(svn_s return SVN_NO_ERROR; } -/* Allocate a representation_t array in POOL and return it in *REPS_P. - * Deserialize the data in REP_STREAM and DIGEST_STREAM and store the - * resulting representations into the *REPS_P. +/* Allocate a svn_fs_x__representation_t array in POOL and return it in + * REPS_P. Deserialize the data in REP_STREAM and DIGEST_STREAM and store + * the resulting representations into the *REPS_P. */ static svn_error_t * read_reps(apr_array_header_t **reps_p, @@ -721,8 +695,7 @@ svn_fs_x__read_noderevs_container(svn_fs svn_packed__data_root_t *root; svn_packed__int_stream_t *structs_stream; svn_packed__int_stream_t *ids_stream; - svn_packed__int_stream_t *data_reps_stream; - svn_packed__int_stream_t *prop_reps_stream; + svn_packed__int_stream_t *reps_stream; svn_packed__int_stream_t *noderevs_stream; svn_packed__byte_stream_t *digests_stream; @@ -734,34 +707,27 @@ svn_fs_x__read_noderevs_container(svn_fs /* get streams */ structs_stream = svn_packed__first_int_stream(root); ids_stream = svn_packed__first_int_substream(structs_stream); - data_reps_stream = svn_packed__next_int_stream(ids_stream); - prop_reps_stream = svn_packed__next_int_stream(data_reps_stream); - noderevs_stream = svn_packed__next_int_stream(prop_reps_stream); + reps_stream = svn_packed__next_int_stream(ids_stream); + noderevs_stream = svn_packed__next_int_stream(reps_stream); digests_stream = svn_packed__first_byte_stream(root); /* read ids array */ count = svn_packed__int_count(svn_packed__first_int_substream(ids_stream)); noderevs->ids - = apr_array_make(result_pool, (int)count, sizeof(binary_id_t)); + = apr_array_make(result_pool, (int)count, sizeof(svn_fs_x__id_t)); for (i = 0; i < count; ++i) { - binary_id_t id; + svn_fs_x__id_t id; - id.node_id.change_set = (svn_revnum_t)svn_packed__get_int(ids_stream); - id.node_id.number = svn_packed__get_uint(ids_stream); - id.copy_id.change_set = (svn_revnum_t)svn_packed__get_int(ids_stream); - id.copy_id.number = svn_packed__get_uint(ids_stream); - id.noderev_id.change_set = (svn_revnum_t)svn_packed__get_int(ids_stream); - id.noderev_id.number = svn_packed__get_uint(ids_stream); + id.change_set = (svn_revnum_t)svn_packed__get_int(ids_stream); + id.number = svn_packed__get_uint(ids_stream); - APR_ARRAY_PUSH(noderevs->ids, binary_id_t) = id; + APR_ARRAY_PUSH(noderevs->ids, svn_fs_x__id_t) = id; } /* read rep arrays */ - SVN_ERR(read_reps(&noderevs->data_reps, data_reps_stream, digests_stream, - result_pool)); - SVN_ERR(read_reps(&noderevs->prop_reps, prop_reps_stream, digests_stream, + SVN_ERR(read_reps(&noderevs->reps, reps_stream, digests_stream, result_pool)); /* read noderevs array */ @@ -776,6 +742,8 @@ svn_fs_x__read_noderevs_container(svn_fs noderev.flags = (apr_uint32_t)svn_packed__get_uint(noderevs_stream); noderev.id = (int)svn_packed__get_uint(noderevs_stream); + noderev.node_id = (int)svn_packed__get_uint(noderevs_stream); + noderev.copy_id = (int)svn_packed__get_uint(noderevs_stream); noderev.predecessor_id = (int)svn_packed__get_uint(noderevs_stream); noderev.predecessor_count = (int)svn_packed__get_uint(noderevs_stream); @@ -808,8 +776,7 @@ svn_fs_x__serialize_noderevs_container(v svn_stringbuf_t *serialized; apr_size_t size = noderevs->ids->elt_size * noderevs->ids->nelts - + noderevs->data_reps->elt_size * noderevs->data_reps->nelts - + noderevs->prop_reps->elt_size * noderevs->prop_reps->nelts + + noderevs->reps->elt_size * noderevs->reps->nelts + noderevs->noderevs->elt_size * noderevs->noderevs->nelts + 10 * noderevs->noderevs->elt_size + 100; @@ -821,8 +788,7 @@ svn_fs_x__serialize_noderevs_container(v /* serialize sub-structures */ svn_fs_x__serialize_string_table(context, &noderevs->paths); svn_fs_x__serialize_apr_array(context, &noderevs->ids); - svn_fs_x__serialize_apr_array(context, &noderevs->data_reps); - svn_fs_x__serialize_apr_array(context, &noderevs->prop_reps); + svn_fs_x__serialize_apr_array(context, &noderevs->reps); svn_fs_x__serialize_apr_array(context, &noderevs->noderevs); /* return the serialized result */ @@ -845,8 +811,7 @@ svn_fs_x__deserialize_noderevs_container /* de-serialize sub-structures */ svn_fs_x__deserialize_string_table(noderevs, &noderevs->paths); svn_fs_x__deserialize_apr_array(noderevs, &noderevs->ids, pool); - svn_fs_x__deserialize_apr_array(noderevs, &noderevs->data_reps, pool); - svn_fs_x__deserialize_apr_array(noderevs, &noderevs->prop_reps, pool); + svn_fs_x__deserialize_apr_array(noderevs, &noderevs->reps, pool); svn_fs_x__deserialize_apr_array(noderevs, &noderevs->noderevs, pool); /* done */ @@ -880,12 +845,11 @@ svn_fs_x__noderevs_get_func(void **out, void *baton, apr_pool_t *pool) { - node_revision_t *noderev; + svn_fs_x__noderev_t *noderev; binary_noderev_t *binary_noderev; - + apr_array_header_t ids; - apr_array_header_t data_reps; - apr_array_header_t prop_reps; + apr_array_header_t reps; apr_array_header_t noderevs; apr_uint32_t idx = *(apr_uint32_t *)baton; @@ -897,18 +861,19 @@ svn_fs_x__noderevs_get_func(void **out, (const void *const *)&container->paths); resolve_apr_array_header(&ids, container, &container->ids); - resolve_apr_array_header(&data_reps, container, &container->data_reps); - resolve_apr_array_header(&prop_reps, container, &container->prop_reps); + resolve_apr_array_header(&reps, container, &container->reps); resolve_apr_array_header(&noderevs, container, &container->noderevs); - + /* allocate result struct and fill it field by field */ noderev = apr_pcalloc(pool, sizeof(*noderev)); binary_noderev = &APR_ARRAY_IDX(&noderevs, idx, binary_noderev_t); - + noderev->kind = (svn_node_kind_t)(binary_noderev->flags & NODEREV_KIND_MASK); - SVN_ERR(get_id(&noderev->id, &ids, binary_noderev->id, pool)); + SVN_ERR(get_id(&noderev->noderev_id, &ids, binary_noderev->id)); + SVN_ERR(get_id(&noderev->node_id, &ids, binary_noderev->node_id)); + SVN_ERR(get_id(&noderev->copy_id, &ids, binary_noderev->copy_id)); SVN_ERR(get_id(&noderev->predecessor_id, &ids, - binary_noderev->predecessor_id, pool)); + binary_noderev->predecessor_id)); if (binary_noderev->flags & NODEREV_HAS_COPYFROM) { @@ -942,9 +907,9 @@ svn_fs_x__noderevs_get_func(void **out, noderev->predecessor_count = binary_noderev->predecessor_count; - SVN_ERR(get_representation(&noderev->prop_rep, &prop_reps, + SVN_ERR(get_representation(&noderev->prop_rep, &reps, binary_noderev->prop_rep, pool)); - SVN_ERR(get_representation(&noderev->data_rep, &data_reps, + SVN_ERR(get_representation(&noderev->data_rep, &reps, binary_noderev->data_rep, pool)); if (binary_noderev->flags & NODEREV_HAS_CPATH)
