Return-Path: X-Original-To: apmail-subversion-commits-archive@minotaur.apache.org Delivered-To: apmail-subversion-commits-archive@minotaur.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id A49E1F574 for ; Thu, 28 Mar 2013 22:27:57 +0000 (UTC) Received: (qmail 56408 invoked by uid 500); 28 Mar 2013 22:27:57 -0000 Delivered-To: apmail-subversion-commits-archive@subversion.apache.org Received: (qmail 56384 invoked by uid 500); 28 Mar 2013 22:27:57 -0000 Mailing-List: contact commits-help@subversion.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@subversion.apache.org Delivered-To: mailing list commits@subversion.apache.org Received: (qmail 56377 invoked by uid 99); 28 Mar 2013 22:27:57 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 28 Mar 2013 22:27:57 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 28 Mar 2013 22:27:54 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 192CB23888E4; Thu, 28 Mar 2013 22:27:34 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1462329 - in /subversion/branches/fsfs-format7/subversion/libsvn_fs_fs: cached_data.c fs_fs.c index.c index.h pack.c recovery.c transaction.c Date: Thu, 28 Mar 2013 22:27:33 -0000 To: commits@subversion.apache.org From: stefan2@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20130328222734.192CB23888E4@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: stefan2 Date: Thu Mar 28 22:27:33 2013 New Revision: 1462329 URL: http://svn.apache.org/r1462329 Log: On the fsfs-format7 branch: Add support for item containers, that is items may now contain a collection of other items (e.g. noderevs). The latter can no longer be addressed in and read directly from the rev / pack file but wil require the container item to be read and may *then* be extracted using a sub-item index value as key. We extend the index file interface to store (rev,item)->(offset,sub-item) as log-to-phys mapping and (offset)->(len,type,count,(rev,item)*) for the phys-to-log mapping. Index files and pack algorithm now have full container support. Other parts will assert (by checking for sub-item==0) that no containers are being used currently. * subversion/libsvn_fs_fs/index.h (svn_fs_fs__p2l_entry_t): all p2l entries cover a variable list of items (svn_fs_fs__l2p_proto_index_add_entry): add sub-item parameter (svn_fs_fs__item_offset): return sub-item alongside offset * subversion/libsvn_fs_fs/index.c (l2p_page_t, l2p_proto_entry_t): add sub-items to l2p data (svn_fs_fs__l2p_proto_index_add_entry): store sub-item as well (svn_fs_fs__l2p_index_create): copy sub-items values to final index (get_l2p_header_body): clarify a comment (get_l2p_page): read sub-items from l2p index file (l2p_page_baton_t): add output variables (l2p_page_get_offset, l2p_page_access_func): return offset *and* sub-item (l2p_index_lookup, l2p_proto_index_lookup): update (svn_fs_fs__p2l_proto_index_add_entry, svn_fs_fs__p2l_index_create, read_entry): handle sub-item lists in p2l index data (svn_fs_fs__item_offset): update (svn_fs_fs__serialize_l2p_page, svn_fs_fs__deserialize_l2p_page, svn_fs_fs__serialize_p2l_page, svn_fs_fs__deserialize_p2l_page): add support for the new struct members * subversion/libsvn_fs_fs/fs_fs.c (write_revision_zero): update index files in rev 0 template * subversion/libsvn_fs_fs/cached_data.c (dgb__log_access, open_and_seek_revision, open_and_seek_transaction): update API callers (svn_fs_fs__rev_get_root, create_rep_state_body, auto_set_start_offset, block_read_windows, block_read_changes, block_read_noderev, block_read): ditto; assert non-container items * subversion/libsvn_fs_fs/pack.c (copy_p2l_entry): new copy utility (copy_item_to_temp, copy_rep_to_temp, copy_node_to_temp): use utility function to duplicate index data (add_item_rep_mapping): handle containers with != 1 entry (compare_p2l_info, compare_p2l_info_rev): sort by first sub-item (sort_reps, copy_items_from_temp): adapt to struct change (write_l2p_index): use a priority queue to cover all container sub-items (append_revision): assert that no containers are used in single revs * subversion/libsvn_fs_fs/recovery.c (recover_find_max_ids, svn_fs_fs__find_max_ids): adapt to internal API change; assert() no containers in pre-f7 repos * subversion/libsvn_fs_fs/transaction.c (store_l2p_index_entry, rep_write_contents_close, write_hash_rep, write_hash_delta_rep, write_final_rev, write_final_changed_path_info, commit_body): adapt to API change; don't use containers yet Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/recovery.c subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/cached_data.c Thu Mar 28 22:27:33 2013 @@ -74,6 +74,7 @@ dgb__log_access(svn_fs_t *fs, fs_fs_data_t *ffd = fs->fsap_data; apr_off_t offset = -1; apr_off_t end_offset = 0; + apr_uint32_t sub_item = 0; apr_array_header_t *entries; svn_fs_fs__p2l_entry_t *entry = NULL; int i; @@ -84,8 +85,8 @@ dgb__log_access(svn_fs_t *fs, const char *pack = ""; /* determine rev / pack file offset */ - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, revision, NULL, item_index, - scratch_pool)); + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs, revision, NULL, + item_index, scratch_pool)); /* constructing the pack file description */ if (revision < ffd->min_unpacked_rev) @@ -214,11 +215,13 @@ open_and_seek_revision(apr_file_t **file { apr_file_t *rev_file; apr_off_t offset = -1; + apr_uint32_t sub_item = 0; SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool)); SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, rev, pool)); - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev, NULL, item, pool)); + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs, rev, NULL, item, + pool)); SVN_ERR(aligned_seek(fs, rev_file, NULL, offset, pool)); *file = rev_file; @@ -237,12 +240,13 @@ open_and_seek_transaction(apr_file_t **f { apr_file_t *rev_file; apr_off_t offset; + apr_uint32_t sub_item = 0; SVN_ERR(svn_io_file_open(&rev_file, path_txn_proto_rev(fs, &rep->txn_id, pool), APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool)); - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, SVN_INVALID_REVNUM, + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs, SVN_INVALID_REVNUM, &rep->txn_id, rep->item_index, pool)); SVN_ERR(aligned_seek(fs, rev_file, NULL, offset, pool)); @@ -530,6 +534,7 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro fs_fs_data_t *ffd = fs->fsap_data; apr_file_t *revision_file; apr_off_t root_offset; + apr_uint32_t root_sub_item; svn_fs_id_t *root_id = NULL; svn_boolean_t is_cached; @@ -561,8 +566,10 @@ svn_fs_fs__rev_get_root(svn_fs_id_t **ro return SVN_NO_ERROR; } - SVN_ERR(svn_fs_fs__item_offset(&root_offset, fs, rev, NULL, + SVN_ERR(svn_fs_fs__item_offset(&root_offset, &root_sub_item, + fs, rev, NULL, SVN_FS_FS__ITEM_INDEX_ROOT_NODE, pool)); + SVN_ERR_ASSERT(root_sub_item == 0); } SVN_ERR(get_fs_id_at_offset(&root_id, revision_file, fs, rev, @@ -700,8 +707,11 @@ create_rep_state_body(rep_state_t **rep_ /* ... we can re-use the same, already open file object */ apr_off_t offset; - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rep->revision, NULL, + apr_uint32_t sub_item; + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, + fs, rep->revision, NULL, rep->item_index, pool)); + SVN_ERR_ASSERT(sub_item == 0); SVN_ERR(aligned_seek(fs, (*shared_file)->file, NULL, offset, pool)); rs->file = *shared_file; @@ -1223,9 +1233,12 @@ auto_set_start_offset(rep_state_t *rs, a { if (rs->start == -1) { - SVN_ERR(svn_fs_fs__item_offset(&rs->start, rs->file->fs, + apr_uint32_t sub_item; + SVN_ERR(svn_fs_fs__item_offset(&rs->start, &sub_item, rs->file->fs, rs->revision, NULL, rs->item_index, pool)); + SVN_ERR_ASSERT(sub_item == 0); + rs->start += rs->header_size; } @@ -2240,15 +2253,18 @@ block_read_windows(svn_fs_fs__rep_header || (!rep_header->is_delta && !ffd->combined_window_cache)) return SVN_NO_ERROR; + /* we don't support containers, yet */ + SVN_ERR_ASSERT(entry->item_count == 1); + shared_file.file = file; shared_file.stream = stream; shared_file.fs = fs; - shared_file.revision = entry->revision; + shared_file.revision = entry->items[0].revision; shared_file.pool = pool; rs.file = &shared_file; - rs.revision = entry->revision; - rs.item_index = entry->item_index; + rs.revision = entry->items[0].revision; + rs.item_index = entry->items[0].number; rs.header_size = rep_header->header_size; rs.start = entry->offset + rs.header_size; rs.current = rep_header->is_delta ? 4 : 0; @@ -2380,12 +2396,15 @@ block_read_changes(apr_array_header_t ** if (!must_read && !ffd->changes_cache) return SVN_NO_ERROR; + /* we don't support containers, yet */ + SVN_ERR_ASSERT(entry->item_count == 1); + /* already in cache? */ if (!must_read && ffd->changes_cache) { svn_boolean_t is_cached = FALSE; SVN_ERR(svn_cache__has_key(&is_cached, ffd->changes_cache, - &entry->revision, pool)); + &entry->items[0].revision, pool)); if (is_cached) return SVN_NO_ERROR; } @@ -2399,7 +2418,8 @@ block_read_changes(apr_array_header_t ** /* cache for future reference */ if (ffd->changes_cache) - SVN_ERR(svn_cache__set(ffd->changes_cache, &entry->revision, *changes, pool)); + SVN_ERR(svn_cache__set(ffd->changes_cache, &entry->items[0].revision, + *changes, pool)); return SVN_NO_ERROR; } @@ -2419,6 +2439,9 @@ block_read_noderev(node_revision_t **nod if (!must_read && !ffd->node_revision_cache) return SVN_NO_ERROR; + /* we don't support containers, yet */ + SVN_ERR_ASSERT(entry->item_count == 1); + /* already in cache? */ if (!must_read && ffd->node_revision_cache) { @@ -2441,9 +2464,9 @@ block_read_noderev(node_revision_t **nod if (ffd->node_revision_cache) SVN_ERR(svn_cache__set(ffd->node_revision_cache, key, *noderev_p, pool)); - if ( entry->item_index == SVN_FS_FS__ITEM_INDEX_ROOT_NODE + if ( entry->items[0].number == SVN_FS_FS__ITEM_INDEX_ROOT_NODE && ffd->rev_root_id_cache) - SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &entry->revision, + SVN_ERR(svn_cache__set(ffd->rev_root_id_cache, &entry->items[0].revision, (void *)(*noderev_p)->id, pool)); return SVN_NO_ERROR; @@ -2461,6 +2484,7 @@ block_read(void **result, fs_fs_data_t *ffd = fs->fsap_data; apr_off_t offset = 0; apr_off_t block_start = 0; + apr_uint32_t sub_item = 0; apr_array_header_t *entries; int run_count = 0; int i; @@ -2471,10 +2495,10 @@ block_read(void **result, /* don't try this on transaction protorev files */ SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision)); - /* index lookup: find the OFFSET of the item we *must* read plus - * the list of items in the same block. */ - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, revision, NULL, item_index, - iterpool)); + /* index lookup: find the OFFSET of the item we *must* read plus (in the + * "do-while" block) the list of items in the same block. */ + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs, revision, NULL, + item_index, iterpool)); do { SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, fs, revision, offset, @@ -2484,13 +2508,25 @@ block_read(void **result, /* read all items from the block */ for (i = 0; i < entries->nelts; ++i) { + svn_boolean_t is_result; + apr_pool_t *pool; + svn_fs_fs__p2l_entry_t* entry = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t); - svn_boolean_t is_result = result && entry->revision == revision - && entry->item_index == item_index; + + /* skip empty sections */ + if (entry->type == SVN_FS_FS__ITEM_TYPE_UNUSED) + continue; + + /* we don't support containers, yet */ + SVN_ERR_ASSERT(entry->item_count == 1); + + is_result = result && entry->item_count + && entry->items[0].revision == revision + && entry->items[0].number == item_index; /* select the pool that we want the item to be allocated in */ - apr_pool_t *pool = is_result ? result_pool : iterpool; + pool = is_result ? result_pool : iterpool; /* handle all items that start within this block and are relatively * small (i.e. < block size). Always read the item we need to return. @@ -2500,8 +2536,8 @@ block_read(void **result, { void *item = NULL; pair_cache_key_t key; - key.revision = entry->revision; - key.second = entry->item_index; + key.revision = entry->items[0].revision; + key.second = entry->items[0].number; SVN_ERR(svn_io_file_seek(revision_file, SEEK_SET, &entry->offset, iterpool)); Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/fs_fs.c Thu Mar 28 22:27:33 2013 @@ -925,9 +925,10 @@ write_revision_zero(svn_fs_t *fs) SVN_ERR(svn_io_file_create_binary (path, "\0\1\x80\x40\1\1" /* rev 0, single page */ - "\4\4" /* page size: count, bytes */ - "\0\x6b\x12\1", /* phys offsets + 1 */ - 12, + "\x8\4" /* page size: bytes, count */ + "\0\x6b\x12\1" /* phys offsets + 1 */ + "\0\0\0\0", /* sub-item indexes (all 0) */ + 16, fs->pool)); SVN_ERR(svn_io_set_file_read_only(path, FALSE, fs->pool)); @@ -935,13 +936,13 @@ write_revision_zero(svn_fs_t *fs) SVN_ERR(svn_io_file_create_binary (path, "\0" /* start rev */ - "\x80\x80\4\1\x13" /* 64k pages, 1 page using 19 bytes */ + "\x80\x80\4\1\x15" /* 64k pages, 1 page using 21 bytes */ "\0" /* offset entry 0 page 1 */ - "\x11\1\0\3" /* len, type, rev, item */ - "\x59\5\0\2" - "\1\6\0\1" - "\x95\xff\3\0\0\0", /* last entry fills up 64k page */ - 25, + "\x11\1\1\0\3" /* len, type, count, (rev, item)* */ + "\x59\5\1\0\2" + "\1\6\1\0\1" + "\x95\xff\3\0\0", /* last entry fills up 64k page */ + 27, fs->pool)); SVN_ERR(svn_io_set_file_read_only(path, FALSE, fs->pool)); } Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c Thu Mar 28 22:27:33 2013 @@ -89,17 +89,26 @@ typedef struct l2p_page_t * packed or non-packed rev file. Offset will be -1 for unused / * invalid item index values. */ apr_off_t *offsets; + + /* In case that the item is stored inside a container, this is the + * identifying index of the item within that container. 0 for the + * container itself or for items that aren't containers. */ + apr_uint32_t *sub_items; } l2p_page_t; /* All of the log-to-phys proto index file consist of entires of this type. */ typedef struct l2p_proto_entry_t { - /* phys offset + 1. 0 for "new revision" entries. */ + /* phys offset + 1 of the data container. 0 for "new revision" entries. */ apr_uint64_t offset; /* corresponding item index. 0 for "new revision" entries. */ apr_uint64_t item_index; + + /* index within the container starting @ offset. 0 for "new revision" + * entries and for items with no outer container. */ + apr_uint32_t sub_item; } l2p_proto_entry_t; /* Master run-time data structure of an phys-to-log index. It contains @@ -436,6 +445,7 @@ svn_fs_fs__l2p_proto_index_add_revision( svn_error_t * svn_fs_fs__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) { @@ -452,6 +462,9 @@ svn_fs_fs__l2p_proto_index_add_entry(apr SVN_ERR_ASSERT(item_index < UINT_MAX / 2); entry.item_index = item_index; + /* no limits on the container sub-item index */ + entry.sub_item = sub_item; + return svn_error_trace(write_entry_to_proto_index(proto_index, entry, pool)); } @@ -495,19 +508,21 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs to the target file in a second step */ apr_pool_t *local_pool = svn_pool_create(pool); apr_array_header_t *page_counts - = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); + = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); apr_array_header_t *page_sizes - = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); + = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); apr_array_header_t *entry_counts - = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); + = apr_array_make(local_pool, 16, sizeof(apr_uint64_t)); - /* collects the item offsets for the current revision */ + /* collect the item offsets and sub-item value for the current revision */ apr_array_header_t *offsets - = apr_array_make(local_pool, 256, sizeof(apr_uint64_t)); + = apr_array_make(local_pool, 256, sizeof(apr_uint64_t)); + apr_array_header_t *sub_items + = apr_array_make(local_pool, 256, sizeof(apr_uint32_t)); /* 64k blocks, spill after 16MB */ svn_spillbuf_t *buffer - = svn_spillbuf__create(0x10000, 0x1000000, local_pool); + = svn_spillbuf__create(0x10000, 0x1000000, local_pool); /* start at the beginning of the source file */ SVN_ERR(svn_io_file_open(&proto_index, proto_file_name, @@ -542,7 +557,17 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs for (k = i; k < i + entry_count; ++k) { - apr_uint64_t value = APR_ARRAY_IDX(offsets, k, apr_uint64_t); + apr_uint64_t value + = APR_ARRAY_IDX(offsets, k, apr_uint64_t); + SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, + encode_uint(encoded, value), + local_pool)); + } + + for (k = i; k < i + entry_count; ++k) + { + apr_uint64_t value + = APR_ARRAY_IDX(sub_items, k, apr_uint32_t); SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, encode_uint(encoded, value), local_pool)); @@ -554,6 +579,7 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs } apr_array_clear(offsets); + apr_array_clear(sub_items); /* store the number of pages in this revision */ APR_ARRAY_PUSH(page_counts, apr_uint64_t) @@ -565,12 +591,18 @@ svn_fs_fs__l2p_index_create(svn_fs_t *fs { /* store the mapping in our array */ int idx = (apr_size_t)proto_entry.item_index; + SVN_ERR_ASSERT(offsets->nelts == sub_items->nelts); + while (idx >= offsets->nelts) - APR_ARRAY_PUSH(offsets, apr_uint64_t) = 0; /* defaults to offset - '-1' / 'invalid' */ + { + APR_ARRAY_PUSH(offsets, apr_uint64_t) = 0; /* defaults to offset + '-1' / 'invalid' */ + APR_ARRAY_PUSH(sub_items, apr_uint32_t) = 0; + } SVN_ERR_ASSERT(APR_ARRAY_IDX(offsets, idx, apr_uint64_t) == 0); APR_ARRAY_IDX(offsets, idx, apr_uint64_t) = proto_entry.offset; + APR_ARRAY_IDX(sub_items, idx, apr_uint64_t) = proto_entry.sub_item; } } @@ -793,7 +825,7 @@ get_l2p_header_body(l2p_header_t **heade = apr_pcalloc(pool, (result->revision_count + 1) * sizeof(*result->page_table_index)); - /* read per-revision page table sizes */ + /* read per-revision page table sizes (i.e. number of pages per rev) */ page_table_index = 0; result->page_table_index[0] = page_table_index; for (i = 0; i < result->revision_count; ++i) @@ -922,8 +954,10 @@ get_l2p_page(l2p_page_t **page, result->entry_count = table_entry->entry_count; result->offsets = apr_pcalloc(pool, result->entry_count * sizeof(*result->offsets)); + result->sub_items = apr_pcalloc(pool, result->entry_count + * sizeof(*result->sub_items)); - /* read all page entries (offsets in rev file) */ + /* read all page entries (offsets in rev file and container sub-items) */ for (i = 0; i < result->entry_count; ++i) { SVN_ERR(packed_stream_get(&value, *stream)); @@ -931,16 +965,22 @@ get_l2p_page(l2p_page_t **page, '0' in the index file */ } + for (i = 0; i < result->entry_count; ++i) + { + SVN_ERR(packed_stream_get(&value, *stream)); + result->sub_items[i] = (apr_off_t)value; + } + *page = result; return SVN_NO_ERROR; } -/* Request data structure for l2p_page_access_func. This one is input - * parameters only, i.e. the request results will be passed back otherwise. +/* Request data structure for l2p_page_access_func. */ typedef struct l2p_page_baton_t { + /* in data */ /* revision. Used for error messages only */ svn_revnum_t revision; @@ -949,16 +989,24 @@ typedef struct l2p_page_baton_t /* offset within the cached page */ apr_uint32_t page_offset; + + /* out data */ + /* absolute item or container offset in rev / pack file */ + apr_off_t offset; + + /* 0 -> container / item itself; sub-item in container otherwise */ + apr_uint32_t sub_item; + } l2p_page_baton_t; /* Return the rev / pack file offset of the item at BATON->PAGE_OFFSET in * OFFSETS of PAGE and write it to *OFFSET. */ static svn_error_t * -l2p_page_get_offset(apr_off_t *offset, - l2p_page_baton_t *baton, +l2p_page_get_offset(l2p_page_baton_t *baton, const l2p_page_t *page, - const apr_off_t *offsets) + const apr_off_t *offsets, + const apr_uint32_t *sub_items) { /* overflow check */ if (page->entry_count <= baton->page_offset) @@ -968,7 +1016,8 @@ l2p_page_get_offset(apr_off_t *offset, baton->item_index, baton->revision); /* return the result */ - *offset = offsets[baton->page_offset]; + baton->offset = offsets[baton->page_offset]; + baton->sub_item = sub_items[baton->page_offset]; return SVN_NO_ERROR; } @@ -987,9 +1036,11 @@ l2p_page_access_func(void **out, const l2p_page_t *page = data; const apr_off_t *offsets = svn_temp_deserializer__ptr(page, (const void *const *)&page->offsets); + const apr_uint32_t *sub_items + = svn_temp_deserializer__ptr(page, (const void *const *)&page->sub_items); /* return the requested data */ - return l2p_page_get_offset((apr_off_t *)out, baton, page, offsets); + return l2p_page_get_offset(baton, page, offsets, sub_items); } /* Data request structure used by l2p_page_table_access_func. @@ -1160,6 +1211,7 @@ prefetch_l2p_pages(svn_boolean_t *end, */ static svn_error_t * l2p_index_lookup(apr_off_t *offset, + apr_uint32_t *sub_item, svn_fs_t *fs, svn_revnum_t revision, apr_uint64_t item_index, @@ -1172,6 +1224,7 @@ l2p_index_lookup(apr_off_t *offset, packed_number_stream_t *stream = NULL; svn_fs_fs__page_cache_key_t key = { 0 }; svn_boolean_t is_cached = FALSE; + void *dummy = NULL; /* read index master data structure and extract the info required to * access the l2p index page for (REVISION,ITEM_INDEX)*/ @@ -1188,9 +1241,10 @@ l2p_index_lookup(apr_off_t *offset, key.is_packed = is_packed_rev(fs, revision); key.page = info_baton.page_no; - SVN_ERR(svn_cache__get_partial((void**)offset, &is_cached, + SVN_ERR(svn_cache__get_partial(&dummy, &is_cached, ffd->l2p_page_cache, &key, l2p_page_access_func, &page_baton, pool)); + if (!is_cached) { /* we need to read the info from disk (might already be in the @@ -1213,7 +1267,8 @@ l2p_index_lookup(apr_off_t *offset, /* cache the page and extract the result we need */ SVN_ERR(svn_cache__set(ffd->l2p_page_cache, &key, page, pool)); - SVN_ERR(l2p_page_get_offset(offset, &page_baton, page, page->offsets)); + SVN_ERR(l2p_page_get_offset(&page_baton, page, page->offsets, + page->sub_items)); /* prefetch pages from following and preceding revisions */ pages = apr_array_make(pool, 16, sizeof(l2p_page_table_entry_t)); @@ -1250,6 +1305,9 @@ l2p_index_lookup(apr_off_t *offset, SVN_ERR(packed_stream_close(stream)); + *offset = page_baton.offset; + *sub_item = page_baton.sub_item; + return SVN_NO_ERROR; } @@ -1259,6 +1317,7 @@ l2p_index_lookup(apr_off_t *offset, */ static svn_error_t * l2p_proto_index_lookup(apr_off_t *offset, + apr_uint32_t *sub_item, svn_fs_t *fs, const svn_fs_fs__id_part_t *txn_id, apr_uint64_t item_index, @@ -1286,6 +1345,7 @@ l2p_proto_index_lookup(apr_off_t *offset if (!eof && entry.item_index == item_index) { *offset = (apr_off_t)entry.offset - 1; + *sub_item = (apr_off_t)entry.sub_item; break; } } @@ -1377,6 +1437,14 @@ svn_fs_fs__p2l_proto_index_add_entry(apr &written, pool)); SVN_ERR_ASSERT(written == sizeof(*entry)); + if (entry->item_count) + { + written = entry->item_count * sizeof(*entry->items); + SVN_ERR(svn_io_file_write_full(proto_index, entry->items, written, + &written, pool)); + SVN_ERR_ASSERT(written == entry->item_count * sizeof(*entry->items)); + } + return SVN_NO_ERROR; } @@ -1391,6 +1459,7 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs apr_uint64_t page_size = ffd->p2l_page_size; apr_file_t *proto_index = NULL; int i; + apr_uint32_t sub_item; svn_boolean_t eof = FALSE; apr_file_t *index_file; unsigned char encoded[ENCODED_INT_LENGTH]; @@ -1410,6 +1479,9 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs svn_spillbuf_t *buffer = svn_spillbuf__create(0x10000, 0x1000000, local_pool); + /* for loop temps ... */ + apr_pool_t *iter_pool = svn_pool_create(pool); + /* start at the beginning of the source file */ SVN_ERR(svn_io_file_open(&proto_index, proto_file_name, APR_READ | APR_CREATE | APR_BUFFERED, @@ -1420,14 +1492,25 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs { svn_fs_fs__p2l_entry_t entry; apr_size_t read = 0; + apr_size_t to_read; apr_uint64_t entry_end; svn_boolean_t new_page = svn_spillbuf__get_size(buffer) == 0; /* (attempt to) read the next entry from the source */ SVN_ERR(svn_io_file_read_full2(proto_index, &entry, sizeof(entry), - &read, &eof, local_pool)); + &read, &eof, iter_pool)); SVN_ERR_ASSERT(eof || read == sizeof(entry)); + if (entry.item_count && !eof) + { + to_read = entry.item_count * sizeof(*entry.items); + entry.items = apr_palloc(iter_pool, to_read); + + SVN_ERR(svn_io_file_read_full2(proto_index, entry.items, to_read, + &read, &eof, iter_pool)); + SVN_ERR_ASSERT(eof || read == to_read); + } + /* "unused" (and usually non-existent) section to cover the offsets at the end the of the last page. */ if (eof) @@ -1435,12 +1518,13 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs entry.offset = last_entry_end; entry.size = APR_ALIGN(entry.offset, page_size) - entry.offset; entry.type = 0; - entry.revision = 0; - entry.item_index = 0; + entry.item_count = 0; + entry.items = NULL; } - if (entry.revision == SVN_INVALID_REVNUM) - entry.revision = revision; + for (sub_item = 0; sub_item < entry.item_count; ++sub_item) + if (entry.items[sub_item].revision == SVN_INVALID_REVNUM) + entry.items[sub_item].revision = revision; /* end tables while entry is extending behind them */ entry_end = entry.offset + entry.size; @@ -1460,23 +1544,34 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs if (new_page) SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, encode_uint(encoded, entry.offset), - local_pool)); + iter_pool)); - /* write entry */ + /* write simple item / container entry */ SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, encode_uint(encoded, entry.size), - local_pool)); + iter_pool)); SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, encode_uint(encoded, entry.type), - local_pool)); - SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, - encode_uint(encoded, entry.revision), - local_pool)); + iter_pool)); SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, - encode_uint(encoded, entry.item_index), - local_pool)); + encode_uint(encoded, entry.item_count), + iter_pool)); + + /* container contents (only one for non-container items) */ + for (sub_item = 0; sub_item < entry.item_count; ++sub_item) + { + const svn_fs_fs__id_part_t *item = &entry.items[sub_item]; + SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, + encode_uint(encoded, item->revision), + iter_pool)); + SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded, + encode_uint(encoded, item->number), + iter_pool)); + } last_entry_end = entry_end; + + svn_pool_clear(iter_pool); } /* store length of last table */ @@ -1518,6 +1613,7 @@ svn_fs_fs__p2l_index_create(svn_fs_t *fs SVN_ERR(svn_io_file_close(index_file, local_pool)); SVN_ERR(svn_io_set_file_read_only(file_name, FALSE, local_pool)); + svn_pool_destroy(iter_pool); svn_pool_destroy(local_pool); return SVN_NO_ERROR; @@ -1679,6 +1775,7 @@ read_entry(packed_number_stream_t *strea apr_pool_t *pool) { apr_uint64_t value; + apr_uint32_t sub_item; svn_fs_fs__p2l_entry_t entry; @@ -1688,9 +1785,24 @@ read_entry(packed_number_stream_t *strea SVN_ERR(packed_stream_get(&value, stream)); entry.type = (int)value; SVN_ERR(packed_stream_get(&value, stream)); - entry.revision = (svn_revnum_t)value; - SVN_ERR(packed_stream_get(&value, stream)); - entry.item_index = value; + entry.item_count = (svn_revnum_t)value; + + if (entry.item_count == 0) + { + entry.items = NULL; + } + else + { + entry.items + = apr_pcalloc(pool, entry.item_count * sizeof(*entry.items)); + for (sub_item = 0; sub_item < entry.item_count; ++sub_item) + { + SVN_ERR(packed_stream_get(&value, stream)); + entry.items[sub_item].revision = (svn_revnum_t)value; + SVN_ERR(packed_stream_get(&value, stream)); + entry.items[sub_item].number = value; + } + } APR_ARRAY_PUSH(result, svn_fs_fs__p2l_entry_t) = entry; *item_offset += entry.size; @@ -1908,6 +2020,7 @@ svn_fs_fs__p2l_index_lookup(apr_array_he svn_error_t * svn_fs_fs__item_offset(apr_off_t *offset, + apr_uint32_t *sub_item, svn_fs_t *fs, svn_revnum_t revision, const svn_fs_fs__id_part_t *txn_id, @@ -1917,6 +2030,9 @@ svn_fs_fs__item_offset(apr_off_t *offset fs_fs_data_t *ffd = fs->fsap_data; if (ffd->format < SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT) { + /* older fsfs formats don't have containers */ + *sub_item = 0; + /* older fsfs formats use the manifest file to re-map the offsets */ *offset = (apr_off_t)item_index; if (!txn_id && is_packed_rev(fs, revision)) @@ -1930,9 +2046,11 @@ svn_fs_fs__item_offset(apr_off_t *offset } else if (txn_id) - SVN_ERR(l2p_proto_index_lookup(offset, fs, txn_id, item_index, pool)); + SVN_ERR(l2p_proto_index_lookup(offset, sub_item, + fs, txn_id, item_index, pool)); else - SVN_ERR(l2p_index_lookup(offset, fs, revision, item_index, pool)); + SVN_ERR(l2p_index_lookup(offset, sub_item, + fs, revision, item_index, pool)); return SVN_NO_ERROR; } @@ -2016,10 +2134,13 @@ svn_fs_fs__serialize_l2p_page(void **dat table_size + sizeof(*page) + 32, pool); - /* offsets array */ + /* offsets and sub_items arrays */ svn_temp_serializer__add_leaf(context, (const void * const *)&page->offsets, table_size); + svn_temp_serializer__add_leaf(context, + (const void * const *)&page->sub_items, + table_size); /* return the serialized result */ serialized = svn_temp_serializer__get(context); @@ -2038,8 +2159,9 @@ svn_fs_fs__deserialize_l2p_page(void **o { l2p_page_t *page = data; - /* resolve the only pointer in the struct */ + /* resolve the pointers in the struct */ svn_temp_deserializer__resolve(page, (void**)&page->offsets); + svn_temp_deserializer__resolve(page, (void**)&page->sub_items); /* done */ *out = page; @@ -2105,6 +2227,8 @@ svn_fs_fs__serialize_p2l_page(void **dat svn_temp_serializer__context_t *context; svn_stringbuf_t *serialized; apr_size_t table_size = page->elt_size * page->nelts; + svn_fs_fs__p2l_entry_t *entries = (svn_fs_fs__p2l_entry_t *)page->elts; + int i; /* serialize array header and all its elements */ context = svn_temp_serializer__init(page, @@ -2113,9 +2237,17 @@ svn_fs_fs__serialize_p2l_page(void **dat pool); /* items in the array */ - svn_temp_serializer__add_leaf(context, - (const void * const *)&page->elts, - table_size); + svn_temp_serializer__push(context, + (const void * const *)&page->elts, + table_size); + + for (i = 0; i < page->nelts; ++i) + svn_temp_serializer__add_leaf(context, + (const void * const *)&entries[i].items, + entries[i].item_count + * sizeof(*entries[i].items)); + + svn_temp_serializer__pop(context); /* return the serialized result */ serialized = svn_temp_serializer__get(context); @@ -2133,10 +2265,17 @@ svn_fs_fs__deserialize_p2l_page(void **o apr_pool_t *pool) { apr_array_header_t *page = (apr_array_header_t *)data; + svn_fs_fs__p2l_entry_t *entries; + int i; /* resolve the only pointer in the struct */ svn_temp_deserializer__resolve(page, (void**)&page->elts); + /* resolve sub-struct pointers*/ + entries = (svn_fs_fs__p2l_entry_t *)page->elts; + for (i = 0; i < page->nelts; ++i) + svn_temp_deserializer__resolve(entries, (void**)&entries[i].items); + /* patch up members */ page->pool = pool; page->nalloc = page->nelts; Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h Thu Mar 28 22:27:33 2013 @@ -62,11 +62,13 @@ typedef struct svn_fs_fs__p2l_entry_t /* type of the item (see SVN_FS_FS__ITEM_TYPE_*) defines */ unsigned type; - /* revision that the item belongs to */ - svn_revnum_t revision; + /* Number of items in this block / container. Their list can be found + * in *ITEMS. 0 for unused sections. 1 for non-container items, + * > 1 for containers. */ + apr_uint32_t item_count; - /* logical index of the item within that revision */ - apr_uint64_t item_index; + /* List of items in that block / container */ + svn_fs_fs__id_part_t *items; } svn_fs_fs__p2l_entry_t; /* Open / create a log-to-phys index file with the full file path name @@ -85,18 +87,20 @@ svn_error_t * svn_fs_fs__l2p_proto_index_add_revision(apr_file_t *proto_index, apr_pool_t *pool); -/* Add a new mapping, ITEM_INDEX to OFFSET, to log-to-phys index file in - * PROTO_INDEX. Please note that mappings may be added in any order but - * duplicate entries for the same ITEM_INDEX are not supported. Not all - * possible index values need to be used. OFFSET may be -1 to mark - * 'invalid' item indexes but that is already implied for all item indexes - * not explicitly given a mapping. +/* 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 + * in any order but duplicate entries for the same ITEM_INDEX, SUB_ITEM + * are not supported. Not all possible index values need to be used. + * (OFFSET, SUB_ITEM) may be (-1, 0) to mark 'invalid' item indexes but + * that is already implied for all item indexes not explicitly given a + * mapping. * * Use POOL for allocations. */ svn_error_t * svn_fs_fs__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); @@ -160,14 +164,16 @@ svn_fs_fs__p2l_index_lookup(apr_array_he apr_pool_t *pool); /* Use the log-to-phys mapping files in FS to find the packed / non-packed / - * proto-rev file offset of either (REVISION, ITEM_INDEX) or (TXN_ID, - * ITEM_INDEX). For committed revision, TXN_ID must be NULL. For format 6 - * and older repositories, we simply map the revision local offset given - * as ITEM_INDEX to the actual file offset (when packed). + * proto-rev file offset and container sub-item of either (REVISION, + * ITEM_INDEX) or (TXN_ID, ITEM_INDEX). *SUB_ITEM will be 0 for non- + * container items. For committed revision, TXN_ID must be NULL. For + * format 6 and older repositories, we simply map the revision local offset + * given as ITEM_INDEX to the actual file offset (when packed). * Use POOL for allocations. */ svn_error_t * svn_fs_fs__item_offset(apr_off_t *offset, + apr_uint32_t *sub_item, svn_fs_t *fs, svn_revnum_t revision, const svn_fs_fs__id_part_t *txn_id, Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c Thu Mar 28 22:27:33 2013 @@ -25,6 +25,7 @@ #include "svn_dirent_uri.h" #include "svn_sorts.h" #include "private/svn_temp_serializer.h" +#include "private/svn_subr_private.h" #include "fs_fs.h" #include "pack.h" @@ -419,6 +420,23 @@ write_null_bytes(apr_file_t *dest, return SVN_NO_ERROR; } +/* Return a (deep) copy of ENTRY, allocated in POOL. + */ +static svn_fs_fs__p2l_entry_t * +copy_p2l_entry(svn_fs_fs__p2l_entry_t *entry, + apr_pool_t *pool) +{ + svn_fs_fs__p2l_entry_t *new_entry = apr_palloc(pool, sizeof(*new_entry)); + *new_entry = *entry; + + if (new_entry->item_count) + new_entry->items = apr_pmemdup(pool, + entry->items, + entry->item_count * sizeof(*entry->items)); + + return new_entry; +} + /* Copy the "simple" item (changes list or property representation) from * the current position in REV_FILE to TEMP_FILE using CONTEXT. Add a * copy of ENTRY to ENTRIES but with an updated offset value that points @@ -432,9 +450,8 @@ copy_item_to_temp(pack_context_t *contex svn_fs_fs__p2l_entry_t *entry, apr_pool_t *pool) { - svn_fs_fs__p2l_entry_t *new_entry = apr_palloc(context->info_pool, - sizeof(*new_entry)); - *new_entry = *entry; + svn_fs_fs__p2l_entry_t *new_entry + = copy_p2l_entry(entry, context->info_pool); new_entry->offset = 0; SVN_ERR(svn_io_file_seek(temp_file, SEEK_CUR, &new_entry->offset, pool)); APR_ARRAY_PUSH(entries, svn_fs_fs__p2l_entry_t *) = new_entry; @@ -465,19 +482,23 @@ static void add_item_rep_mapping(pack_context_t *context, rep_info_t *info) { - /* index of INFO */ - int idx = get_item_array_index(context, - info->entry->revision, - info->entry->item_index); - - /* make sure the index exists in the array */ - while (context->reps_infos->nelts <= idx) - APR_ARRAY_PUSH(context->reps_infos, rep_info_t *) = NULL; - - /* set the element. If there is already an entry, there are probably - * two items claiming to be the same -> bail out */ - assert(!APR_ARRAY_IDX(context->reps_infos, idx, rep_info_t *)); - APR_ARRAY_IDX(context->reps_infos, idx, rep_info_t *) = info; + apr_uint32_t i; + for (i = 0; i < info->entry->item_count; ++i) + { + /* index of INFO */ + int idx = get_item_array_index(context, + info->entry->items[i].revision, + info->entry->items[i].number); + + /* make sure the index exists in the array */ + while (context->reps_infos->nelts <= idx) + APR_ARRAY_PUSH(context->reps_infos, rep_info_t *) = NULL; + + /* set the element. If there is already an entry, there are probably + * two items claiming to be the same -> bail out */ + assert(!APR_ARRAY_IDX(context->reps_infos, idx, rep_info_t *)); + APR_ARRAY_IDX(context->reps_infos, idx, rep_info_t *) = info; + } } /* Copy representation item identified by ENTRY from the current position @@ -496,8 +517,7 @@ copy_rep_to_temp(pack_context_t *context /* create a copy of ENTRY, make it point to the copy destination and * store it in CONTEXT */ - rep_info->entry = apr_palloc(context->info_pool, sizeof(*rep_info->entry)); - *rep_info->entry = *entry; + rep_info->entry = copy_p2l_entry(entry, context->info_pool); rep_info->entry->offset = 0; SVN_ERR(svn_io_file_seek(context->reps_file, SEEK_CUR, &rep_info->entry->offset, pool)); @@ -611,8 +631,7 @@ copy_node_to_temp(pack_context_t *contex /* create a copy of ENTRY, make it point to the copy destination and * store it in CONTEXT */ - rep_info->entry = apr_palloc(context->info_pool, sizeof(*rep_info->entry)); - *rep_info->entry = *entry; + rep_info->entry = copy_p2l_entry(entry, context->info_pool); rep_info->entry->offset = 0; SVN_ERR(svn_io_file_seek(context->reps_file, SEEK_CUR, &rep_info->entry->offset, pool)); @@ -707,11 +726,15 @@ compare_p2l_info(const svn_fs_fs__p2l_en const svn_fs_fs__p2l_entry_t * const * rhs) { assert(*lhs != *rhs); + if ((*lhs)->item_count == 0) + return (*lhs)->item_count == 0 ? 0 : -1; + if ((*lhs)->item_count == 0) + return 1; - if ((*lhs)->revision == (*rhs)->revision) - return (*lhs)->item_index > (*rhs)->item_index ? -1 : 1; + if ((*lhs)->items[0].revision == (*rhs)->items[0].revision) + return (*lhs)->items[0].number > (*rhs)->items[0].number ? -1 : 1; - return (*lhs)->revision > (*rhs)->revision ? -1 : 1; + return (*lhs)->items[0].revision > (*rhs)->items[0].revision ? -1 : 1; } /* Sort svn_fs_fs__p2l_entry_t * array ENTRIES by age. Place the latest @@ -732,21 +755,15 @@ compare_p2l_info_rev(const svn_fs_fs__p2 const svn_fs_fs__p2l_entry_t * const * rhs) { assert(*lhs != *rhs); + if ((*lhs)->item_count == 0) + return (*lhs)->item_count == 0 ? 0 : -1; + if ((*lhs)->item_count == 0) + return 1; - if ((*lhs)->revision == (*rhs)->revision) + if ((*lhs)->items[0].revision == (*rhs)->items[0].revision) return 0; - return (*lhs)->revision < (*rhs)->revision ? -1 : 1; -} - -/* Sort svn_fs_fs__p2l_entry_t * array ENTRIES by revision alone. - * Place the oldest items first. - */ -static void -sort_by_rev(apr_array_header_t *entries) -{ - qsort(entries->elts, entries->nelts, entries->elt_size, - (int (*)(const void *, const void *))compare_p2l_info_rev); + return (*lhs)->items[0].revision < (*rhs)->items[0].revision ? -1 : 1; } /* Part of the placement algorithm: starting at INFO, place all items @@ -813,7 +830,8 @@ sort_reps(pack_context_t *context) rep_info_t *info = APR_ARRAY_IDX(context->reps_infos, i, rep_info_t *); if ( info && info->entry - && info->entry->item_index == SVN_FS_FS__ITEM_INDEX_ROOT_NODE) + && info->entry->item_count == 1 + && info->entry->items[0].number == SVN_FS_FS__ITEM_INDEX_ROOT_NODE) do { APR_ARRAY_PUSH(context->reps, svn_fs_fs__p2l_entry_t *) @@ -890,11 +908,14 @@ copy_items_from_temp(pack_context_t *con /* Yes. To up with NUL bytes and don't forget to create * an P2L index entry marking this section as unused. */ svn_fs_fs__p2l_entry_t null_entry; + svn_fs_fs__id_part_t rev_item + = { 0, SVN_FS_FS__ITEM_INDEX_UNUSED }; + null_entry.offset = context->pack_offset; null_entry.size = bytes_to_alignment; null_entry.type = SVN_FS_FS__ITEM_TYPE_UNUSED; - null_entry.revision = 0; - null_entry.item_index = SVN_FS_FS__ITEM_INDEX_UNUSED; + null_entry.item_count = 1; + null_entry.items = &rev_item; SVN_ERR(write_null_bytes(context->pack_file, bytes_to_alignment, iterpool)); @@ -948,6 +969,8 @@ write_l2p_index(pack_context_t *context, apr_pool_t *iterpool = svn_pool_create(pool); svn_revnum_t prev_rev = SVN_INVALID_REVNUM; int i; + svn__priority_queue_t *queue; + apr_size_t count = 0; /* lump all items into one bucket. As target, use the bucket that * probably has the most entries already. */ @@ -955,27 +978,54 @@ write_l2p_index(pack_context_t *context, append_entries(context->reps, context->file_props); append_entries(context->reps, context->dir_props); - /* we need to write the index in ascending revision order */ - sort_by_rev(context->reps); - - /* write index entries */ + /* somewhat uncleanly re-purpose the SIZE field (the current content is + no longer needed): store the initial item count of each sub-container + in its size value. We will need that info after we decreased ITEM_COUNT + to the number of sub-items yet to process. */ for (i = 0; i < context->reps->nelts; ++i) { svn_fs_fs__p2l_entry_t *entry = APR_ARRAY_IDX(context->reps, i, svn_fs_fs__p2l_entry_t *); + entry->size = entry->item_count; + count += entry->item_count; + } + + /* we need to write the index in ascending revision order */ + queue = svn__priority_queue_create + (context->reps, + (int (*)(const void *, const void *))compare_p2l_info_rev); + + /* write index entries */ + for (i = 0; i < count; ++i) + { + svn_fs_fs__p2l_entry_t *entry + = *(svn_fs_fs__p2l_entry_t **)svn__priority_queue_peek(queue); + svn__priority_queue_pop(queue); + + if (entry->item_count == 0) + continue; /* next revision? */ - if (prev_rev != entry->revision) + if (prev_rev != entry->items[0].revision) { - prev_rev = entry->revision; + prev_rev = entry->items[0].revision; SVN_ERR(svn_fs_fs__l2p_proto_index_add_revision (context->proto_l2p_index, iterpool)); } /* add entry */ SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry - (context->proto_l2p_index, - entry->offset, entry->item_index, iterpool)); + (context->proto_l2p_index, entry->offset, + (apr_uint32_t)(entry->size - entry->item_count), + entry->items[0].number, iterpool)); + + /* process remaining sub-items (if any) of that container later */ + if (--entry->item_count) + { + SVN_ERR_ASSERT(entry->items[0].revision <= entry->items[1].revision); + ++entry->items; + svn__priority_queue_push(queue, entry); + } /* keep memory usage in check */ if (i % 256 == 0) @@ -1174,11 +1224,14 @@ append_revision(pack_context_t *context, offset = entry->offset; if (offset < finfo.size) { + /* there should be true containers */ + SVN_ERR_ASSERT(entry->item_count == 1); + entry->offset += context->pack_offset; offset += entry->size; SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry - (context->proto_l2p_index, - entry->offset, entry->item_index, iterpool)); + (context->proto_l2p_index, entry->offset, 0, + entry->items[0].number, iterpool)); SVN_ERR(svn_fs_fs__p2l_proto_index_add_entry (context->proto_p2l_index, entry, iterpool)); } @@ -1638,8 +1691,8 @@ pack_body(void *baton, pb->fs, i, ffd->max_files_per_dir, ffd->revprop_pack_size, ffd->compress_packed_revprops - ? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT - : SVN_DELTA_COMPRESSION_LEVEL_NONE, + ? SVN__COMPRESSION_ZLIB_DEFAULT + : SVN__COMPRESSION_NONE, pb->notify_func, pb->notify_baton, pb->cancel_func, pb->cancel_baton, iterpool)); } Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/recovery.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/recovery.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/recovery.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/recovery.c Thu Mar 28 22:27:33 2013 @@ -159,6 +159,7 @@ recover_find_max_ids(svn_fs_t *fs, svn_r apr_hash_index_t *hi; apr_pool_t *iterpool; node_revision_t *noderev; + apr_uint32_t sub_item; SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool)); SVN_ERR(svn_fs_fs__read_noderev(&noderev, @@ -184,8 +185,9 @@ recover_find_max_ids(svn_fs_t *fs, svn_r /* We could use get_dir_contents(), but this is much cheaper. It does rely on directory entries being stored as PLAIN reps, though. */ - SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev, NULL, + SVN_ERR(svn_fs_fs__item_offset(&offset, &sub_item, fs, rev, NULL, noderev->data_rep->item_index, pool)); + SVN_ERR_ASSERT(sub_item == 0); SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &offset, pool)); baton.stream = svn_stream_from_aprfile2(rev_file, TRUE, pool); @@ -267,11 +269,13 @@ recover_find_max_ids(svn_fs_t *fs, svn_r continue; SVN_ERR(svn_fs_fs__item_offset(&child_dir_offset, + &sub_item, fs, rev_item->revision, NULL, rev_item->number, iterpool)); + SVN_ERR_ASSERT(sub_item == 0); SVN_ERR(recover_find_max_ids(fs, rev, rev_file, child_dir_offset, max_node_id, max_copy_id, iterpool)); } @@ -288,6 +292,7 @@ svn_fs_fs__find_max_ids(svn_fs_t *fs, sv { fs_fs_data_t *ffd = fs->fsap_data; apr_off_t root_offset; + apr_uint32_t sub_item; apr_file_t *rev_file; svn_fs_id_t *root_id; @@ -295,11 +300,12 @@ svn_fs_fs__find_max_ids(svn_fs_t *fs, sv SVN_ERR_ASSERT(ffd->format < SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT); SVN_ERR(svn_fs_fs__rev_get_root(&root_id, fs, youngest, pool)); - SVN_ERR(svn_fs_fs__item_offset(&root_offset, fs, + SVN_ERR(svn_fs_fs__item_offset(&root_offset, &sub_item, fs, svn_fs_fs__id_rev(root_id), NULL, svn_fs_fs__id_item(root_id), pool)); + SVN_ERR_ASSERT(sub_item == 0); SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, fs, youngest, pool)); SVN_ERR(recover_find_max_ids(fs, youngest, rev_file, root_offset, Modified: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c URL: http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c?rev=1462329&r1=1462328&r2=1462329&view=diff ============================================================================== --- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c (original) +++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/transaction.c Thu Mar 28 22:27:33 2013 @@ -1631,7 +1631,7 @@ store_l2p_index_entry(svn_fs_t *fs, const char *path = path_l2p_proto_index(fs, txn_id, pool); apr_file_t *file; SVN_ERR(svn_fs_fs__l2p_proto_index_open(&file, path, pool)); - SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry(file, offset, + SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry(file, offset, 0, item_index, pool)); SVN_ERR(svn_io_file_close(file, pool)); } @@ -2155,12 +2155,16 @@ rep_write_contents_close(void *baton) if (!old_rep) { svn_fs_fs__p2l_entry_t entry; + svn_fs_fs__id_part_t rev_item; + rev_item.revision = SVN_INVALID_REVNUM; + rev_item.number = rep->item_index; + entry.offset = b->rep_offset; SVN_ERR(get_file_offset(&offset, b->file, b->pool)); entry.size = offset - b->rep_offset; entry.type = SVN_FS_FS__ITEM_TYPE_FILE_REP; - entry.revision = SVN_INVALID_REVNUM; - entry.item_index = rep->item_index; + entry.item_count = 1; + entry.items = &rev_item; SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->pool)); SVN_ERR(store_p2l_index_entry(b->fs, &rep->txn_id, &entry, b->pool)); @@ -2402,6 +2406,7 @@ write_hash_rep(representation_t *rep, else { svn_fs_fs__p2l_entry_t entry; + svn_fs_fs__id_part_t rev_item; /* Write out our cosmetic end marker. */ SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n")); @@ -2409,12 +2414,15 @@ write_hash_rep(representation_t *rep, SVN_ERR(allocate_item_index(&rep->item_index, fs, txn_id, offset, pool)); + rev_item.revision = SVN_INVALID_REVNUM; + rev_item.number = rep->item_index; + entry.offset = offset; SVN_ERR(get_file_offset(&offset, file, pool)); entry.size = offset - entry.offset; entry.type = item_type; - entry.revision = SVN_INVALID_REVNUM; - entry.item_index = rep->item_index; + entry.item_count = 1; + entry.items = &rev_item; SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, pool)); /* update the representation */ @@ -2526,6 +2534,7 @@ write_hash_delta_rep(representation_t *r else { svn_fs_fs__p2l_entry_t entry; + svn_fs_fs__id_part_t rev_item; /* Write out our cosmetic end marker. */ SVN_ERR(get_file_offset(&rep_end, file, pool)); @@ -2534,12 +2543,15 @@ write_hash_delta_rep(representation_t *r SVN_ERR(allocate_item_index(&rep->item_index, fs, txn_id, offset, pool)); + rev_item.revision = SVN_INVALID_REVNUM; + rev_item.number = rep->item_index; + entry.offset = offset; SVN_ERR(get_file_offset(&offset, file, pool)); entry.size = offset - entry.offset; entry.type = item_type; - entry.revision = SVN_INVALID_REVNUM; - entry.item_index = rep->item_index; + entry.item_count = 1; + entry.items = &rev_item; SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, pool)); @@ -2867,12 +2879,14 @@ write_final_rev(const svn_fs_id_t **new_ if (ffd->format >= SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT) { svn_fs_fs__p2l_entry_t entry; + rev_item.revision = SVN_INVALID_REVNUM; + entry.offset = my_offset; SVN_ERR(get_file_offset(&my_offset, file, pool)); entry.size = my_offset - entry.offset; entry.type = SVN_FS_FS__ITEM_TYPE_NODEREV; - entry.revision = SVN_INVALID_REVNUM; - entry.item_index = rev_item.number; + entry.item_count = 1; + entry.items = &rev_item; SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, pool)); } @@ -2911,12 +2925,15 @@ write_final_changed_path_info(apr_off_t if (ffd->format >= SVN_FS_FS__MIN_LOG_ADDRESSING_FORMAT) { svn_fs_fs__p2l_entry_t entry; + svn_fs_fs__id_part_t rev_item + = {SVN_INVALID_REVNUM, SVN_FS_FS__ITEM_INDEX_CHANGES}; + entry.offset = offset; SVN_ERR(get_file_offset(&offset, file, pool)); entry.size = offset - entry.offset; entry.type = SVN_FS_FS__ITEM_TYPE_CHANGES; - entry.revision = SVN_INVALID_REVNUM; - entry.item_index = SVN_FS_FS__ITEM_INDEX_CHANGES; + entry.item_count = 1; + entry.items = &rev_item; SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, pool)); SVN_ERR(store_l2p_index_entry(fs, txn_id, entry.offset, @@ -3107,12 +3124,15 @@ commit_body(void *baton, apr_pool_t *poo svn_stringbuf_t *trailer; apr_off_t root_offset; + apr_uint32_t sub_item; SVN_ERR(svn_fs_fs__item_offset(&root_offset, + &sub_item, cb->fs, svn_fs_fs__id_rev(new_root_id), NULL, svn_fs_fs__id_item(new_root_id), pool)); + SVN_ERR_ASSERT(sub_item == 0); trailer = svn_fs_fs__unparse_revision_trailer (root_offset, changed_path_offset,