Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.c Tue Oct 11 
09:11:50 2016
@@ -381,16 +381,9 @@ typedef struct packed_revprops_t
   /* sum of values in SIZES */
   apr_size_t total_size;
 
-  /* size of the revprops in PACKED_REVPROPS */
-  apr_array_header_t *sizes;
-
-  /* offset of the revprops in PACKED_REVPROPS */
-  apr_array_header_t *offsets;
-
-
-  /* concatenation of the serialized representation of all revprops
-   * in the pack, i.e. the pack content without header and compression */
-  svn_stringbuf_t *packed_revprops;
+  /* Array of svn_string_t, containing the serialized revprops for
+   * REVISION * I. */
+  apr_array_header_t *revprops;
 
   /* content of the manifest.
    * Sorted list of manifest_entry_t. */
@@ -409,7 +402,7 @@ static svn_error_t *
 parse_revprop(apr_hash_t **properties,
               svn_fs_t *fs,
               svn_revnum_t revision,
-              svn_string_t *content,
+              const svn_string_t *content,
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
@@ -433,6 +426,35 @@ parse_revprop(apr_hash_t **properties,
   return SVN_NO_ERROR;
 }
 
+/* Verify the checksum attached to CONTENT and remove it.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+verify_checksum(svn_stringbuf_t *content,
+                apr_pool_t *scratch_pool)
+{
+  const apr_byte_t *digest;
+  svn_checksum_t *actual, *expected;
+
+  /* Verify the checksum. */
+  if (content->len < sizeof(apr_uint32_t))
+    return svn_error_create(SVN_ERR_CORRUPT_PACKED_DATA, NULL,
+                            "File too short");
+
+  content->len -= sizeof(apr_uint32_t);
+  digest = (apr_byte_t *)content->data + content->len;
+
+  expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
+  SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
+                       content->len, scratch_pool));
+
+  if (!svn_checksum_match(actual, expected))
+    SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool, 
+                                      "checksum mismatch"));
+
+  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.
  *
@@ -467,10 +489,17 @@ read_non_packed_revprop(apr_hash_t **pro
 
   if (content)
     {
+      svn_string_t *as_string;
+
+      /* Consistency check. */
+      SVN_ERR_W(verify_checksum(content, scratch_pool),
+                apr_psprintf(scratch_pool,
+                             "Revprop file for r%ld is corrupt",
+                             rev));
+
       /* The contents string becomes part of the *PROPERTIES structure, i.e.
        * we must make sure it lives at least as long as the latter. */
-      svn_string_t *as_string = svn_string_create_from_buf(content,
-                                                           result_pool);
+      as_string = svn_string_create_from_buf(content, result_pool);
       SVN_ERR(parse_revprop(properties, fs, rev, as_string,
                             result_pool, iterpool));
     }
@@ -480,6 +509,32 @@ read_non_packed_revprop(apr_hash_t **pro
   return SVN_NO_ERROR;
 }
 
+/* Serialize ROOT into FILE and append a checksum to it.
+ * Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+write_packed_data_checksummed(svn_packed__data_root_t *root,
+                              apr_file_t *file,
+                              apr_pool_t *scratch_pool)
+{
+  svn_checksum_t *checksum;
+  svn_stream_t *stream;
+
+  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  stream = svn_checksum__wrap_write_stream(&checksum, stream,
+                                           svn_checksum_fnv1a_32x4,
+                                           scratch_pool);
+  SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
+  SVN_ERR(svn_stream_close(stream));
+
+  /* Append the checksum */
+  SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+                                 svn_checksum_size(checksum), NULL,
+                                 scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Serialize the packed revprops MANIFEST into FILE.
  * Use SCRATCH_POOL for temporary allocations.
  */
@@ -489,8 +544,6 @@ write_manifest(apr_file_t *file,
                apr_pool_t *scratch_pool)
 {
   int i;
-  svn_checksum_t *checksum;
-  svn_stream_t *stream;
   svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
 
   /* one top-level stream per struct element */
@@ -508,17 +561,26 @@ write_manifest(apr_file_t *file,
     }
 
   /* Write to file and calculate the checksum. */
-  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
-  stream = svn_checksum__wrap_write_stream(&checksum, stream,
-                                           svn_checksum_fnv1a_32x4,
-                                           scratch_pool);
-  SVN_ERR(svn_packed__data_write(stream, root, scratch_pool));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(write_packed_data_checksummed(root, file, scratch_pool));
 
-  /* Append the checksum */
-  SVN_ERR(svn_io_file_write_full(file, checksum->digest,
-                                 svn_checksum_size(checksum), NULL,
-                                 scratch_pool));
+  return SVN_NO_ERROR;
+}
+
+/* Read *ROOT from CONTENT and verify its checksum.  Allocate *ROOT in
+ * RESULT_POOL and use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+read_packed_data_checksummed(svn_packed__data_root_t **root,
+                             svn_stringbuf_t *content,
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
+{
+  svn_stream_t *stream;
+
+  SVN_ERR(verify_checksum(content, scratch_pool));
+
+  stream = svn_stream_from_stringbuf(content, scratch_pool);
+  SVN_ERR(svn_packed__data_read(root, stream, result_pool, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -534,39 +596,19 @@ read_manifest(apr_array_header_t **manif
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool)
 {
-  apr_size_t data_len;
   apr_size_t i;
   apr_size_t count;
 
-  svn_stream_t *stream;
   svn_packed__data_root_t *root;
   svn_packed__int_stream_t *start_rev_stream;
   svn_packed__int_stream_t *tag_stream;
-  const apr_byte_t *digest;
-  svn_checksum_t *actual, *expected;
-
-  /* Verify the checksum. */
-  if (content->len < sizeof(apr_uint32_t))
-    return svn_error_createf(SVN_ERR_FS_CORRUPT_REVPROP_MANIFEST, NULL,
-                             "Revprop manifest too short for revision r%ld",
-                             revision);
-
-  data_len = content->len - sizeof(apr_uint32_t);
-  digest = (apr_byte_t *)content->data + data_len;
 
-  expected = svn_checksum__from_digest_fnv1a_32x4(digest, scratch_pool);
-  SVN_ERR(svn_checksum(&actual, svn_checksum_fnv1a_32x4, content->data,
-                       data_len, scratch_pool));
-
-  if (!svn_checksum_match(actual, expected))
-    SVN_ERR(svn_checksum_mismatch_err(expected, actual, scratch_pool, 
-                                      _("checksum mismatch in revprop "
-                                        "manifest for revision r%ld"),
-                                      revision));
-
-  /* read everything from the buffer */
-  stream = svn_stream_from_stringbuf(content, scratch_pool);
-  SVN_ERR(svn_packed__data_read(&root, stream, result_pool, scratch_pool));
+  /* Verify the checksum and decode packed data. */
+  SVN_ERR_W(read_packed_data_checksummed(&root, content, result_pool,
+                                         scratch_pool),
+            apr_psprintf(scratch_pool,
+                         "Revprop manifest file for r%ld is corrupt",
+                         revision));
 
   /* get streams */
   start_rev_stream = svn_packed__first_int_stream(root);
@@ -716,9 +758,9 @@ same_shard(svn_fs_t *fs,
   return (r1 / ffd->max_files_per_dir) == (r2 / ffd->max_files_per_dir);
 }
 
-/* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS
- * and make PACKED_REVPROPS point to the first serialized revprop.  If
- * READ_ALL is set, initialize the SIZES and OFFSETS members as well.
+/* Given FS and the full packed file content in CONTENT and make
+ * PACKED_REVPROPS point to the first serialized revprop.  If READ_ALL
+ * is set, initialize the SIZES and OFFSETS members as well.
  *
  * Parse the revprops for REVPROPS->REVISION and set the PROPERTIES as
  * well as the SERIALIZED_SIZE member.  If revprop caching has been
@@ -727,33 +769,31 @@ same_shard(svn_fs_t *fs,
 static svn_error_t *
 parse_packed_revprops(svn_fs_t *fs,
                       packed_revprops_t *revprops,
+                      svn_stringbuf_t *content,
                       svn_boolean_t read_all,
                       apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 {
-  apr_uint64_t first_rev, count, i;
-  apr_size_t offset;
+  apr_size_t count, i;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   svn_boolean_t cache_all = has_revprop_cache(fs, scratch_pool);
-  const apr_byte_t *p, *end;
+  svn_packed__data_root_t *root;
+  svn_packed__byte_stream_t *revprops_stream;
+  svn_revnum_t first_rev = revprops->entry.start_rev;
 
-  /* 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(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 */
-  p = (apr_byte_t *)uncompressed->data;
-  end = p + uncompressed->len;
-  p = svn__decode_uint(&first_rev, p, end);
-  p = svn__decode_uint(&count, p, end);
+  /* Verify the checksum and decode packed data. */
+  SVN_ERR_W(read_packed_data_checksummed(&root, content, result_pool,
+                                         scratch_pool),
+            apr_psprintf(scratch_pool,
+                         "Revprop pack file for r%ld is corrupt",
+                         first_rev));
+
+  /* get streams */
+  revprops_stream = svn_packed__first_byte_stream(root);
+  count = svn_packed__byte_block_count(revprops_stream);
 
   /* Check revision range for validity. */
-  if (   !same_shard(fs, revprops->revision, first_rev)
-      || !same_shard(fs, revprops->revision, first_rev + count - 1)
-      || count < 1)
+  if (!same_shard(fs, first_rev, first_rev + count - 1) || count < 1)
     return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                              _("Revprop pack for revision r%ld"
                                " contains revprops for r%ld .. r%ld"),
@@ -770,71 +810,35 @@ parse_packed_revprops(svn_fs_t *fs,
                                " starts at non-packed revisions r%ld"),
                              revprops->revision, (svn_revnum_t)first_rev);
 
-  /* Read the item sizes from the header. */
-  revprops->sizes = apr_array_make(result_pool, (int)count, sizeof(offset));
-  revprops->offsets = apr_array_make(result_pool, (int)count, sizeof(offset));
-
-  for (i = 0, offset = 0, revprops->total_size = 0; i < count; ++i)
+  /* Request all data (just references to data already expanded in ROOT) */
+  revprops->revprops = apr_array_make(result_pool, (int)count,
+                                      sizeof(svn_string_t));
+  for (i = 0, revprops->total_size = 0; i < count; ++i)
     {
-      apr_uint64_t size64;
-      apr_size_t size;
-
-      /* read & check the serialized size */
-      p = svn__decode_uint(&size64, p, end);
-      if (size64 > uncompressed->len - offset)
-        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                "Packed revprop size exceeds pack file size");
-
-      size = (apr_size_t)size64;
+      svn_string_t *props = apr_array_push(revprops->revprops);
+      props->data = svn_packed__get_bytes(revprops_stream, &props->len);
 
-      /* fill REVPROPS data structures */
-      APR_ARRAY_PUSH(revprops->sizes, apr_size_t) = size;
-      APR_ARRAY_PUSH(revprops->offsets, apr_size_t) = offset;
-      revprops->total_size += size;
-
-      offset += size;
+      revprops->total_size += props->len;
     }
 
-  /* make PACKED_REVPROPS point to the first char after the header.
-   * This is where the serialized revprops are. */
-  offset = p - (apr_byte_t *)uncompressed->data;
-
-  revprops->packed_revprops = svn_stringbuf_create_empty(result_pool);
-  revprops->packed_revprops->data = uncompressed->data + offset;
-  revprops->packed_revprops->len = uncompressed->len - offset;
-  revprops->packed_revprops->blocksize = uncompressed->blocksize - offset;
-
-  /* Verify that the last offset size does not extend beyond file sans
-   * header (we only checked against the full file contents). */
-  if (revprops->total_size > revprops->packed_revprops->len)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            "Packed revprop size exceeds pack file size");
-
-  /* STREAM still points to the first entry in the sizes list. */
-  SVN_ERR_ASSERT(revprops->entry.start_rev = (svn_revnum_t)first_rev);
-
-  /* Now parse, revision by revision, the size and content of each
-   * revisions' revprops. */
-  for (i = 0, offset = 0; i < count; ++i)
+  /* Now parse the serialized revprops. */
+  for (i = 0; i < count; ++i)
     {
-      svn_string_t serialized;
-
-      svn_revnum_t revision = (svn_revnum_t)(first_rev + i);
-      apr_size_t size = APR_ARRAY_IDX(revprops->sizes, (int)i, apr_size_t);
-      offset = APR_ARRAY_IDX(revprops->offsets, (int)i, apr_size_t);
+      const svn_string_t *serialized;
+      svn_revnum_t revision;
 
       svn_pool_clear(iterpool);
 
-      serialized.data = revprops->packed_revprops->data + offset;
-      serialized.len = size;
+      serialized = &APR_ARRAY_IDX(revprops->revprops, (int)i, svn_string_t);
+      revision = first_rev + (long)i;
 
       /* Parse this revprops list, if necessary */
       if (revision == revprops->revision)
         {
           /* Parse (and possibly cache) the one revprop list we care about. */
           SVN_ERR(parse_revprop(&revprops->properties, fs, revision,
-                                &serialized, result_pool, iterpool));
-          revprops->serialized_size = serialized.len;
+                                serialized, result_pool, iterpool));
+          revprops->serialized_size = serialized->len;
 
           /* If we only wanted the revprops for REVISION then we are done. */
           if (!read_all && !cache_all)
@@ -844,7 +848,7 @@ parse_packed_revprops(svn_fs_t *fs,
         {
           /* Parse and cache all other revprop lists. */
           apr_hash_t *properties;
-          SVN_ERR(parse_revprop(&properties, fs, revision, &serialized,
+          SVN_ERR(parse_revprop(&properties, fs, revision, serialized,
                                 iterpool, iterpool));
         }
     }
@@ -871,7 +875,6 @@ read_pack_revprop(packed_revprops_t **re
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   svn_boolean_t missing = FALSE;
-  svn_error_t *err;
   packed_revprops_t *result;
   int i;
 
@@ -889,11 +892,11 @@ read_pack_revprop(packed_revprops_t **re
 
   /* try to read the packed revprops. This may require retries if we have
    * concurrent writers. */
-  for (i = 0;
-       i < SVN_FS_X__RECOVERABLE_RETRY_COUNT && !result->packed_revprops;
-       ++i)
+  for (i = 0; i < SVN_FS_X__RECOVERABLE_RETRY_COUNT; ++i)
     {
       const char *file_path;
+      svn_stringbuf_t *contents = NULL;
+
       svn_pool_clear(iterpool);
 
       /* there might have been concurrent writes.
@@ -902,11 +905,21 @@ read_pack_revprop(packed_revprops_t **re
       SVN_ERR(get_revprop_packname(fs, result, result_pool, iterpool));
       file_path = get_revprop_pack_filepath(result, &result->entry,
                                             iterpool);
-      SVN_ERR(svn_fs_x__try_stringbuf_from_file(&result->packed_revprops,
+      SVN_ERR(svn_fs_x__try_stringbuf_from_file(&contents,
                                 &missing,
                                 file_path,
                                 i + 1 < SVN_FS_X__RECOVERABLE_RETRY_COUNT,
-                                result_pool));
+                                iterpool));
+
+      if (contents)
+        {
+          SVN_ERR_W(parse_packed_revprops(fs, result, contents, read_all,
+                                          result_pool, iterpool),
+                    apr_psprintf(iterpool,
+                                 "Revprop pack file for r%ld is corrupt",
+                                 rev));
+          break;
+        }
 
       /* If we could not find the file, there was a write.
        * So, we should refresh our revprop generation info as well such
@@ -918,17 +931,10 @@ read_pack_revprop(packed_revprops_t **re
     }
 
   /* the file content should be available now */
-  if (!result->packed_revprops)
+  if (!result->revprops)
     return svn_error_createf(SVN_ERR_FS_PACKED_REVPROP_READ_FAILURE, NULL,
                   _("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, result_pool, iterpool);
-  svn_pool_destroy(iterpool);
-  if (err)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
-                  _("Revprop pack file for r%ld is corrupt"), rev);
-
   *revprops = result;
 
   return SVN_NO_ERROR;
@@ -1006,6 +1012,29 @@ svn_fs_x__get_revision_proplist(apr_hash
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_x__write_non_packed_revprops(apr_file_t *file,
+                                    apr_hash_t *proplist,
+                                    apr_pool_t *scratch_pool)
+{
+  svn_stream_t *stream;
+  svn_checksum_t *checksum;
+
+  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  stream = svn_checksum__wrap_write_stream(&checksum, stream,
+                                           svn_checksum_fnv1a_32x4,
+                                           scratch_pool);
+  SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
+  SVN_ERR(svn_stream_close(stream));
+
+  /* Append the checksum */
+  SVN_ERR(svn_io_file_write_full(file, checksum->digest,
+                                 svn_checksum_size(checksum), NULL,
+                                 scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Serialize the revision property list PROPLIST of revision REV in
  * filesystem FS to a non-packed file.  Return the name of that temporary
  * file in *TMP_PATH and the file path that it must be moved to in
@@ -1025,16 +1054,13 @@ write_non_packed_revprop(const char **fi
                          apr_pool_t *scratch_pool)
 {
   apr_file_t *file;
-  svn_stream_t *stream;
   *final_path = svn_fs_x__path_revprops(fs, rev, result_pool);
 
   *tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
   SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
                                           scratch_pool));
 
-  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
-  SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_fs_x__write_non_packed_revprops(file, proplist, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1096,51 +1122,8 @@ switch_to_new_revprop(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* Write VALUE to STREAM using 7/8b encoding. */
-static svn_error_t *
-write_encoded_uint(svn_stream_t *stream,
-                   apr_uint64_t value)
-{
-  apr_byte_t buffer[SVN__MAX_ENCODED_UINT_LEN];
-  apr_size_t len;
-
-  len = svn__encode_uint(buffer, value) - buffer;
-  SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len));
-
-  return SVN_NO_ERROR;
-}
-
-/* Write a pack file header to STREAM that starts at revision START_REVISION
- * and contains the indexes [START,END) of SIZES.
- */
-static svn_error_t *
-serialize_revprops_header(svn_stream_t *stream,
-                          svn_revnum_t start_revision,
-                          apr_array_header_t *sizes,
-                          int start,
-                          int end,
-                          apr_pool_t *scratch_pool)
-{
-  int i;
-  SVN_ERR_ASSERT(start < end);
-
-  /* start revision and entry count */
-  SVN_ERR(write_encoded_uint(stream, start_revision));
-  SVN_ERR(write_encoded_uint(stream, end - start));
-
-  /* the sizes array */
-  for (i = start; i < end; ++i)
-    SVN_ERR(write_encoded_uint(stream, APR_ARRAY_IDX(sizes, i, apr_size_t)));
-
-  return SVN_NO_ERROR;
-}
-
 /* 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
- * CHANGED_INDEX may be outside the [START,END) range, i.e. no new data is
- * taken in that case but only a subset of the old data will be copied.
+ * from REVPROPS for the indexes [START,END).
  *
  * NEW_TOTAL_SIZE is a hint for pre-allocating buffers of appropriate size.
  * SCRATCH_POOL is used for temporary allocations.
@@ -1150,60 +1133,27 @@ repack_revprops(svn_fs_t *fs,
                 packed_revprops_t *revprops,
                 int start,
                 int end,
-                int changed_index,
-                svn_stringbuf_t *new_serialized,
                 apr_size_t new_total_size,
                 apr_file_t *file,
                 apr_pool_t *scratch_pool)
 {
-  svn_fs_x__data_t *ffd = fs->fsap_data;
-  svn_stream_t *stream;
   int i;
 
-  /* create data empty buffers and the stream object */
-  svn_stringbuf_t *uncompressed
-    = svn_stringbuf_create_ensure((apr_size_t)new_total_size, scratch_pool);
-  svn_stringbuf_t *compressed
-    = svn_stringbuf_create_empty(scratch_pool);
-  stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
-
-  /* write the header*/
-  SVN_ERR(serialize_revprops_header(stream,
-                                    revprops->entry.start_rev + start,
-                                    revprops->sizes, start, end,
-                                    scratch_pool));
+  svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
+  svn_packed__byte_stream_t *revprops_stream
+    = svn_packed__create_bytes_stream(root);
 
   /* append the serialized revprops */
   for (i = start; i < end; ++i)
-    if (i == changed_index)
-      {
-        SVN_ERR(svn_stream_write(stream,
-                                 new_serialized->data,
-                                 &new_serialized->len));
-      }
-    else
-      {
-        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,
-                                 &size));
-      }
+    {
+      const svn_string_t *props
+        = &APR_ARRAY_IDX(revprops->revprops, i, svn_string_t);
 
-  /* flush the stream buffer (if any) to our underlying data buffer */
-  SVN_ERR(svn_stream_close(stream));
+      svn_packed__add_bytes(revprops_stream, props->data, props->len);
+    }
 
-  /* compress / store the data */
-  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 file, flush and close it */
-  SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
-                                 NULL, scratch_pool));
+  /* Write to file. */
+  SVN_ERR(write_packed_data_checksummed(root, file, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -1263,6 +1213,14 @@ repack_file_open(apr_file_t **file,
   return SVN_NO_ERROR;
 }
 
+/* Return the length of the serialized reprop list of index I in REVPROPS. */
+static apr_size_t
+props_len(packed_revprops_t *revprops,
+          int i)
+{
+  return APR_ARRAY_IDX(revprops->revprops, i, svn_string_t).len;
+}
+
 /* For revision REV in filesystem FS, set the revision properties to
  * PROPLIST.  Return a new file in *TMP_PATH that the caller shall move
  * to *FINAL_PATH to make the change visible.  Files to be deleted will
@@ -1289,6 +1247,7 @@ write_packed_revprop(const char **final_
   svn_stringbuf_t *serialized;
   apr_size_t new_total_size;
   int changed_index;
+  int count;
 
   /* read the current revprop generation. This value will not change
    * while we hold the global write lock to this FS. */
@@ -1305,17 +1264,18 @@ write_packed_revprop(const char **final_
   SVN_ERR(svn_fs_x__write_properties(stream, proplist, scratch_pool));
   SVN_ERR(svn_stream_close(stream));
 
-  /* calculate the size of the new data */
+  /* estimate the size of the new data */
+  count = revprops->revprops->nelts;
   changed_index = (int)(rev - revprops->entry.start_rev);
   new_total_size = revprops->total_size - revprops->serialized_size
                  + serialized->len
-                 + (revprops->offsets->nelts + 2) * SVN_INT64_BUFFER_SIZE;
+                 + (count + 2) * SVN_INT64_BUFFER_SIZE;
 
-  APR_ARRAY_IDX(revprops->sizes, changed_index, apr_size_t) = serialized->len;
+  APR_ARRAY_IDX(revprops->revprops, changed_index, svn_string_t)
+    = *svn_stringbuf__morph_into_string(serialized);
 
   /* can we put the new data into the same pack as the before? */
-  if (   new_total_size < ffd->revprop_pack_size
-      || revprops->sizes->nelts == 1)
+  if (new_total_size < ffd->revprop_pack_size || count == 1)
     {
       /* simply replace the old pack file with new content as we do it
        * in the non-packed case */
@@ -1325,9 +1285,8 @@ write_packed_revprop(const char **final_
       *tmp_path = apr_pstrcat(result_pool, *final_path, ".tmp", SVN_VA_NULL);
       SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *tmp_path,
                                               scratch_pool));
-      SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
-                              changed_index, serialized, new_total_size,
-                              file, scratch_pool));
+      SVN_ERR(repack_revprops(fs, revprops, 0, count,
+                              new_total_size, file, scratch_pool));
     }
   else
     {
@@ -1335,31 +1294,29 @@ write_packed_revprop(const char **final_
       int right_count, left_count;
 
       int left = 0;
-      int right = revprops->sizes->nelts - 1;
+      int right = count - 1;
       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_size_t)
-            < right_size + APR_ARRAY_IDX(revprops->sizes, right, apr_size_t))
+        if (  left_size + props_len(revprops, left)
+            < right_size + props_len(revprops, right))
           {
-            left_size += APR_ARRAY_IDX(revprops->sizes, left, apr_size_t)
-                      + SVN_INT64_BUFFER_SIZE;
+            left_size += props_len(revprops, left) + SVN_INT64_BUFFER_SIZE;
             ++left;
           }
         else
           {
-            right_size += APR_ARRAY_IDX(revprops->sizes, right, apr_size_t)
-                       + SVN_INT64_BUFFER_SIZE;
+            right_size += props_len(revprops, right) + SVN_INT64_BUFFER_SIZE;
             --right;
           }
 
        /* since the items need much less than SVN_INT64_BUFFER_SIZE
         * bytes to represent their length, the split may not be optimal */
       left_count = left;
-      right_count = revprops->sizes->nelts - left;
+      right_count = count - left;
 
       /* if new_size is large, one side may exceed the pack size limit.
        * In that case, split before and after the modified revprop.*/
@@ -1367,7 +1324,7 @@ write_packed_revprop(const char **final_
           || right_size > ffd->revprop_pack_size)
         {
           left_count = changed_index;
-          right_count = revprops->sizes->nelts - left_count - 1;
+          right_count = count - left_count - 1;
         }
 
       /* Allocate this here such that we can call the repack functions with
@@ -1384,19 +1341,17 @@ write_packed_revprop(const char **final_
                                    files_to_delete, batch,
                                    scratch_pool, scratch_pool));
           SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
-                                  changed_index, serialized, new_total_size,
-                                  file, scratch_pool));
+                                  new_total_size, file, scratch_pool));
         }
 
-      if (left_count + right_count < revprops->sizes->nelts)
+      if (left_count + right_count < count)
         {
           SVN_ERR(repack_file_open(&file, fs, revprops, rev,
                                    files_to_delete, batch,
                                    scratch_pool, scratch_pool));
           SVN_ERR(repack_revprops(fs, revprops, changed_index,
                                   changed_index + 1,
-                                  changed_index, serialized, new_total_size,
-                                  file, scratch_pool));
+                                  new_total_size, file, scratch_pool));
         }
 
       if (right_count)
@@ -1404,11 +1359,8 @@ write_packed_revprop(const char **final_
           SVN_ERR(repack_file_open(&file, fs, revprops, rev + 1,
                                    files_to_delete,  batch,
                                    scratch_pool, scratch_pool));
-          SVN_ERR(repack_revprops(fs, revprops,
-                                  revprops->sizes->nelts - right_count,
-                                  revprops->sizes->nelts, changed_index,
-                                  serialized, new_total_size, file,
-                                  scratch_pool));
+          SVN_ERR(repack_revprops(fs, revprops, count - right_count, count,
+                                  new_total_size, file, scratch_pool));
         }
 
       /* write the new manifest */
@@ -1438,11 +1390,13 @@ svn_fs_x__set_revision_proplist(svn_fs_t
   const char *perms_reference;
   apr_array_header_t *files_to_delete = NULL;
   svn_fs_x__batch_fsync_t *batch;
+  svn_fs_x__data_t *ffd = fs->fsap_data;
 
   SVN_ERR(svn_fs_x__ensure_revision_exists(rev, fs, scratch_pool));
 
   /* Perform all fsyncs through this instance. */
-  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
+  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, ffd->flush_to_disk,
+                                       scratch_pool));
 
   /* this info will not change while we hold the global FS write lock */
   is_packed = svn_fs_x__is_packed_revprop(fs, rev);
@@ -1564,34 +1518,19 @@ copy_revprops(svn_fs_t *fs,
               void *cancel_baton,
               apr_pool_t *scratch_pool)
 {
-  svn_stream_t *pack_stream;
   apr_file_t *pack_file;
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
 
-  /* create empty data buffer and a write stream on top of it */
-  svn_stringbuf_t *uncompressed
-    = svn_stringbuf_create_ensure(total_size, scratch_pool);
-  svn_stringbuf_t *compressed
-    = svn_stringbuf_create_empty(scratch_pool);
-  pack_stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
-
-  /* write the pack file header */
-  SVN_ERR(serialize_revprops_header(pack_stream, start_rev, sizes, 0,
-                                    sizes->nelts, iterpool));
-
-  /* Create the auto-fsync'ing pack file. */
-  SVN_ERR(svn_fs_x__batch_fsync_open_file(&pack_file, batch,
-                                          svn_dirent_join(pack_file_dir,
-                                                          pack_filename,
-                                                          scratch_pool),
-                                          scratch_pool));
+  svn_packed__data_root_t *root = svn_packed__data_create_root(scratch_pool);
+  svn_packed__byte_stream_t *stream
+    = svn_packed__create_bytes_stream(root);
 
   /* Iterate over the revisions in this shard, squashing them together. */
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       const char *path;
-      svn_stream_t *stream;
+      svn_stringbuf_t *props;
 
       svn_pool_clear(iterpool);
 
@@ -1600,21 +1539,24 @@ copy_revprops(svn_fs_t *fs,
 
       /* Copy all the bits from the non-packed revprop file to the end of
        * the pack file. */
-      SVN_ERR(svn_stream_open_readonly(&stream, path, iterpool, iterpool));
-      SVN_ERR(svn_stream_copy3(stream, pack_stream,
-                               cancel_func, cancel_baton, iterpool));
+      SVN_ERR(svn_stringbuf_from_file2(&props, path, iterpool));
+      SVN_ERR_W(verify_checksum(props, iterpool),
+                apr_psprintf(iterpool, "Failed to read revprops for r%ld.",
+                             rev));
+
+      svn_packed__add_bytes(stream, props->data, props->len);
     }
 
-  /* flush stream buffers to content buffer */
-  SVN_ERR(svn_stream_close(pack_stream));
+  /* Create the auto-fsync'ing pack file. */
+  SVN_ERR(svn_fs_x__batch_fsync_open_file(&pack_file, batch,
+                                          svn_dirent_join(pack_file_dir,
+                                                          pack_filename,
+                                                          scratch_pool),
+                                          scratch_pool));
 
-  /* compress the content (or just store it for COMPRESSION_LEVEL 0) */
-  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
-                        compressed, compression_level));
+  /* write all to disk */
+  SVN_ERR(write_packed_data_checksummed(root, pack_file, scratch_pool));
 
-  /* write the pack file content to disk */
-  SVN_ERR(svn_io_file_write_full(pack_file, compressed->data, compressed->len,
-                                 NULL, scratch_pool));
   svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/revprops.h Tue Oct 11 
09:11:50 2016
@@ -46,6 +46,17 @@ svn_fs_x__reset_revprop_generation_file(
 void
 svn_fs_x__invalidate_revprop_generation(svn_fs_t *fs);
 
+/* Utility function serializing PROPLIST into FILE and adding the checksum.
+ * Use SCRATCH_POOL for temporary allocations.
+ *
+ * Call this only when creating initial revprop file contents.
+ * For modifications use svn_fs_x__set_revision_proplist.
+ */
+svn_error_t *
+svn_fs_x__write_non_packed_revprops(apr_file_t *file,
+                                    apr_hash_t *proplist,
+                                    apr_pool_t *scratch_pool);
+
 /* Read the revprops for revision REV in FS and return them in *PROPLIST_P.
  * If BYPASS_CACHE is set, don't consult the disks but always read from disk.
  * If REFRESH is set, update the revprop generation info; otherwise access

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c 
(original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.c Tue Oct 
11 09:11:50 2016
@@ -259,6 +259,9 @@ serialize_dir(svn_fs_x__dir_data_t *dir,
                            * sizeof(svn_fs_x__dirent_t*);
   apr_size_t lengths_len = (count + over_provision) * sizeof(apr_uint32_t);
 
+  /* Estimate the size of a directory entry + its name. */
+  enum { ENTRY_SIZE = sizeof(svn_fs_x__dirent_t) + 32 };
+
   /* copy the hash entries to an auxiliary struct of known layout */
   dir_data.count = count;
   dir_data.txn_filesize = dir->txn_filesize;
@@ -274,7 +277,8 @@ serialize_dir(svn_fs_x__dir_data_t *dir,
    * estimate for the size of the buffer that we will need. */
   context = svn_temp_serializer__init(&dir_data,
                                       sizeof(dir_data),
-                                      50 + count * 200 + entries_len,
+                                      50 + count * ENTRY_SIZE
+                                         + entries_len + lengths_len,
                                       scratch_pool);
 
   /* serialize entries references */
@@ -675,16 +679,18 @@ svn_fs_x__deserialize_node_revision(void
 }
 
 /* Utility function that returns the directory serialized inside CONTEXT
- * to DATA and DATA_LEN. */
+ * to DATA and DATA_LEN.  If OVERPROVISION is set, allocate some extra
+ * room for future in-place changes by svn_fs_x__replace_dir_entry. */
 static svn_error_t *
 return_serialized_dir_context(svn_temp_serializer__context_t *context,
                               void **data,
-                              apr_size_t *data_len)
+                              apr_size_t *data_len,
+                              svn_boolean_t overprovision)
 {
   svn_stringbuf_t *serialized = svn_temp_serializer__get(context);
 
   *data = serialized->data;
-  *data_len = serialized->blocksize;
+  *data_len = overprovision ? serialized->blocksize : serialized->len;
   ((dir_data_t *)serialized->data)->len = serialized->len;
 
   return SVN_NO_ERROR;
@@ -702,7 +708,8 @@ svn_fs_x__serialize_dir_entries(void **d
    * and return the serialized data */
   return return_serialized_dir_context(serialize_dir(dir, pool),
                                        data,
-                                       data_len);
+                                       data_len,
+                                       FALSE);
 }
 
 svn_error_t *
@@ -832,6 +839,10 @@ svn_fs_x__extract_dir_entry(void **out,
   const apr_uint32_t *lengths =
     svn_temp_deserializer__ptr(data, (const void *const *)&dir_data->lengths);
 
+  /* Before we return, make sure we tell the caller this data is even still
+     relevant. */
+  b->out_of_date = dir_data->txn_filesize != b->txn_filesize;
+
   /* Special case: Early out for empty directories.
      That simplifies tests further down the road. */
   *out = NULL;
@@ -860,7 +871,7 @@ svn_fs_x__extract_dir_entry(void **out,
 
   /* 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. */
-  if (found && dir_data->txn_filesize == b->txn_filesize)
+  if (found && !b->out_of_date)
     {
       const svn_fs_x__dirent_t *source =
           svn_temp_deserializer__ptr(entries, (const void *const 
*)&entries[pos]);
@@ -1020,9 +1031,7 @@ svn_fs_x__replace_dir_entry(void **data,
   serialize_dir_entry(context, &entries[pos], &length);
 
   /* return the updated serialized data */
-  SVN_ERR (return_serialized_dir_context(context,
-                                         data,
-                                         data_len));
+  SVN_ERR(return_serialized_dir_context(context, data, data_len, TRUE));
 
   /* since the previous call may have re-allocated the buffer, the lengths
    * pointer may no longer point to the entry in that buffer. Therefore,
@@ -1117,47 +1126,29 @@ deserialize_change(void *buffer,
   svn_temp_deserializer__resolve(change, (void **)&change->copyfrom_path);
 }
 
-/* Auxiliary structure representing the content of a svn_fs_x__change_t array.
-   This structure is much easier to (de-)serialize than an APR array.
- */
-typedef struct changes_data_t
-{
-  /* number of entries in the array */
-  int count;
-
-  /* reference to the changes */
-  svn_fs_x__change_t **changes;
-} changes_data_t;
-
 svn_error_t *
 svn_fs_x__serialize_changes(void **data,
                             apr_size_t *data_len,
                             void *in,
                             apr_pool_t *pool)
 {
-  apr_array_header_t *array = in;
-  changes_data_t changes;
+  svn_fs_x__changes_list_t *changes = in;
   svn_temp_serializer__context_t *context;
   svn_stringbuf_t *serialized;
   int i;
 
-  /* initialize our auxiliary data structure and link it to the
-   * array elements */
-  changes.count = array->nelts;
-  changes.changes = (svn_fs_x__change_t **)array->elts;
-
   /* serialize it and all its elements */
-  context = svn_temp_serializer__init(&changes,
-                                      sizeof(changes),
-                                      changes.count * 250,
+  context = svn_temp_serializer__init(changes,
+                                      sizeof(*changes),
+                                      changes->count * 250,
                                       pool);
 
   svn_temp_serializer__push(context,
-                            (const void * const *)&changes.changes,
-                            changes.count * sizeof(**changes.changes));
+                            (const void * const *)&changes->changes,
+                            changes->count * sizeof(*changes->changes));
 
-  for (i = 0; i < changes.count; ++i)
-    serialize_change(context, &changes.changes[i]);
+  for (i = 0; i < changes->count; ++i)
+    serialize_change(context, &changes->changes[i]);
 
   svn_temp_serializer__pop(context);
 
@@ -1177,9 +1168,7 @@ svn_fs_x__deserialize_changes(void **out
                               apr_pool_t *result_pool)
 {
   int i;
-  changes_data_t *changes = (changes_data_t *)data;
-  apr_array_header_t *array = apr_array_make(result_pool, 0,
-                                             sizeof(svn_fs_x__change_t *));
+  svn_fs_x__changes_list_t *changes = (svn_fs_x__changes_list_t *)data;
 
   /* de-serialize our auxiliary data structure */
   svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
@@ -1189,15 +1178,8 @@ svn_fs_x__deserialize_changes(void **out
     deserialize_change(changes->changes,
                        (svn_fs_x__change_t **)&changes->changes[i]);
 
-  /* Use the changes buffer as the array's data buffer
-   * (DATA remains valid for at least as long as POOL). */
-  array->elts = (char *)changes->changes;
-  array->nelts = changes->count;
-  array->nalloc = changes->count;
-
   /* done */
-  *out = array;
+  *out = changes;
 
   return SVN_NO_ERROR;
 }
-

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h 
(original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/temp_serializer.h Tue Oct 
11 09:11:50 2016
@@ -182,6 +182,12 @@ typedef struct svn_fs_x__ede_baton_t
   /** Current length of the in-txn in-disk representation of the directory.
    * SVN_INVALID_FILESIZE if unknown. */
   svn_filesize_t txn_filesize;
+
+  /** Will be set by the callback.  If FALSE, the cached data is out of date.
+   * We need this indicator because the svn_cache__t interface will always
+   * report the lookup as a success (FOUND==TRUE) if the generic lookup was
+   * successful -- regardless of what the entry extraction callback does. */
+  svn_boolean_t out_of_date;
 } svn_fs_x__ede_baton_t;
 
 /**
@@ -260,9 +266,34 @@ svn_fs_x__deserialize_rep_header(void **
                                  apr_size_t data_len,
                                  apr_pool_t *result_pool);
 
+/*** Block of changes in a changed paths list. */
+typedef struct svn_fs_x__changes_list_t
+{
+  /* Offset of the first element in CHANGES within the changed paths list
+     on disk. */
+  apr_off_t start_offset;
+
+  /* Offset of the first element behind CHANGES within the changed paths
+     list on disk. */
+  apr_off_t end_offset;
+
+  /* End of list reached? This may have false negatives in case the number
+     of elements in the list is a multiple of our block / range size. */
+  svn_boolean_t eol;
+
+  /* Array of #svn_fs_x__change_t * representing a consecutive sub-range of
+     elements in a changed paths list. */
+
+  /* number of entries in the array */
+  int count;
+
+  /* reference to the changes */
+  svn_fs_x__change_t **changes;
+
+} svn_fs_x__changes_list_t;
+
 /**
- * Implements #svn_cache__serialize_func_t for an #apr_array_header_t of
- * #svn_fs_x__change_t *.
+ * Implements #svn_cache__serialize_func_t for a #svn_fs_x__changes_list_t.
  */
 svn_error_t *
 svn_fs_x__serialize_changes(void **data,
@@ -271,8 +302,7 @@ svn_fs_x__serialize_changes(void **data,
                             apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__deserialize_func_t for an #apr_array_header_t of
- * #svn_fs_x__change_t *.
+ * Implements #svn_cache__deserialize_func_t for a #svn_fs_x__changes_list_t.
  */
 svn_error_t *
 svn_fs_x__deserialize_changes(void **out,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.c Tue Oct 11 
09:11:50 2016
@@ -43,6 +43,7 @@
 #include "rep-cache.h"
 #include "index.h"
 #include "batch_fsync.h"
+#include "revprops.h"
 
 #include "private/svn_fs_util.h"
 #include "private/svn_fspath.h"
@@ -973,16 +974,6 @@ fold_change(apr_hash_t *changed_paths,
       /* This path already exists in the hash, so we have to merge
          this change into the already existing one. */
 
-      /* Sanity check: we should be talking about the same node
-         revision ID as our last change except where the last change
-         was a deletion. */
-      if (!svn_fs_x__id_eq(&old_change->noderev_id, &change->noderev_id)
-          && (old_change->change_kind != svn_fs_path_change_delete))
-        return svn_error_create
-          (SVN_ERR_FS_CORRUPT, NULL,
-           _("Invalid change ordering: new node revision ID "
-             "without delete"));
-
       /* Sanity check: an add, replacement, or reset must be the first
          thing to follow a deletion. */
       if ((old_change->change_kind == svn_fs_path_change_delete)
@@ -1941,7 +1932,6 @@ svn_error_t *
 svn_fs_x__add_change(svn_fs_t *fs,
                      svn_fs_x__txn_id_t txn_id,
                      const char *path,
-                     const svn_fs_x__id_t *id,
                      svn_fs_path_change_kind_t change_kind,
                      svn_boolean_t text_mod,
                      svn_boolean_t prop_mod,
@@ -1964,7 +1954,6 @@ svn_fs_x__add_change(svn_fs_t *fs,
 
   change.path.data = path;
   change.path.len = strlen(path);
-  change.noderev_id = *id;
   change.change_kind = change_kind;
   change.text_mod = text_mod;
   change.prop_mod = prop_mod;
@@ -2289,7 +2278,7 @@ rep_write_get_baton(rep_write_baton_t **
                                                        b->local_pool),
                               b->local_pool);
 
-  SVN_ERR(svn_fs_x__get_file_offset(&b->rep_offset, file, b->local_pool));
+  SVN_ERR(svn_io_file_get_offset(&b->rep_offset, file, b->local_pool));
 
   /* Get the base for this delta. */
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->local_pool));
@@ -2312,8 +2301,7 @@ rep_write_get_baton(rep_write_baton_t **
                                      b->local_pool));
 
   /* Now determine the offset of the actual svndiff data. */
-  SVN_ERR(svn_fs_x__get_file_offset(&b->delta_start, file,
-                                    b->local_pool));
+  SVN_ERR(svn_io_file_get_offset(&b->delta_start, file, b->local_pool));
 
   /* Cleanup in case something goes wrong. */
   apr_pool_cleanup_register(b->local_pool, b, rep_write_cleanup,
@@ -2525,7 +2513,7 @@ rep_write_contents_close(void *baton)
   SVN_ERR(svn_stream_close(b->delta_stream));
 
   /* Determine the length of the svndiff data. */
-  SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->local_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->local_pool));
   rep->size = offset - b->delta_start;
 
   /* Fill in the rest of the representation field. */
@@ -2577,7 +2565,7 @@ rep_write_contents_close(void *baton)
       noderev_id.number = rep->id.number;
 
       entry.offset = b->rep_offset;
-      SVN_ERR(svn_fs_x__get_file_offset(&offset, b->file, b->local_pool));
+      SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->local_pool));
       entry.size = offset - b->rep_offset;
       entry.type = SVN_FS_X__ITEM_TYPE_FILE_REP;
       entry.item_count = 1;
@@ -2816,7 +2804,7 @@ write_container_delta_rep(svn_fs_x__repr
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, scratch_pool));
   SVN_ERR(svn_fs_x__get_contents(&source, fs, base_rep, FALSE, scratch_pool));
 
-  SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
 
   /* Write out the rep header. */
   if (base_rep)
@@ -2837,7 +2825,7 @@ write_container_delta_rep(svn_fs_x__repr
                                                            scratch_pool),
                                   scratch_pool);
   SVN_ERR(svn_fs_x__write_rep_header(&header, file_stream, scratch_pool));
-  SVN_ERR(svn_fs_x__get_file_offset(&delta_start, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&delta_start, file, scratch_pool));
 
   /* Prepare to write the svndiff data. */
   svn_txdelta_to_svndiff3(&diff_wh,
@@ -2886,7 +2874,7 @@ write_container_delta_rep(svn_fs_x__repr
       svn_fs_x__id_t noderev_id;
 
       /* Write out our cosmetic end marker. */
-      SVN_ERR(svn_fs_x__get_file_offset(&rep_end, file, scratch_pool));
+      SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
       SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
       SVN_ERR(svn_stream_close(file_stream));
 
@@ -2899,7 +2887,7 @@ write_container_delta_rep(svn_fs_x__repr
       noderev_id.number = rep->id.number;
 
       entry.offset = offset;
-      SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+      SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
       entry.size = offset - entry.offset;
       entry.type = item_type;
       entry.item_count = 1;
@@ -3042,7 +3030,6 @@ write_final_rev(svn_fs_x__id_t *new_id_p
   svn_fs_x__change_set_t change_set = svn_fs_x__change_set_by_rev(rev);
   svn_stream_t *file_stream;
   apr_pool_t *subpool;
-  svn_fs_x__change_t *change;
 
   /* Check to see if this is a transaction node. */
   if (txn_id == SVN_FS_X__INVALID_TXN_ID)
@@ -3153,7 +3140,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
   if (noderev->copyroot_rev == SVN_INVALID_REVNUM)
     noderev->copyroot_rev = rev;
 
-  SVN_ERR(svn_fs_x__get_file_offset(&my_offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&my_offset, file, scratch_pool));
 
   SVN_ERR(store_l2p_index_entry(fs, txn_id, my_offset,
                                 noderev->noderev_id.number, scratch_pool));
@@ -3212,7 +3199,7 @@ write_final_rev(svn_fs_x__id_t *new_id_p
   noderev_id.change_set = SVN_FS_X__INVALID_CHANGE_SET;
 
   entry.offset = my_offset;
-  SVN_ERR(svn_fs_x__get_file_offset(&my_offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&my_offset, file, scratch_pool));
   entry.size = my_offset - entry.offset;
   entry.type = SVN_FS_X__ITEM_TYPE_NODEREV;
   entry.item_count = 1;
@@ -3220,38 +3207,12 @@ write_final_rev(svn_fs_x__id_t *new_id_p
 
   SVN_ERR(store_p2l_index_entry(fs, txn_id, &entry, scratch_pool));
 
-  /* Update the ID within the changed paths list. */
-  change = svn_hash_gets(changed_paths, noderev->created_path);
-  if (change)
-    change->noderev_id = noderev->noderev_id;
-
   /* Return our ID that references the revision file. */
   *new_id_p = new_id;
 
   return SVN_NO_ERROR;
 }
 
-/* Reset all in-transaction noderev-IDs in CHANGED_PATHS.  They should
-   belong to deleted nodes only.  At any rate, these IDs become invalid
-   as soon as transaction got committed.
-   Perform temporary allocations in SCRATCH_POOL. */
-static svn_error_t *
-sanitize_changed_path_info(apr_hash_t *changed_paths,
-                           apr_pool_t *scratch_pool)
-{
-  apr_hash_index_t *hi;
-  for (hi = apr_hash_first(scratch_pool, changed_paths);
-       hi;
-       hi = apr_hash_next(hi))
-    {
-      svn_fs_x__change_t *change = apr_hash_this_val(hi);
-      if (svn_fs_x__is_txn(change->noderev_id.change_set))
-        svn_fs_x__id_reset(&change->noderev_id);
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Write the changed path info CHANGED_PATHS from transaction TXN_ID to the
    permanent rev-file FILE representing NEW_REV in filesystem FS.  *OFFSET_P
    is set the to offset in the file of the beginning of this information.
@@ -3272,7 +3233,7 @@ write_final_changed_path_info(apr_off_t
   svn_fs_x__id_t rev_item
     = {SVN_INVALID_REVNUM, SVN_FS_X__ITEM_INDEX_CHANGES};
 
-  SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
 
   /* write to target file & calculate checksum */
   stream = svn_checksum__wrap_write_stream_fnv1a_32x4(&entry.fnv1_checksum,
@@ -3286,7 +3247,7 @@ write_final_changed_path_info(apr_off_t
 
   /* reference changes from the indexes */
   entry.offset = offset;
-  SVN_ERR(svn_fs_x__get_file_offset(&offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
   entry.size = offset - entry.offset;
   entry.type = SVN_FS_X__ITEM_TYPE_CHANGES;
   entry.item_count = 1;
@@ -3434,7 +3395,6 @@ write_final_revprop(const char **path,
   svn_string_t date;
   svn_string_t *client_date;
   apr_file_t *file;
-  svn_stream_t *stream;
 
   SVN_ERR(svn_fs_x__txn_proplist(&props, txn, scratch_pool));
 
@@ -3463,9 +3423,7 @@ write_final_revprop(const char **path,
   SVN_ERR(svn_fs_x__batch_fsync_open_file(&file, batch, *path, scratch_pool));
 
   /* Write the new contents to the final revprops file. */
-  stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
-  SVN_ERR(svn_fs_x__write_properties(stream, props, scratch_pool));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_fs_x__write_non_packed_revprops(file, props, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -3636,36 +3594,30 @@ write_next_file(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
-/* Baton type to be used with bump_ids. */
-typedef struct bump_ids_baton_t
-{
-  svn_fs_t *fs;
-  svn_revnum_t new_rev;
-  svn_fs_x__batch_fsync_t *batch;
-} bump_ids_baton_t;
-
-/* Bump the 'current' and 'txn-current' files in BATON->FS. */
+/* Bump the 'current' file in FS to NEW_REV.  Schedule fsyncs in BATCH.
+ * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
-bump_ids(void *baton,
-         apr_pool_t *scratch_pool)
+bump_current(svn_fs_t *fs,
+             svn_revnum_t new_rev,
+             svn_fs_x__batch_fsync_t *batch,
+             apr_pool_t *scratch_pool)
 {
-  bump_ids_baton_t *b = baton;
   const char *current_filename;
 
   /* Write the 'next' file. */
-  SVN_ERR(write_next_file(b->fs, b->new_rev, b->batch, scratch_pool));
+  SVN_ERR(write_next_file(fs, new_rev, batch, scratch_pool));
 
   /* Commit all changes to disk. */
-  SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
+  SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
 
   /* Make the revision visible to all processes and threads. */
-  current_filename = svn_fs_x__path_current(b->fs, scratch_pool);
-  SVN_ERR(svn_fs_x__move_into_place(svn_fs_x__path_next(b->fs, scratch_pool),
+  current_filename = svn_fs_x__path_current(fs, scratch_pool);
+  SVN_ERR(svn_fs_x__move_into_place(svn_fs_x__path_next(fs, scratch_pool),
                                     current_filename, current_filename,
-                                    b->batch, scratch_pool));
+                                    batch, scratch_pool));
 
   /* Make the new revision permanently visible. */
-  SVN_ERR(svn_fs_x__batch_fsync_run(b->batch, scratch_pool));
+  SVN_ERR(svn_fs_x__batch_fsync_run(batch, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -3733,7 +3685,6 @@ commit_body(void *baton,
   svn_fs_x__txn_id_t txn_id = svn_fs_x__txn_get_id(cb->txn);
   apr_hash_t *changed_paths;
   svn_fs_x__batch_fsync_t *batch;
-  bump_ids_baton_t bump_ids_baton;
   apr_array_header_t *directory_ids
     = apr_array_make(scratch_pool, 4, sizeof(svn_fs_x__pair_cache_key_t));
 
@@ -3779,7 +3730,8 @@ commit_body(void *baton,
 
   /* Use this to force all data to be flushed to physical storage
      (to the degree our environment will allow). */
-  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, scratch_pool));
+  SVN_ERR(svn_fs_x__batch_fsync_create(&batch, ffd->flush_to_disk,
+                                       scratch_pool));
 
   /* Set up the target directory. */
   SVN_ERR(auto_create_shard(cb->fs, new_rev, batch, subpool));
@@ -3791,7 +3743,7 @@ commit_body(void *baton,
      ### not complete for any reason the transaction will be lost. */
   SVN_ERR(get_writable_final_rev(&proto_file, cb->fs, txn_id, new_rev,
                                  batch, subpool));
-  SVN_ERR(svn_fs_x__get_file_offset(&initial_offset, proto_file, subpool));
+  SVN_ERR(svn_io_file_get_offset(&initial_offset, proto_file, subpool));
   svn_pool_clear(subpool);
 
   /* Write out all the node-revisions and directory contents. */
@@ -3803,7 +3755,6 @@ commit_body(void *baton,
   svn_pool_clear(subpool);
 
   /* Write the changed-path information. */
-  SVN_ERR(sanitize_changed_path_info(changed_paths, subpool));
   SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
                                         cb->fs, txn_id, changed_paths,
                                         new_rev, subpool));
@@ -3833,16 +3784,8 @@ commit_body(void *baton,
   SVN_ERR(verify_as_revision_before_current_plus_plus(cb->fs, new_rev,
                                                       subpool));
 
-  /* Bump 'current' and 'txn-current'.
-     The latter is a piggy-back allocation of a new txn ID such that
-     reusing this FS for multiple commits does not involve additional
-     fsync latencies.  If that txn ID goes to waste, it's not a big loss
-     because we've got 18 quintillion of them ... */
-  bump_ids_baton.fs = cb->fs;
-  bump_ids_baton.new_rev = new_rev;
-  bump_ids_baton.batch = batch;
-  SVN_ERR(svn_fs_x__with_txn_current_lock(cb->fs, bump_ids, &bump_ids_baton,
-                                          subpool));
+  /* Bump 'current'. */
+  SVN_ERR(bump_current(cb->fs, new_rev, batch, subpool));
 
   /* At this point the new revision is committed and globally visible
      so let the caller know it succeeded by giving it the new revision
@@ -3920,6 +3863,8 @@ svn_fs_x__commit(svn_revnum_t *new_rev_p
 
   if (ffd->rep_sharing_allowed)
     {
+      svn_error_t *err;
+
       SVN_ERR(svn_fs_x__open_rep_cache(fs, scratch_pool));
 
       /* Write new entries to the rep-sharing database.
@@ -3930,9 +3875,21 @@ svn_fs_x__commit(svn_revnum_t *new_rev_p
       /* ### A commit that touches thousands of files will starve other
              (reader/writer) commits for the duration of the below call.
              Maybe write in batches? */
-      SVN_SQLITE__WITH_TXN(
-        write_reps_to_cache(fs, cb.reps_to_cache, scratch_pool),
-        ffd->rep_cache_db);
+      SVN_ERR(svn_sqlite__begin_transaction(ffd->rep_cache_db));
+      err = write_reps_to_cache(fs, cb.reps_to_cache, scratch_pool);
+      err = svn_sqlite__finish_transaction(ffd->rep_cache_db, err);
+
+      if (svn_error_find_cause(err, SVN_ERR_SQLITE_ROLLBACK_FAILED))
+        {
+          /* Failed rollback means that our db connection is unusable, and
+             the only thing we can do is close it.  The connection will be
+             reopened during the next operation with rep-cache.db. */
+          return svn_error_trace(
+              svn_error_compose_create(err,
+                                       svn_fs_x__close_rep_cache(fs)));
+        }
+      else if (err)
+        return svn_error_trace(err);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/transaction.h Tue Oct 11 
09:11:50 2016
@@ -64,8 +64,8 @@ svn_fs_x__with_txn_current_lock(svn_fs_t
    call BODY with BATON and that subpool, destroy the subpool (releasing
    the locks) and return what BODY returned.
 
-   This combines svn_fs_fs__with_write_lock, svn_fs_fs__with_pack_lock,
-   and svn_fs_fs__with_txn_current_lock, ensuring correct lock ordering. */
+   This combines svn_fs_x__with_write_lock, svn_fs_x__with_pack_lock,
+   and svn_fs_x__with_txn_current_lock, ensuring correct lock ordering. */
 svn_error_t *
 svn_fs_x__with_all_locks(svn_fs_t *fs,
                          svn_error_t *(*body)(void *baton,
@@ -167,9 +167,9 @@ svn_fs_x__set_entry(svn_fs_t *fs,
                     apr_pool_t *scratch_pool);
 
 /* Add a change to the changes record for filesystem FS in transaction
-   TXN_ID.  Mark path PATH, having noderev-id ID, as changed according to
-   the type in CHANGE_KIND.  If the text representation was changed set
-   TEXT_MOD to TRUE, and likewise for PROP_MOD as well as MERGEINFO_MOD.
+   TXN_ID.  Mark path PATH as changed according to the type in
+   CHANGE_KIND.  If the text representation was changed set TEXT_MOD
+   to TRUE, and likewise for PROP_MOD as well as MERGEINFO_MOD.
    If this change was the result of a copy, set COPYFROM_REV and
    COPYFROM_PATH to the revision and path of the copy source, otherwise
    they should be set to SVN_INVALID_REVNUM and NULL.  Perform any
@@ -178,7 +178,6 @@ svn_error_t *
 svn_fs_x__add_change(svn_fs_t *fs,
                      svn_fs_x__txn_id_t txn_id,
                      const char *path,
-                     const svn_fs_x__id_t *id,
                      svn_fs_path_change_kind_t change_kind,
                      svn_boolean_t text_mod,
                      svn_boolean_t prop_mod,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/tree.c Tue Oct 11 
09:11:50 2016
@@ -224,18 +224,16 @@ parent_path_relpath(svn_fs_x__dag_path_t
 
 /* Add a change to the changes table in FS, keyed on transaction id
    TXN_ID, and indicated that a change of kind CHANGE_KIND occurred on
-   PATH (whose node revision id is--or was, in the case of a
-   deletion--NODEREV_ID), and optionally that TEXT_MODs, PROP_MODs or
-   MERGEINFO_MODs occurred.  If the change resulted from a copy,
-   COPYFROM_REV and COPYFROM_PATH specify under which revision and path
-   the node was copied from.  If this was not part of a copy, COPYFROM_REV
-   should be SVN_INVALID_REVNUM.  Use SCRATCH_POOL for temporary allocations.
+   PATH, and optionally that TEXT_MODs, PROP_MODs or MERGEINFO_MODs
+   occurred.  If the change resulted from a copy, COPYFROM_REV and
+   COPYFROM_PATH specify under which revision and path the node was
+   copied from.  If this was not part of a copy, COPYFROM_REV should
+   be SVN_INVALID_REVNUM.  Use SCRATCH_POOL for temporary allocations.
  */
 static svn_error_t *
 add_change(svn_fs_t *fs,
            svn_fs_x__txn_id_t txn_id,
            const char *path,
-           const svn_fs_x__id_t *noderev_id,
            svn_fs_path_change_kind_t change_kind,
            svn_boolean_t text_mod,
            svn_boolean_t prop_mod,
@@ -248,8 +246,7 @@ add_change(svn_fs_t *fs,
   return svn_fs_x__add_change(fs, txn_id,
                               svn_fs__canonicalize_abspath(path,
                                                            scratch_pool),
-                              noderev_id, change_kind,
-                              text_mod, prop_mod, mergeinfo_mod,
+                              change_kind, text_mod, prop_mod, mergeinfo_mod,
                               node_kind, copyfrom_rev, copyfrom_path,
                               scratch_pool);
 }
@@ -388,26 +385,6 @@ x_node_created_path(const char **created
 }
 
 
-/* Set *KIND_P to the type of node located at PATH under ROOT.
-   Perform temporary allocations in SCRATCH_POOL. */
-static svn_error_t *
-node_kind(svn_node_kind_t *kind_p,
-          svn_fs_root_t *root,
-          const char *path,
-          apr_pool_t *scratch_pool)
-{
-  dag_node_t *node;
-
-  /* Get the node id. */
-  SVN_ERR(svn_fs_x__get_temp_dag_node(&node, root, path, scratch_pool));
-
-  /* Use the node id to get the real kind. */
-  *kind_p = svn_fs_x__dag_node_kind(node);
-
-  return SVN_NO_ERROR;
-}
-
-
 /* Set *KIND_P to the type of node present at PATH under ROOT.  If
    PATH does not exist under ROOT, set *KIND_P to svn_node_none.  Use
    SCRATCH_POOL for temporary allocation. */
@@ -417,7 +394,16 @@ svn_fs_x__check_path(svn_node_kind_t *ki
                      const char *path,
                      apr_pool_t *scratch_pool)
 {
-  svn_error_t *err = node_kind(kind_p, root, path, scratch_pool);
+  dag_node_t *node;
+
+  /* Get the node id. */
+  svn_error_t *err = svn_fs_x__get_temp_dag_node(&node, root, path,
+                                                 scratch_pool);
+
+  /* Use the node id to get the real kind. */
+  if (!err)
+    *kind_p = svn_fs_x__dag_node_kind(node);
+
   if (err &&
       ((err->apr_err == SVN_ERR_FS_NOT_FOUND)
        || (err->apr_err == SVN_ERR_FS_NOT_DIRECTORY)))
@@ -584,7 +570,6 @@ x_change_node_prop(svn_fs_root_t *root,
 
   /* Make a record of this modification in the changes table. */
   SVN_ERR(add_change(root->fs, txn_id, path,
-                     svn_fs_x__dag_get_id(dag_path->node),
                      svn_fs_path_change_modify, FALSE, TRUE, mergeinfo_mod,
                      svn_fs_x__dag_node_kind(dag_path->node),
                      SVN_INVALID_REVNUM, NULL, subpool));
@@ -1457,7 +1442,7 @@ x_make_dir(svn_fs_root_t *root,
   svn_fs_x__update_dag_cache(sub_dir);
 
   /* Make a record of this modification in the changes table. */
-  SVN_ERR(add_change(root->fs, txn_id, path, svn_fs_x__dag_get_id(sub_dir),
+  SVN_ERR(add_change(root->fs, txn_id, path,
                      svn_fs_path_change_add, FALSE, FALSE, FALSE,
                      svn_node_dir, SVN_INVALID_REVNUM, NULL, subpool));
 
@@ -1517,7 +1502,6 @@ x_delete_node(svn_fs_root_t *root,
 
   /* Make a record of this modification in the changes table. */
   SVN_ERR(add_change(root->fs, txn_id, path,
-                     svn_fs_x__dag_get_id(dag_path->node),
                      svn_fs_path_change_delete, FALSE, FALSE, FALSE, kind,
                      SVN_INVALID_REVNUM, NULL, subpool));
 
@@ -1654,8 +1638,7 @@ copy_helper(svn_fs_root_t *from_root,
       /* Make a record of this modification in the changes table. */
       SVN_ERR(svn_fs_x__get_dag_node(&new_node, to_root, to_path,
                                      scratch_pool, scratch_pool));
-      SVN_ERR(add_change(to_root->fs, txn_id, to_path,
-                         svn_fs_x__dag_get_id(new_node), kind, FALSE,
+      SVN_ERR(add_change(to_root->fs, txn_id, to_path, kind, FALSE,
                          FALSE, FALSE, svn_fs_x__dag_node_kind(from_node),
                          from_root->rev, from_canonpath, scratch_pool));
     }
@@ -1795,7 +1778,7 @@ x_make_file(svn_fs_root_t *root,
   svn_fs_x__update_dag_cache(child);
 
   /* Make a record of this modification in the changes table. */
-  SVN_ERR(add_change(root->fs, txn_id, path, svn_fs_x__dag_get_id(child),
+  SVN_ERR(add_change(root->fs, txn_id, path,
                      svn_fs_path_change_add, TRUE, FALSE, FALSE,
                      svn_node_file, SVN_INVALID_REVNUM, NULL, subpool));
 
@@ -2003,7 +1986,6 @@ apply_textdelta(void *baton,
 
   /* Make a record of this modification in the changes table. */
   return add_change(tb->root->fs, txn_id, tb->path,
-                    svn_fs_x__dag_get_id(tb->node),
                     svn_fs_path_change_modify, TRUE, FALSE, FALSE,
                     svn_node_file, SVN_INVALID_REVNUM, NULL, scratch_pool);
 }
@@ -2144,7 +2126,6 @@ apply_text(void *baton,
 
   /* Make a record of this modification in the changes table. */
   return add_change(tb->root->fs, txn_id, tb->path,
-                    svn_fs_x__dag_get_id(tb->node),
                     svn_fs_path_change_modify, TRUE, FALSE, FALSE,
                     svn_node_file, SVN_INVALID_REVNUM, NULL, scratch_pool);
 }
@@ -2255,92 +2236,142 @@ x_get_file_delta_stream(svn_txdelta_stre
 
 /* Finding Changes */
 
-/* Copy CHANGE into a FS API object allocated in RESULT_POOL and return
-   it in *RESULT_P.  Pass CONTEXT to the ID API object being created. */
+/* Implement changes_iterator_vtable_t.get for in-txn change lists.
+   There is no specific FSAP data type, a simple APR hash iterator
+   to the underlying collection is sufficient. */
+static svn_error_t *
+x_txn_changes_iterator_get(svn_fs_path_change3_t **change,
+                           svn_fs_path_change_iterator_t *iterator)
+{
+  apr_hash_index_t *hi = iterator->fsap_data;
+
+  if (hi)
+    {
+      *change = apr_hash_this_val(hi);
+      iterator->fsap_data = apr_hash_next(hi);
+    }
+  else
+    {
+      *change = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static changes_iterator_vtable_t txn_changes_iterator_vtable =
+{
+  x_txn_changes_iterator_get
+};
+
+/* FSAP data structure for in-revision changes list iterators. */
+typedef struct fs_revision_changes_iterator_data_t
+{
+  /* Context that tells the lower layers from where to fetch the next
+     block of changes. */
+  svn_fs_x__changes_context_t *context;
+
+  /* Changes to send. */
+  apr_array_header_t *changes;
+
+  /* Current indexes within CHANGES. */
+  int idx;
+
+  /* A cleanable scratch pool in case we need one.
+     No further sub-pool creation necessary. */
+  apr_pool_t *scratch_pool;
+} fs_revision_changes_iterator_data_t;
+
 static svn_error_t *
-construct_fs_path_change(svn_fs_path_change2_t **result_p,
-                         svn_fs_x__id_context_t *context,
-                         svn_fs_x__change_t *change,
-                         apr_pool_t *result_pool)
+x_revision_changes_iterator_get(svn_fs_path_change3_t **change,
+                                svn_fs_path_change_iterator_t *iterator)
 {
-  const svn_fs_id_t *id
-    = svn_fs_x__id_create(context, &change->noderev_id, result_pool);
-  svn_fs_path_change2_t *result
-    = svn_fs__path_change_create_internal(id, change->change_kind,
-                                          result_pool);
+  fs_revision_changes_iterator_data_t *data = iterator->fsap_data;
 
-  result->text_mod = change->text_mod;
-  result->prop_mod = change->prop_mod;
-  result->node_kind = change->node_kind;
+  /* If we exhausted our block of changes and did not reach the end of the
+     list, yet, fetch the next block.  Note that that block may be empty. */
+  if ((data->idx >= data->changes->nelts) && !data->context->eol)
+    {
+      apr_pool_t *changes_pool = data->changes->pool;
 
-  result->copyfrom_known = change->copyfrom_known;
-  result->copyfrom_rev = change->copyfrom_rev;
-  result->copyfrom_path = change->copyfrom_path;
+      /* Drop old changes block, read new block. */
+      svn_pool_clear(changes_pool);
+      SVN_ERR(svn_fs_x__get_changes(&data->changes, data->context,
+                                    changes_pool, data->scratch_pool));
+      data->idx = 0;
 
-  result->mergeinfo_mod = change->mergeinfo_mod;
+      /* Immediately release any temporary data. */
+      svn_pool_clear(data->scratch_pool);
+    }
 
-  *result_p = result;
+  if (data->idx < data->changes->nelts)
+    {
+      *change = APR_ARRAY_IDX(data->changes, data->idx,
+                              svn_fs_x__change_t *);
+      ++data->idx;
+    }
+  else
+    {
+      *change = NULL;
+    }
 
   return SVN_NO_ERROR;
 }
 
-/* Set *CHANGED_PATHS_P to a newly allocated hash containing
-   descriptions of the paths changed under ROOT.  The hash is keyed
-   with const char * paths and has svn_fs_path_change2_t * values.  Use
-   POOL for all allocations. */
-static svn_error_t *
-x_paths_changed(apr_hash_t **changed_paths_p,
-                svn_fs_root_t *root,
-                apr_pool_t *pool)
+static changes_iterator_vtable_t rev_changes_iterator_vtable =
 {
-  apr_hash_t *changed_paths;
-  svn_fs_path_change2_t *path_change;
-  svn_fs_x__id_context_t *context
-    = svn_fs_x__id_create_context(root->fs, pool);
+  x_revision_changes_iterator_get
+};
 
+static svn_error_t *
+x_report_changes(svn_fs_path_change_iterator_t **iterator,
+                 svn_fs_root_t *root,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
+{
+  svn_fs_path_change_iterator_t *result = apr_pcalloc(result_pool,
+                                                      sizeof(*result));
   if (root->is_txn_root)
     {
-      apr_hash_index_t *hi;
+      apr_hash_t *changed_paths;
       SVN_ERR(svn_fs_x__txn_changes_fetch(&changed_paths, root->fs,
                                           svn_fs_x__root_txn_id(root),
-                                          pool));
-      for (hi = apr_hash_first(pool, changed_paths);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          svn_fs_x__change_t *change = apr_hash_this_val(hi);
-          SVN_ERR(construct_fs_path_change(&path_change, context, change,
-                                           pool));
-          apr_hash_set(changed_paths,
-                       apr_hash_this_key(hi), apr_hash_this_key_len(hi),
-                       path_change);
-        }
+                                          result_pool));
+
+      result->fsap_data = apr_hash_first(result_pool, changed_paths);
+      result->vtable = &txn_changes_iterator_vtable;
     }
   else
     {
-      apr_array_header_t *changes;
-      int i;
-
-      SVN_ERR(svn_fs_x__get_changes(&changes, root->fs, root->rev, pool));
-
-      changed_paths = svn_hash__make(pool);
-      for (i = 0; i < changes->nelts; ++i)
-        {
-          svn_fs_x__change_t *change = APR_ARRAY_IDX(changes, i,
-                                                     svn_fs_x__change_t *);
-          SVN_ERR(construct_fs_path_change(&path_change, context, change,
-                                           pool));
-          apr_hash_set(changed_paths, change->path.data, change->path.len,
-                       path_change);
-        }
+      /* The block of changes that we retrieve need to live in a separately
+         cleanable pool. */
+      apr_pool_t *changes_pool = svn_pool_create(result_pool);
+
+      /* Our iteration context info. */
+      fs_revision_changes_iterator_data_t *data = apr_pcalloc(result_pool,
+                                                              sizeof(*data));
+
+      /* This pool must remain valid as long as ITERATOR lives but will
+         be used only for temporary allocations and will be cleaned up
+         frequently.  So, this must be a sub-pool of RESULT_POOL. */
+      data->scratch_pool = svn_pool_create(result_pool);
+
+      /* Fetch the first block of data. */
+      SVN_ERR(svn_fs_x__create_changes_context(&data->context,
+                                               root->fs, root->rev,
+                                               result_pool, scratch_pool));
+      SVN_ERR(svn_fs_x__get_changes(&data->changes, data->context,
+                                    changes_pool, scratch_pool));
+
+      /* Return the fully initialized object. */
+      result->fsap_data = data;
+      result->vtable = &rev_changes_iterator_vtable;
     }
 
-  *changed_paths_p = changed_paths;
+  *iterator = result;
 
   return SVN_NO_ERROR;
 }
 
-
 
 /* Our coolio opaque history object. */
 typedef struct fs_history_data_t
@@ -3169,7 +3200,8 @@ x_get_mergeinfo(svn_mergeinfo_catalog_t
 
 /* The vtable associated with root objects. */
 static root_vtable_t root_vtable = {
-  x_paths_changed,
+  NULL,
+  x_report_changes,
   svn_fs_x__check_path,
   x_node_history,
   x_node_id,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/util.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/util.c Tue Oct 11 
09:11:50 2016
@@ -535,6 +535,7 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
                                  svn_revnum_t revnum,
                                  apr_pool_t *scratch_pool)
 {
+  svn_fs_x__data_t *ffd = fs->fsap_data;
   const char *final_path;
   char buf[SVN_INT64_BUFFER_SIZE];
   apr_size_t len = svn__i64toa(buf, revnum);
@@ -543,8 +544,8 @@ svn_fs_x__write_min_unpacked_rev(svn_fs_
   final_path = svn_fs_x__path_min_unpacked_rev(fs, scratch_pool);
 
   SVN_ERR(svn_io_write_atomic2(final_path, buf, len + 1,
-                               final_path /* copy_perms */, TRUE,
-                               scratch_pool));
+                               final_path /* copy_perms */,
+                               ffd->flush_to_disk, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -567,7 +568,7 @@ svn_fs_x__read_current(svn_revnum_t *rev
   return SVN_NO_ERROR;
 }
 
-/* Atomically update the 'current' file to hold the specifed REV.
+/* Atomically update the 'current' file to hold the specified REV.
    Perform temporary allocations in SCRATCH_POOL. */
 svn_error_t *
 svn_fs_x__write_current(svn_fs_t *fs,
@@ -644,22 +645,6 @@ svn_fs_x__try_stringbuf_from_file(svn_st
 
 /* Fetch the current offset of FILE into *OFFSET_P. */
 svn_error_t *
-svn_fs_x__get_file_offset(apr_off_t *offset_p,
-                          apr_file_t *file,
-                          apr_pool_t *scratch_pool)
-{
-  apr_off_t offset;
-
-  /* Note that, for buffered files, one (possibly surprising) side-effect
-     of this call is to flush any unwritten data to disk. */
-  offset = 0;
-  SVN_ERR(svn_io_file_seek(file, APR_CUR, &offset, scratch_pool));
-  *offset_p = offset;
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_fs_x__read_content(svn_stringbuf_t **content,
                        const char *fname,
                        apr_pool_t *result_pool)

Modified: subversion/branches/ra-git/subversion/libsvn_fs_x/util.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_x/util.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_x/util.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_x/util.h Tue Oct 11 
09:11:50 2016
@@ -369,7 +369,7 @@ svn_fs_x__check_file_buffer_numeric(cons
                                     apr_pool_t *scratch_pool);
 
 /* Set *MIN_UNPACKED_REV to the integer value read from the file returned
- * by #svn_fs_fs__path_min_unpacked_rev() for FS.
+ * by #svn_fs_x__path_min_unpacked_rev() for FS.
  * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
@@ -422,13 +422,6 @@ svn_fs_x__try_stringbuf_from_file(svn_st
                                   svn_boolean_t last_attempt,
                                   apr_pool_t *result_pool);
 
-/* Fetch the current offset of FILE into *OFFSET_P.
- * Perform temporary allocations in SCRATCH_POOL. */
-svn_error_t *
-svn_fs_x__get_file_offset(apr_off_t *offset_p,
-                          apr_file_t *file,
-                          apr_pool_t *scratch_pool);
-
 /* Read the file FNAME and store the contents in *BUF.
    Allocations are performed in RESULT_POOL. */
 svn_error_t *
@@ -456,7 +449,7 @@ svn_fs_x__read_number_from_stream(apr_in
    Temporary allocations are from SCRATCH_POOL.
 
    This function almost duplicates svn_io_file_move(), but it tries to
-   guarantee a flush. */
+   guarantee a flush if BATCH->FLUSH_TO_DISK is non-zero. */
 svn_error_t *
 svn_fs_x__move_into_place(const char *old_filename,
                           const char *new_filename,

Modified: subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_ra_local/ra_plugin.c Tue Oct 
11 09:11:50 2016
@@ -1134,19 +1134,19 @@ svn_ra_local__get_log(svn_ra_session_t *
   receiver = log_receiver_wrapper;
   receiver_baton = &lb;
 
-  return svn_repos_get_logs4(sess->repos,
-                             abs_paths,
-                             start,
-                             end,
-                             limit,
-                             discover_changed_paths,
-                             strict_node_history,
-                             include_merged_revisions,
-                             revprops,
-                             NULL, NULL,
-                             receiver,
-                             receiver_baton,
-                             pool);
+  return svn_repos__get_logs_compat(sess->repos,
+                                    abs_paths,
+                                    start,
+                                    end,
+                                    limit,
+                                    discover_changed_paths,
+                                    strict_node_history,
+                                    include_merged_revisions,
+                                    revprops,
+                                    NULL, NULL,
+                                    receiver,
+                                    receiver_baton,
+                                    pool);
 }
 
 
@@ -1362,7 +1362,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
           if (dirent_fields & SVN_DIRENT_SIZE)
             {
               /* size  */
-              if (entry->kind == svn_node_dir)
+              if (fs_entry->kind == svn_node_dir)
                 entry->size = 0;
               else
                 SVN_ERR(svn_fs_file_length(&(entry->size), root,


Reply via email to