subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
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 GMT
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,



Mime
View raw message