You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by st...@apache.org on 2016/04/29 20:38:56 UTC

svn commit: r1741682 [8/26] - in /subversion/branches/authzperf: ./ build/ build/ac-macros/ build/generator/ contrib/server-side/svncutter/ notes/ notes/api-errata/1.9/ notes/move-tracking/ subversion/ subversion/bindings/ctypes-python/ subversion/bind...

Modified: subversion/branches/authzperf/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_fs/transaction.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_fs/transaction.c Fri Apr 29 18:38:53 2016
@@ -576,16 +576,62 @@ unparse_dir_entry(svn_fs_dirent_t *diren
                   svn_stream_t *stream,
                   apr_pool_t *pool)
 {
-  const char *val
-    = apr_psprintf(pool, "%s %s",
-                   (dirent->kind == svn_node_file) ? SVN_FS_FS__KIND_FILE
-                                                   : SVN_FS_FS__KIND_DIR,
-                   svn_fs_fs__id_unparse(dirent->id, pool)->data);
-
-  SVN_ERR(svn_stream_printf(stream, pool, "K %" APR_SIZE_T_FMT "\n%s\n"
-                            "V %" APR_SIZE_T_FMT "\n%s\n",
-                            strlen(dirent->name), dirent->name,
-                            strlen(val), val));
+  apr_size_t to_write;
+  svn_string_t *id_str = svn_fs_fs__id_unparse(dirent->id, pool);
+  apr_size_t name_len = strlen(dirent->name);
+
+  /* Note that sizeof == len + 1, i.e. accounts for the space between
+   * type and ID. */
+  apr_size_t type_len = (dirent->kind == svn_node_file)
+                      ? sizeof(SVN_FS_FS__KIND_FILE)
+                      : sizeof(SVN_FS_FS__KIND_DIR);
+  apr_size_t value_len = type_len + id_str->len;
+
+  /* A buffer with sufficient space for 
+   * - both string lines
+   * - 4 newlines
+   * - 2 lines K/V lines containing a number each
+   */
+  char *buffer = apr_palloc(pool,   name_len + value_len
+                                  + 4
+                                  + 2 * (2 + SVN_INT64_BUFFER_SIZE));
+
+  /* Now construct the value. */
+  char *p = buffer;
+
+  /* The "K length(name)\n" line. */
+  p[0] = 'K';
+  p[1] = ' ';
+  p += 2;
+  p += svn__i64toa(p, name_len);
+  *(p++) = '\n';
+
+  /* The line with the key, i.e. dir entry name. */
+  memcpy(p, dirent->name, name_len);
+  p += name_len;
+  *(p++) = '\n';
+
+  /* The "V length(type+id)\n" line. */
+  p[0] = 'V';
+  p[1] = ' ';
+  p += 2;
+  p += svn__i64toa(p, value_len);
+  *(p++) = '\n';
+
+  /* The line with the type and ID. */
+  memcpy(p,
+         (dirent->kind == svn_node_file) ? SVN_FS_FS__KIND_FILE
+                                         : SVN_FS_FS__KIND_DIR,
+         type_len - 1);
+  p += type_len - 1;
+  *(p++) = ' ';
+  memcpy(p, id_str->data, id_str->len);
+  p+=id_str->len;
+  *(p++) = '\n';
+
+  /* Add the entry to the output stream. */
+  to_write = p - buffer;
+  SVN_ERR(svn_stream_write(stream, buffer, &to_write));
   return SVN_NO_ERROR;
 }
 
@@ -951,6 +997,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 */
@@ -971,7 +1018,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;
 }
@@ -1239,9 +1286,6 @@ svn_fs_fs__get_txn(transaction_t **txn_p
   svn_fs_id_t *root_id;
 
   txn = apr_pcalloc(pool, sizeof(*txn));
-  txn->proplist = apr_hash_make(pool);
-
-  SVN_ERR(get_txn_proplist(txn->proplist, fs, txn_id, pool));
   root_id = svn_fs_fs__id_txn_create_root(txn_id, pool);
 
   SVN_ERR(svn_fs_fs__get_node_revision(&noderev, fs, root_id, pool, pool));
@@ -1503,8 +1547,6 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
       out = svn_stream_from_aprfile2(file, TRUE, pool);
       SVN_ERR(unparse_dir_entries(entries, out, subpool));
 
-      svn_pool_clear(subpool);
-
       /* Mark the node-rev's data rep as mutable. */
       rep = apr_pcalloc(pool, sizeof(*rep));
       rep->revision = SVN_INVALID_REVNUM;
@@ -1513,6 +1555,29 @@ svn_fs_fs__set_entry(svn_fs_t *fs,
       parent_noderev->data_rep = rep;
       SVN_ERR(svn_fs_fs__put_node_revision(fs, parent_noderev->id,
                                            parent_noderev, FALSE, pool));
+
+      /* Immediately populate the txn dir cache to avoid re-reading
+       * the file we just wrote. */
+      if (ffd->txn_dir_cache)
+        {
+          const char *key
+            = svn_fs_fs__id_unparse(parent_noderev->id, subpool)->data;
+          svn_fs_fs__dir_data_t dir_data;
+
+          /* Flush APR buffers. */
+          SVN_ERR(svn_io_file_flush(file, subpool));
+
+          /* Obtain final file size to update txn_dir_cache. */
+          SVN_ERR(svn_io_file_size_get(&filesize, file, subpool));
+
+          /* Store in the cache. */
+          dir_data.entries = entries;
+          dir_data.txn_filesize = filesize;
+          SVN_ERR(svn_cache__set(ffd->txn_dir_cache, key, &dir_data,
+                                 subpool));
+        }
+
+      svn_pool_clear(subpool);
     }
   else
     {
@@ -1721,11 +1786,17 @@ allocate_item_index(apr_uint64_t *item_i
       /* read number, increment it and write it back to disk */
       SVN_ERR(svn_io_file_open(&file,
                          svn_fs_fs__path_txn_item_index(fs, txn_id, pool),
-                         APR_READ | APR_WRITE | APR_CREATE | APR_BUFFERED,
+                         APR_READ | APR_WRITE | APR_CREATE,
                          APR_OS_DEFAULT, pool));
       SVN_ERR(svn_io_file_read_full2(file, buffer, sizeof(buffer)-1,
                                      &bytes_read, &eof, pool));
-      if (bytes_read)
+
+      /* Item index file should be shorter than SVN_INT64_BUFFER_SIZE,
+         otherwise we truncate data. */
+      if (!eof)
+          return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                                  _("Unexpected itemidx file length"));
+      else if (bytes_read)
         SVN_ERR(svn_cstring_atoui64(item_index, buffer));
       else
         *item_index = SVN_FS_FS__ITEM_INDEX_FIRST_USER;
@@ -2109,7 +2180,7 @@ rep_write_get_baton(struct rep_write_bat
                                                              b->scratch_pool),
                                     b->scratch_pool);
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&b->rep_offset, file, b->scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&b->rep_offset, file, b->scratch_pool));
 
   /* Get the base for this delta. */
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, FALSE, b->scratch_pool));
@@ -2132,8 +2203,8 @@ rep_write_get_baton(struct rep_write_bat
                                       b->scratch_pool));
 
   /* Now determine the offset of the actual svndiff data. */
-  SVN_ERR(svn_fs_fs__get_file_offset(&b->delta_start, file,
-                                     b->scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&b->delta_start, file,
+                                 b->scratch_pool));
 
   /* Cleanup in case something goes wrong. */
   apr_pool_cleanup_register(b->scratch_pool, b, rep_write_cleanup,
@@ -2180,6 +2251,10 @@ get_shared_rep(representation_t **old_re
   if (!ffd->rep_sharing_allowed)
     return SVN_NO_ERROR;
 
+  /* Can't look up if we don't know the key (happens for directories). */
+  if (!rep->has_sha1)
+    return SVN_NO_ERROR;
+
   /* Check and see if we already have a representation somewhere that's
      identical to the one we just wrote out.  Start with the hash lookup
      because it is cheapest. */
@@ -2296,6 +2371,7 @@ get_shared_rep(representation_t **old_re
 }
 
 /* Copy the hash sum calculation results from MD5_CTX, SHA1_CTX into REP.
+ * SHA1 results are only be set if SHA1_CTX is not NULL.
  * Use POOL for allocations.
  */
 static svn_error_t *
@@ -2308,10 +2384,12 @@ digests_final(representation_t *rep,
 
   SVN_ERR(svn_checksum_final(&checksum, md5_ctx, pool));
   memcpy(rep->md5_digest, checksum->digest, svn_checksum_size(checksum));
-  SVN_ERR(svn_checksum_final(&checksum, sha1_ctx, pool));
-  rep->has_sha1 = checksum != NULL;
+  rep->has_sha1 = sha1_ctx != NULL;
   if (rep->has_sha1)
-    memcpy(rep->sha1_digest, checksum->digest, svn_checksum_size(checksum));
+    {
+      SVN_ERR(svn_checksum_final(&checksum, sha1_ctx, pool));
+      memcpy(rep->sha1_digest, checksum->digest, svn_checksum_size(checksum));
+    }
 
   return SVN_NO_ERROR;
 }
@@ -2335,7 +2413,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_fs__get_file_offset(&offset, b->file, b->scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->scratch_pool));
   rep->size = offset - b->delta_start;
 
   /* Fill in the rest of the representation field. */
@@ -2382,7 +2460,7 @@ rep_write_contents_close(void *baton)
       svn_fs_fs__p2l_entry_t entry;
 
       entry.offset = b->rep_offset;
-      SVN_ERR(svn_fs_fs__get_file_offset(&offset, b->file, b->scratch_pool));
+      SVN_ERR(svn_io_file_get_offset(&offset, b->file, b->scratch_pool));
       entry.size = offset - b->rep_offset;
       entry.type = SVN_FS_FS__ITEM_TYPE_FILE_REP;
       entry.item.revision = SVN_INVALID_REVNUM;
@@ -2516,6 +2594,8 @@ struct write_container_baton
   apr_size_t size;
 
   svn_checksum_ctx_t *md5_ctx;
+
+  /* SHA1 calculation is optional. If not needed, this will be NULL. */
   svn_checksum_ctx_t *sha1_ctx;
 };
 
@@ -2530,7 +2610,8 @@ write_container_handler(void *baton,
   struct write_container_baton *whb = baton;
 
   SVN_ERR(svn_checksum_update(whb->md5_ctx, data, *len));
-  SVN_ERR(svn_checksum_update(whb->sha1_ctx, data, *len));
+  if (whb->sha1_ctx)
+    SVN_ERR(svn_checksum_update(whb->sha1_ctx, data, *len));
 
   SVN_ERR(svn_stream_write(whb->stream, data, len));
   whb->size += *len;
@@ -2592,7 +2673,7 @@ write_container_rep(representation_t *re
   representation_t *old_rep;
   apr_off_t offset = 0;
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, scratch_pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, file, scratch_pool));
 
   whb = apr_pcalloc(scratch_pool, sizeof(*whb));
 
@@ -2602,7 +2683,8 @@ write_container_rep(representation_t *re
                                   scratch_pool);
   whb->size = 0;
   whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
+  if (item_type != SVN_FS_FS__ITEM_TYPE_DIR_REP)
+    whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
   stream = svn_stream_create(whb, scratch_pool);
   svn_stream_set_write(stream, write_container_handler);
@@ -2639,7 +2721,7 @@ write_container_rep(representation_t *re
                                   offset, scratch_pool));
 
       entry.offset = offset;
-      SVN_ERR(svn_fs_fs__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.revision = SVN_INVALID_REVNUM;
@@ -2706,7 +2788,7 @@ write_container_delta_rep(representation
   SVN_ERR(choose_delta_base(&base_rep, fs, noderev, is_props, scratch_pool));
   SVN_ERR(svn_fs_fs__get_contents(&source, fs, base_rep, FALSE, scratch_pool));
 
-  SVN_ERR(svn_fs_fs__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)
@@ -2726,7 +2808,7 @@ write_container_delta_rep(representation
                                                            scratch_pool),
                                   scratch_pool);
   SVN_ERR(svn_fs_fs__write_rep_header(&header, file_stream, scratch_pool));
-  SVN_ERR(svn_fs_fs__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,
@@ -2741,7 +2823,8 @@ write_container_delta_rep(representation
                                         scratch_pool);
   whb->size = 0;
   whb->md5_ctx = svn_checksum_ctx_create(svn_checksum_md5, scratch_pool);
-  whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
+  if (item_type != SVN_FS_FS__ITEM_TYPE_DIR_REP)
+    whb->sha1_ctx = svn_checksum_ctx_create(svn_checksum_sha1, scratch_pool);
 
   /* serialize the hash */
   stream = svn_stream_create(whb, scratch_pool);
@@ -2772,14 +2855,14 @@ write_container_delta_rep(representation
       svn_fs_fs__p2l_entry_t entry;
 
       /* Write out our cosmetic end marker. */
-      SVN_ERR(svn_fs_fs__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(allocate_item_index(&rep->item_index, fs, &rep->txn_id,
                                   offset, scratch_pool));
 
       entry.offset = offset;
-      SVN_ERR(svn_fs_fs__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.revision = SVN_INVALID_REVNUM;
@@ -2840,9 +2923,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 "
@@ -2895,6 +2977,9 @@ get_final_id(svn_fs_fs__id_part_t *part,
    INITIAL_OFFSET is the offset of the proto-rev-file on entry to
    commit_body.
 
+   Collect the pair_cache_key_t of all directories written to the
+   committed cache in DIRECTORY_IDS.
+
    If REPS_TO_CACHE is not NULL, append to it a copy (allocated in
    REPS_POOL) of each data rep that is new in this revision.
 
@@ -2916,6 +3001,7 @@ write_final_rev(const svn_fs_id_t **new_
                 apr_uint64_t start_node_id,
                 apr_uint64_t start_copy_id,
                 apr_off_t initial_offset,
+                apr_array_header_t *directory_ids,
                 apr_array_header_t *reps_to_cache,
                 apr_hash_t *reps_hash,
                 apr_pool_t *reps_pool,
@@ -2958,14 +3044,17 @@ write_final_rev(const svn_fs_id_t **new_
           svn_pool_clear(subpool);
           SVN_ERR(write_final_rev(&new_id, file, rev, fs, dirent->id,
                                   start_node_id, start_copy_id, initial_offset,
-                                  reps_to_cache, reps_hash, reps_pool, FALSE,
-                                  subpool));
+                                  directory_ids, reps_to_cache, reps_hash,
+                                  reps_pool, FALSE, subpool));
           if (new_id && (svn_fs_fs__id_rev(new_id) == rev))
             dirent->id = svn_fs_fs__id_copy(new_id, pool);
         }
 
       if (noderev->data_rep && is_txn_rep(noderev->data_rep))
         {
+          pair_cache_key_t *key;
+          svn_fs_fs__dir_data_t dir_data;
+
           /* Write out the contents of this directory as a text rep. */
           noderev->data_rep->revision = rev;
           if (ffd->deltify_directories)
@@ -2981,6 +3070,23 @@ write_final_rev(const svn_fs_id_t **new_
                                         SVN_FS_FS__ITEM_TYPE_DIR_REP, pool));
 
           reset_txn_in_rep(noderev->data_rep);
+
+          /* Cache the new directory contents.  Otherwise, subsequent reads
+           * or commits will likely have to reconstruct, verify and parse
+           * it again. */
+          key = apr_array_push(directory_ids);
+          key->revision = noderev->data_rep->revision;
+          key->second = noderev->data_rep->item_index;
+
+          /* Store directory contents under the new revision number but mark
+           * it as "stale" by setting the file length to 0.  Committed dirs
+           * will report -1, in-txn dirs will report > 0, so that this can
+           * never match.  We reset that to -1 after the commit is complete.
+           */
+          dir_data.entries = entries;
+          dir_data.txn_filesize = 0;
+
+          SVN_ERR(svn_cache__set(ffd->dir_cache, key, &dir_data, subpool));
         }
     }
   else
@@ -3042,7 +3148,7 @@ write_final_rev(const svn_fs_id_t **new_
     noderev->copyroot_rev = rev;
 
   /* root nodes have a fixed ID in log addressing mode */
-  SVN_ERR(svn_fs_fs__get_file_offset(&my_offset, file, pool));
+  SVN_ERR(svn_io_file_get_offset(&my_offset, file, pool));
   if (svn_fs_fs__use_log_addressing(fs) && at_root)
     {
       /* reference the root noderev from the log-to-phys index */
@@ -3115,7 +3221,7 @@ write_final_rev(const svn_fs_id_t **new_
       rev_item.revision = SVN_INVALID_REVNUM;
 
       entry.offset = my_offset;
-      SVN_ERR(svn_fs_fs__get_file_offset(&my_offset, file, pool));
+      SVN_ERR(svn_io_file_get_offset(&my_offset, file, pool));
       entry.size = my_offset - entry.offset;
       entry.type = SVN_FS_FS__ITEM_TYPE_NODEREV;
       entry.item = rev_item;
@@ -3148,7 +3254,7 @@ write_final_changed_path_info(apr_off_t
   svn_stream_t *stream;
   svn_checksum_ctx_t *fnv1a_checksum_ctx;
 
-  SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
+  SVN_ERR(svn_io_file_get_offset(&offset, file, pool));
 
   /* write to target file & calculate checksum */
   stream = fnv1a_wrap_stream(&fnv1a_checksum_ctx,
@@ -3164,7 +3270,7 @@ write_final_changed_path_info(apr_off_t
       svn_fs_fs__p2l_entry_t entry;
 
       entry.offset = offset;
-      SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
+      SVN_ERR(svn_io_file_get_offset(&offset, file, pool));
       entry.size = offset - entry.offset;
       entry.type = SVN_FS_FS__ITEM_TYPE_CHANGES;
       entry.item.revision = SVN_INVALID_REVNUM;
@@ -3335,6 +3441,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;
@@ -3374,7 +3481,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));
@@ -3423,6 +3531,41 @@ svn_fs_fs__add_index_data(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Mark the directories cached in FS with the keys from DIRECTORY_IDS
+ * as "valid" now.  Use SCRATCH_POOL for temporaries. */
+static svn_error_t *
+promote_cached_directories(svn_fs_t *fs,
+                           apr_array_header_t *directory_ids,
+                           apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_pool_t *iterpool;
+  int i;
+
+  if (!ffd->dir_cache)
+    return SVN_NO_ERROR;
+
+  iterpool = svn_pool_create(scratch_pool);
+  for (i = 0; i < directory_ids->nelts; ++i)
+    {
+      const pair_cache_key_t *key
+        = &APR_ARRAY_IDX(directory_ids, i, pair_cache_key_t);
+
+      svn_pool_clear(iterpool);
+
+      /* Currently, the entry for KEY - if it still exists - is marked
+       * as "stale" and would not be used.  Mark it as current for in-
+       * revison data. */
+      SVN_ERR(svn_cache__set_partial(ffd->dir_cache, key,
+                                     svn_fs_fs__reset_txn_filesize, NULL,
+                                     iterpool));
+    }
+
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 /* Baton used for commit_body below. */
 struct commit_baton {
   svn_revnum_t *new_rev_p;
@@ -3452,6 +3595,8 @@ commit_body(void *baton, apr_pool_t *poo
   apr_off_t initial_offset, changed_path_offset;
   const svn_fs_fs__id_part_t *txn_id = svn_fs_fs__txn_get_id(cb->txn);
   apr_hash_t *changed_paths;
+  apr_array_header_t *directory_ids = apr_array_make(pool, 4,
+                                                     sizeof(pair_cache_key_t));
 
   /* Re-Read the current repository format.  All our repo upgrade and
      config evaluation strategies are such that existing information in
@@ -3499,14 +3644,14 @@ commit_body(void *baton, apr_pool_t *poo
   /* Get a write handle on the proto revision file. */
   SVN_ERR(get_writable_proto_rev(&proto_file, &proto_file_lockcookie,
                                  cb->fs, txn_id, pool));
-  SVN_ERR(svn_fs_fs__get_file_offset(&initial_offset, proto_file, pool));
+  SVN_ERR(svn_io_file_get_offset(&initial_offset, proto_file, pool));
 
   /* Write out all the node-revisions and directory contents. */
   root_id = svn_fs_fs__id_txn_create_root(txn_id, pool);
   SVN_ERR(write_final_rev(&new_root_id, proto_file, new_rev, cb->fs, root_id,
                           start_node_id, start_copy_id, initial_offset,
-                          cb->reps_to_cache, cb->reps_hash, cb->reps_pool,
-                          TRUE, pool));
+                          directory_ids, cb->reps_to_cache, cb->reps_hash,
+                          cb->reps_pool, TRUE, pool));
 
   /* Write the changed-path information. */
   SVN_ERR(write_final_changed_path_info(&changed_path_offset, proto_file,
@@ -3534,7 +3679,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
@@ -3587,7 +3733,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
@@ -3599,7 +3746,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));
@@ -3615,6 +3762,10 @@ commit_body(void *baton, apr_pool_t *poo
 
   ffd->youngest_rev_cache = new_rev;
 
+  /* Make the directory contents alreday cached for the new revision
+   * visible. */
+  SVN_ERR(promote_cached_directories(cb->fs, directory_ids, pool));
+
   /* Remove this transaction directory. */
   SVN_ERR(svn_fs_fs__purge_txn(cb->fs, cb->txn->id, pool));
 
@@ -3673,6 +3824,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.
@@ -3683,9 +3836,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/authzperf/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_fs/tree.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_fs/tree.c Fri Apr 29 18:38:53 2016
@@ -209,17 +209,15 @@ auto_clear_dag_cache(fs_fs_dag_cache_t*
     }
 }
 
-/* For the given REVISION and PATH, return the respective entry in CACHE.
-   If the entry is empty, its NODE member will be NULL and the caller
-   may then set it to the corresponding DAG node allocated in CACHE->POOL.
+/* Returns a 32 bit hash value for the given REVISION and PATH of exactly
+ * PATH_LEN chars.
  */
-static cache_entry_t *
-cache_lookup( fs_fs_dag_cache_t *cache
-            , svn_revnum_t revision
-            , const char *path)
+static apr_uint32_t
+hash_func(svn_revnum_t revision,
+          const char *path,
+          apr_size_t path_len)
 {
-  apr_size_t i, bucket_index;
-  apr_size_t path_len = strlen(path);
+  apr_size_t i;
   apr_uint32_t hash_value = (apr_uint32_t)revision;
 
 #if SVN_UNALIGNED_ACCESS_IS_OK
@@ -227,20 +225,7 @@ cache_lookup( fs_fs_dag_cache_t *cache
   const apr_uint32_t factor = 0xd1f3da69;
 #endif
 
-  /* optimistic lookup: hit the same bucket again? */
-  cache_entry_t *result = &cache->buckets[cache->last_hit];
-  if (   (result->revision == revision)
-      && (result->path_len == path_len)
-      && !memcmp(result->path, path, path_len))
-    {
-      /* Remember the position of the last node we found in this cache. */
-      if (result->node)
-        cache->last_non_empty = cache->last_hit;
-
-      return result;
-    }
-
-  /* need to do a full lookup.  Calculate the hash value
+  /* Calculate the hash value
      (HASH_VALUE has been initialized to REVISION).
 
      Note that the actual hash function is arbitrary as long as its result
@@ -283,6 +268,37 @@ cache_lookup( fs_fs_dag_cache_t *cache
      */
     hash_value = hash_value * 32 + (hash_value + (unsigned char)path[i]);
 
+  return hash_value;
+}
+
+/* For the given REVISION and PATH, return the respective node found in
+ * CACHE.  If there is none, return NULL.
+ */
+static dag_node_t *
+cache_lookup( fs_fs_dag_cache_t *cache
+            , svn_revnum_t revision
+            , const char *path)
+{
+  apr_size_t bucket_index;
+  apr_size_t path_len = strlen(path);
+  apr_uint32_t hash_value;
+
+  /* optimistic lookup: hit the same bucket again? */
+  cache_entry_t *result = &cache->buckets[cache->last_hit];
+  if (   (result->revision == revision)
+      && (result->path_len == path_len)
+      && !memcmp(result->path, path, path_len))
+    {
+      /* Remember the position of the last node we found in this cache. */
+      if (result->node)
+        cache->last_non_empty = cache->last_hit;
+
+      return result->node;
+    }
+
+  /* need to do a full lookup. */
+  hash_value = hash_func(revision, path, path_len);
+
   bucket_index = hash_value + (hash_value >> 16);
   bucket_index = (bucket_index + (bucket_index >> 8)) % BUCKET_COUNT;
 
@@ -297,16 +313,7 @@ cache_lookup( fs_fs_dag_cache_t *cache
       || (result->path_len != path_len)
       || memcmp(result->path, path, path_len))
     {
-      result->hash_value = hash_value;
-      result->revision = revision;
-      if (result->path_len < path_len)
-        result->path = apr_palloc(cache->pool, path_len + 1);
-      result->path_len = path_len;
-      memcpy(result->path, path, path_len + 1);
-
-      result->node = NULL;
-
-      cache->insertions++;
+      return NULL;
     }
   else if (result->node)
     {
@@ -315,7 +322,46 @@ cache_lookup( fs_fs_dag_cache_t *cache
       cache->last_non_empty = bucket_index;
     }
 
-  return result;
+  return result->node;
+}
+
+/* Store a copy of NODE in CACHE, taking  REVISION and PATH as key.
+ * This function will clean the cache at regular intervals.
+ */
+static void
+cache_insert(fs_fs_dag_cache_t *cache,
+             svn_revnum_t revision,
+             const char *path,
+             dag_node_t *node)
+{
+  apr_size_t bucket_index;
+  apr_size_t path_len = strlen(path);
+  apr_uint32_t hash_value;
+  cache_entry_t *entry;
+
+  auto_clear_dag_cache(cache);
+
+  /* calculate the bucket index to use */
+  hash_value = hash_func(revision, path, path_len);
+
+  bucket_index = hash_value + (hash_value >> 16);
+  bucket_index = (bucket_index + (bucket_index >> 8)) % BUCKET_COUNT;
+
+  /* access the corresponding bucket and remember its location */
+  entry = &cache->buckets[bucket_index];
+  cache->last_hit = bucket_index;
+
+  /* if it is *NOT* a match,  clear the bucket, expect the caller to fill
+     in the node and count it as an insertion */
+  entry->hash_value = hash_value;
+  entry->revision = revision;
+  if (entry->path_len < path_len)
+    entry->path = apr_palloc(cache->pool, path_len + 1);
+  entry->path_len = path_len;
+  memcpy(entry->path, path, path_len + 1);
+
+  entry->node = svn_fs_fs__dag_dup(node, cache->pool);
+  cache->insertions++;
 }
 
 /* Optimistic lookup using the last seen non-empty location in CACHE.
@@ -393,11 +439,9 @@ dag_node_cache_get(dag_node_t **node_p,
       /* immutable DAG node. use the global caches for it */
 
       fs_fs_data_t *ffd = root->fs->fsap_data;
-      cache_entry_t *bucket;
 
-      auto_clear_dag_cache(ffd->dag_node_cache);
-      bucket = cache_lookup(ffd->dag_node_cache, root->rev, path);
-      if (bucket->node == NULL)
+      node = cache_lookup(ffd->dag_node_cache, root->rev, path);
+      if (node == NULL)
         {
           locate_cache(&cache, &key, root, path, pool);
           SVN_ERR(svn_cache__get((void **)&node, &found, cache, key, pool));
@@ -408,14 +452,13 @@ dag_node_cache_get(dag_node_t **node_p,
               svn_fs_fs__dag_set_fs(node, root->fs);
 
               /* Retain the DAG node in L1 cache. */
-              bucket->node = svn_fs_fs__dag_dup(node,
-                                                ffd->dag_node_cache->pool);
+              cache_insert(ffd->dag_node_cache, root->rev, path, node);
             }
         }
       else
         {
           /* Copy the node from L1 cache into the passed-in POOL. */
-          node = svn_fs_fs__dag_dup(bucket->node, pool);
+          node = svn_fs_fs__dag_dup(node, pool);
         }
     }
   else
@@ -1232,11 +1275,15 @@ get_dag(dag_node_t **dag_node_p,
     {
       /* Canonicalize the input PATH.  As it turns out, >95% of all paths
        * seen here during e.g. svnadmin verify are non-canonical, i.e.
-       * miss the leading '/'.  Unconditional canonicalization has a net
-       * performance benefit over previously checking path for being
-       * canonical. */
-      path = svn_fs__canonicalize_abspath(path, pool);
-      SVN_ERR(dag_node_cache_get(&node, root, path, pool));
+       * miss the leading '/'.  Check for those quickly.
+       *
+       * For normalized paths, it is much faster to check the path than
+       * to attempt a second cache lookup (which would fail). */
+      if (*path != '/' || !svn_fs__is_canonical_abspath(path))
+        {
+          path = svn_fs__canonicalize_abspath(path, pool);
+          SVN_ERR(dag_node_cache_get(&node, root, path, pool));
+        }
 
       if (! node)
         {
@@ -1427,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. */
@@ -1459,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
@@ -1900,13 +1930,13 @@ merge(svn_stringbuf_t *conflict_p,
     /* Now compare the prop-keys of the skels.  Note that just because
        the keys are different -doesn't- mean the proplists have
        different contents. */
-    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, src_nr, anc_nr, TRUE, pool));
+    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, src_nr, anc_nr, pool));
     if (! same)
       return conflict_err(conflict_p, target_path);
 
     /* The directory entries got changed in the repository but the directory
        properties did not. */
-    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, tgt_nr, anc_nr, TRUE, pool));
+    SVN_ERR(svn_fs_fs__prop_rep_equal(&same, fs, tgt_nr, anc_nr, pool));
     if (! same)
       {
         /* There is an incoming prop change for this directory.
@@ -3188,23 +3218,18 @@ fs_contents_changed(svn_boolean_t *chang
       (SVN_ERR_FS_GENERAL, NULL,
        _("Cannot compare file contents between two different filesystems"));
 
-  /* Check that both paths are files. */
-  {
-    svn_node_kind_t kind;
-
-    SVN_ERR(svn_fs_fs__check_path(&kind, root1, path1, pool));
-    if (kind != svn_node_file)
-      return svn_error_createf
-        (SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path1);
-
-    SVN_ERR(svn_fs_fs__check_path(&kind, root2, path2, pool));
-    if (kind != svn_node_file)
-      return svn_error_createf
-        (SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path2);
-  }
-
   SVN_ERR(get_dag(&node1, root1, path1, pool));
+  /* Make sure that path is file. */
+  if (svn_fs_fs__dag_node_kind(node1) != svn_node_file)
+    return svn_error_createf
+      (SVN_ERR_FS_NOT_FILE, NULL, _("'%s' is not a file"), path1);
+
   SVN_ERR(get_dag(&node2, root2, path2, pool));
+  /* Make sure that path is file. */
+  if (svn_fs_fs__dag_node_kind(node2) != svn_node_file)
+    return svn_error_createf
+      (SVN_ERR_FS_NOT_FILE, NULL, _("'%s' is not a file"), path2);
+
   return svn_fs_fs__dag_things_different(NULL, changed_p,
                                          node1, node2, strict, pool);
 }
@@ -4300,6 +4325,7 @@ fs_get_mergeinfo(svn_mergeinfo_catalog_t
 /* The vtable associated with root objects. */
 static root_vtable_t root_vtable = {
   fs_paths_changed,
+  NULL,
   svn_fs_fs__check_path,
   fs_node_history,
   svn_fs_fs__node_id,

Modified: subversion/branches/authzperf/subversion/libsvn_fs_fs/util.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_fs/util.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_fs/util.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_fs/util.c Fri Apr 29 18:38:53 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;
 }
@@ -566,22 +568,6 @@ svn_fs_fs__try_stringbuf_from_file(svn_s
 }
 
 svn_error_t *
-svn_fs_fs__get_file_offset(apr_off_t *offset_p,
-                           apr_file_t *file,
-                           apr_pool_t *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, pool));
-  *offset_p = offset;
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
 svn_fs_fs__read_content(svn_stringbuf_t **content,
                         const char *fname,
                         apr_pool_t *pool)
@@ -635,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;
@@ -644,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. */
@@ -655,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/authzperf/subversion/libsvn_fs_fs/util.h
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_fs/util.h?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_fs/util.h (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_fs/util.h Fri Apr 29 18:38:53 2016
@@ -363,12 +363,6 @@ svn_fs_fs__try_stringbuf_from_file(svn_s
                                    svn_boolean_t last_attempt,
                                    apr_pool_t *pool);
 
-/* Fetch the current offset of FILE into *OFFSET_P. */
-svn_error_t *
-svn_fs_fs__get_file_offset(apr_off_t *offset_p,
-                           apr_file_t *file,
-                           apr_pool_t *pool);
-
 /* Read the file FNAME and store the contents in *BUF.
    Allocations are performed in POOL. */
 svn_error_t *
@@ -394,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/authzperf/subversion/libsvn_fs_fs/verify.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_fs/verify.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_fs/verify.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_fs/verify.c Fri Apr 29 18:38:53 2016
@@ -30,6 +30,7 @@
 
 #include "cached_data.h"
 #include "rep-cache.h"
+#include "revprops.h"
 #include "util.h"
 #include "index.h"
 
@@ -479,7 +480,7 @@ expect_buffer_nul(apr_file_t *file,
         apr_off_t offset;
 
         SVN_ERR(svn_io_file_name_get(&file_name, file, pool));
-        SVN_ERR(svn_fs_fs__get_file_offset(&offset, file, pool));
+        SVN_ERR(svn_io_file_get_offset(&offset, file, pool));
         offset -= size - i;
 
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
@@ -721,6 +722,10 @@ verify_revprops(svn_fs_t *fs,
   svn_revnum_t revision;
   apr_pool_t *iterpool = svn_pool_create(pool);
 
+  /* Invalidate the revprop cache once.
+   * Use the cache inside the loop to speed up packed revprop access. */
+  svn_fs_fs__reset_revprop_cache(fs);
+
   for (revision = start; revision < end; ++revision)
     {
       svn_string_t *date;
@@ -731,7 +736,8 @@ verify_revprops(svn_fs_t *fs,
       /* Access the svn:date revprop.
        * This implies parsing all revprops for that revision. */
       SVN_ERR(svn_fs_fs__revision_prop(&date, fs, revision,
-                                       SVN_PROP_REVISION_DATE, iterpool));
+                                       SVN_PROP_REVISION_DATE, FALSE,
+                                       iterpool, iterpool));
 
       /* The time stamp is the only revprop that, if given, needs to
        * have a valid content. */

Modified: subversion/branches/authzperf/subversion/libsvn_fs_util/fs-util.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_util/fs-util.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_util/fs-util.c Fri Apr 29 18:38:53 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/authzperf/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Fri Apr 29 18:38:53 2016
@@ -58,6 +58,7 @@
 /subversion/branches/log-addressing/subversion/libsvn_fs_x:1511324
 /subversion/branches/log-g-performance/subversion/libsvn_fs_x:870941-871032
 /subversion/branches/merge-skips-obstructions/subversion/libsvn_fs_x:874525-874615
+/subversion/branches/move-tracking-2/subversion/libsvn_fs_x:1606692-1714632
 /subversion/branches/multi-layer-moves/subversion/libsvn_fs_x:1239019-1300930
 /subversion/branches/nfc-nfd-aware-client/subversion/libsvn_fs_x:870276,870376
 /subversion/branches/node_pool/subversion/libsvn_fs_x:1304828-1305388
@@ -93,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,1653608,
 1658482
-/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1613053-1706376
+/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
+/subversion/trunk/subversion/libsvn_fs_x:1414756-1509914,1613053-1741675

Modified: subversion/branches/authzperf/subversion/libsvn_fs_x/batch_fsync.c
URL: http://svn.apache.org/viewvc/subversion/branches/authzperf/subversion/libsvn_fs_x/batch_fsync.c?rev=1741682&r1=1741681&r2=1741682&view=diff
==============================================================================
--- subversion/branches/authzperf/subversion/libsvn_fs_x/batch_fsync.c (original)
+++ subversion/branches/authzperf/subversion/libsvn_fs_x/batch_fsync.c Fri Apr 29 18:38:53 2016
@@ -327,6 +327,8 @@ internal_open_file(apr_file_t **file,
   svn_error_t *err;
   apr_pool_t *pool;
   to_sync_t *to_sync;
+  svn_node_kind_t kind;
+  svn_boolean_t is_new_file;
 
   /* If we already have a handle for PATH, return that. */
   to_sync = svn_hash_gets(batch->files, path);
@@ -336,9 +338,30 @@ internal_open_file(apr_file_t **file,
       return SVN_NO_ERROR;
     }
 
+  /* Calling fsync in PATH is going to be expensive in any case, so we can
+   * allow for some extra overhead figuring out whether the file already
+   * exists.  If it doesn't, be sure to schedule parent folder updates, if
+   * required on this platform.
+   *
+   * See svn_fs_x__batch_fsync_new_path() for when such extra fsyncs may be
+   * needed at all. */
+
+#ifdef SVN_ON_POSIX
+
+  is_new_file = FALSE;
+  if (flags & APR_CREATE)
+    {
+      /* We might actually be about to create a new file.
+       * Check whether the file already exists. */
+      SVN_ERR(svn_io_check_path(path, &kind, scratch_pool));
+      is_new_file = kind == svn_node_none;
+    }
+
+#endif
+
   /* To be able to process each file in a separate thread, they must use
    * separate, thread-safe pools.  Allocating a sub-pool from the standard
-   * thread-pool achieves exactly that. */
+   * memory pool achieves exactly that. */
   pool = svn_pool_create(NULL);
   err = svn_io_file_open(file, path, flags, APR_OS_DEFAULT, pool);
   if (err)
@@ -357,6 +380,16 @@ internal_open_file(apr_file_t **file,
                 apr_pstrdup(apr_hash_pool_get(batch->files), path),
                 to_sync);
 
+  /* If we just created a new file, schedule any additional necessary fsyncs.
+   * Note that this can only recurse once since the parent folder already
+   * exists on disk. */
+#ifdef SVN_ON_POSIX
+
+  if (is_new_file)
+    SVN_ERR(svn_fs_x__batch_fsync_new_path(batch, path, scratch_pool));
+
+#endif
+
   return SVN_NO_ERROR;
 }
 
@@ -468,20 +501,26 @@ svn_fs_x__batch_fsync_run(svn_fs_x__batc
 
 #if APR_HAS_THREADS
 
-      apr_status_t status = APR_SUCCESS;
-      status = apr_thread_pool_push(thread_pool, flush_task, to_sync,
-                                    0, NULL);
-      if (status)
-        to_sync->result = svn_error_wrap_apr(status, _("Can't push task"));
+      /* If there are multiple fsyncs to perform, run them in parallel.
+       * Otherwise, skip the thread-pool and synchronization overhead. */
+      if (apr_hash_count(batch->files) > 1)
+        {
+          apr_status_t status = APR_SUCCESS;
+          status = apr_thread_pool_push(thread_pool, flush_task, to_sync,
+                                        0, NULL);
+          if (status)
+            to_sync->result = svn_error_wrap_apr(status, _("Can't push task"));
+          else
+            tasks++;
+        }
       else
-        tasks++;
-
-#else
-
-      to_sync->result = svn_error_trace(svn_io_file_flush_to_disk
-                                           (to_sync->file, to_sync->pool));
 
 #endif
+
+        {
+          to_sync->result = svn_error_trace(svn_io_file_flush_to_disk
+                                              (to_sync->file, to_sync->pool));
+        }
     }
 
   /* Wait for all outstanding flush operations to complete. */