You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by rh...@apache.org on 2015/11/30 11:24:23 UTC

svn commit: r1717223 [16/50] - in /subversion/branches/ra-git: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ contrib/hook-scripts/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/...

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c Mon Nov 30 10:24:16 2015
@@ -25,9 +25,11 @@
 #include "svn_pools.h"
 #include "svn_hash.h"
 #include "svn_dirent_uri.h"
+#include "svn_sorts.h"
 
 #include "fs_fs.h"
 #include "revprops.h"
+#include "temp_serializer.h"
 #include "util.h"
 
 #include "private/svn_subr_private.h"
@@ -36,11 +38,6 @@
 
 #include "svn_private_config.h"
 
-/* Give writing processes 10 seconds to replace an existing revprop
-   file with a new one. After that time, we assume that the writing
-   process got aborted and that we have re-read revprops. */
-#define REVPROP_CHANGE_TIMEOUT (10 * 1000000)
-
 svn_error_t *
 svn_fs_fs__upgrade_pack_revprops(svn_fs_t *fs,
                                  svn_fs_upgrade_notify_t notify_func,
@@ -144,9 +141,6 @@ typedef struct packed_revprops_t
   /* revision number to read (not necessarily the first in the pack) */
   svn_revnum_t revision;
 
-  /* current revprop generation. Used when populating the revprop cache */
-  apr_int64_t generation;
-
   /* the actual revision properties */
   apr_hash_t *properties;
 
@@ -189,35 +183,73 @@ typedef struct packed_revprops_t
 
 /* Parse the serialized revprops in CONTENT and return them in *PROPERTIES.
  * Also, put them into the revprop cache, if activated, for future use.
- * Three more parameters are being used to update the revprop cache: FS is
- * our file system, the revprops belong to REVISION and the global revprop
- * GENERATION is used as well.
  *
- * The returned hash will be allocated in POOL, SCRATCH_POOL is being used
- * for temporary allocations.
+ * The returned hash will be allocated in RESULT_POOL, SCRATCH_POOL is being
+ * used for temporary allocations.
  */
 static svn_error_t *
 parse_revprop(apr_hash_t **properties,
               svn_fs_t *fs,
               svn_revnum_t revision,
-              apr_int64_t generation,
               svn_string_t *content,
-              apr_pool_t *pool,
+              apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
   svn_stream_t *stream = svn_stream_from_string(content, scratch_pool);
-  *properties = apr_hash_make(pool);
+  *properties = apr_hash_make(result_pool);
 
-  SVN_ERR_W(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR, pool),
+  SVN_ERR_W(svn_hash_read2(*properties, stream, SVN_HASH_TERMINATOR,
+                           result_pool),
             apr_psprintf(scratch_pool, "Failed to parse revprops for r%ld.",
                          revision));
 
   return SVN_NO_ERROR;
 }
 
+void
+svn_fs_fs__reset_revprop_cache(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  ffd->revprop_prefix = 0;
+}
+
+/* If FS has not a revprop cache prefix set, generate one.
+ * Always call this before accessing the revprop cache.
+ */
+static svn_error_t *
+prepare_revprop_cache(svn_fs_t *fs,
+                      apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  if (!ffd->revprop_prefix)
+    SVN_ERR(svn_atomic__unique_counter(&ffd->revprop_prefix));
+
+  return SVN_NO_ERROR;
+}
+
+/* Store the unparsed revprop hash CONTENT for REVISION in FS's revprop
+ * cache.  Use SCRATCH_POOL for temporary allocations. */
+static svn_error_t *
+cache_revprops(svn_fs_t *fs,
+               svn_revnum_t revision,
+               svn_string_t *content,
+               apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  pair_cache_key_t key;
+
+  /* Make sure prepare_revprop_cache() has been called. */
+  SVN_ERR_ASSERT(ffd->revprop_prefix);
+  key.revision = revision;
+  key.second = ffd->revprop_prefix;
+
+  SVN_ERR(svn_cache__set(ffd->revprop_cache, &key, content, scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Read the non-packed revprops for revision REV in FS, put them into the
- * revprop cache if activated and return them in *PROPERTIES.  GENERATION
- * is the current revprop generation.
+ * revprop cache if PROPULATE_CACHE is set and return them in *PROPERTIES. 
  *
  * If the data could not be read due to an otherwise recoverable error,
  * leave *PROPERTIES unchanged. No error will be returned in that case.
@@ -228,7 +260,7 @@ static svn_error_t *
 read_non_packed_revprop(apr_hash_t **properties,
                         svn_fs_t *fs,
                         svn_revnum_t rev,
-                        apr_int64_t generation,
+                        svn_boolean_t populate_cache,
                         apr_pool_t *pool)
 {
   svn_stringbuf_t *content = NULL;
@@ -249,9 +281,13 @@ read_non_packed_revprop(apr_hash_t **pro
     }
 
   if (content)
-    SVN_ERR(parse_revprop(properties, fs, rev, generation,
-                          svn_stringbuf__morph_into_string(content),
-                          pool, iterpool));
+    {
+      svn_string_t *as_string = svn_stringbuf__morph_into_string(content);
+      SVN_ERR(parse_revprop(properties, fs, rev, as_string, pool, iterpool));
+
+      if (populate_cache)
+        SVN_ERR(cache_revprops(fs, rev, as_string, iterpool));
+    }
 
   svn_pool_clear(iterpool);
 
@@ -272,12 +308,13 @@ get_min_filename_len(packed_revprops_t *
 }
 
 /* Given FS and REVPROPS->REVISION, fill the FILENAME, FOLDER and MANIFEST
- * members. Use POOL for allocating results and SCRATCH_POOL for temporaries.
+ * members. Use RESULT_POOL for allocating results and SCRATCH_POOL for
+ * temporaries.
  */
 static svn_error_t *
 get_revprop_packname(svn_fs_t *fs,
                      packed_revprops_t *revprops,
-                     apr_pool_t *pool,
+                     apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -298,18 +335,20 @@ get_revprop_packname(svn_fs_t *fs,
       --rev_count;
     }
 
-  revprops->manifest = apr_array_make(pool, rev_count, sizeof(const char*));
+  revprops->manifest = apr_array_make(result_pool, rev_count,
+                                      sizeof(const char*));
 
   /* No line in the file can be less than this number of chars long. */
   min_filename_len = get_min_filename_len(revprops);
 
   /* Read the content of the manifest file */
   revprops->folder
-    = svn_fs_fs__path_revprops_pack_shard(fs, revprops->revision, pool);
+    = svn_fs_fs__path_revprops_pack_shard(fs, revprops->revision,
+                                          result_pool);
   manifest_file_path
-    = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
+    = svn_dirent_join(revprops->folder, PATH_MANIFEST, result_pool);
 
-  SVN_ERR(svn_fs_fs__read_content(&content, manifest_file_path, pool));
+  SVN_ERR(svn_fs_fs__read_content(&content, manifest_file_path, result_pool));
 
   /* There CONTENT must have a certain minimal size and there no
    * unterminated lines at the end of the file.  Both guarantees also
@@ -392,7 +431,8 @@ same_shard(svn_fs_t *fs,
 /* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS,
  * fill the START_REVISION member, and make PACKED_REVPROPS point to the
  * first serialized revprop.  If READ_ALL is set, initialize the SIZES
- * and OFFSETS members as well.
+ * and OFFSETS members as well.  If POPULATE_CACHE is set, cache all
+ * revprops found in this pack.
  *
  * Parse the revprops for REVPROPS->REVISION and set the PROPERTIES as
  * well as the SERIALIZED_SIZE member.  If revprop caching has been
@@ -402,20 +442,22 @@ static svn_error_t *
 parse_packed_revprops(svn_fs_t *fs,
                       packed_revprops_t *revprops,
                       svn_boolean_t read_all,
-                      apr_pool_t *pool,
+                      svn_boolean_t populate_cache,
+                      apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 {
   svn_stream_t *stream;
   apr_int64_t first_rev, count, i;
-  apr_off_t offset;
+  apr_size_t offset;
   const char *header_end;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
   /* decompress (even if the data is only "stored", there is still a
    * length header to remove) */
   svn_stringbuf_t *compressed = revprops->packed_revprops;
-  svn_stringbuf_t *uncompressed = svn_stringbuf_create_empty(pool);
-  SVN_ERR(svn__decompress(compressed, uncompressed, APR_SIZE_MAX));
+  svn_stringbuf_t *uncompressed = svn_stringbuf_create_empty(result_pool);
+  SVN_ERR(svn__decompress(compressed->data, compressed->len,
+                          uncompressed, APR_SIZE_MAX));
 
   /* read first revision number and number of revisions in the pack */
   stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
@@ -453,18 +495,21 @@ parse_packed_revprops(svn_fs_t *fs,
 
   offset = header_end - uncompressed->data + 2;
 
-  revprops->packed_revprops = svn_stringbuf_create_empty(pool);
+  revprops->packed_revprops = svn_stringbuf_create_empty(result_pool);
   revprops->packed_revprops->data = uncompressed->data + offset;
   revprops->packed_revprops->len = (apr_size_t)(uncompressed->len - offset);
-  revprops->packed_revprops->blocksize = (apr_size_t)(uncompressed->blocksize - offset);
+  revprops->packed_revprops->blocksize = (apr_size_t)(uncompressed->blocksize
+                                                      - offset);
 
   /* STREAM still points to the first entry in the sizes list. */
   revprops->start_revision = (svn_revnum_t)first_rev;
   if (read_all)
     {
       /* Init / construct REVPROPS members. */
-      revprops->sizes = apr_array_make(pool, (int)count, sizeof(offset));
-      revprops->offsets = apr_array_make(pool, (int)count, sizeof(offset));
+      revprops->sizes = apr_array_make(result_pool, (int)count,
+                                       sizeof(offset));
+      revprops->offsets = apr_array_make(result_pool, (int)count,
+                                         sizeof(offset));
     }
 
   /* Now parse, revision by revision, the size and content of each
@@ -489,21 +534,24 @@ parse_packed_revprops(svn_fs_t *fs,
 
       if (revision == revprops->revision)
         {
+          /* Parse (and possibly cache) the one revprop list we care about. */
           SVN_ERR(parse_revprop(&revprops->properties, fs, revision,
-                                revprops->generation, &serialized,
-                                pool, iterpool));
+                                &serialized, result_pool, iterpool));
           revprops->serialized_size = serialized.len;
 
           /* If we only wanted the revprops for REVISION then we are done. */
-          if (!read_all)
+          if (!read_all && !populate_cache)
             break;
         }
 
+      if (populate_cache)
+        SVN_ERR(cache_revprops(fs, revision, &serialized, iterpool));
+
       if (read_all)
         {
           /* fill REVPROPS data structures */
-          APR_ARRAY_PUSH(revprops->sizes, apr_off_t) = serialized.len;
-          APR_ARRAY_PUSH(revprops->offsets, apr_off_t) = offset;
+          APR_ARRAY_PUSH(revprops->sizes, apr_size_t) = serialized.len;
+          APR_ARRAY_PUSH(revprops->offsets, apr_size_t) = offset;
         }
       revprops->total_size += serialized.len;
 
@@ -514,7 +562,7 @@ parse_packed_revprops(svn_fs_t *fs,
 }
 
 /* In filesystem FS, read the packed revprops for revision REV into
- * *REVPROPS.  Use GENERATION to populate the revprop cache, if enabled.
+ * *REVPROPS. Populate the revprop cache, if POPULATE_CACHE is set.
  * If you want to modify revprop contents / update REVPROPS, READ_ALL
  * must be set.  Otherwise, only the properties of REV are being provided.
  * Allocate data in POOL.
@@ -523,8 +571,8 @@ static svn_error_t *
 read_pack_revprop(packed_revprops_t **revprops,
                   svn_fs_t *fs,
                   svn_revnum_t rev,
-                  apr_int64_t generation,
                   svn_boolean_t read_all,
+                  svn_boolean_t populate_cache,
                   apr_pool_t *pool)
 {
   apr_pool_t *iterpool = svn_pool_create(pool);
@@ -544,7 +592,6 @@ read_pack_revprop(packed_revprops_t **re
   /* initialize the result data structure */
   result = apr_pcalloc(pool, sizeof(*result));
   result->revision = rev;
-  result->generation = generation;
 
   /* try to read the packed revprops. This may require retries if we have
    * concurrent writers. */
@@ -575,7 +622,8 @@ read_pack_revprop(packed_revprops_t **re
                   _("Failed to read revprop pack file for r%ld"), rev);
 
   /* parse it. RESULT will be complete afterwards. */
-  err = parse_packed_revprops(fs, result, read_all, pool, iterpool);
+  err = parse_packed_revprops(fs, result, read_all, populate_cache, pool,
+                              iterpool);
   svn_pool_destroy(iterpool);
   if (err)
     return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
@@ -594,16 +642,48 @@ svn_error_t *
 svn_fs_fs__get_revision_proplist(apr_hash_t **proplist_p,
                                  svn_fs_t *fs,
                                  svn_revnum_t rev,
-                                 apr_pool_t *pool)
+                                 svn_boolean_t refresh,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  apr_int64_t generation = 0;
+
+  /* Only populate the cache if we did not just cross a sync barrier.
+   * This is to eliminate overhead from code that always sets REFRESH.
+   * For callers that want caching, the caching kicks in on read "later". */
+  svn_boolean_t populate_cache = !refresh;
 
   /* not found, yet */
   *proplist_p = NULL;
 
   /* should they be available at all? */
-  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
+  SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, scratch_pool));
+
+  if (refresh)
+    {
+      /* Previous cache contents is invalid now. */
+      svn_fs_fs__reset_revprop_cache(fs);
+    }
+  else
+    {
+      /* Try cache lookup first. */
+      svn_boolean_t is_cached;
+      pair_cache_key_t key;
+
+      /* Auto-alloc prefix and construct the key. */
+      SVN_ERR(prepare_revprop_cache(fs, scratch_pool));
+      key.revision = rev;
+      key.second = ffd->revprop_prefix;
+
+      /* The only way that this might error out is due to parser error. */
+      SVN_ERR_W(svn_cache__get((void **) proplist_p, &is_cached,
+                               ffd->revprop_cache, &key, result_pool),
+                apr_psprintf(scratch_pool,
+                             "Failed to parse revprops for r%ld.",
+                             rev));
+      if (is_cached)
+        return SVN_NO_ERROR;
+    }
 
   /* if REV had not been packed when we began, try reading it from the
    * non-packed shard.  If that fails, we will fall through to packed
@@ -611,7 +691,7 @@ svn_fs_fs__get_revision_proplist(apr_has
   if (!svn_fs_fs__is_packed_revprop(fs, rev))
     {
       svn_error_t *err = read_non_packed_revprop(proplist_p, fs, rev,
-                                                 generation, pool);
+                                                 populate_cache, result_pool);
       if (err)
         {
           if (!APR_STATUS_IS_ENOENT(err->apr_err)
@@ -629,7 +709,8 @@ svn_fs_fs__get_revision_proplist(apr_has
   if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT && !*proplist_p)
     {
       packed_revprops_t *revprops;
-      SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, FALSE, pool));
+      SVN_ERR(read_pack_revprop(&revprops, fs, rev, FALSE, populate_cache,
+                                result_pool));
       *proplist_p = revprops->properties;
     }
 
@@ -657,17 +738,23 @@ write_non_packed_revprop(const char **fi
                          apr_hash_t *proplist,
                          apr_pool_t *pool)
 {
+  apr_file_t *file;
   svn_stream_t *stream;
   *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
 
   /* ### do we have a directory sitting around already? we really shouldn't
      ### have to get the dirname here. */
-  SVN_ERR(svn_stream_open_unique(&stream, tmp_path,
-                                 svn_dirent_dirname(*final_path, pool),
-                                 svn_io_file_del_none, pool, pool));
+  SVN_ERR(svn_io_open_unique_file3(&file, tmp_path,
+                                   svn_dirent_dirname(*final_path, pool),
+                                   svn_io_file_del_none, pool, pool));
+  stream = svn_stream_from_aprfile2(file, TRUE, pool);
   SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(stream));
 
+  /* Flush temporary file to disk and close it. */
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -738,8 +825,8 @@ serialize_revprops_header(svn_stream_t *
        * We only allocate a few bytes each iteration -- even with a
        * million iterations we would still be in good shape memory-wise.
        */
-      apr_off_t size = APR_ARRAY_IDX(sizes, i, apr_off_t);
-      SVN_ERR(svn_stream_printf(stream, iterpool, "%" APR_OFF_T_FMT "\n",
+      apr_size_t size = APR_ARRAY_IDX(sizes, i, apr_size_t);
+      SVN_ERR(svn_stream_printf(stream, iterpool, "%" APR_SIZE_T_FMT "\n",
                                 size));
     }
 
@@ -750,7 +837,7 @@ serialize_revprops_header(svn_stream_t *
   return SVN_NO_ERROR;
 }
 
-/* Writes the a pack file to FILE_STREAM.  It copies the serialized data
+/* Writes the a pack file to FILE.  It copies the serialized data
  * from REVPROPS for the indexes [START,END) except for index CHANGED_INDEX.
  *
  * The data for the latter is taken from NEW_SERIALIZED.  Note, that
@@ -767,8 +854,8 @@ repack_revprops(svn_fs_t *fs,
                 int end,
                 int changed_index,
                 svn_stringbuf_t *new_serialized,
-                apr_off_t new_total_size,
-                svn_stream_t *file_stream,
+                apr_size_t new_total_size,
+                apr_file_t *file,
                 apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -796,10 +883,8 @@ repack_revprops(svn_fs_t *fs,
       }
     else
       {
-        apr_size_t size
-            = (apr_size_t)APR_ARRAY_IDX(revprops->sizes, i, apr_off_t);
-        apr_size_t offset
-            = (apr_size_t)APR_ARRAY_IDX(revprops->offsets, i, apr_off_t);
+        apr_size_t size = APR_ARRAY_IDX(revprops->sizes, i, apr_size_t);
+        apr_size_t offset = APR_ARRAY_IDX(revprops->offsets, i, apr_size_t);
 
         SVN_ERR(svn_stream_write(stream,
                                  revprops->packed_revprops->data + offset,
@@ -810,15 +895,17 @@ repack_revprops(svn_fs_t *fs,
   SVN_ERR(svn_stream_close(stream));
 
   /* compress / store the data */
-  SVN_ERR(svn__compress(uncompressed,
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
                         compressed,
                         ffd->compress_packed_revprops
                           ? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT
                           : SVN_DELTA_COMPRESSION_LEVEL_NONE));
 
-  /* finally, write the content to the target stream and close it */
-  SVN_ERR(svn_stream_write(file_stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(file_stream));
+  /* finally, write the content to the target file, flush and close it */
+  SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
+                                 NULL, pool));
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -826,23 +913,22 @@ repack_revprops(svn_fs_t *fs,
 /* Allocate a new pack file name for revisions
  *     [REVPROPS->START_REVISION + START, REVPROPS->START_REVISION + END - 1]
  * of REVPROPS->MANIFEST.  Add the name of old file to FILES_TO_DELETE,
- * auto-create that array if necessary.  Return an open file stream to
- * the new file in *STREAM allocated in POOL.
+ * auto-create that array if necessary.  Return an open file *FILE that is
+ * allocated in POOL.
  */
 static svn_error_t *
-repack_stream_open(svn_stream_t **stream,
-                   svn_fs_t *fs,
-                   packed_revprops_t *revprops,
-                   int start,
-                   int end,
-                   apr_array_header_t **files_to_delete,
-                   apr_pool_t *pool)
+repack_file_open(apr_file_t **file,
+                 svn_fs_t *fs,
+                 packed_revprops_t *revprops,
+                 int start,
+                 int end,
+                 apr_array_header_t **files_to_delete,
+                 apr_pool_t *pool)
 {
   apr_int64_t tag;
   const char *tag_string;
   svn_string_t *new_filename;
   int i;
-  apr_file_t *file;
   int manifest_offset
     = (int)(revprops->start_revision - revprops->manifest_start);
 
@@ -874,12 +960,11 @@ repack_stream_open(svn_stream_t **stream
     APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
       = new_filename->data;
 
-  /* create a file stream for the new file */
-  SVN_ERR(svn_io_file_open(&file, svn_dirent_join(revprops->folder,
-                                                  new_filename->data,
-                                                  pool),
+  /* open the file */
+  SVN_ERR(svn_io_file_open(file, svn_dirent_join(revprops->folder,
+                                                 new_filename->data,
+                                                 pool),
                            APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
-  *stream = svn_stream_from_aprfile2(file, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -901,14 +986,14 @@ write_packed_revprop(const char **final_
 {
   fs_fs_data_t *ffd = fs->fsap_data;
   packed_revprops_t *revprops;
-  apr_int64_t generation = 0;
   svn_stream_t *stream;
+  apr_file_t *file;
   svn_stringbuf_t *serialized;
-  apr_off_t new_total_size;
+  apr_size_t new_total_size;
   int changed_index;
 
   /* read contents of the current pack file */
-  SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, TRUE, pool));
+  SVN_ERR(read_pack_revprop(&revprops, fs, rev, TRUE, FALSE, pool));
 
   /* serialize the new revprops */
   serialized = svn_stringbuf_create_empty(pool);
@@ -922,7 +1007,7 @@ write_packed_revprop(const char **final_
                  + serialized->len
                  + (revprops->offsets->nelts + 2) * SVN_INT64_BUFFER_SIZE;
 
-  APR_ARRAY_IDX(revprops->sizes, changed_index, apr_off_t) = serialized->len;
+  APR_ARRAY_IDX(revprops->sizes, changed_index, apr_size_t) = serialized->len;
 
   /* can we put the new data into the same pack as the before? */
   if (   new_total_size < ffd->revprop_pack_size
@@ -933,11 +1018,11 @@ write_packed_revprop(const char **final_
 
       *final_path = svn_dirent_join(revprops->folder, revprops->filename,
                                     pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
       SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
                               changed_index, serialized, new_total_size,
-                              stream, pool));
+                              file, pool));
     }
   else
     {
@@ -946,23 +1031,23 @@ write_packed_revprop(const char **final_
 
       int left = 0;
       int right = revprops->sizes->nelts - 1;
-      apr_off_t left_size = 2 * SVN_INT64_BUFFER_SIZE;
-      apr_off_t right_size = 2 * SVN_INT64_BUFFER_SIZE;
+      apr_size_t left_size = 2 * SVN_INT64_BUFFER_SIZE;
+      apr_size_t right_size = 2 * SVN_INT64_BUFFER_SIZE;
 
       /* let left and right side grow such that their size difference
        * is minimal after each step. */
       while (left <= right)
-        if (  left_size + APR_ARRAY_IDX(revprops->sizes, left, apr_off_t)
-            < right_size + APR_ARRAY_IDX(revprops->sizes, right, apr_off_t))
+        if (  left_size + APR_ARRAY_IDX(revprops->sizes, left, apr_size_t)
+            < right_size + APR_ARRAY_IDX(revprops->sizes, right, apr_size_t))
           {
-            left_size += APR_ARRAY_IDX(revprops->sizes, left, apr_off_t)
+            left_size += APR_ARRAY_IDX(revprops->sizes, left, apr_size_t)
                       + SVN_INT64_BUFFER_SIZE;
             ++left;
           }
         else
           {
-            right_size += APR_ARRAY_IDX(revprops->sizes, right, apr_off_t)
-                        + SVN_INT64_BUFFER_SIZE;
+            right_size += APR_ARRAY_IDX(revprops->sizes, right, apr_size_t)
+                       + SVN_INT64_BUFFER_SIZE;
             --right;
           }
 
@@ -983,50 +1068,51 @@ write_packed_revprop(const char **final_
       /* write the new, split files */
       if (left_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, 0,
-                                     left_count, files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, 0,
+                                   left_count, files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (left_count + right_count < revprops->sizes->nelts)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, changed_index,
-                                     changed_index + 1, files_to_delete,
-                                     pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, changed_index,
+                                   changed_index + 1, files_to_delete,
+                                   pool));
           SVN_ERR(repack_revprops(fs, revprops, changed_index,
                                   changed_index + 1,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (right_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops,
-                                     revprops->sizes->nelts - right_count,
-                                     revprops->sizes->nelts,
-                                     files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops,
+                                   revprops->sizes->nelts - right_count,
+                                   revprops->sizes->nelts,
+                                   files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops,
                                   revprops->sizes->nelts - right_count,
                                   revprops->sizes->nelts, changed_index,
-                                  serialized, new_total_size, stream,
+                                  serialized, new_total_size, file,
                                   pool));
         }
 
       /* write the new manifest */
       *final_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
-
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
+      stream = svn_stream_from_aprfile2(file, TRUE, pool);
       for (i = 0; i < revprops->manifest->nelts; ++i)
         {
           const char *filename = APR_ARRAY_IDX(revprops->manifest, i,
                                                const char*);
           SVN_ERR(svn_stream_printf(stream, pool, "%s\n", filename));
         }
-
       SVN_ERR(svn_stream_close(stream));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
     }
 
   return SVN_NO_ERROR;
@@ -1059,6 +1145,9 @@ svn_fs_fs__set_revision_proplist(svn_fs_
     SVN_ERR(write_non_packed_revprop(&final_path, &tmp_path,
                                      fs, rev, proplist, pool));
 
+  /* Previous cache contents is invalid now. */
+  svn_fs_fs__reset_revprop_cache(fs);
+
   /* We use the rev file of this revision as the perms reference,
    * because when setting revprops for the first time, the revprop
    * file won't exist and therefore can't serve as its own reference.
@@ -1165,7 +1254,6 @@ svn_fs_fs__copy_revprops(const char *pac
   apr_file_t *pack_file;
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_stream_t *stream;
 
   /* create empty data buffer and a write stream on top of it */
   svn_stringbuf_t *uncompressed
@@ -1189,6 +1277,7 @@ svn_fs_fs__copy_revprops(const char *pac
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       const char *path;
+      svn_stream_t *stream;
 
       svn_pool_clear(iterpool);
 
@@ -1207,12 +1296,14 @@ svn_fs_fs__copy_revprops(const char *pac
   SVN_ERR(svn_stream_close(pack_stream));
 
   /* compress the content (or just store it for COMPRESSION_LEVEL 0) */
-  SVN_ERR(svn__compress(uncompressed, compressed, compression_level));
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
+                        compressed, compression_level));
 
   /* write the pack file content to disk */
-  stream = svn_stream_from_aprfile2(pack_file, FALSE, scratch_pool);
-  SVN_ERR(svn_stream_write(stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_io_file_write_full(pack_file, compressed->data, compressed->len,
+                                 NULL, scratch_pool));
+  SVN_ERR(svn_io_file_flush_to_disk(pack_file, scratch_pool));
+  SVN_ERR(svn_io_file_close(pack_file, scratch_pool));
 
   svn_pool_destroy(iterpool);
 
@@ -1224,19 +1315,24 @@ svn_fs_fs__pack_revprops_shard(const cha
                                const char *shard_path,
                                apr_int64_t shard,
                                int max_files_per_dir,
-                               apr_off_t max_pack_size,
+                               apr_int64_t max_pack_size,
                                int compression_level,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool)
 {
   const char *manifest_file_path, *pack_filename = NULL;
+  apr_file_t *manifest_file;
   svn_stream_t *manifest_stream;
   svn_revnum_t start_rev, end_rev, rev;
-  apr_off_t total_size;
+  apr_size_t total_size;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_array_header_t *sizes;
 
+  /* Sanitize config file values. */
+  apr_size_t max_size = (apr_size_t)MIN(MAX(max_pack_size, 1),
+                                        SVN_MAX_OBJECT_SIZE);
+
   /* Some useful paths. */
   manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST,
                                        scratch_pool);
@@ -1247,8 +1343,12 @@ svn_fs_fs__pack_revprops_shard(const cha
 
   /* Create the new directory and manifest file stream. */
   SVN_ERR(svn_io_dir_make(pack_file_dir, APR_OS_DEFAULT, scratch_pool));
-  SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
-                                   scratch_pool, scratch_pool));
+
+  SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+                           APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, scratch_pool));
+  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE,
+                                             scratch_pool);
 
   /* revisions to handle. Special case: revision 0 */
   start_rev = (svn_revnum_t) (shard * max_files_per_dir);
@@ -1260,7 +1360,7 @@ svn_fs_fs__pack_revprops_shard(const cha
        works. */
 
   /* initialize the revprop size info */
-  sizes = apr_array_make(scratch_pool, max_files_per_dir, sizeof(apr_off_t));
+  sizes = apr_array_make(scratch_pool, max_files_per_dir, sizeof(apr_size_t));
   total_size = 2 * SVN_INT64_BUFFER_SIZE;
 
   /* Iterate over the revisions in this shard, determine their size and
@@ -1280,11 +1380,11 @@ svn_fs_fs__pack_revprops_shard(const cha
       /* if we already have started a pack file and this revprop cannot be
        * appended to it, write the previous pack file. */
       if (sizes->nelts != 0 &&
-          total_size + SVN_INT64_BUFFER_SIZE + finfo.size > max_pack_size)
+          total_size + SVN_INT64_BUFFER_SIZE + finfo.size > max_size)
         {
           SVN_ERR(svn_fs_fs__copy_revprops(pack_file_dir, pack_filename,
                                            shard_path, start_rev, rev-1,
-                                           sizes, (apr_size_t)total_size,
+                                           sizes, total_size,
                                            compression_level, cancel_func,
                                            cancel_baton, iterpool));
 
@@ -1303,7 +1403,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                 pack_filename));
 
       /* add to list of files to put into the current pack file */
-      APR_ARRAY_PUSH(sizes, apr_off_t) = finfo.size;
+      APR_ARRAY_PUSH(sizes, apr_size_t) = finfo.size;
       total_size += SVN_INT64_BUFFER_SIZE + finfo.size;
     }
 
@@ -1315,8 +1415,10 @@ svn_fs_fs__pack_revprops_shard(const cha
                                      compression_level, cancel_func,
                                      cancel_baton, iterpool));
 
-  /* flush the manifest file and update permissions */
+  /* flush the manifest file to disk and update permissions */
   SVN_ERR(svn_stream_close(manifest_stream));
+  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, iterpool));
+  SVN_ERR(svn_io_file_close(manifest_file, iterpool));
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, iterpool));
 
   svn_pool_destroy(iterpool);
@@ -1347,7 +1449,7 @@ svn_fs_fs__delete_revprops_shard(const c
                                  apr_psprintf(iterpool, "%d", i),
                                  iterpool);
           if (cancel_func)
-            SVN_ERR((*cancel_func)(cancel_baton));
+            SVN_ERR(cancel_func(cancel_baton));
 
           SVN_ERR(svn_io_remove_file2(path, TRUE, iterpool));
         }

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h Mon Nov 30 10:24:16 2015
@@ -58,15 +58,23 @@ svn_fs_fs__upgrade_cleanup_pack_revprops
                                          void *cancel_baton,
                                          apr_pool_t *scratch_pool);
 
+/* Invalidate the revprop cache in FS. */
+void
+svn_fs_fs__reset_revprop_cache(svn_fs_t *fs);
+
 /* Read the revprops for revision REV in FS and return them in *PROPERTIES_P.
+ * If REFRESH is set, clear the revprop cache before accessing the data.
  *
- * Allocations will be done in POOL.
+ * The result will be allocated in RESULT_POOL; SCRATCH_POOL is used for
+ * temporaries.
  */
 svn_error_t *
 svn_fs_fs__get_revision_proplist(apr_hash_t **proplist_p,
                                  svn_fs_t *fs,
                                  svn_revnum_t rev,
-                                 apr_pool_t *pool);
+                                 svn_boolean_t refresh,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
 
 /* Set the revision property list of revision REV in filesystem FS to
    PROPLIST.  Use POOL for temporary allocations. */
@@ -134,7 +142,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                const char *shard_path,
                                apr_int64_t shard,
                                int max_files_per_dir,
-                               apr_off_t max_pack_size,
+                               apr_int64_t max_pack_size,
                                int compression_level,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c Mon Nov 30 10:24:16 2015
@@ -70,8 +70,9 @@ typedef enum rep_kind_t
  */
 typedef struct rep_stats_t
 {
-  /* absolute offset in the file */
-  apr_off_t offset;
+  /* offset in the revision file (phys. addressing) /
+   * item index within REVISION (log. addressing) */
+  apr_uint64_t item_index;
 
   /* item length in bytes */
   apr_uint64_t size;
@@ -92,8 +93,36 @@ typedef struct rep_stats_t
   /* classification of the representation. values of rep_kind_t */
   char kind;
 
+  /* length of the delta chain, including this representation,
+   * saturated to 255 - if need be */
+  apr_byte_t chain_length;
 } rep_stats_t;
 
+/* Represents a link in the rep delta chain.  REVISION + ITEM_INDEX points
+ * to BASE_REVISION + BASE_ITEM_INDEX.  We collect this info while scanning
+ * a f7 repo in a single pass and resolve it afterwards. */
+typedef struct rep_ref_t
+{
+  /* Revision that contains this representation. */
+  svn_revnum_t revision;
+
+  /* Item index of this rep within REVISION. */
+  apr_uint64_t item_index;
+
+  /* Revision of the representation we deltified against.
+   * -1 if this representation is either PLAIN or a self-delta. */
+  svn_revnum_t base_revision;
+
+  /* Item index of that rep within BASE_REVISION. */
+  apr_uint64_t base_item_index;
+
+  /* Length of the PLAIN / DELTA line in the source file in bytes.
+   * We use this to update the info in the rep stats after scanning the
+   * whole file. */
+  apr_uint16_t header_size;
+
+} rep_ref_t;
+
 /* Represents a single revision.
  * There will be only one instance per revision. */
 typedef struct revision_info_t
@@ -176,23 +205,6 @@ typedef struct query_t
   void *cancel_baton;
 } query_t;
 
-/* Return the length of REV_FILE in *FILE_SIZE.
- * Use SCRATCH_POOL for temporary allocations.
- */
-static svn_error_t *
-get_file_size(apr_off_t *file_size,
-              svn_fs_fs__revision_file_t *rev_file,
-              apr_pool_t *scratch_pool)
-{
-  apr_finfo_t finfo;
-
-  SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, rev_file->file,
-                               scratch_pool));
-
-  *file_size = finfo.size;
-  return SVN_NO_ERROR;
-}
-
 /* Initialize the LARGEST_CHANGES member in STATS with a capacity of COUNT
  * entries.  Allocate the result in RESULT_POOL.
  */
@@ -345,13 +357,13 @@ add_change(svn_fs_fs__stats_t *stats,
 
 /* Comparator used for binary search comparing the absolute file offset
  * of a representation to some other offset. DATA is a *rep_stats_t,
- * KEY is a pointer to an apr_off_t.
+ * KEY is a pointer to an apr_uint64_t.
  */
 static int
-compare_representation_offsets(const void *data, const void *key)
+compare_representation_item_index(const void *data, const void *key)
 {
-  apr_off_t lhs = (*(const rep_stats_t *const *)data)->offset;
-  apr_off_t rhs = *(const apr_off_t *)key;
+  apr_uint64_t lhs = (*(const rep_stats_t *const *)data)->item_index;
+  apr_uint64_t rhs = *(const apr_uint64_t *)key;
 
   if (lhs < rhs)
     return -1;
@@ -362,7 +374,7 @@ compare_representation_offsets(const voi
  * return it in *REVISION_INFO. For performance reasons, we skip the
  * lookup if the info is already provided.
  *
- * In that revision, look for the rep_stats_t object for offset OFFSET.
+ * In that revision, look for the rep_stats_t object for item ITEM_INDEX.
  * If it already exists, set *IDX to its index in *REVISION_INFO's
  * representations list and return the representation object. Otherwise,
  * set the index to where it must be inserted and return NULL.
@@ -372,7 +384,7 @@ find_representation(int *idx,
                     query_t *query,
                     revision_info_t **revision_info,
                     svn_revnum_t revision,
-                    apr_off_t offset)
+                    apr_uint64_t item_index)
 {
   revision_info_t *info;
   *idx = -1;
@@ -392,14 +404,14 @@ find_representation(int *idx,
 
   /* look for the representation */
   *idx = svn_sort__bsearch_lower_bound(info->representations,
-                                       &offset,
-                                       compare_representation_offsets);
+                                       &item_index,
+                                       compare_representation_item_index);
   if (*idx < info->representations->nelts)
     {
       /* return the representation, if this is the one we were looking for */
       rep_stats_t *result
         = APR_ARRAY_IDX(info->representations, *idx, rep_stats_t *);
-      if (result->offset == offset)
+      if (result->item_index == item_index)
         return result;
     }
 
@@ -428,7 +440,7 @@ parse_representation(rep_stats_t **repre
 
   /* look it up */
   result = find_representation(&idx, query, &revision_info, rep->revision,
-                               (apr_off_t)rep->item_index);
+                               rep->item_index);
   if (!result)
     {
       /* not parsed, yet (probably a rep in the same revision).
@@ -436,9 +448,8 @@ parse_representation(rep_stats_t **repre
        */
       result = apr_pcalloc(result_pool, sizeof(*result));
       result->revision = rep->revision;
-      result->expanded_size = (rep->expanded_size ? rep->expanded_size
-                                                  : rep->size);
-      result->offset = (apr_off_t)rep->item_index;
+      result->expanded_size = rep->expanded_size;
+      result->item_index = rep->item_index;
       result->size = rep->size;
 
       /* In phys. addressing mode, follow link to the actual representation.
@@ -447,7 +458,8 @@ parse_representation(rep_stats_t **repre
       if (!svn_fs_fs__use_log_addressing(query->fs))
         {
           svn_fs_fs__rep_header_t *header;
-          apr_off_t offset = revision_info->offset + result->offset;
+          apr_off_t offset = revision_info->offset
+                           + (apr_off_t)rep->item_index;
 
           SVN_ERR_ASSERT(revision_info->rev_file);
           SVN_ERR(svn_io_file_seek(revision_info->rev_file->file, APR_SET,
@@ -457,6 +469,23 @@ parse_representation(rep_stats_t **repre
                                              scratch_pool, scratch_pool));
 
           result->header_size = header->header_size;
+
+          /* Determine length of the delta chain. */
+          if (header->type == svn_fs_fs__rep_delta)
+            {
+              int base_idx;
+              rep_stats_t *base_rep
+                = find_representation(&base_idx, query, NULL,
+                                      header->base_revision,
+                                      header->base_item_index);
+
+              result->chain_length = 1 + MIN(base_rep->chain_length,
+                                             (apr_byte_t)0xfe);
+            }
+          else
+            {
+              result->chain_length = 1;
+            }
         }
 
       svn_sort__array_insert(revision_info->representations, &result, idx);
@@ -729,12 +758,12 @@ read_phys_pack_file(query_t *query,
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, base,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* process each revision in the pack file */
   for (i = 0; i < query->shard_size; ++i)
@@ -798,7 +827,7 @@ read_phys_revision_file(query_t *query,
                         apr_pool_t *scratch_pool)
 {
   revision_info_t *info = apr_pcalloc(result_pool, sizeof(*info));
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   /* cancellation support */
@@ -808,7 +837,7 @@ read_phys_revision_file(query_t *query,
   /* read the whole pack file into memory */
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, revision,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* create the revision info for the current rev */
   info->representations = apr_array_make(result_pool, 4, sizeof(rep_stats_t*));
@@ -885,6 +914,70 @@ read_item(svn_stringbuf_t **contents,
   return SVN_NO_ERROR;
 }
 
+/* Predicate comparing the two rep_ref_t** LHS and RHS by the respective
+ * representation's revision.
+ */
+static int
+compare_representation_refs(const void *lhs, const void *rhs)
+{
+  svn_revnum_t lhs_rev = (*(const rep_ref_t *const *)lhs)->revision;
+  svn_revnum_t rhs_rev = (*(const rep_ref_t *const *)rhs)->revision;
+
+  if (lhs_rev < rhs_rev)
+    return -1;
+  return (lhs_rev > rhs_rev ? 1 : 0);
+}
+
+/* Given all the presentations found in a single rev / pack file as
+ * rep_ref_t * in REP_REFS, update the delta chain lengths in QUERY.
+ * REP_REFS and its contents can then be discarded.
+ */
+static svn_error_t *
+resolve_representation_refs(query_t *query,
+                            apr_array_header_t *rep_refs)
+{
+  int i;
+
+  /* Because delta chains can only point to previous revs, after sorting
+   * REP_REFS, all base refs have already been updated. */
+  svn_sort__array(rep_refs, compare_representation_refs);
+
+  /* Build up the CHAIN_LENGTH values. */
+  for (i = 0; i < rep_refs->nelts; ++i)
+    {
+      int idx;
+      rep_ref_t *ref = APR_ARRAY_IDX(rep_refs, i, rep_ref_t *);
+      rep_stats_t *rep = find_representation(&idx, query, NULL,
+                                             ref->revision, ref->item_index);
+
+      /* No dangling pointers and all base reps have been processed. */
+      SVN_ERR_ASSERT(rep);
+      SVN_ERR_ASSERT(!rep->chain_length);
+
+      /* Set the HEADER_SIZE as we found it during the scan. */
+      rep->header_size = ref->header_size;
+
+      /* The delta chain got 1 element longer. */
+      if (ref->base_revision == SVN_INVALID_REVNUM)
+        {
+          rep->chain_length = 1;
+        }
+      else
+        {
+          rep_stats_t *base;
+
+          base = find_representation(&idx, query, NULL, ref->base_revision,
+                                     ref->base_item_index);
+          SVN_ERR_ASSERT(base);
+          SVN_ERR_ASSERT(base->chain_length);
+
+          rep->chain_length = 1 + MIN(base->chain_length, (apr_byte_t)0xfe);
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Process the logically addressed revision contents of revisions BASE to
  * BASE + COUNT - 1 in QUERY.
  *
@@ -905,6 +998,12 @@ read_log_rev_or_packfile(query_t *query,
   int i;
   svn_fs_fs__revision_file_t *rev_file;
 
+  /* We collect the delta chain links as we scan the file.  Afterwards,
+   * we determine the lengths of those delta chains and throw this
+   * temporary container away. */
+  apr_array_header_t *rep_refs = apr_array_make(scratch_pool, 64,
+                                                sizeof(rep_ref_t *));
+
   /* we will process every revision in the rev / pack file */
   for (i = 0; i < count; ++i)
     {
@@ -947,6 +1046,8 @@ read_log_rev_or_packfile(query_t *query,
       /* process all entries (and later continue with the next block) */
       for (i = 0; i < entries->nelts; ++i)
         {
+          svn_stringbuf_t *item;
+          revision_info_t *info;
           svn_fs_fs__p2l_entry_t *entry
             = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
 
@@ -959,32 +1060,64 @@ read_log_rev_or_packfile(query_t *query,
             continue;
 
           /* read and process interesting items */
+          info = APR_ARRAY_IDX(query->revisions, entry->item.revision,
+                               revision_info_t*);
+
           if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
             {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
               SVN_ERR(read_item(&item, rev_file, entry, iterpool, iterpool));
               SVN_ERR(read_noderev(query, item, info, result_pool, iterpool));
             }
           else if (entry->type == SVN_FS_FS__ITEM_TYPE_CHANGES)
             {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
               SVN_ERR(read_item(&item, rev_file, entry, iterpool, iterpool));
               info->change_count
                 = get_log_change_count(item->data + 0, item->len);
               info->changes_len += entry->size;
             }
+          else if (   (entry->type == SVN_FS_FS__ITEM_TYPE_FILE_REP)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_DIR_REP)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_FILE_PROPS)
+                   || (entry->type == SVN_FS_FS__ITEM_TYPE_DIR_PROPS))
+            {
+              /* Collect the delta chain link. */
+              svn_fs_fs__rep_header_t *header;
+              rep_ref_t *ref = apr_pcalloc(scratch_pool, sizeof(*ref));
+
+              SVN_ERR(svn_io_file_aligned_seek(rev_file->file,
+                                               rev_file->block_size,
+                                               NULL, entry->offset,
+                                               iterpool));
+              SVN_ERR(svn_fs_fs__read_rep_header(&header,
+                                                 rev_file->stream,
+                                                 iterpool, iterpool));
+
+              ref->header_size = header->header_size;
+              ref->revision = entry->item.revision;
+              ref->item_index = entry->item.number;
+
+              if (header->type == svn_fs_fs__rep_delta)
+                {
+                  ref->base_item_index = header->base_item_index;
+                  ref->base_revision = header->base_revision;
+                }
+              else
+                {
+                  ref->base_item_index = SVN_FS_FS__ITEM_INDEX_UNUSED;
+                  ref->base_revision = SVN_INVALID_REVNUM;
+                }
+
+              APR_ARRAY_PUSH(rep_refs, rep_ref_t *) = ref;
+            }
 
           /* advance offset */
           offset += entry->size;
         }
     }
 
+  /* Resolve the delta chain links. */
+  SVN_ERR(resolve_representation_refs(query, rep_refs));
+
   /* clean up and close file handles */
   svn_pool_destroy(iterpool);
 
@@ -1111,6 +1244,7 @@ add_rep_stats(svn_fs_fs__representation_
 
   stats->references += rep->ref_count;
   stats->expanded_size += rep->ref_count * rep->expanded_size;
+  stats->chain_len += rep->chain_length;
 }
 
 /* Aggregate the info the in revision_info_t * array REVISIONS into the

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/structure?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/structure Mon Nov 30 10:24:16 2015
@@ -198,9 +198,9 @@ Shard packing:
     (i.e. same min packed revision)
 
 Addressing:
-  Format 1-6: Physical addressing; uses fixed positions within a rev file
+  Format 1+: Physical addressing; uses fixed positions within a rev file
   Format 7+:  Logical addressing; uses item index that will be translated
-    on-the-fly to the actual rev / pack file location
+    on-the-fly to the actual rev / pack file location (default for 7+ created)
 
 Repository IDs:
   Format 1+:  The first line of db/uuid contains the repository UUID
@@ -525,6 +525,7 @@ A revision file contains a concatenation
   * Text and property representations
   * Node-revisions
   * The changed-path data
+  * Two offsets at the very end (physical addressing only)
   * Index data (logical addressing only)
   * Revision / pack file footer (logical addressing only)
 
@@ -578,8 +579,9 @@ defined:
     representations may not be handled correctly by SVN before 1.7.20,
     1.8.12 and 1.9.0, if they have 0 <size> fields for non-empty contents.
     Releases 1.8.0 through 1.8.11 may have falsely created instances of
-    that (see issue #4554).  Finally, 0 <size> fields are NEVER legal for
-    DELTA representations.
+    that (see issue #4554).  Finally, 0 <size> fields are only ever legal
+    for DELTA representations if the reconstructed full-text is actually
+    empty.
 
 The predecessor of a node-rev crosses both soft and true copies;
 together with the count field, it allows efficient determination of
@@ -756,6 +758,9 @@ Format 7 introduces logical addressing t
 to be translated / mapped to physical rev / pack file offsets.
 These indexes are appended to the respective rev / pack file.
 
+The indexes map (revision number, item-index) pairs to absolute file offsets
+and absolute file offsets to (revision number, item-index, item metadata).
+
 Details of the binary format used by these index files can be
 found in structure-indexes.
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/structure-indexes
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/structure-indexes?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/structure-indexes (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/structure-indexes Mon Nov 30 10:24:16 2015
@@ -13,10 +13,10 @@ to read and cache any data without trave
 
 Rev and pack files are immutable, so the same is true for index data.
 During a transaction or while packing a file, a proto index file gets
-written (actually, one log-to-phys and one phys-to-log).  Its format is
-a simple concatenation of runtime structs and as such, an implementation
-detail subject to change.  A proto index basically aggregates all the
-information that must later be transformed into the final index.
+written (actually, one log-to-phys and one phys-to-log).  They use a
+simpler, less compact format with fixed record lengths.  A proto index
+basically aggregates all the information that must later be transformed
+into the final index.
 
 
 General design concerns
@@ -192,11 +192,11 @@ at the beginning of the file is optional
 
   <bof>         /* begin of proto index file for revision r and following */
   (0, 0)        /* mark start of revision r, optional for first rev */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 1 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 2 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   ...
   <eof>         /* end of file. */
 
@@ -343,10 +343,12 @@ For performance reasons we use a modifie
 
   h0 = fnv_1a([b0 b4 b8 ..]), ..., h3 = fnv_1a([b3 b7 b11 ..])
 
-* combine the big endian representation of these checksums plus the
-  remnant of the original stream into a 12 to 15 byte long intermediate
+* concatenate the big endian representation of these checksums (4 bytes
+  each) plus the remnant of the original stream into a 16 to 19 byte long
+  intermediate:
 
-  [i0 .. iK], 12 <= K+1 <= 15
+  [i0 .. iK] = [big-endian(h0) ... big-endian(h3) remnant ], 16 <= K+1 <= 19
 
-* FNV checksum = fnv_1a([i0 .. iK]) in big endian representation
+* fold the variable-length intermediate into a compact 32 bit checksum:
 
+  FNV checksum = fnv_1a([i0 .. iK])

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.c?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.c Mon Nov 30 10:24:16 2015
@@ -103,9 +103,7 @@ serialize_svn_string(svn_temp_serializer
   if (string == NULL)
     return;
 
-  svn_temp_serializer__push(context,
-                            (const void * const *)s,
-                            sizeof(*string));
+  svn_temp_serializer__push(context, (const void * const *)s, sizeof(**s));
 
   /* the "string" content may actually be arbitrary binary data.
    * Thus, we cannot use svn_temp_serializer__add_string. */
@@ -143,7 +141,7 @@ serialize_representation(svn_temp_serial
   /* serialize the representation struct itself */
   svn_temp_serializer__add_leaf(context,
                                 (const void * const *)representation,
-                                sizeof(*rep));
+                                sizeof(**representation));
 }
 
 /* auxiliary structure representing the content of a directory array */
@@ -153,6 +151,10 @@ typedef struct dir_data_t
    * (it's int because the directory is an APR array) */
   int count;
 
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown (i.e. committed data). */
+  svn_filesize_t txn_filesize;
+
   /* number of unused dir entry buckets in the index */
   apr_size_t over_provision;
 
@@ -187,7 +189,7 @@ serialize_dir_entry(svn_temp_serializer_
 
   svn_temp_serializer__push(context,
                             (const void * const *)entry_p,
-                            sizeof(svn_fs_dirent_t));
+                            sizeof(**entry_p));
 
   svn_fs_fs__id_serialize(context, &entry->id);
   svn_temp_serializer__add_string(context, &entry->name);
@@ -198,24 +200,27 @@ serialize_dir_entry(svn_temp_serializer_
   svn_temp_serializer__pop(context);
 }
 
-/* Utility function to serialize the ENTRIES into a new serialization
+/* Utility function to serialize the DIR into a new serialization
  * context to be returned. Allocation will be made form POOL.
  */
 static svn_temp_serializer__context_t *
-serialize_dir(apr_array_header_t *entries, apr_pool_t *pool)
+serialize_dir(svn_fs_fs__dir_data_t *dir, apr_pool_t *pool)
 {
   dir_data_t dir_data;
   int i = 0;
   svn_temp_serializer__context_t *context;
+  apr_array_header_t *entries = dir->entries;
 
   /* calculate sizes */
   int count = entries->nelts;
   apr_size_t over_provision = 2 + count / 4;
-  apr_size_t entries_len = (count + over_provision) * sizeof(svn_fs_dirent_t*);
-  apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
+  apr_size_t total_count = count + over_provision;
+  apr_size_t entries_len = total_count * sizeof(*dir_data.entries);
+  apr_size_t lengths_len = total_count * sizeof(*dir_data.lengths);
 
   /* copy the hash entries to an auxiliary struct of known layout */
   dir_data.count = count;
+  dir_data.txn_filesize = dir->txn_filesize;
   dir_data.over_provision = over_provision;
   dir_data.operations = 0;
   dir_data.entries = apr_palloc(pool, entries_len);
@@ -252,24 +257,29 @@ serialize_dir(apr_array_header_t *entrie
   return context;
 }
 
-/* Utility function to reconstruct a dir entries array from serialized data
+/* Utility function to reconstruct a dir entries struct from serialized data
  * in BUFFER and DIR_DATA. Allocation will be made form POOL.
  */
-static apr_array_header_t *
+static svn_fs_fs__dir_data_t *
 deserialize_dir(void *buffer, dir_data_t *dir_data, apr_pool_t *pool)
 {
-  apr_array_header_t *result
-    = apr_array_make(pool, dir_data->count, sizeof(svn_fs_dirent_t *));
+  svn_fs_fs__dir_data_t *result;
   apr_size_t i;
   apr_size_t count;
   svn_fs_dirent_t *entry;
   svn_fs_dirent_t **entries;
 
+  /* Construct empty directory object. */
+  result = apr_pcalloc(pool, sizeof(*result));
+  result->entries
+    = apr_array_make(pool, dir_data->count, sizeof(svn_fs_dirent_t *));
+  result->txn_filesize = dir_data->txn_filesize;
+
   /* resolve the reference to the entries array */
   svn_temp_deserializer__resolve(buffer, (void **)&dir_data->entries);
   entries = dir_data->entries;
 
-  /* fixup the references within each entry and add it to the hash */
+  /* fixup the references within each entry and add it to the RESULT */
   for (i = 0, count = dir_data->count; i < count; ++i)
     {
       svn_temp_deserializer__resolve(entries, (void **)&entries[i]);
@@ -280,7 +290,7 @@ deserialize_dir(void *buffer, dir_data_t
       svn_fs_fs__id_deserialize(entry, (svn_fs_id_t **)&entry->id);
 
       /* add the entry to the hash */
-      APR_ARRAY_PUSH(result, svn_fs_dirent_t *) = entry;
+      APR_ARRAY_PUSH(result->entries, svn_fs_dirent_t *) = entry;
     }
 
   /* return the now complete hash */
@@ -405,7 +415,7 @@ serialize_txdelta_ops(svn_temp_serialize
   /* the ops form a contiguous chunk of memory with no further references */
   svn_temp_serializer__add_leaf(context,
                                 (const void * const *)ops,
-                                count * sizeof(svn_txdelta_op_t));
+                                count * sizeof(**ops));
 }
 
 /* Utility function to serialize W in the given serialization CONTEXT.
@@ -417,9 +427,7 @@ serialize_txdeltawindow(svn_temp_seriali
   svn_txdelta_window_t *window = *w;
 
   /* serialize the window struct itself */
-  svn_temp_serializer__push(context,
-                            (const void * const *)w,
-                            sizeof(svn_txdelta_window_t));
+  svn_temp_serializer__push(context, (const void * const *)w, sizeof(**w));
 
   /* serialize its sub-structures */
   serialize_txdelta_ops(context, &window->ops, window->num_ops);
@@ -496,8 +504,7 @@ svn_fs_fs__serialize_manifest(void **dat
   apr_array_header_t *manifest = in;
 
   *data_len = sizeof(apr_off_t) *manifest->nelts;
-  *data = apr_palloc(pool, *data_len);
-  memcpy(*data, manifest->elts, *data_len);
+  *data = apr_pmemdup(pool, manifest->elts, *data_len);
 
   return SVN_NO_ERROR;
 }
@@ -592,7 +599,7 @@ svn_fs_fs__serialize_properties(void **d
   /* create our auxiliary data structure */
   properties.count = apr_hash_count(hash);
   properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
-  properties.values = apr_palloc(pool, sizeof(const char*) * properties.count);
+  properties.values = apr_palloc(pool, sizeof(const svn_string_t *) * properties.count);
 
   /* populate it with the hash entries */
   for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i)
@@ -656,6 +663,44 @@ svn_fs_fs__deserialize_properties(void *
 }
 
 svn_error_t *
+svn_fs_fs__serialize_revprops(void **data,
+                              apr_size_t *data_len,
+                              void *in,
+                              apr_pool_t *pool)
+{
+  svn_string_t *buffer = in;
+
+  *data = (void *)buffer->data;
+  *data_len = buffer->len;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_revprops(void **out,
+                                void *data,
+                                apr_size_t data_len,
+                                apr_pool_t *pool)
+{
+  apr_hash_t *properties;
+  svn_stream_t *stream;
+
+  svn_string_t buffer;
+  buffer.data = data;
+  buffer.len = data_len;
+
+  stream = svn_stream_from_string(&buffer, pool);
+  properties = svn_hash__make(pool);
+
+  SVN_ERR(svn_hash_read2(properties, stream, SVN_HASH_TERMINATOR, pool));
+
+  /* done */
+  *out = properties;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_fs__serialize_id(void **data,
                         apr_size_t *data_len,
                         void *in,
@@ -764,7 +809,7 @@ svn_fs_fs__serialize_dir_entries(void **
                                  void *in,
                                  apr_pool_t *pool)
 {
-  apr_array_header_t *dir = in;
+  svn_fs_fs__dir_data_t *dir = in;
 
   /* serialize the dir content into a new serialization context
    * and return the serialized data */
@@ -803,6 +848,20 @@ svn_fs_fs__get_sharded_offset(void **out
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__extract_dir_filesize(void **out,
+                                const void *data,
+                                apr_size_t data_len,
+                                void *baton,
+                                apr_pool_t *pool)
+{
+  const dir_data_t *dir_data = data;
+
+  *(svn_filesize_t *)out = dir_data->txn_filesize;
+
+  return SVN_NO_ERROR;
+}
+
 /* Utility function that returns the lowest index of the first entry in
  * *ENTRIES that points to a dir entry with a name equal or larger than NAME.
  * If an exact match has been found, *FOUND will be set to TRUE. COUNT is
@@ -857,7 +916,7 @@ svn_fs_fs__extract_dir_entry(void **out,
                              apr_pool_t *pool)
 {
   const dir_data_t *dir_data = data;
-  const char* name = baton;
+  const extract_dir_entry_baton_t *entry_baton = baton;
   svn_boolean_t found;
 
   /* resolve the reference to the entries array */
@@ -870,13 +929,14 @@ svn_fs_fs__extract_dir_entry(void **out,
 
   /* binary search for the desired entry by name */
   apr_size_t pos = find_entry((svn_fs_dirent_t **)entries,
-                              name,
+                              entry_baton->name,
                               dir_data->count,
                               &found);
 
-  /* de-serialize that entry or return NULL, if no match has been found */
+  /* de-serialize that entry or return NULL, if no match has been found.
+   * Be sure to check that the directory contents is still up-to-date. */
   *out = NULL;
-  if (found)
+  if (found && dir_data->txn_filesize == entry_baton->txn_filesize)
     {
       const svn_fs_dirent_t *source =
           svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
@@ -889,8 +949,7 @@ svn_fs_fs__extract_dir_entry(void **out,
       apr_size_t size = lengths[pos];
 
       /* copy & deserialize the entry */
-      svn_fs_dirent_t *new_entry = apr_palloc(pool, size);
-      memcpy(new_entry, source, size);
+      svn_fs_dirent_t *new_entry = apr_pmemdup(pool, source, size);
 
       svn_temp_deserializer__resolve(new_entry, (void **)&new_entry->name);
       svn_fs_fs__id_deserialize(new_entry, (svn_fs_id_t **)&new_entry->id);
@@ -911,31 +970,34 @@ slowly_replace_dir_entry(void **data,
 {
   replace_baton_t *replace_baton = (replace_baton_t *)baton;
   dir_data_t *dir_data = (dir_data_t *)*data;
-  apr_array_header_t *dir;
+  svn_fs_fs__dir_data_t *dir;
   int idx = -1;
   svn_fs_dirent_t *entry;
+  apr_array_header_t *entries;
 
   SVN_ERR(svn_fs_fs__deserialize_dir_entries((void **)&dir,
                                              *data,
                                              dir_data->len,
                                              pool));
 
-  entry = svn_fs_fs__find_dir_entry(dir, replace_baton->name, &idx);
+  entries = dir->entries;
+  entry = svn_fs_fs__find_dir_entry(entries, replace_baton->name, &idx);
 
   /* Replacement or removal? */
   if (replace_baton->new_entry)
     {
       /* Replace ENTRY with / insert the NEW_ENTRY */
       if (entry)
-        APR_ARRAY_IDX(dir, idx, svn_fs_dirent_t *) = replace_baton->new_entry;
+        APR_ARRAY_IDX(entries, idx, svn_fs_dirent_t *)
+          = replace_baton->new_entry;
       else
-        svn_sort__array_insert(dir, &replace_baton->new_entry, idx);
+        svn_sort__array_insert(entries, &replace_baton->new_entry, idx);
     }
   else
     {
       /* Remove the old ENTRY. */
       if (entry)
-        svn_sort__array_delete(dir, idx, 1);
+        svn_sort__array_delete(entries, idx, 1);
     }
 
   return svn_fs_fs__serialize_dir_entries(data, data_len, dir, pool);
@@ -957,6 +1019,12 @@ svn_fs_fs__replace_dir_entry(void **data
 
   svn_temp_serializer__context_t *context;
 
+  /* update the cached file length info.
+   * Because we are writing to the cache, it is fair to assume that the
+   * caller made sure that the current contents is consistent with the
+   * previous state of the directory file. */
+  dir_data->txn_filesize = replace_baton->txn_filesize;
+
   /* after quite a number of operations, let's re-pack everything.
    * This is to limit the number of wasted space as we cannot overwrite
    * existing data but must always append. */
@@ -1046,6 +1114,18 @@ svn_fs_fs__replace_dir_entry(void **data
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__reset_txn_filesize(void **data,
+                              apr_size_t *data_len,
+                              void *baton,
+                              apr_pool_t *pool)
+{
+  dir_data_t *dir_data = (dir_data_t *)*data;
+  dir_data->txn_filesize = SVN_INVALID_FILESIZE;
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t  *
 svn_fs_fs__serialize_rep_header(void **data,
                                 apr_size_t *data_len,
@@ -1055,7 +1135,7 @@ svn_fs_fs__serialize_rep_header(void **d
   svn_fs_fs__rep_header_t *copy = apr_palloc(pool, sizeof(*copy));
   *copy = *(svn_fs_fs__rep_header_t *)in;
 
-  *data_len = sizeof(svn_fs_fs__rep_header_t);
+  *data_len = sizeof(*copy);
   *data = copy;
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.h?rev=1717223&r1=1717222&r2=1717223&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.h Mon Nov 30 10:24:16 2015
@@ -156,6 +156,26 @@ svn_fs_fs__deserialize_properties(void *
                                   apr_pool_t *pool);
 
 /**
+ * Implements #svn_cache__serialize_func_t for a properties hash
+ * (@a in is an #apr_hash_t of svn_string_t elements, keyed by const char*).
+ */
+svn_error_t *
+svn_fs_fs__serialize_revprops(void **data,
+                              apr_size_t *data_len,
+                              void *in,
+                              apr_pool_t *pool);
+
+/**
+ * Implements #svn_cache__deserialize_func_t for a properties hash
+ * (@a *out is an #apr_hash_t of svn_string_t elements, keyed by const char*).
+ */
+svn_error_t *
+svn_fs_fs__deserialize_revprops(void **out,
+                                void *data,
+                                apr_size_t data_len,
+                                apr_pool_t *pool);
+
+/**
  * Implements #svn_cache__serialize_func_t for #svn_fs_id_t
  */
 svn_error_t *
@@ -192,7 +212,7 @@ svn_fs_fs__deserialize_node_revision(voi
                                      apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__serialize_func_t for a directory contents array
+ * Implements #svn_cache__serialize_func_t for a #svn_fs_fs__dir_data_t
  */
 svn_error_t *
 svn_fs_fs__serialize_dir_entries(void **data,
@@ -201,7 +221,7 @@ svn_fs_fs__serialize_dir_entries(void **
                                  apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__deserialize_func_t for a directory contents array
+ * Implements #svn_cache__deserialize_func_t for a #svn_fs_fs__dir_data_t
  */
 svn_error_t *
 svn_fs_fs__deserialize_dir_entries(void **out,
@@ -221,9 +241,38 @@ svn_fs_fs__get_sharded_offset(void **out
                               apr_pool_t *pool);
 
 /**
+ * Implements #svn_cache__partial_getter_func_t.
+ * Set (svn_filesize_t) @a *out to the filesize info stored with the
+ * serialized directory in @a data of @a data_len.  @a baton is unused.
+ */
+svn_error_t *
+svn_fs_fs__extract_dir_filesize(void **out,
+                                const void *data,
+                                apr_size_t data_len,
+                                void *baton,
+                                apr_pool_t *pool);
+
+/**
+ * Describes the entry to be found in a directory: Identifies the entry
+ * by @a name and requires the directory file size to be @a filesize.
+ */
+typedef struct extract_dir_entry_baton_t
+{
+  /** name of the directory entry to return */
+  const char *name;
+
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown. */
+  svn_filesize_t txn_filesize;
+} extract_dir_entry_baton_t;
+
+
+/**
  * Implements #svn_cache__partial_getter_func_t for a single
  * #svn_fs_dirent_t within a serialized directory contents hash,
- * identified by its name (const char @a *baton).
+ * identified by its name (in (extract_dir_entry_baton_t *) @a *baton).
+ * If the filesize specified in the baton does not match the cached
+ * value for this directory, @a *out will be NULL as well.
  */
 svn_error_t *
 svn_fs_fs__extract_dir_entry(void **out,
@@ -236,7 +285,10 @@ svn_fs_fs__extract_dir_entry(void **out,
  * Describes the change to be done to a directory: Set the entry
  * identify by @a name to the value @a new_entry. If the latter is
  * @c NULL, the entry shall be removed if it exists. Otherwise it
- * will be replaced or automatically added, respectively.
+ * will be replaced or automatically added, respectively.  The
+ * @a filesize allows readers to identify stale cache data (e.g.
+ * due to concurrent access to txns); writers use it to update the
+ * cached file size info.
  */
 typedef struct replace_baton_t
 {
@@ -245,6 +297,10 @@ typedef struct replace_baton_t
 
   /** directory entry to insert instead */
   svn_fs_dirent_t *new_entry;
+
+  /** Current length of the in-txn in-disk representation of the directory.
+   * SVN_INVALID_FILESIZE if unknown. */
+  svn_filesize_t txn_filesize;
 } replace_baton_t;
 
 /**
@@ -259,6 +315,17 @@ svn_fs_fs__replace_dir_entry(void **data
                              apr_pool_t *pool);
 
 /**
+ * Implements #svn_cache__partial_setter_func_t for a #svn_fs_fs__dir_data_t
+ * at @a *data, resetting its txn_filesize field to SVN_INVALID_FILESIZE.
+ * &a baton should be NULL.
+ */
+svn_error_t *
+svn_fs_fs__reset_txn_filesize(void **data,
+                              apr_size_t *data_len,
+                              void *baton,
+                              apr_pool_t *pool);
+
+/**
  * Implements #svn_cache__serialize_func_t for a #svn_fs_fs__rep_header_t.
  */
 svn_error_t *