Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.c Tue Oct 11 
09:11:50 2016
@@ -221,7 +221,7 @@ typedef struct pack_context_t
    * to NULL that we already processed. */
   apr_array_header_t *reps;
 
-  /* array of int, marking for each revision, the which offset their items
+  /* array of int, marking for each revision, at which offset their items
    * begin in REPS.  Will be filled in phase 2 and be cleared after
    * each revision range. */
   apr_array_header_t *rev_offsets;
@@ -233,6 +233,9 @@ typedef struct pack_context_t
   /* pool used for temporary data structures that will be cleaned up when
    * the next range of revisions is being processed */
   apr_pool_t *info_pool;
+
+  /* ensure that all filesystem changes are written to disk. */
+  svn_boolean_t flush_to_disk;
 } pack_context_t;
 
 /* Create and initialize a new pack context for packing shard SHARD_REV in
@@ -240,7 +243,7 @@ typedef struct pack_context_t
  * and return the structure in *CONTEXT.
  *
  * Limit the number of items being copied per iteration to MAX_ITEMS.
- * Set CANCEL_FUNC and CANCEL_BATON as well.
+ * Set FLUSH_TO_DISK, CANCEL_FUNC and CANCEL_BATON as well.
  */
 static svn_error_t *
 initialize_pack_context(pack_context_t *context,
@@ -249,6 +252,7 @@ initialize_pack_context(pack_context_t *
                         const char *shard_dir,
                         svn_revnum_t shard_rev,
                         int max_items,
+                        svn_boolean_t flush_to_disk,
                         svn_cancel_func_t cancel_func,
                         void *cancel_baton,
                         apr_pool_t *pool)
@@ -325,6 +329,8 @@ initialize_pack_context(pack_context_t *
   context->info_pool = svn_pool_create(pool);
   context->paths = svn_prefix_tree__create(context->info_pool);
 
+  context->flush_to_disk = flush_to_disk;
+
   return SVN_NO_ERROR;
 }
 
@@ -349,6 +355,7 @@ reset_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_file_trunc(context->reps_file, 0, pool));
 
   svn_pool_clear(context->info_pool);
+  context->paths = svn_prefix_tree__create(context->info_pool);
 
   return SVN_NO_ERROR;
 }
@@ -385,7 +392,8 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_remove_file2(proto_p2l_index_path, FALSE, pool));
 
   /* Ensure that packed file is written to disk.*/
-  SVN_ERR(svn_io_file_flush_to_disk(context->pack_file, pool));
+  if (context->flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(context->pack_file, pool));
   SVN_ERR(svn_io_file_close(context->pack_file, pool));
 
   return SVN_NO_ERROR;
@@ -700,7 +708,7 @@ tweak_path_for_ordering(const char *orig
  */
 static svn_error_t *
 copy_node_to_temp(pack_context_t *context,
-                  apr_file_t *rev_file,
+                  svn_fs_fs__revision_file_t *rev_file,
                   svn_fs_fs__p2l_entry_t *entry,
                   apr_pool_t *pool)
 {
@@ -708,13 +716,10 @@ copy_node_to_temp(pack_context_t *contex
                                          sizeof(*path_order));
   node_revision_t *noderev;
   const char *sort_path;
-  svn_stream_t *stream;
   apr_off_t source_offset = entry->offset;
 
   /* read & parse noderev */
-  stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
-  SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool, pool));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_fs_fs__read_noderev(&noderev, rev_file->stream, pool, pool));
 
   /* create a copy of ENTRY, make it point to the copy destination and
    * store it in CONTEXT */
@@ -724,9 +729,9 @@ copy_node_to_temp(pack_context_t *contex
   add_item_rep_mapping(context, entry);
 
   /* copy the noderev to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &source_offset, pool));
-  SVN_ERR(copy_file_data(context, context->reps_file, rev_file, entry->size,
-                         pool));
+  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &source_offset, pool));
+  SVN_ERR(copy_file_data(context, context->reps_file, rev_file->file,
+                         entry->size, pool));
 
   /* if the node has a data representation, make that the node's "base".
    * This will (often) cause the noderev to be placed right in front of
@@ -803,11 +808,11 @@ compare_ref_to_item(const reference_t *
 
 /* Look for the least significant bit set in VALUE and return the smallest
  * number with the same property, i.e. the largest power of 2 that is a
- * factor in VALUE. */
+ * factor in VALUE.  Edge case: roundness(0) := 0 . */
 static int
 roundness(int value)
 {
-  return value ? value - (value & (value - 1)) : INT_MAX;
+  return value - (value & (value - 1));
 }
 
 /* For all paths in first COUNT entries in PATH_ORDER, mark their latest
@@ -896,14 +901,19 @@ sort_reps_range(pack_context_t *context,
       /* Class 1:
        * Pretty round _and_ a significant stop in the node's delta chain.
        * This may pick up more than one representation from the same chain
-       * but that's rare not a problem.  Prefer simple checks here. */
+       * but that's rare and not a problem.  Prefer simple checks here.
+       *
+       * The divider of 4 is arbitrary but seems to work well in practice.
+       * Larger values increase the number of items in the "hot zone".
+       * Smaller values make delta chains at HEAD more likely to contain
+       * "cold zone" representations. */
       svn_boolean_t likely_target
         =    (round >= ffd->max_linear_deltification)
-          && (4 * round >= path_order[i]->predecessor_count);
+          && (round >= path_order[i]->predecessor_count / 4);
 
       /* Class 2:
        * Anything from short node chains.  The default of 16 is generous
-       * but we'd rather include to many than to few nodes here to keep
+       * but we'd rather include too many than too few nodes here to keep
        * seeks between different regions of this pack file at a minimum. */
       svn_boolean_t likely_head
         =   path_order[i]->predecessor_count
@@ -1046,7 +1056,7 @@ sort_items(apr_array_header_t *entries)
 /* Return the remaining unused bytes in the current block in CONTEXT's
  * pack file.
  */
-static apr_ssize_t
+static apr_off_t
 get_block_left(pack_context_t *context)
 {
   fs_fs_data_t *ffd = context->fs->fsap_data;
@@ -1379,7 +1389,7 @@ pack_range(pack_context_t *context,
                     SVN_ERR(copy_rep_to_temp(context, rev_file->file, entry,
                                              iterpool2));
                   else if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
-                    SVN_ERR(copy_node_to_temp(context, rev_file->file, entry,
+                    SVN_ERR(copy_node_to_temp(context, rev_file, entry,
                                               iterpool2));
                   else
                     SVN_ERR_ASSERT(entry->type == SVN_FS_FS__ITEM_TYPE_UNUSED);
@@ -1438,17 +1448,19 @@ append_revision(pack_context_t *context,
   apr_off_t offset = 0;
   apr_pool_t *iterpool = svn_pool_create(pool);
   svn_fs_fs__revision_file_t *rev_file;
-  svn_filesize_t revfile_size;
+  svn_filesize_t revdata_size;
 
-  /* Copy all the bits from the rev file to the end of the pack file. */
+  /* Copy all non-index contents the rev file to the end of the pack file. */
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, context->fs,
                                            context->start_rev, pool,
                                            iterpool));
-  /* Get the size of the file. */
-  SVN_ERR(svn_io_file_size_get(&revfile_size, rev_file->file, pool));
+  SVN_ERR(svn_fs_fs__auto_read_footer(rev_file));
+  revdata_size = rev_file->l2p_offset;
 
+  SVN_ERR(svn_io_file_aligned_seek(rev_file->file, ffd->block_size, NULL, 0,
+                                   iterpool));
   SVN_ERR(copy_file_data(context, context->pack_file, rev_file->file,
-                         revfile_size, iterpool));
+                         revdata_size, iterpool));
 
   /* mark the start of a new revision */
   SVN_ERR(svn_fs_fs__l2p_proto_index_add_revision(context->proto_l2p_index,
@@ -1456,7 +1468,7 @@ append_revision(pack_context_t *context,
 
   /* read the phys-to-log index file until we covered the whole rev file.
    * That index contains enough info to build both target indexes from it. */
-  while (offset < revfile_size)
+  while (offset < revdata_size)
     {
       /* read one cluster */
       int i;
@@ -1480,7 +1492,7 @@ append_revision(pack_context_t *context,
 
           /* process entry while inside the rev file */
           offset = entry->offset;
-          if (offset < revfile_size)
+          if (offset < revdata_size)
             {
               entry->offset += context->pack_offset;
               offset += entry->size;
@@ -1494,7 +1506,7 @@ append_revision(pack_context_t *context,
     }
 
   svn_pool_destroy(iterpool);
-  context->pack_offset += revfile_size;
+  context->pack_offset += revdata_size;
 
   SVN_ERR(svn_fs_fs__close_revision_file(rev_file));
 
@@ -1505,8 +1517,9 @@ append_revision(pack_context_t *context,
  *
  * Pack the revision shard starting at SHARD_REV in filesystem FS from
  * SHARD_DIR into the PACK_FILE_DIR, using POOL for allocations.  Limit
- * the extra memory consumption to MAX_MEM bytes.  CANCEL_FUNC and
- * CANCEL_BATON are what you think they are.
+ * the extra memory consumption to MAX_MEM bytes.  If FLUSH_TO_DISK is
+ * non-zero, do not return until the data has actually been written on
+ * the disk.  CANCEL_FUNC and CANCEL_BATON are what you think they are.
  */
 static svn_error_t *
 pack_log_addressed(svn_fs_t *fs,
@@ -1514,6 +1527,7 @@ pack_log_addressed(svn_fs_t *fs,
                    const char *shard_dir,
                    svn_revnum_t shard_rev,
                    apr_size_t max_mem,
+                   svn_boolean_t flush_to_disk,
                    svn_cancel_func_t cancel_func,
                    void *cancel_baton,
                    apr_pool_t *pool)
@@ -1546,8 +1560,8 @@ pack_log_addressed(svn_fs_t *fs,
 
   /* set up a pack context */
   SVN_ERR(initialize_pack_context(&context, fs, pack_file_dir, shard_dir,
-                                  shard_rev, max_items, cancel_func,
-                                  cancel_baton, pool));
+                                  shard_rev, max_items, flush_to_disk,
+                                  cancel_func, cancel_baton, pool));
 
   /* phase 1: determine the size of the revisions to pack */
   SVN_ERR(svn_fs_fs__l2p_get_max_ids(&max_ids, fs, shard_rev,
@@ -1559,6 +1573,7 @@ pack_log_addressed(svn_fs_t *fs,
     if (   APR_ARRAY_IDX(max_ids, i, apr_uint64_t)
         <= (apr_uint64_t)max_items - item_count)
       {
+        item_count += APR_ARRAY_IDX(max_ids, i, apr_uint64_t);
         context.end_rev++;
       }
     else
@@ -1670,14 +1685,16 @@ svn_fs_fs__get_packed_offset(apr_off_t *
  *
  * Pack the revision shard starting at SHARD_REV containing exactly
  * MAX_FILES_PER_DIR revisions from SHARD_PATH into the PACK_FILE_DIR,
- * using POOL for allocations.  CANCEL_FUNC and CANCEL_BATON are what you
- * think they are.
+ * using POOL for allocations.  If FLUSH_TO_DISK is non-zero, do not
+ * return until the data has actually been written on the disk.
+ * CANCEL_FUNC and CANCEL_BATON are what you think they are.
  */
 static svn_error_t *
 pack_phys_addressed(const char *pack_file_dir,
                     const char *shard_path,
                     svn_revnum_t start_rev,
                     int max_files_per_dir,
+                    svn_boolean_t flush_to_disk,
                     svn_cancel_func_t cancel_func,
                     void *cancel_baton,
                     apr_pool_t *pool)
@@ -1715,6 +1732,7 @@ pack_phys_addressed(const char *pack_fil
       svn_stream_t *rev_stream;
       const char *path;
       apr_off_t offset;
+      apr_file_t *rev_file;
 
       svn_pool_clear(iterpool);
 
@@ -1728,10 +1746,15 @@ pack_phys_addressed(const char *pack_fil
       SVN_ERR(svn_stream_printf(manifest_stream, iterpool,
                                 "%" APR_OFF_T_FMT "\n", offset));
 
-      /* Copy all the bits from the rev file to the end of the pack file. */
-      SVN_ERR(svn_stream_open_readonly(&rev_stream, path, iterpool, iterpool));
+      /* Copy all the bits from the rev file to the end of the pack file.
+       * Use unbuffered apr_file_t since we're going to write using 16kb
+       * chunks. */
+      SVN_ERR(svn_io_file_open(&rev_file, path, APR_READ, APR_OS_DEFAULT,
+                               iterpool));
+      rev_stream = svn_stream_from_aprfile2(rev_file, FALSE, iterpool);
       SVN_ERR(svn_stream_copy3(rev_stream,
-                               svn_stream_from_aprfile2(pack_file, TRUE, pool),
+                               svn_stream_from_aprfile2(pack_file, TRUE,
+                                                        iterpool),
                                cancel_func, cancel_baton, iterpool));
     }
 
@@ -1739,14 +1762,16 @@ pack_phys_addressed(const char *pack_fil
   SVN_ERR(svn_stream_close(manifest_stream));
 
   /* Ensure that pack file is written to disk. */
-  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, pool));
+  if (flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(manifest_file, pool));
   SVN_ERR(svn_io_file_close(manifest_file, pool));
 
   /* disallow write access to the manifest file */
   SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, iterpool));
 
   /* Ensure that pack file is written to disk. */
-  SVN_ERR(svn_io_file_flush_to_disk(pack_file, pool));
+  if (flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(pack_file, pool));
   SVN_ERR(svn_io_file_close(pack_file, pool));
 
   svn_pool_destroy(iterpool);
@@ -1757,8 +1782,9 @@ pack_phys_addressed(const char *pack_fil
 /* In filesystem FS, pack the revision SHARD containing exactly
  * MAX_FILES_PER_DIR revisions from SHARD_PATH into the PACK_FILE_DIR,
  * using POOL for allocations.  Try to limit the amount of temporary
- * memory needed to MAX_MEM bytes.  CANCEL_FUNC and CANCEL_BATON are what
- * you think they are.
+ * memory needed to MAX_MEM bytes.  If FLUSH_TO_DISK is non-zero, do
+ * not return until the data has actually been written on the disk.
+ * CANCEL_FUNC and CANCEL_BATON are what you think they are.
  *
  * If for some reason we detect a partial packing already performed, we
  * remove the pack file and start again.
@@ -1772,6 +1798,7 @@ pack_rev_shard(svn_fs_t *fs,
                apr_int64_t shard,
                int max_files_per_dir,
                apr_size_t max_mem,
+               svn_boolean_t flush_to_disk,
                svn_cancel_func_t cancel_func,
                void *cancel_baton,
                apr_pool_t *pool)
@@ -1791,12 +1818,13 @@ pack_rev_shard(svn_fs_t *fs,
 
   /* Index information files */
   if (svn_fs_fs__use_log_addressing(fs))
-    SVN_ERR(pack_log_addressed(fs, pack_file_dir, shard_path, shard_rev,
-                               max_mem, cancel_func, cancel_baton, pool));
+    SVN_ERR(pack_log_addressed(fs, pack_file_dir, shard_path,
+                               shard_rev, max_mem, flush_to_disk,
+                               cancel_func, cancel_baton, pool));
   else
     SVN_ERR(pack_phys_addressed(pack_file_dir, shard_path, shard_rev,
-                                max_files_per_dir, cancel_func,
-                                cancel_baton, pool));
+                                max_files_per_dir, flush_to_disk,
+                                cancel_func, cancel_baton, pool));
 
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, pool));
   SVN_ERR(svn_io_set_file_read_only(pack_file_path, FALSE, pool));
@@ -1815,6 +1843,7 @@ struct pack_baton
   void *notify_baton;
   svn_cancel_func_t cancel_func;
   void *cancel_baton;
+  size_t max_mem;
 
   /* Additional entries valid when entering pack_shard(). */
   const char *revs_dir;
@@ -1862,6 +1891,7 @@ synced_pack_shard(void *baton,
                                              ffd->compress_packed_revprops
                                                ? SVN__COMPRESSION_ZLIB_DEFAULT
                                                : SVN__COMPRESSION_NONE,
+                                             ffd->flush_to_disk,
                                              pb->cancel_func,
                                              pb->cancel_baton,
                                              pool));
@@ -1938,8 +1968,8 @@ pack_shard(struct pack_baton *baton,
   /* pack the revision content */
   SVN_ERR(pack_rev_shard(baton->fs, rev_pack_file_dir, baton->rev_shard_path,
                          baton->shard, ffd->max_files_per_dir,
-                         DEFAULT_MAX_MEM, baton->cancel_func,
-                         baton->cancel_baton, pool));
+                         baton->max_mem, ffd->flush_to_disk,
+                         baton->cancel_func, baton->cancel_baton, pool));
 
   /* For newer repo formats, we only acquired the pack lock so far.
      Before modifying the repo state by switching over to the packed
@@ -2048,6 +2078,7 @@ pack_body(void *baton,
 
 svn_error_t *
 svn_fs_fs__pack(svn_fs_t *fs,
+                apr_size_t max_mem,
                 svn_fs_pack_notify_t notify_func,
                 void *notify_baton,
                 svn_cancel_func_t cancel_func,
@@ -2093,6 +2124,7 @@ svn_fs_fs__pack(svn_fs_t *fs,
   pb.notify_baton = notify_baton;
   pb.cancel_func = cancel_func;
   pb.cancel_baton = cancel_baton;
+  pb.max_mem = max_mem ? max_mem : DEFAULT_MAX_MEM;
 
   if (ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT)
     {

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/pack.h Tue Oct 11 
09:11:50 2016
@@ -26,13 +26,19 @@
 #include "fs.h"
 
 /* Possibly pack the repository at PATH.  This just take full shards, and
-   combines all the revision files into a single one, with a manifest header.
+   combines all the revision files into a single one, with a manifest header
+   when required by the repository format.
+
+   MAX_MEM limits the size of in-memory data structures needed for reordering
+   items in format 7 repositories.  0 means use the built-in default.
+
    If given, NOTIFY_FUNC will be called with NOTIFY_BATON to report progress.
    Use optional CANCEL_FUNC/CANCEL_BATON for cancellation support.
 
    Existing filesystem references need not change.  */
 svn_error_t *
 svn_fs_fs__pack(svn_fs_t *fs,
+                apr_size_t max_mem,
                 svn_fs_pack_notify_t notify_func,
                 void *notify_baton,
                 svn_cancel_func_t cancel_func,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.c Tue Oct 11 
09:11:50 2016
@@ -100,12 +100,15 @@ open_rep_cache(void *baton,
                            0, NULL, 0,
                            fs->pool, pool));
 
-  SVN_ERR(svn_sqlite__read_schema_version(&version, sdb, pool));
+  SVN_SQLITE__ERR_CLOSE(svn_sqlite__read_schema_version(&version, sdb, pool),
+                        sdb);
   if (version < REP_CACHE_SCHEMA_FORMAT)
     {
       /* Must be 0 -- an uninitialized (no schema) database. Create
          the schema. Results in schema version of 1.  */
-      SVN_ERR(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA));
+      SVN_SQLITE__ERR_CLOSE(svn_sqlite__exec_statements(sdb,
+                                                        STMT_CREATE_SCHEMA),
+                            sdb);
     }
 
   /* This is used as a flag that the database is available so don't
@@ -126,6 +129,21 @@ svn_fs_fs__open_rep_cache(svn_fs_t *fs,
 }
 
 svn_error_t *
+svn_fs_fs__close_rep_cache(svn_fs_t *fs)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  if (ffd->rep_cache_db)
+    {
+      SVN_ERR(svn_sqlite__close(ffd->rep_cache_db));
+      ffd->rep_cache_db = NULL;
+      ffd->rep_cache_db_opened = 0;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
 svn_fs_fs__exists_rep_cache(svn_boolean_t *exists,
                             svn_fs_t *fs, apr_pool_t *pool)
 {
@@ -239,7 +257,7 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
    If you extend this function, check the callsite to see if you have
    to make it not-ignore additional error codes.  */
 svn_error_t *
-svn_fs_fs__get_rep_reference(representation_t **rep,
+svn_fs_fs__get_rep_reference(representation_t **rep_p,
                              svn_fs_t *fs,
                              svn_checksum_t *checksum,
                              apr_pool_t *pool)
@@ -247,6 +265,7 @@ svn_fs_fs__get_rep_reference(representat
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
+  representation_t *rep;
 
   SVN_ERR_ASSERT(ffd->rep_sharing_allowed);
   if (! ffd->rep_cache_db)
@@ -265,28 +284,28 @@ svn_fs_fs__get_rep_reference(representat
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   if (have_row)
     {
-      *rep = apr_pcalloc(pool, sizeof(**rep));
-      svn_fs_fs__id_txn_reset(&(*rep)->txn_id);
-      memcpy((*rep)->sha1_digest, checksum->digest,
-             sizeof((*rep)->sha1_digest));
-      (*rep)->has_sha1 = TRUE;
-      (*rep)->revision = svn_sqlite__column_revnum(stmt, 0);
-      (*rep)->item_index = svn_sqlite__column_int64(stmt, 1);
-      (*rep)->size = svn_sqlite__column_int64(stmt, 2);
-      (*rep)->expanded_size = svn_sqlite__column_int64(stmt, 3);
-
-      SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, *rep, pool));
+      rep = apr_pcalloc(pool, sizeof(*rep));
+      svn_fs_fs__id_txn_reset(&(rep->txn_id));
+      memcpy(rep->sha1_digest, checksum->digest, sizeof(rep->sha1_digest));
+      rep->has_sha1 = TRUE;
+      rep->revision = svn_sqlite__column_revnum(stmt, 0);
+      rep->item_index = svn_sqlite__column_int64(stmt, 1);
+      rep->size = svn_sqlite__column_int64(stmt, 2);
+      rep->expanded_size = svn_sqlite__column_int64(stmt, 3);
     }
   else
-    *rep = NULL;
+    rep = NULL;
 
   SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (*rep)
+  if (rep)
     {
+      svn_error_t *err;
+
+      SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, rep, pool));
+
       /* Check that REP refers to a revision that exists in FS. */
-      svn_error_t *err = svn_fs_fs__ensure_revision_exists((*rep)->revision,
-                                                           fs, pool);
+      err = svn_fs_fs__ensure_revision_exists(rep->revision, fs, pool);
       if (err)
         return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
                                  "Checksum '%s' in rep-cache is beyond HEAD",
@@ -294,6 +313,7 @@ svn_fs_fs__get_rep_reference(representat
                                                                  pool));
     }
 
+  *rep_p = rep;
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/rep-cache.h Tue Oct 11 
09:11:50 2016
@@ -40,6 +40,10 @@ svn_error_t *
 svn_fs_fs__open_rep_cache(svn_fs_t *fs,
                           apr_pool_t *pool);
 
+/* Close the rep cache database associated with FS. */
+svn_error_t *
+svn_fs_fs__close_rep_cache(svn_fs_t *fs);
+
 /* Set *EXISTS to TRUE iff the rep-cache DB file exists. */
 svn_error_t *
 svn_fs_fs__exists_rep_cache(svn_boolean_t *exists,
@@ -60,11 +64,11 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                               apr_pool_t *pool);
 
 /* Return the representation REP in FS which has fulltext CHECKSUM.
-   REP is allocated in POOL.  If the rep cache database has not been
-   opened, just set *REP to NULL.  Returns SVN_ERR_FS_CORRUPT if
+   *REP_P is allocated in POOL.  If the rep cache database has not been
+   opened, just set *REP_P to NULL.  Returns SVN_ERR_FS_CORRUPT if
    a reference beyond HEAD is detected. */
 svn_error_t *
-svn_fs_fs__get_rep_reference(representation_t **rep,
+svn_fs_fs__get_rep_reference(representation_t **rep_p,
                              svn_fs_t *fs,
                              svn_checksum_t *checksum,
                              apr_pool_t *pool);

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=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.c Tue Oct 11 
09:11:50 2016
@@ -79,6 +79,7 @@ svn_fs_fs__upgrade_pack_revprops(svn_fs_
                                              shard, ffd->max_files_per_dir,
                                              (int)(0.9 * 
ffd->revprop_pack_size),
                                              compression_level,
+                                             ffd->flush_to_disk,
                                              cancel_func, cancel_baton,
                                              iterpool));
       if (notify_func)
@@ -738,6 +739,7 @@ write_non_packed_revprop(const char **fi
                          apr_hash_t *proplist,
                          apr_pool_t *pool)
 {
+  fs_fs_data_t *ffd = fs->fsap_data;
   apr_file_t *file;
   svn_stream_t *stream;
   *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
@@ -752,7 +754,8 @@ write_non_packed_revprop(const char **fi
   SVN_ERR(svn_stream_close(stream));
 
   /* Flush temporary file to disk and close it. */
-  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  if (ffd->flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(file, pool));
   SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
@@ -775,8 +778,10 @@ switch_to_new_revprop(svn_fs_t *fs,
                       apr_array_header_t *files_to_delete,
                       apr_pool_t *pool)
 {
+  fs_fs_data_t *ffd = fs->fsap_data;
+
   SVN_ERR(svn_fs_fs__move_into_place(tmp_path, final_path, perms_reference,
-                                     pool));
+                                     ffd->flush_to_disk, pool));
 
   /* Clean up temporary files, if necessary. */
   if (files_to_delete)
@@ -831,7 +836,7 @@ serialize_revprops_header(svn_stream_t *
     }
 
   /* the double newline char indicates the end of the header */
-  SVN_ERR(svn_stream_printf(stream, iterpool, "\n"));
+  SVN_ERR(svn_stream_puts(stream, "\n"));
 
   svn_pool_destroy(iterpool);
   return SVN_NO_ERROR;
@@ -904,7 +909,8 @@ repack_revprops(svn_fs_t *fs,
   /* 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));
+  if (ffd->flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(file, pool));
   SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
@@ -927,7 +933,7 @@ repack_file_open(apr_file_t **file,
 {
   apr_int64_t tag;
   const char *tag_string;
-  svn_string_t *new_filename;
+  const char *new_filename;
   int i;
   int manifest_offset
     = (int)(revprops->start_revision - revprops->manifest_start);
@@ -951,18 +957,18 @@ repack_file_open(apr_file_t **file,
                              old_filename);
 
   SVN_ERR(svn_cstring_atoi64(&tag, tag_string + 1));
-  new_filename = svn_string_createf(pool, "%ld.%" APR_INT64_T_FMT,
-                                    revprops->start_revision + start,
-                                    ++tag);
+  new_filename = apr_psprintf(pool, "%ld.%" APR_INT64_T_FMT,
+                              revprops->start_revision + start,
+                              ++tag);
 
   /* update the manifest to point to the new file */
   for (i = start; i < end; ++i)
     APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
-      = new_filename->data;
+      = new_filename;
 
   /* open the file */
   SVN_ERR(svn_io_file_open(file, svn_dirent_join(revprops->folder,
-                                                 new_filename->data,
+                                                 new_filename,
                                                  pool),
                            APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
 
@@ -1111,7 +1117,8 @@ write_packed_revprop(const char **final_
           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));
+      if (ffd->flush_to_disk)
+        SVN_ERR(svn_io_file_flush_to_disk(file, pool));
       SVN_ERR(svn_io_file_close(file, pool));
     }
 
@@ -1246,6 +1253,7 @@ svn_fs_fs__copy_revprops(const char *pac
                          apr_array_header_t *sizes,
                          apr_size_t total_size,
                          int compression_level,
+                         svn_boolean_t flush_to_disk,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *scratch_pool)
@@ -1278,6 +1286,7 @@ svn_fs_fs__copy_revprops(const char *pac
     {
       const char *path;
       svn_stream_t *stream;
+      apr_file_t *file;
 
       svn_pool_clear(iterpool);
 
@@ -1286,8 +1295,11 @@ svn_fs_fs__copy_revprops(const char *pac
                              iterpool);
 
       /* 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));
+       * the pack file.  Use unbuffered apr_file_t since we're going to
+       * write using 16kb chunks. */
+      SVN_ERR(svn_io_file_open(&file, path, APR_READ, APR_OS_DEFAULT,
+                               iterpool));
+      stream = svn_stream_from_aprfile2(file, FALSE, iterpool);
       SVN_ERR(svn_stream_copy3(stream, pack_stream,
                                cancel_func, cancel_baton, iterpool));
     }
@@ -1302,7 +1314,8 @@ svn_fs_fs__copy_revprops(const char *pac
   /* write the pack file content to disk */
   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));
+  if (flush_to_disk)
+    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);
@@ -1317,6 +1330,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                int max_files_per_dir,
                                apr_int64_t max_pack_size,
                                int compression_level,
+                               svn_boolean_t flush_to_disk,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool)
@@ -1388,8 +1402,9 @@ svn_fs_fs__pack_revprops_shard(const cha
           SVN_ERR(svn_fs_fs__copy_revprops(pack_file_dir, pack_filename,
                                            shard_path, start_rev, rev-1,
                                            sizes, total_size,
-                                           compression_level, cancel_func,
-                                           cancel_baton, iterpool));
+                                           compression_level, flush_to_disk,
+                                           cancel_func, cancel_baton,
+                                           iterpool));
 
           /* next pack file starts empty again */
           apr_array_clear(sizes);
@@ -1415,12 +1430,13 @@ svn_fs_fs__pack_revprops_shard(const cha
     SVN_ERR(svn_fs_fs__copy_revprops(pack_file_dir, pack_filename,
                                      shard_path, start_rev, rev-1,
                                      sizes, (apr_size_t)total_size,
-                                     compression_level, cancel_func,
-                                     cancel_baton, iterpool));
+                                     compression_level, flush_to_disk,
+                                     cancel_func, cancel_baton, iterpool));
 
   /* 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));
+  if (flush_to_disk)
+    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));
 

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=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/revprops.h Tue Oct 11 
09:11:50 2016
@@ -111,8 +111,9 @@ svn_fs_fs__packed_revprop_available(svn_
  * a hint on which initial buffer size we should use to hold the pack file
  * content.
  *
- * CANCEL_FUNC and CANCEL_BATON are used as usual. Temporary allocations
- * are done in SCRATCH_POOL.
+ * If FLUSH_TO_DISK is non-zero, do not return until the data has actually
+ * been written on the disk.  CANCEL_FUNC and CANCEL_BATON are used as usual.
+ * Temporary allocations are done in SCRATCH_POOL.
  */
 svn_error_t *
 svn_fs_fs__copy_revprops(const char *pack_file_dir,
@@ -123,6 +124,7 @@ svn_fs_fs__copy_revprops(const char *pac
                          apr_array_header_t *sizes,
                          apr_size_t total_size,
                          int compression_level,
+                         svn_boolean_t flush_to_disk,
                          svn_cancel_func_t cancel_func,
                          void *cancel_baton,
                          apr_pool_t *scratch_pool);
@@ -134,8 +136,9 @@ svn_fs_fs__copy_revprops(const char *pac
  * have no unpacked data anymore.  Call upgrade_cleanup_pack_revprops after
  * the bump.
  *
- * NOTIFY_FUNC and NOTIFY_BATON as well as CANCEL_FUNC and CANCEL_BATON are
- * used in the usual way.  Temporary allocations are done in SCRATCH_POOL.
+ * If FLUSH_TO_DISK is non-zero, do not return until the data has actually
+ * been written on the disk.  CANCEL_FUNC and CANCEL_BATON areused in the
+ * usual way.  Temporary allocations are done in SCRATCH_POOL.
  */
 svn_error_t *
 svn_fs_fs__pack_revprops_shard(const char *pack_file_dir,
@@ -144,6 +147,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                int max_files_per_dir,
                                apr_int64_t max_pack_size,
                                int compression_level,
+                               svn_boolean_t flush_to_disk,
                                svn_cancel_func_t cancel_func,
                                void *cancel_baton,
                                apr_pool_t *scratch_pool);

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=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/stats.c Tue Oct 11 
09:11:50 2016
@@ -681,19 +681,25 @@ get_phys_change_count(query_t *query,
                       revision_info_t *revision_info,
                       apr_pool_t *scratch_pool)
 {
-  /* We are going to use our own sub-pool here because the changes object
-   * may well be >100MB and SCRATCH_POOL may not get cleared until all other
-   * info has been read by read_phys_revision().  Therefore, tidy up early.
-   */
-  apr_pool_t *subpool = svn_pool_create(scratch_pool);
-  apr_array_header_t *changes;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  svn_fs_fs__changes_context_t *context;
 
-  SVN_ERR(svn_fs_fs__get_changes(&changes, query->fs,
-                                 revision_info->revision, subpool));
-  revision_info->change_count = changes->nelts;
+  /* Fetch the first block of data. */
+  SVN_ERR(svn_fs_fs__create_changes_context(&context, query->fs,
+                                            revision_info->revision,
+                                            scratch_pool));
 
-  /* Release potentially tons of memory. */
-  svn_pool_destroy(subpool);
+  revision_info->change_count = 0;
+  while (!context->eol)
+    {
+      apr_array_header_t *changes;
+
+      svn_pool_clear(iterpool);
+      SVN_ERR(svn_fs_fs__get_changes(&changes, context, iterpool, iterpool));
+      revision_info->change_count = changes->nelts;
+    }
+
+  svn_pool_destroy(iterpool);
 
   return SVN_NO_ERROR;
 }

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=1764214&r1=1764213&r2=1764214&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 Tue 
Oct 11 09:11:50 2016
@@ -788,16 +788,18 @@ svn_fs_fs__deserialize_node_revision(voi
 }
 
 /* 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_fs__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;
@@ -815,7 +817,24 @@ svn_fs_fs__serialize_dir_entries(void **
    * and return the serialized data */
   return return_serialized_dir_context(serialize_dir(dir, pool),
                                        data,
-                                       data_len);
+                                       data_len,
+                                       FALSE);
+}
+
+svn_error_t *
+svn_fs_fs__serialize_txndir_entries(void **data,
+                                    apr_size_t *data_len,
+                                    void *in,
+                                    apr_pool_t *pool)
+{
+  svn_fs_fs__dir_data_t *dir = in;
+
+  /* serialize the dir content into a new serialization context
+   * and return the serialized data */
+  return return_serialized_dir_context(serialize_dir(dir, pool),
+                                       data,
+                                       data_len,
+                                       TRUE);
 }
 
 svn_error_t *
@@ -916,7 +935,7 @@ svn_fs_fs__extract_dir_entry(void **out,
                              apr_pool_t *pool)
 {
   const dir_data_t *dir_data = data;
-  const extract_dir_entry_baton_t *entry_baton = baton;
+  extract_dir_entry_baton_t *entry_baton = baton;
   svn_boolean_t found;
 
   /* resolve the reference to the entries array */
@@ -935,8 +954,11 @@ svn_fs_fs__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. */
+  entry_baton->out_of_date
+    = dir_data->txn_filesize != entry_baton->txn_filesize;
+
   *out = NULL;
-  if (found && dir_data->txn_filesize == entry_baton->txn_filesize)
+  if (found && !entry_baton->out_of_date)
     {
       const svn_fs_dirent_t *source =
           svn_temp_deserializer__ptr(entries, (const void *const 
*)&entries[pos]);
@@ -1097,9 +1119,7 @@ svn_fs_fs__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,
@@ -1204,47 +1224,29 @@ deserialize_change(void *buffer, change_
   svn_temp_deserializer__resolve(change, (void **)&change->info.copyfrom_path);
 }
 
-/* Auxiliary structure representing the content of a 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 */
-  change_t **changes;
-} changes_data_t;
-
 svn_error_t *
 svn_fs_fs__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_fs__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 = (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(change_t*));
+                            (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);
 
@@ -1264,8 +1266,7 @@ svn_fs_fs__deserialize_changes(void **ou
                                apr_pool_t *pool)
 {
   int i;
-  changes_data_t *changes = (changes_data_t *)data;
-  apr_array_header_t *array = apr_array_make(pool, 0, sizeof(change_t *));
+  svn_fs_fs__changes_list_t *changes = (svn_fs_fs__changes_list_t *)data;
 
   /* de-serialize our auxiliary data structure */
   svn_temp_deserializer__resolve(changes, (void**)&changes->changes);
@@ -1275,14 +1276,8 @@ svn_fs_fs__deserialize_changes(void **ou
     deserialize_change(changes->changes,
                        (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_fs/temp_serializer.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/temp_serializer.h?rev=1764214&r1=1764213&r2=1764214&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 Tue 
Oct 11 09:11:50 2016
@@ -221,6 +221,16 @@ svn_fs_fs__serialize_dir_entries(void **
                                  apr_pool_t *pool);
 
 /**
+ * Same as svn_fs_fs__serialize_dir_entries but allocates extra room for
+ * in-place modification.
+ */
+svn_error_t *
+svn_fs_fs__serialize_txndir_entries(void **data,
+                                    apr_size_t *data_len,
+                                    void *in,
+                                    apr_pool_t *pool);
+
+/**
  * Implements #svn_cache__deserialize_func_t for a #svn_fs_fs__dir_data_t
  */
 svn_error_t *
@@ -264,6 +274,12 @@ typedef struct extract_dir_entry_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;
 } extract_dir_entry_baton_t;
 
 
@@ -343,9 +359,34 @@ svn_fs_fs__deserialize_rep_header(void *
                                   apr_size_t data_len,
                                   apr_pool_t *pool);
 
+/*** Block of changes in a changed paths list. */
+typedef struct svn_fs_fs__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 */
+  change_t **changes;
+
+} svn_fs_fs__changes_list_t;
+
 /**
- * Implements #svn_cache__serialize_func_t for an #apr_array_header_t of
- * #change_t *.
+ * Implements #svn_cache__serialize_func_t for a #svn_fs_fs__changes_list_t.
  */
 svn_error_t *
 svn_fs_fs__serialize_changes(void **data,
@@ -354,8 +395,7 @@ svn_fs_fs__serialize_changes(void **data
                              apr_pool_t *pool);
 
 /**
- * Implements #svn_cache__deserialize_func_t for an #apr_array_header_t of
- * #change_t *.
+ * Implements #svn_cache__deserialize_func_t for a #svn_fs_fs__changes_list_t.
  */
 svn_error_t *
 svn_fs_fs__deserialize_changes(void **out,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/transaction.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/transaction.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/transaction.c Tue Oct 11 
09:11:50 2016
@@ -442,7 +442,7 @@ get_writable_proto_rev(apr_file_t **file
   /* Now open the prototype revision file and seek to the end. */
   err = svn_io_file_open(file,
                          svn_fs_fs__path_txn_proto_rev(fs, txn_id, pool),
-                         APR_READ | APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT,
+                         APR_WRITE | APR_BUFFERED, APR_OS_DEFAULT,
                          pool);
 
   /* You might expect that we could dispense with the following seek
@@ -932,20 +932,36 @@ svn_fs_fs__paths_changed(apr_hash_t **ch
                          svn_revnum_t rev,
                          apr_pool_t *pool)
 {
-  apr_hash_t *changed_paths;
-  apr_array_header_t *changes;
-  int i;
+  apr_hash_t *changed_paths = svn_hash__make(pool);
+  svn_fs_fs__changes_context_t *context;
 
-  SVN_ERR(svn_fs_fs__get_changes(&changes, fs, rev, pool));
+  apr_pool_t *iterpool = svn_pool_create(pool);
 
-  changed_paths = svn_hash__make(pool);
-  for (i = 0; i < changes->nelts; ++i)
+  /* Fetch all data block-by-block. */
+  SVN_ERR(svn_fs_fs__create_changes_context(&context, fs, rev, pool));
+  while (!context->eol)
     {
-      change_t *change = APR_ARRAY_IDX(changes, i, change_t *);
-      apr_hash_set(changed_paths, change->path.data, change->path.len,
-                   &change->info);
+      apr_array_header_t *changes;
+      int i;
+
+      svn_pool_clear(iterpool);
+
+      /* Be sure to allocate the changes in the result POOL, even though
+         we don't need the array itself afterwards.  Copying the entries
+         from a temp pool to the result POOL would be expensive and saves
+         use less then 10% memory. */
+      SVN_ERR(svn_fs_fs__get_changes(&changes, context, pool, iterpool));
+
+      for (i = 0; i < changes->nelts; ++i)
+        {
+          change_t *change = APR_ARRAY_IDX(changes, i, change_t *);
+          apr_hash_set(changed_paths, change->path.data, change->path.len,
+                       &change->info);
+        }
     }
 
+  svn_pool_destroy(iterpool);
+
   *changed_paths_p = changed_paths;
 
   return SVN_NO_ERROR;
@@ -997,6 +1013,7 @@ static svn_error_t *
 get_and_increment_txn_key_body(void *baton, apr_pool_t *pool)
 {
   struct get_and_increment_txn_key_baton *cb = baton;
+  fs_fs_data_t *ffd = cb->fs->fsap_data;
   const char *txn_current_filename
     = svn_fs_fs__path_txn_current(cb->fs, pool);
   char new_id_str[SVN_INT64_BUFFER_SIZE + 1]; /* add space for a newline */
@@ -1017,7 +1034,7 @@ get_and_increment_txn_key_body(void *bat
   SVN_ERR(svn_io_write_atomic2(txn_current_filename, new_id_str,
                                line_length + 1,
                                txn_current_filename /* copy_perms path */,
-                               TRUE, pool));
+                               ffd->flush_to_disk, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1714,9 +1731,11 @@ svn_fs_fs__add_change(svn_fs_t *fs,
   return svn_io_file_close(file, pool);
 }
 
-/* If the transaction TXN_ID in FS uses logical addressing, store the
- * (ITEM_INDEX, OFFSET) pair in the txn's log-to-phys proto index file.
+/* Store the (ITEM_INDEX, OFFSET) pair in the txn's log-to-phys proto
+ * index file.
  * Use POOL for allocations.
+ * This function assumes that transaction TXN_ID in FS uses logical
+ * addressing.
  */
 static svn_error_t *
 store_l2p_index_entry(svn_fs_t *fs,
@@ -1725,37 +1744,40 @@ store_l2p_index_entry(svn_fs_t *fs,
                       apr_uint64_t item_index,
                       apr_pool_t *pool)
 {
-  if (svn_fs_fs__use_log_addressing(fs))
-    {
-      const char *path = svn_fs_fs__path_l2p_proto_index(fs, txn_id, pool);
-      apr_file_t *file;
-      SVN_ERR(svn_fs_fs__l2p_proto_index_open(&file, path, pool));
-      SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry(file, offset,
-                                                   item_index, pool));
-      SVN_ERR(svn_io_file_close(file, pool));
-    }
+  const char *path;
+  apr_file_t *file;
+
+  SVN_ERR_ASSERT(svn_fs_fs__use_log_addressing(fs));
+
+  path = svn_fs_fs__path_l2p_proto_index(fs, txn_id, pool);
+  SVN_ERR(svn_fs_fs__l2p_proto_index_open(&file, path, pool));
+  SVN_ERR(svn_fs_fs__l2p_proto_index_add_entry(file, offset,
+                                               item_index, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
 
-/* If the transaction TXN_ID in FS uses logical addressing, store ENTRY
- * in the phys-to-log proto index file of transaction TXN_ID.
+/* Store ENTRY in the phys-to-log proto index file of transaction TXN_ID.
  * Use POOL for allocations.
+ * This function assumes that transaction TXN_ID in FS uses logical
+ * addressing.
  */
 static svn_error_t *
 store_p2l_index_entry(svn_fs_t *fs,
                       const svn_fs_fs__id_part_t *txn_id,
-                      svn_fs_fs__p2l_entry_t *entry,
+                      const svn_fs_fs__p2l_entry_t *entry,
                       apr_pool_t *pool)
 {
-  if (svn_fs_fs__use_log_addressing(fs))
-    {
-      const char *path = svn_fs_fs__path_p2l_proto_index(fs, txn_id, pool);
-      apr_file_t *file;
-      SVN_ERR(svn_fs_fs__p2l_proto_index_open(&file, path, pool));
-      SVN_ERR(svn_fs_fs__p2l_proto_index_add_entry(file, entry, pool));
-      SVN_ERR(svn_io_file_close(file, pool));
-    }
+  const char *path;
+  apr_file_t *file;
+
+  SVN_ERR_ASSERT(svn_fs_fs__use_log_addressing(fs));
+
+  path = svn_fs_fs__path_p2l_proto_index(fs, txn_id, pool);
+  SVN_ERR(svn_fs_fs__p2l_proto_index_open(&file, path, pool));
+  SVN_ERR(svn_fs_fs__p2l_proto_index_add_entry(file, entry, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -2174,10 +2196,10 @@ rep_write_get_baton(struct rep_write_bat
                                  b->scratch_pool));
 
   b->file = file;
-  b->rep_stream = fnv1a_wrap_stream(&b->fnv1a_checksum_ctx,
-                                    svn_stream_from_aprfile2(file, TRUE,
-                                                             b->scratch_pool),
-                                    b->scratch_pool);
+  b->rep_stream = svn_stream_from_aprfile2(file, TRUE, b->scratch_pool);
+  if (svn_fs_fs__use_log_addressing(fs))
+    b->rep_stream = fnv1a_wrap_stream(&b->fnv1a_checksum_ctx, b->rep_stream,
+                                      b->scratch_pool);
 
   SVN_ERR(svn_io_file_get_offset(&b->rep_offset, file, b->scratch_pool));
 
@@ -2454,7 +2476,7 @@ rep_write_contents_close(void *baton)
   /* Write out the new node-rev information. */
   SVN_ERR(svn_fs_fs__put_node_revision(b->fs, b->noderev->id, b->noderev,
                                        FALSE, b->scratch_pool));
-  if (!old_rep)
+  if (!old_rep && svn_fs_fs__use_log_addressing(b->fs))
     {
       svn_fs_fs__p2l_entry_t entry;
 
@@ -2468,12 +2490,17 @@ rep_write_contents_close(void *baton)
                                       b->fnv1a_checksum_ctx,
                                       b->scratch_pool));
 
-      SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->scratch_pool));
       SVN_ERR(store_p2l_index_entry(b->fs, &rep->txn_id, &entry,
                                     b->scratch_pool));
     }
 
   SVN_ERR(svn_io_file_close(b->file, b->scratch_pool));
+
+  /* Write the sha1->rep mapping *after* we successfully written node
+   * revision to disk. */
+  if (!old_rep)
+    SVN_ERR(store_sha1_rep_mapping(b->fs, b->noderev, b->scratch_pool));
+
   SVN_ERR(unlock_proto_rev(b->fs, &rep->txn_id, b->lockcookie,
                            b->scratch_pool));
   svn_pool_destroy(b->scratch_pool);
@@ -2676,10 +2703,12 @@ write_container_rep(representation_t *re
 
   whb = apr_pcalloc(scratch_pool, sizeof(*whb));
 
-  whb->stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
-                                  svn_stream_from_aprfile2(file, TRUE,
-                                                           scratch_pool),
-                                  scratch_pool);
+  whb->stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  if (svn_fs_fs__use_log_addressing(fs))
+    whb->stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx, whb->stream,
+                                    scratch_pool);
+  else
+    fnv1a_checksum_ctx = NULL;
   whb->size = 0;
   whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
   if (item_type != SVN_FS_FS__ITEM_TYPE_DIR_REP)
@@ -2708,16 +2737,18 @@ write_container_rep(representation_t *re
 
       /* Use the old rep for this content. */
       memcpy(rep, old_rep, sizeof (*rep));
+      return SVN_NO_ERROR;
     }
-  else
-    {
-      svn_fs_fs__p2l_entry_t entry;
 
-      /* Write out our cosmetic end marker. */
-      SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n"));
+  /* Write out our cosmetic end marker. */
+  SVN_ERR(svn_stream_puts(whb->stream, "ENDREP\n"));
 
-      SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id,
-                                  offset, scratch_pool));
+  SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id,
+                              offset, scratch_pool));
+
+  if (svn_fs_fs__use_log_addressing(fs))
+    {
+      svn_fs_fs__p2l_entry_t entry;
 
       entry.offset = offset;
       SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
@@ -2730,11 +2761,11 @@ write_container_rep(representation_t *re
                                       scratch_pool));
 
       SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool));
-
-      /* update the representation */
-      rep->size = whb->size;
     }
 
+  /* update the representation */
+  rep->size = whb->size;
+
   return SVN_NO_ERROR;
 }
 
@@ -2802,10 +2833,12 @@ write_container_delta_rep(representation
       header.type = svn_fs_fs__rep_self_delta;
     }
 
-  file_stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
-                                  svn_stream_from_aprfile2(file, TRUE,
-                                                           scratch_pool),
-                                  scratch_pool);
+  file_stream = svn_stream_from_aprfile2(file, TRUE, scratch_pool);
+  if (svn_fs_fs__use_log_addressing(fs))
+    file_stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx, file_stream,
+                                    scratch_pool);
+  else
+    fnv1a_checksum_ctx = NULL;
   SVN_ERR(svn_fs_fs__write_rep_header(&header, file_stream, scratch_pool));
   SVN_ERR(svn_io_file_get_offset(&delta_start, file, scratch_pool));
 
@@ -2848,17 +2881,19 @@ write_container_delta_rep(representation
 
       /* Use the old rep for this content. */
       memcpy(rep, old_rep, sizeof (*rep));
+      return SVN_NO_ERROR;
     }
-  else
-    {
-      svn_fs_fs__p2l_entry_t entry;
 
-      /* Write out our cosmetic end marker. */
-      SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
-      SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
+  /* Write out our cosmetic end marker. */
+  SVN_ERR(svn_io_file_get_offset(&rep_end, file, scratch_pool));
+  SVN_ERR(svn_stream_puts(file_stream, "ENDREP\n"));
+
+  SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id,
+                              offset, scratch_pool));
 
-      SVN_ERR(allocate_item_index(&rep->item_index, fs, &rep->txn_id,
-                                  offset, scratch_pool));
+  if (svn_fs_fs__use_log_addressing(fs))
+    {
+      svn_fs_fs__p2l_entry_t entry;
 
       entry.offset = offset;
       SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
@@ -2871,11 +2906,11 @@ write_container_delta_rep(representation
                                       scratch_pool));
 
       SVN_ERR(store_p2l_index_entry(fs, &rep->txn_id, &entry, scratch_pool));
-
-      /* update the representation */
-      rep->size = rep_end - delta_start;
     }
 
+  /* update the representation */
+  rep->size = rep_end - delta_start;
+
   return SVN_NO_ERROR;
 }
 
@@ -2922,9 +2957,8 @@ validate_root_noderev(svn_fs_t *fs,
      to a repository that has triggered the bug somewhere in its root
      noderev's history.
    */
-  if (root_noderev->predecessor_count != -1
-      && (root_noderev->predecessor_count - head_predecessor_count)
-         != (rev - head_revnum))
+  if (   (root_noderev->predecessor_count - head_predecessor_count)
+      != (rev - head_revnum))
     {
       return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                _("predecessor count for "
@@ -3207,9 +3241,12 @@ write_final_rev(const svn_fs_id_t **new_
   if (at_root)
     SVN_ERR(validate_root_noderev(fs, noderev, rev, pool));
 
-  file_stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
-                                  svn_stream_from_aprfile2(file, TRUE, pool),
-                                  pool);
+  file_stream = svn_stream_from_aprfile2(file, TRUE, pool);
+  if (svn_fs_fs__use_log_addressing(fs))
+    file_stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx, file_stream, pool);
+  else
+    fnv1a_checksum_ctx = NULL;
+
   SVN_ERR(svn_fs_fs__write_noderev(file_stream, noderev, ffd->format,
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
                                    pool));
@@ -3256,10 +3293,13 @@ write_final_changed_path_info(apr_off_t
 
   SVN_ERR(svn_io_file_get_offset(&offset, file, pool));
 
-  /* write to target file & calculate checksum */
-  stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
-                             svn_stream_from_aprfile2(file, TRUE, pool),
-                             pool);
+  /* write to target file & calculate checksum if needed */
+  stream = svn_stream_from_aprfile2(file, TRUE, pool);
+  if (svn_fs_fs__use_log_addressing(fs))
+    stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx, stream, pool);
+  else
+    fnv1a_checksum_ctx = NULL;
+
   SVN_ERR(svn_fs_fs__write_changes(stream, fs, changed_paths, TRUE, pool));
 
   *offset_p = offset;
@@ -3441,6 +3481,7 @@ static svn_error_t *
 write_final_revprop(const char *path,
                     const char *perms_reference,
                     svn_fs_txn_t *txn,
+                    svn_boolean_t flush_to_disk,
                     apr_pool_t *pool)
 {
   apr_hash_t *txnprops;
@@ -3480,7 +3521,8 @@ write_final_revprop(const char *path,
   SVN_ERR(svn_hash_write2(txnprops, stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(stream));
 
-  SVN_ERR(svn_io_file_flush_to_disk(revprop_file, pool));
+  if (flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(revprop_file, pool));
   SVN_ERR(svn_io_file_close(revprop_file, pool));
 
   SVN_ERR(svn_io_copy_perms(perms_reference, path, pool));
@@ -3677,7 +3719,8 @@ commit_body(void *baton, apr_pool_t *poo
                                      NULL, pool));
     }
 
-  SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
+  if (ffd->flush_to_disk)
+    SVN_ERR(svn_io_file_flush_to_disk(proto_file, pool));
   SVN_ERR(svn_io_file_close(proto_file, pool));
 
   /* We don't unlock the prototype revision file immediately to avoid a
@@ -3730,7 +3773,8 @@ commit_body(void *baton, apr_pool_t *poo
   rev_filename = svn_fs_fs__path_rev(cb->fs, new_rev, pool);
   proto_filename = svn_fs_fs__path_txn_proto_rev(cb->fs, txn_id, pool);
   SVN_ERR(svn_fs_fs__move_into_place(proto_filename, rev_filename,
-                                     old_rev_filename, pool));
+                                     old_rev_filename, ffd->flush_to_disk,
+                                     pool));
 
   /* Now that we've moved the prototype revision file out of the way,
      we can unlock it (since further attempts to write to the file
@@ -3742,7 +3786,7 @@ commit_body(void *baton, apr_pool_t *poo
   SVN_ERR_ASSERT(! svn_fs_fs__is_packed_revprop(cb->fs, new_rev));
   revprop_filename = svn_fs_fs__path_revprops(cb->fs, new_rev, pool);
   SVN_ERR(write_final_revprop(revprop_filename, old_rev_filename,
-                              cb->txn, pool));
+                              cb->txn, ffd->flush_to_disk, pool));
 
   /* Update the 'current' file. */
   SVN_ERR(verify_as_revision_before_current_plus_plus(cb->fs, new_rev, pool));
@@ -3820,6 +3864,8 @@ svn_fs_fs__commit(svn_revnum_t *new_rev_
 
   if (ffd->rep_sharing_allowed)
     {
+      svn_error_t *err;
+
       SVN_ERR(svn_fs_fs__open_rep_cache(fs, pool));
 
       /* Write new entries to the rep-sharing database.
@@ -3830,9 +3876,21 @@ svn_fs_fs__commit(svn_revnum_t *new_rev_
       /* ### 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, 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, 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_fs__close_rep_cache(fs)));
+        }
+      else if (err)
+        return svn_error_trace(err);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/tree.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/tree.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/tree.c Tue Oct 11 
09:11:50 2016
@@ -1474,29 +1474,6 @@ fs_node_created_path(const char **create
   return SVN_NO_ERROR;
 }
 
-
-/* Set *KIND_P to the type of node located at PATH under ROOT.
-   Perform temporary allocations in POOL. */
-static svn_error_t *
-node_kind(svn_node_kind_t *kind_p,
-          svn_fs_root_t *root,
-          const char *path,
-          apr_pool_t *pool)
-{
-  const svn_fs_id_t *node_id;
-  dag_node_t *node;
-
-  /* Get the node id. */
-  SVN_ERR(svn_fs_fs__node_id(&node_id, root, path, pool));
-
-  /* Use the node id to get the real kind. */
-  SVN_ERR(svn_fs_fs__dag_get_node(&node, root->fs, node_id, pool));
-  *kind_p = svn_fs_fs__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
    POOL for temporary allocation. */
@@ -1506,17 +1483,23 @@ svn_fs_fs__check_path(svn_node_kind_t *k
                       const char *path,
                       apr_pool_t *pool)
 {
-  svn_error_t *err = node_kind(kind_p, root, path, pool);
+  dag_node_t *node;
+  svn_error_t *err;
+
+  err = get_dag(&node, root, path, pool);
   if (err &&
       ((err->apr_err == SVN_ERR_FS_NOT_FOUND)
        || (err->apr_err == SVN_ERR_FS_NOT_DIRECTORY)))
     {
       svn_error_clear(err);
-      err = SVN_NO_ERROR;
       *kind_p = svn_node_none;
+      return SVN_NO_ERROR;
     }
+  else if (err)
+    return svn_error_trace(err);
 
-  return svn_error_trace(err);
+  *kind_p = svn_fs_fs__dag_node_kind(node);
+  return SVN_NO_ERROR;
 }
 
 /* Set *VALUE_P to the value of the property named PROPNAME of PATH in
@@ -2331,7 +2314,7 @@ svn_fs_fs__commit_txn(const char **confl
 
   if (ffd->pack_after_commit)
     {
-      SVN_ERR(svn_fs_fs__pack(fs, NULL, NULL, NULL, NULL, pool));
+      SVN_ERR(svn_fs_fs__pack(fs, 0, NULL, NULL, NULL, NULL, pool));
     }
 
   return SVN_NO_ERROR;
@@ -3298,6 +3281,187 @@ fs_paths_changed(apr_hash_t **changed_pa
 }
 
 
+/* Copy the contents of ENTRY at PATH with LEN to OUTPUT. */
+static void
+convert_path_change(svn_fs_path_change3_t *output,
+                    const char *path,
+                    size_t path_len,
+                    svn_fs_path_change2_t *entry)
+{
+  output->path.data = path;
+  output->path.len = path_len;
+  output->change_kind = entry->change_kind;
+  output->node_kind = entry->node_kind;
+  output->text_mod = entry->text_mod;
+  output->prop_mod = entry->prop_mod;
+  output->mergeinfo_mod = entry->mergeinfo_mod;
+  output->copyfrom_known = entry->copyfrom_known;
+  output->copyfrom_rev = entry->copyfrom_rev;
+  output->copyfrom_path = entry->copyfrom_path;
+}
+
+/* FSAP data structure for in-txn changes list iterators. */
+typedef struct fs_txn_changes_iterator_data_t
+{
+  /* Current iterator position. */
+  apr_hash_index_t *hi;
+
+  /* For efficiency such that we don't need to dynamically allocate
+     yet another copy of that data. */
+  svn_fs_path_change3_t change;
+} fs_txn_changes_iterator_data_t;
+
+/* Implement changes_iterator_vtable_t.get for in-txn change lists. */
+static svn_error_t *
+fs_txn_changes_iterator_get(svn_fs_path_change3_t **change,
+                            svn_fs_path_change_iterator_t *iterator)
+{
+  fs_txn_changes_iterator_data_t *data = iterator->fsap_data;
+
+  if (data->hi)
+    {
+      const void *key;
+      apr_ssize_t length;
+      void *value;
+      apr_hash_this(data->hi, &key, &length, &value);
+
+      convert_path_change(&data->change, key, length, value);
+
+      *change = &data->change;
+      data->hi = apr_hash_next(data->hi);
+    }
+  else
+    {
+      *change = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static changes_iterator_vtable_t txn_changes_iterator_vtable =
+{
+  fs_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_fs__changes_context_t *context;
+
+  /* Changes to send. */
+  apr_array_header_t *changes;
+
+  /* Current indexes within CHANGES. */
+  int idx;
+
+  /* For efficiency such that we don't need to dynamically allocate
+     yet another copy of that data. */
+  svn_fs_path_change3_t change;
+
+  /* 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;
+
+/* Implement changes_iterator_vtable_t.get for in-revision change lists. */
+static svn_error_t *
+fs_revision_changes_iterator_get(svn_fs_path_change3_t **change,
+                                 svn_fs_path_change_iterator_t *iterator)
+{
+  fs_revision_changes_iterator_data_t *data = iterator->fsap_data;
+
+  /* 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;
+
+      /* Drop old changes block, read new block. */
+      svn_pool_clear(changes_pool);
+      SVN_ERR(svn_fs_fs__get_changes(&data->changes, data->context,
+                                     changes_pool, data->scratch_pool));
+      data->idx = 0;
+
+      /* Immediately release any temporary data. */
+      svn_pool_clear(data->scratch_pool);
+    }
+
+  if (data->idx < data->changes->nelts)
+    {
+      change_t *entry = APR_ARRAY_IDX(data->changes, data->idx, change_t *);
+      convert_path_change(&data->change, entry->path.data, entry->path.len,
+                          &entry->info);
+
+      *change = &data->change;
+      ++data->idx;
+    }
+  else
+    {
+      *change = NULL;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+static changes_iterator_vtable_t rev_changes_iterator_vtable =
+{
+  fs_revision_changes_iterator_get
+};
+
+static svn_error_t *
+fs_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)
+    {
+      fs_txn_changes_iterator_data_t *data = apr_pcalloc(result_pool,
+                                                         sizeof(*data));
+      apr_hash_t *changed_paths;
+      SVN_ERR(svn_fs_fs__txn_changes_fetch(&changed_paths, root->fs,
+                                           root_txn_id(root), result_pool));
+
+      data->hi = apr_hash_first(result_pool, changed_paths);
+      result->fsap_data = data;
+      result->vtable = &txn_changes_iterator_vtable;
+    }
+  else
+    {
+      /* 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_fs__create_changes_context(&data->context,
+                                                root->fs, root->rev,
+                                                result_pool));
+      SVN_ERR(svn_fs_fs__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;
+    }
+
+  *iterator = result;
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Our coolio opaque history object. */
 typedef struct fs_history_data_t
@@ -4342,6 +4506,7 @@ fs_get_mergeinfo(svn_mergeinfo_catalog_t
 /* The vtable associated with root objects. */
 static root_vtable_t root_vtable = {
   fs_paths_changed,
+  fs_report_changes,
   svn_fs_fs__check_path,
   fs_node_history,
   svn_fs_fs__node_id,

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/util.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/util.c Tue Oct 11 
09:11:50 2016
@@ -428,6 +428,7 @@ svn_fs_fs__write_min_unpacked_rev(svn_fs
                                   svn_revnum_t revnum,
                                   apr_pool_t *scratch_pool)
 {
+  fs_fs_data_t *ffd = fs->fsap_data;
   const char *final_path;
   char buf[SVN_INT64_BUFFER_SIZE];
   apr_size_t len = svn__i64toa(buf, revnum);
@@ -436,8 +437,8 @@ svn_fs_fs__write_min_unpacked_rev(svn_fs
   final_path = svn_fs_fs__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;
 }
@@ -519,7 +520,8 @@ svn_fs_fs__write_current(svn_fs_t *fs,
 
   name = svn_fs_fs__path_current(fs, pool);
   SVN_ERR(svn_io_write_atomic2(name, buf, strlen(buf),
-                               name /* copy_perms_path */, TRUE, pool));
+                               name /* copy_perms_path */,
+                               ffd->flush_to_disk, pool));
 
   return SVN_NO_ERROR;
 }
@@ -619,6 +621,7 @@ svn_error_t *
 svn_fs_fs__move_into_place(const char *old_filename,
                            const char *new_filename,
                            const char *perms_reference,
+                           svn_boolean_t flush_to_disk,
                            apr_pool_t *pool)
 {
   svn_error_t *err;
@@ -628,7 +631,7 @@ svn_fs_fs__move_into_place(const char *o
   SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool));
 
   /* Move the file into place. */
-  err = svn_io_file_rename2(old_filename, new_filename, TRUE, pool);
+  err = svn_io_file_rename2(old_filename, new_filename, flush_to_disk, pool);
   if (err && APR_STATUS_IS_EXDEV(err->apr_err))
     {
       /* Can't rename across devices; fall back to copying. */
@@ -639,25 +642,29 @@ svn_fs_fs__move_into_place(const char *o
          ### The code below is duplicates svn_io_file_rename2(), because
              currently we don't have the svn_io_copy_file2() function with
              a flush_to_disk argument. */
-      SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE,
-                               APR_OS_DEFAULT, pool));
-      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
-      SVN_ERR(svn_io_file_close(file, pool));
+      if (flush_to_disk)
+        {
+          SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE,
+                                   APR_OS_DEFAULT, pool));
+          SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+          SVN_ERR(svn_io_file_close(file, pool));
+        }
 
 #ifdef SVN_ON_POSIX
-      {
-        /* On POSIX, the file name is stored in the file's directory entry.
-           Hence, we need to fsync() that directory as well.
-           On other operating systems, we'd only be asking for trouble
-           by trying to open and fsync a directory. */
-        const char *dirname;
-
-        dirname = svn_dirent_dirname(new_filename, pool);
-        SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
-                                 pool));
-        SVN_ERR(svn_io_file_flush_to_disk(file, pool));
-        SVN_ERR(svn_io_file_close(file, pool));
-      }
+      if (flush_to_disk)
+        {
+          /* On POSIX, the file name is stored in the file's directory entry.
+             Hence, we need to fsync() that directory as well.
+             On other operating systems, we'd only be asking for trouble
+             by trying to open and fsync a directory. */
+          const char *dirname;
+
+          dirname = svn_dirent_dirname(new_filename, pool);
+          SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT,
+                                   pool));
+          SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+          SVN_ERR(svn_io_file_close(file, pool));
+        }
 #endif
     }
   else if (err)

Modified: subversion/branches/ra-git/subversion/libsvn_fs_fs/util.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_fs/util.h?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_fs/util.h (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_fs/util.h Tue Oct 11 
09:11:50 2016
@@ -388,11 +388,12 @@ svn_fs_fs__read_number_from_stream(apr_i
    PERMS_REFERENCE.  Temporary allocations are from POOL.
 
    This function almost duplicates svn_io_file_move(), but it tries to
-   guarantee a flush. */
+   guarantee a flush if FLUSH_TO_DISK is non-zero. */
 svn_error_t *
 svn_fs_fs__move_into_place(const char *old_filename,
                            const char *new_filename,
                            const char *perms_reference,
+                           svn_boolean_t flush_to_disk,
                            apr_pool_t *pool);
 
 /* Return TRUE, iff FS uses logical addressing. */

Modified: subversion/branches/ra-git/subversion/libsvn_fs_util/fs-util.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/ra-git/subversion/libsvn_fs_util/fs-util.c?rev=1764214&r1=1764213&r2=1764214&view=diff
==============================================================================
--- subversion/branches/ra-git/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/branches/ra-git/subversion/libsvn_fs_util/fs-util.c Tue Oct 11 
09:11:50 2016
@@ -212,6 +212,21 @@ svn_fs__path_change_create_internal(cons
   return change;
 }
 
+svn_fs_path_change3_t *
+svn_fs__path_change_create_internal2(svn_fs_path_change_kind_t change_kind,
+                                     apr_pool_t *result_pool)
+{
+  svn_fs_path_change3_t *change;
+
+  change = apr_pcalloc(result_pool, sizeof(*change));
+  change->path.data = "";
+  change->change_kind = change_kind;
+  change->mergeinfo_mod = svn_tristate_unknown;
+  change->copyfrom_rev = SVN_INVALID_REVNUM;
+
+  return change;
+}
+
 svn_error_t *
 svn_fs__append_to_merged_froms(svn_mergeinfo_t *output,
                                svn_mergeinfo_t input,

Propchange: subversion/branches/ra-git/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Tue Oct 11 09:11:50 2016
@@ -94,5 +94,5 @@
 /subversion/branches/verify-at-commit/subversion/libsvn_fs_x:1462039-1462408
 
/subversion/branches/verify-keep-going/subversion/libsvn_fs_x:1439280-1492639,1546002-1546110
 /subversion/branches/wc-collate-path/subversion/libsvn_fs_x:1402685-1480384
-/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162
 
4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1649590,
 
1651567,1652068,1652076,1652441,1652451,1653608,1654932,1654934,1654937,1655635,1655649,1655651,1655664,1656176,1657525,1657972,1657978,1658482,1659212,1659217,1659314,1659509,1662668,1665318,1665854,1665894,1667090,1667101,1667538,1669743,1669746,1669749,1669945,1670139,1670953,1673170,1673197,1673202,1673204,1673445,1673454,1673685,1673689,1673875,1674165,1674341,1674400,1674404,1674631,1674669,1674673,1675396,1676667,1677431,1678149,1678151,1678718,1678725,1679169,1679907,1679920-1679924,1679926,1680347,1680460,1680464,1680476,1680819,1681949,1681966,1681974,1681994,1682008,1682076,1682086,1682093,1682259,1682265,1682739,1682864,1683311,1683330,1683378,1683544,1683553,1684047,1686232,1686542,1686546,1686554,1686557,1687061,1687064,1687070-1687071,1687074,1687078-1687079,1688270,1688425,1692650,1693886,1694489,1694848,1696171,1696185,1696627-1696628,1696630,1696758,1697372,1697381,1697387,1697393,1697403,1697405,1701017,1701053,1702600,1702922,1703069,1703142,1703237,1703240,17052
 
66,1705638,1705643,1705646,1705724,1705730,1705739,1706612,1706615,1706617,1706619,1706675-1706676,1706679,1706979-1706980,1707308,1707971-1707973,1707986,1707988-1707989,1708004,1709799,1710017,1710359,1711582,1711672,1712927,1715793,1715947,1716047,1716067,1716784,1716973-1716974,1717332,1717334
-/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1583624-1719651
+/subversion/trunk/subversion/libsvn_fs_fs:1415133-1596500,1596567,1597414,1597989,1598273,1599140,1600872,1601633,1603485-1603487,1603499,1603605,1604128,1604188,1604413-1604414,1604416-1604417,1604421,1604442,1604700,1604717,1604720,1604726,1604755,1604794,1604802,1604824,1604836,1604844,1604902-1604903,1604911,1604925,1604933,1604947,1605059-1605060,1605064-1605065,1605068,1605071-1605073,1605075,1605123,1605188-1605189,1605191,1605197,1605444,1605633,1606132,1606142,1606144,1606514,1606526,1606528,1606551,1606554,1606564,1606598-1606599,1606656,1606658,1606662,1606744,1606840,1607085,1607572,1612407,1612810,1613339,1613872,1614611,1615348,1615351-1615352,1615356,1616338-1616339,1616613,1617586,1617688,1618138,1618151,1618153,1618226,1618641,1618653,1618662,1619068,1619358,1619413,1619769,1619774,1620602,1620909,1620912,1620928,1620930,1621275,1621635,1622931,1622937,1622942,1622946,1622959-1622960,1622963,1622987,1623007,1623368,1623373,1623377,1623379,1623381,1623398,1623402,162
 
4011,1624265,1624512,1626246,1626871,1626873,1626886,1627497-1627498,1627502,1627947-1627949,1627966,1628083,1628093,1628158-1628159,1628161,1628392-1628393,1628415,1628427,1628676,1628738,1628762,1628764,1629854-1629855,1629857,1629865,1629873,1629875,1629879,1630067,1630070,1631049-1631051,1631075,1631115,1631171,1631180,1631185-1631186,1631196-1631197,1631239-1631240,1631548,1631550,1631563,1631567,1631588,1631598,1632646,1632776,1632849,1632851-1632853,1632856-1632857,1632868,1632908,1632926,1633232,1633617-1633618,1634872,1634875,1634879-1634880,1634920,1636478,1636483,1636629,1636644,1637184,1637186,1637330,1637358,1637363,1637393,1639319,1639322,1639335,1639348,1639352,1639355,1639358,1639414,1639419,1639426,1639430,1639436,1639440,1639549,1640061-1640062,1640197,1640915,1640966,1641013,1643139,1643233,1645567,1646021,1646712,1646716,1647537,1647540-1647541,1647820,1647905,1648230,1648238,1648241-1648243,1648253,1648272,1648532,1648537-1648539,1648542,1648591,1648612,1649590,
 
1651567,1652068,1652076,1652441,1652451,1653608,1654932,1654934,1654937,1655635,1655649,1655651,1655664,1656176,1657525,1657972,1657978,1658482,1659212,1659217,1659314,1659509,1662668,1665318,1665854,1665894,1667090,1667101,1667538,1669743,1669746,1669749,1669945,1670139,1670953,1673170,1673197,1673202,1673204,1673445,1673454,1673685,1673689,1673875,1674165,1674341,1674400,1674404,1674631,1674669,1674673,1675396,1676667,1677431,1678149,1678151,1678718,1678725,1679169,1679907,1679920-1679924,1679926,1680347,1680460,1680464,1680476,1680819,1681949,1681966,1681974,1681994,1682008,1682076,1682086,1682093,1682259,1682265,1682739,1682864,1683311,1683330,1683378,1683544,1683553,1684047,1686232,1686542,1686546,1686554,1686557,1687061,1687064,1687070-1687071,1687074,1687078-1687079,1688270,1688425,1692650,1693886,1694489,1694848,1696171,1696185,1696627-1696628,1696630,1696758,1697372,1697381,1697387,1697393,1697403,1697405,1701017,1701053,1702600,1702922,1703069,1703142,1703237,1703240,17052
 
66,1705638,1705643,1705646,1705724,1705730,1705739,1706612,1706615,1706617,1706619,1706675-1706676,1706679,1706979-1706980,1707308,1707971-1707973,1707986,1707988-1707989,1708004,1709388,1709799,1710017,1710359,1710368,1710370,1711507,1711582,1711672,1712927,1715793,1715947,1716047,1716067,1716784,1716973-1716974,1717332,1717334,1717864,1719269,1719336,1719413,1719730,1720015,1721285,1723715,1723720,1723834,1723839,1725179-1725180,1726004,1726099,1726116,1726897,1726995,1727006-1727007,1727028,1727040,1727707,1727822,1730491,1735916,1736357,1736359,1737355-1737356,1740721-1740722,1741096,1741200,1741206,1741214,1741224,1742540,1745055,1745107,1745852,1746006,1746012,1746026
+/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1583624-1764213



Reply via email to