Author: stefan2
Date: Sat Apr 27 19:50:26 2013
New Revision: 1476661

URL: http://svn.apache.org/r1476661
Log:
On the fsfs-format7 branch:  Refine our block stuffing strategy during
pack() to minimize the reads that span more than one block.

* subversion/libsvn_fs_fs/pack.c
  (select_block_entries): don't place parsed items near the end of the block;
                          replace large items overlapping the block boundary
                          with smaller ones from the next block

Modified:
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c

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=1476661&r1=1476660&r2=1476661&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/pack.c Sat Apr 27 
19:50:26 2013
@@ -960,16 +960,72 @@ select_block_entries(int *entries_in_blo
   /* Estimate extra capacity we will gain from container compression. */
   apr_size_t pack_savings = 0;
 
-  /* If the next item does not fit into the current block, auto-pad it. */
+  /* If the next item does not fit into the current block, auto-pad it.
+     Take special care of textual noderevs since their parsers may prefetch
+     up to 80 bytes and we don't want them to cross block boundaries. */
   svn_fs_fs__p2l_entry_t *first_entry
     = APR_ARRAY_IDX(entries, start_index, svn_fs_fs__p2l_entry_t *);
-  if (first_entry->size > capacity_left)
+  apr_off_t safety_margin
+    = first_entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV ? 80 : 0;
+  if (first_entry->size + safety_margin > capacity_left)
     {
       SVN_ERR(auto_pad_block(context, pool));
       capacity_left = ffd->block_size
                     - (context->pack_offset % ffd->block_size);
     }
 
+  /* try pulling in items from the next block if the first item does not fit
+     but is small enough that it might be packed nicely with the next block.
+   */
+  if (   first_entry->size > capacity_left
+      && first_entry->size < ffd->block_size / 2)
+    {
+      /* frist, try to pull in the first N elements from the next block */
+      apr_off_t pulled_in = 0;
+      for (i = start_index + 1; i < entries->nelts; ++i)
+        {
+          svn_fs_fs__p2l_entry_t *entry
+            = APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t *);
+          if (   pulled_in + entry->size > 2 * capacity_left
+              || entry->size > capacity_left)
+            break;
+
+          pulled_in += entry->size;
+        }
+
+      /* if the first one is already to large, look for the largest entry
+         in the next block that still does fit. */
+      if (--i == start_index)
+        {
+          apr_off_t checked = 0;
+          apr_off_t best_size = 0;
+          int best_fit = start_index;
+          for (i = start_index + 1; i < entries->nelts && checked < 
ffd->block_size; ++i)
+            {
+              svn_fs_fs__p2l_entry_t *entry
+                = APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t *);
+              if (entry->size < capacity_left && entry->size > best_size)
+                {
+                  best_fit = i;
+                  best_size = entry->size;
+                }
+
+              checked += entry->size;
+            }
+
+          i = best_fit;
+        }
+
+      /* if we found a such entry(es), swap them with the current one. */
+      if (i != start_index)
+        {
+          APR_ARRAY_IDX(entries, start_index, svn_fs_fs__p2l_entry_t *)
+            = APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t *);
+          APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t *)
+            = first_entry;
+        }
+    }
+
   /* try to fit as many items into the current block as possible */
   for (i = start_index; i < entries->nelts; ++i)
     {
@@ -1070,6 +1126,15 @@ select_block_entries(int *entries_in_blo
       SVN_ERR(svn_fs_fs__p2l_proto_index_add_entry
                 (context->proto_p2l_index, container_entry, pool));
     }
+  else if (*entries_in_block > 1)
+    {
+      /* due to the way our parsers prefetch data, it's a bad idea to end
+       * a block with a textual noderev representations */
+      svn_fs_fs__p2l_entry_t *entry
+        = APR_ARRAY_IDX(entries, i - 1, svn_fs_fs__p2l_entry_t *);
+      if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
+        --*entries_in_block;
+    }
 
   return SVN_NO_ERROR;
 }


Reply via email to