subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From i...@apache.org
Subject svn commit: r1636544 [2/13] - in /subversion/branches/remove-log-addressing: ./ subversion/bindings/javahl/tests/org/apache/subversion/javahl/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion...
Date Tue, 04 Nov 2014 11:40:19 GMT
Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/bdb/changes-table.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/bdb/changes-table.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/bdb/changes-table.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_base/bdb/changes-table.c Tue Nov  4 11:40:16 2014
@@ -121,12 +121,32 @@ svn_fs_bdb__changes_delete(svn_fs_t *fs,
   return SVN_NO_ERROR;
 }
 
+/* Return a deep FS API type copy of SOURCE in internal format and allocate
+ * the result in RESULT_POOL.
+ */
+static svn_fs_path_change2_t *
+change_to_fs_change(const change_t *change,
+                    apr_pool_t *result_pool)
+{
+  svn_fs_path_change2_t *result = svn_fs__path_change_create_internal(
+                                    svn_fs_base__id_copy(change->noderev_id,
+                                                         result_pool),
+                                    change->kind,
+                                    result_pool);
+  result->text_mod = change->text_mod;
+  result->prop_mod = change->prop_mod;
+  result->node_kind = svn_node_unknown;
+  result->copyfrom_known = FALSE;
+
+  return result;
+}
 
 /* Merge the internal-use-only CHANGE into a hash of public-FS
    svn_fs_path_change2_t CHANGES, collapsing multiple changes into a
    single succinct change per path. */
 static svn_error_t *
 fold_change(apr_hash_t *changes,
+            apr_hash_t *deletions,
             const change_t *change)
 {
   apr_pool_t *pool = apr_hash_pool_get(changes);
@@ -185,7 +205,7 @@ fold_change(apr_hash_t *changes,
         case svn_fs_path_change_reset:
           /* A reset here will simply remove the path change from the
              hash. */
-          old_change = NULL;
+          new_change = NULL;
           break;
 
         case svn_fs_path_change_delete:
@@ -194,14 +214,21 @@ fold_change(apr_hash_t *changes,
               /* If the path was introduced in this transaction via an
                  add, and we are deleting it, just remove the path
                  altogether. */
-              old_change = NULL;
+              new_change = NULL;
+            }
+          else if (old_change->change_kind == svn_fs_path_change_replace)
+            {
+              /* A deleting a 'replace' restore the original deletion. */
+              new_change = svn_hash_gets(deletions, path);
+              SVN_ERR_ASSERT(new_change);
             }
           else
             {
               /* A deletion overrules all previous changes. */
-              old_change->change_kind = svn_fs_path_change_delete;
-              old_change->text_mod = change->text_mod;
-              old_change->prop_mod = change->prop_mod;
+              new_change = old_change;
+              new_change->change_kind = svn_fs_path_change_delete;
+              new_change->text_mod = change->text_mod;
+              new_change->prop_mod = change->prop_mod;
             }
           break;
 
@@ -209,38 +236,33 @@ fold_change(apr_hash_t *changes,
         case svn_fs_path_change_replace:
           /* An add at this point must be following a previous delete,
              so treat it just like a replace. */
-          old_change->change_kind = svn_fs_path_change_replace;
-          old_change->node_rev_id = svn_fs_base__id_copy(change->noderev_id,
-                                                         pool);
-          old_change->text_mod = change->text_mod;
-          old_change->prop_mod = change->prop_mod;
+
+          new_change = change_to_fs_change(change, pool);
+          new_change->change_kind = svn_fs_path_change_replace;
+
+          /* Remember the original deletion.
+           * Make sure to allocate the hash key in a durable pool. */
+          svn_hash_sets(deletions,
+                        apr_pstrdup(apr_hash_pool_get(deletions), path),
+                        old_change);
           break;
 
         case svn_fs_path_change_modify:
         default:
+          new_change = old_change;
           if (change->text_mod)
-            old_change->text_mod = TRUE;
+            new_change->text_mod = TRUE;
           if (change->prop_mod)
-            old_change->prop_mod = TRUE;
+            new_change->prop_mod = TRUE;
           break;
         }
-
-      /* Point our new_change to our (possibly modified) old_change. */
-      new_change = old_change;
     }
   else
     {
       /* This change is new to the hash, so make a new public change
          structure from the internal one (in the hash's pool), and dup
          the path into the hash's pool, too. */
-      new_change = svn_fs__path_change_create_internal(
-                       svn_fs_base__id_copy(change->noderev_id, pool),
-                       change->kind,
-                       pool);
-      new_change->text_mod = change->text_mod;
-      new_change->prop_mod = change->prop_mod;
-      new_change->node_kind = svn_node_unknown;
-      new_change->copyfrom_known = FALSE;
+      new_change = change_to_fs_change(change, pool);
       path = apr_pstrdup(pool, change->path);
     }
 
@@ -265,6 +287,8 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
   svn_error_t *err = SVN_NO_ERROR;
   apr_hash_t *changes = apr_hash_make(pool);
   apr_pool_t *subpool = svn_pool_create(pool);
+  apr_pool_t *iterpool = svn_pool_create(pool);
+  apr_hash_t *deletions = apr_hash_make(subpool);
 
   /* Get a cursor on the first record matching KEY, and then loop over
      the records, adding them to the return array. */
@@ -286,11 +310,11 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
       svn_skel_t *result_skel;
 
       /* Clear the per-iteration subpool. */
-      svn_pool_clear(subpool);
+      svn_pool_clear(iterpool);
 
       /* RESULT now contains a change record associated with KEY.  We
          need to parse that skel into an change_t structure ...  */
-      result_skel = svn_skel__parse(result.data, result.size, subpool);
+      result_skel = svn_skel__parse(result.data, result.size, iterpool);
       if (! result_skel)
         {
           err = svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
@@ -298,12 +322,12 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
                                   key);
           goto cleanup;
         }
-      err = svn_fs_base__parse_change_skel(&change, result_skel, subpool);
+      err = svn_fs_base__parse_change_skel(&change, result_skel, iterpool);
       if (err)
         goto cleanup;
 
       /* ... and merge it with our return hash.  */
-      err = fold_change(changes, change);
+      err = fold_change(changes, deletions, change);
       if (err)
         goto cleanup;
 
@@ -319,7 +343,7 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
         {
           apr_hash_index_t *hi;
 
-          for (hi = apr_hash_first(subpool, changes);
+          for (hi = apr_hash_first(iterpool, changes);
                hi;
                hi = apr_hash_next(hi))
             {
@@ -347,6 +371,7 @@ svn_fs_bdb__changes_fetch(apr_hash_t **c
     }
 
   /* Destroy the per-iteration subpool. */
+  svn_pool_destroy(iterpool);
   svn_pool_destroy(subpool);
 
   /* If there are no (more) change records for this KEY, we're

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.c Tue Nov  4 11:40:16 2014
@@ -44,6 +44,7 @@
 #include "rep-cache.h"
 #include "revprops.h"
 #include "transaction.h"
+#include "util.h"
 #include "verify.h"
 #include "svn_private_config.h"
 #include "private/svn_fs_util.h"
@@ -347,20 +348,53 @@ fs_open_for_recovery(svn_fs_t *fs,
                      apr_pool_t *pool,
                      apr_pool_t *common_pool)
 {
+  svn_error_t * err;
+  svn_revnum_t youngest_rev;
+  apr_pool_t * subpool = svn_pool_create(pool);
+
   /* Recovery for FSFS is currently limited to recreating the 'current'
      file from the latest revision. */
 
   /* The only thing we have to watch out for is that the 'current' file
-     might not exist.  So we'll try to create it here unconditionally,
-     and just ignore any errors that might indicate that it's already
-     present. (We'll need it to exist later anyway as a source for the
-     new file's permissions). */
+     might not exist or contain garbage.  So we'll try to read it here
+     and provide or replace the existing file if we couldn't read it.
+     (We'll also need it to exist later anyway as a source for the new
+     file's permissions). */
 
-  /* Use a partly-filled fs pointer first to create 'current'.  This will fail
-     if 'current' already exists, but we don't care about that. */
+  /* Use a partly-filled fs pointer first to create 'current'. */
   fs->path = apr_pstrdup(fs->pool, path);
-  svn_error_clear(svn_io_file_create(svn_fs_fs__path_current(fs, pool),
-                                     "0 1 1\n", pool));
+
+  SVN_ERR(initialize_fs_struct(fs));
+
+  /* Figure out the repo format and check that we can even handle it. */
+  SVN_ERR(svn_fs_fs__read_format_file(fs, subpool));
+
+  /* Now, read 'current' and try to patch it if necessary. */
+  err = svn_fs_fs__youngest_rev(&youngest_rev, fs, subpool);
+  if (err)
+    {
+      const char *file_path;
+
+      /* 'current' file is missing or contains garbage.  Since we are trying
+       * to recover from whatever problem there is, being picky about the
+       * error code here won't do us much good.  If there is a persistent
+       * problem that we can't fix, it will show up when we try rewrite the
+       * file a few lines further below and we will report the failure back
+       * to the caller.
+       *
+       * Start recovery with HEAD = 0. */
+      svn_error_clear(err);
+      file_path = svn_fs_fs__path_current(fs, subpool);
+
+      /* Best effort to ensure the file exists and is valid.
+       * This may fail for r/o filesystems etc. */
+      SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool));
+      SVN_ERR(svn_io_file_create_empty(file_path, subpool));
+      SVN_ERR(svn_fs_fs__write_current(fs, 0, 1, 1, subpool));
+    }
+
+  uninitialize_fs_struct(fs);
+  svn_pool_destroy(subpool);
 
   /* Now open the filesystem properly by calling the vtable method directly. */
   return fs_open(fs, path, common_pool_lock, pool, common_pool);

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs.h Tue Nov  4 11:40:16 2014
@@ -36,7 +36,6 @@
 #include "private/svn_fs_private.h"
 #include "private/svn_sqlite.h"
 #include "private/svn_mutex.h"
-#include "private/svn_named_atomic.h"
 
 #include "id.h"
 
@@ -58,7 +57,8 @@ extern "C" {
 #define PATH_PACK_LOCK_FILE   "pack-lock"        /* Pack lock file */
 #define PATH_REVS_DIR         "revs"             /* Directory of revisions */
 #define PATH_REVPROPS_DIR     "revprops"         /* Directory of revprops */
-#define PATH_TXNS_DIR         "transactions"     /* Directory of transactions */
+#define PATH_TXNS_DIR         "transactions"     /* Directory of transactions in
+                                                    repos w/o log addressing */
 #define PATH_NODE_ORIGINS_DIR "node-origins"     /* Lazy node-origin cache */
 #define PATH_TXN_PROTOS_DIR   "txn-protorevs"    /* Directory of proto-revs */
 #define PATH_TXN_CURRENT      "txn-current"      /* File with next txn key */
@@ -165,7 +165,7 @@ extern "C" {
 #define SVN_FS_FS__MIN_PACK_LOCK_FORMAT 7
 
 /* Minimum format number that stores mergeinfo-mode flag in changed paths */
-#define SVN_FS_FS__MIN_MERGEINFO_IN_CHANGES_FORMAT 7
+#define SVN_FS_FS__MIN_MERGEINFO_IN_CHANGED_FORMAT 7
 
 /* Minimum format number that supports per-instance filesystem IDs. */
 #define SVN_FS_FS__MIN_INSTANCE_ID_FORMAT 7
@@ -327,18 +327,6 @@ typedef struct fs_fs_data_t
      rep key (revision/offset) to svn_stringbuf_t. */
   svn_cache__t *fulltext_cache;
 
-  /* Access object to the atomics namespace used by revprop caching.
-     Will be NULL until the first access. */
-  svn_atomic_namespace__t *revprop_namespace;
-
-  /* Access object to the revprop "generation". Will be NULL until
-     the first access. */
-  svn_named_atomic__t *revprop_generation;
-
-  /* Access object to the revprop update timeout. Will be NULL until
-     the first access. */
-  svn_named_atomic__t *revprop_timeout;
-
   /* Revision property cache.  Maps from (rev,generation) to apr_hash_t. */
   svn_cache__t *revprop_cache;
 

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.c Tue Nov  4 11:40:16 2014
@@ -86,7 +86,7 @@ are likely some errors because of that.
 /* Declarations. */
 
 static svn_error_t *
-get_youngest(svn_revnum_t *youngest_p, const char *fs_path, apr_pool_t *pool);
+get_youngest(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool);
 
 /* Pathname helper functions */
 
@@ -213,7 +213,7 @@ with_some_lock_file(with_lock_baton_t *b
           if (ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
             err = svn_fs_fs__update_min_unpacked_rev(fs, pool);
           if (!err)
-            err = get_youngest(&ffd->youngest_rev_cache, fs->path, pool);
+            err = get_youngest(&ffd->youngest_rev_cache, fs, pool);
         }
 
       if (!err)
@@ -671,8 +671,8 @@ read_config(fs_fs_data_t *ffd,
                                    CONFIG_SECTION_PACKED_REVPROPS,
                                    CONFIG_OPTION_REVPROP_PACK_SIZE,
                                    ffd->compress_packed_revprops
-                                       ? 0x100
-                                       : 0x40));
+                                       ? 0x10
+                                       : 0x4));
 
       ffd->revprop_pack_size *= 1024;
     }
@@ -841,20 +841,16 @@ write_config(svn_fs_t *fs,
 "### much larger than the limit set here.  The threshold will be applied"    NL
 "### before optional compression takes place."                               NL
 "### Large values will reduce disk space usage at the expense of increased"  NL
-"### latency and CPU usage reading and changing individual revprops.  They"  NL
-"### become an advantage when revprop caching has been enabled because a"    NL
-"### lot of data can be read in one go.  Values smaller than 4 kByte will"   NL
-"### not improve latency any further and quickly render revprop packing"     NL
-"### ineffective."                                                           NL
-"### revprop-pack-size is 64 kBytes by default for non-compressed revprop"   NL
-"### pack files and 256 kBytes when compression has been enabled."           NL
-"# " CONFIG_OPTION_REVPROP_PACK_SIZE " = 64"                                 NL
+"### latency and CPU usage reading and changing individual revprops."        NL
+"### Values smaller than 4 kByte will not improve latency any further and "  NL
+"### quickly render revprop packing ineffective."                            NL
+"### revprop-pack-size is 4 kBytes by default for non-compressed revprop"    NL
+"### pack files and 16 kBytes when compression has been enabled."            NL
+"# " CONFIG_OPTION_REVPROP_PACK_SIZE " = 4"                                  NL
 "###"                                                                        NL
 "### To save disk space, packed revprop files may be compressed.  Standard"  NL
 "### revprops tend to allow for very effective compression.  Reading and"    NL
-"### even more so writing, become significantly more CPU intensive.  With"   NL
-"### revprop caching enabled, the overhead can be offset by reduced I/O"     NL
-"### unless you often modify revprops after packing."                        NL
+"### even more so writing, become significantly more CPU intensive."         NL
 "### Compressing packed revprops is disabled by default."                    NL
 "# " CONFIG_OPTION_COMPRESS_PACKED_REVPROPS " = false"                       NL
 ""                                                                           NL
@@ -972,7 +968,7 @@ svn_fs_fs__open(svn_fs_t *fs, const char
   /* Global configuration options. */
   SVN_ERR(read_global_config(fs));
 
-  return get_youngest(&(ffd->youngest_rev_cache), path, pool);
+  return get_youngest(&(ffd->youngest_rev_cache), fs, pool);
 }
 
 /* Wrapper around svn_io_file_create which ignores EEXIST. */
@@ -1054,10 +1050,8 @@ upgrade_body(void *baton, apr_pool_t *po
      dir, make that directory.  */
   if (format < SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT)
     {
-      /* We don't use path_txn_proto_rev() here because it expects
-         we've already bumped our format. */
       SVN_ERR(svn_io_make_dir_recursively(
-          svn_dirent_join(fs->path, PATH_TXN_PROTOS_DIR, pool), pool));
+          svn_fs_fs__path_txn_proto_revs(fs, pool), pool));
     }
 
   /* If our filesystem is new enough, write the min unpacked rev file. */
@@ -1098,6 +1092,7 @@ upgrade_body(void *baton, apr_pool_t *po
 
   /* Bump the format file. */
   SVN_ERR(svn_fs_fs__write_format(fs, TRUE, pool));
+
   if (upgrade_baton->notify_func)
     SVN_ERR(upgrade_baton->notify_func(upgrade_baton->notify_baton,
                                        SVN_FS_FS__FORMAT_NUMBER,
@@ -1141,17 +1136,11 @@ svn_fs_fs__upgrade(svn_fs_t *fs,
    POOL. */
 static svn_error_t *
 get_youngest(svn_revnum_t *youngest_p,
-             const char *fs_path,
+             svn_fs_t *fs,
              apr_pool_t *pool)
 {
-  svn_stringbuf_t *buf;
-  SVN_ERR(svn_fs_fs__read_content(&buf,
-                                  svn_dirent_join(fs_path, PATH_CURRENT,
-                                                  pool),
-                                  pool));
-
-  *youngest_p = SVN_STR_TO_REV(buf->data);
-
+  apr_uint64_t dummy;
+  SVN_ERR(svn_fs_fs__read_current(youngest_p, &dummy, &dummy, fs, pool));
   return SVN_NO_ERROR;
 }
 
@@ -1163,7 +1152,7 @@ svn_fs_fs__youngest_rev(svn_revnum_t *yo
 {
   fs_fs_data_t *ffd = fs->fsap_data;
 
-  SVN_ERR(get_youngest(youngest_p, fs->path, pool));
+  SVN_ERR(get_youngest(youngest_p, fs, pool));
   ffd->youngest_rev_cache = *youngest_p;
 
   return SVN_NO_ERROR;
@@ -1207,7 +1196,7 @@ svn_fs_fs__ensure_revision_exists(svn_re
   if (rev <= ffd->youngest_rev_cache)
     return SVN_NO_ERROR;
 
-  SVN_ERR(get_youngest(&(ffd->youngest_rev_cache), fs->path, pool));
+  SVN_ERR(get_youngest(&(ffd->youngest_rev_cache), fs, pool));
 
   /* Check again. */
   if (rev <= ffd->youngest_rev_cache)
@@ -1281,10 +1270,15 @@ svn_fs_fs__file_text_rep_equal(svn_boole
     }
 
   /* Old repositories may not have the SHA1 checksum handy.
-     This check becomes expensive.  Skip it unless explicitly required. */
+     This check becomes expensive.  Skip it unless explicitly required.
+
+     We already have seen that the ID is different, so produce a likely
+     false negative as allowed by the API description - even though the
+     MD5 matched, there is an extremely slim chance that the SHA1 wouldn't.
+   */
   if (!strict)
     {
-      *equal = TRUE;
+      *equal = FALSE;
       return SVN_NO_ERROR;
     }
 
@@ -1436,65 +1430,22 @@ write_revision_zero(svn_fs_t *fs,
 }
 
 svn_error_t *
-svn_fs_fs__create(svn_fs_t *fs,
-                  const char *path,
-                  apr_pool_t *pool)
+svn_fs_fs__create_file_tree(svn_fs_t *fs,
+                            const char *path,
+                            int format,
+                            int shard_size,
+                            apr_pool_t *pool)
 {
-  int format = SVN_FS_FS__FORMAT_NUMBER;
   fs_fs_data_t *ffd = fs->fsap_data;
-  int shard_size = SVN_FS_FS_DEFAULT_MAX_FILES_PER_DIR;
 
   fs->path = apr_pstrdup(fs->pool, path);
-  /* Process the given filesystem config. */
-  if (fs->config)
-    {
-      svn_version_t *compatible_version;
-      const char *shard_size_str;
-      SVN_ERR(svn_fs__compatible_version(&compatible_version, fs->config,
-                                         pool));
-
-      /* select format number */
-      switch(compatible_version->minor)
-        {
-          case 0: return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
-                 _("FSFS is not compatible with Subversion prior to 1.1"));
-
-          case 1:
-          case 2:
-          case 3: format = 1;
-                  break;
-
-          case 4: format = 2;
-                  break;
-
-          case 5: format = 3;
-                  break;
-
-          case 6:
-          case 7: format = 4;
-                  break;
-
-          case 8: format = 6;
-                  break;
-
-          default:format = SVN_FS_FS__FORMAT_NUMBER;
-        }
-
-      shard_size_str = svn_hash_gets(fs->config, SVN_FS_CONFIG_FSFS_SHARD_SIZE);
-      if (shard_size_str)
-        {
-          apr_int64_t val;
-          SVN_ERR(svn_cstring_strtoi64(&val, shard_size_str, 0,
-                                       APR_INT32_MAX, 10));
-
-          shard_size = (int) val;
-        }
-    }
   ffd->format = format;
 
   /* Use an appropriate sharding mode if supported by the format. */
   if (format >= SVN_FS_FS__MIN_LAYOUT_FORMAT_OPTION_FORMAT)
     ffd->max_files_per_dir = shard_size;
+  else
+    ffd->max_files_per_dir = 0;
 
   /* Create the revision data directories. */
   if (ffd->max_files_per_dir)
@@ -1518,21 +1469,20 @@ svn_fs_fs__create(svn_fs_t *fs,
                                         pool));
 
   /* Create the transaction directory. */
-  SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(path, PATH_TXNS_DIR,
-                                                      pool),
+  SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_txns_dir(fs, pool),
                                       pool));
 
   /* Create the protorevs directory. */
   if (format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT)
-    SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(path, PATH_TXN_PROTOS_DIR,
-                                                      pool),
+    SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_txn_proto_revs(fs,
+                                                                       pool),
                                         pool));
 
   /* Create the 'current' file. */
-  SVN_ERR(svn_io_file_create(svn_fs_fs__path_current(fs, pool),
-                             (format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT
-                              ? "0\n" : "0 1 1\n"),
-                             pool));
+  SVN_ERR(svn_io_file_create_empty(svn_fs_fs__path_current(fs, pool), pool));
+  SVN_ERR(svn_fs_fs__write_current(fs, 0, 1, 1, pool));
+
+  /* Create the 'uuid' file. */
   SVN_ERR(svn_io_file_create_empty(svn_fs_fs__path_lock(fs, pool), pool));
   SVN_ERR(svn_fs_fs__set_uuid(fs, NULL, NULL, pool));
 
@@ -1567,10 +1517,70 @@ svn_fs_fs__create(svn_fs_t *fs,
                                  pool));
     }
 
+  ffd->youngest_rev_cache = 0;
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__create(svn_fs_t *fs,
+                  const char *path,
+                  apr_pool_t *pool)
+{
+  int format = SVN_FS_FS__FORMAT_NUMBER;
+  int shard_size = SVN_FS_FS_DEFAULT_MAX_FILES_PER_DIR;
+
+  /* Process the given filesystem config. */
+  if (fs->config)
+    {
+      svn_version_t *compatible_version;
+      const char *shard_size_str;
+      SVN_ERR(svn_fs__compatible_version(&compatible_version, fs->config,
+                                         pool));
+
+      /* select format number */
+      switch(compatible_version->minor)
+        {
+          case 0: return svn_error_create(SVN_ERR_FS_UNSUPPORTED_FORMAT, NULL,
+                 _("FSFS is not compatible with Subversion prior to 1.1"));
+
+          case 1:
+          case 2:
+          case 3: format = 1;
+                  break;
+
+          case 4: format = 2;
+                  break;
+
+          case 5: format = 3;
+                  break;
+
+          case 6:
+          case 7: format = 4;
+                  break;
+
+          case 8: format = 6;
+                  break;
+
+          default:format = SVN_FS_FS__FORMAT_NUMBER;
+        }
+
+      shard_size_str = svn_hash_gets(fs->config, SVN_FS_CONFIG_FSFS_SHARD_SIZE);
+      if (shard_size_str)
+        {
+          apr_int64_t val;
+          SVN_ERR(svn_cstring_strtoi64(&val, shard_size_str, 0,
+                                       APR_INT32_MAX, 10));
+
+          shard_size = (int) val;
+        }
+    }
+
+  /* Actual FS creation. */
+  SVN_ERR(svn_fs_fs__create_file_tree(fs, path, format, shard_size, pool));
+
   /* This filesystem is ready.  Stamp it with a format number. */
   SVN_ERR(svn_fs_fs__write_format(fs, FALSE, pool));
 
-  ffd->youngest_rev_cache = 0;
   return SVN_NO_ERROR;
 }
 

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/fs_fs.h Tue Nov  4 11:40:16 2014
@@ -122,6 +122,24 @@ svn_error_t *svn_fs_fs__file_checksum(sv
 /* Return whether or not the given FS supports mergeinfo metadata. */
 svn_boolean_t svn_fs_fs__fs_supports_mergeinfo(svn_fs_t *fs);
 
+/* Under the repository db PATH, create a FSFS repository with FORMAT,
+ * the given SHARD_SIZE and start logical addressing at revision
+ * MIN_LOG_ADDRESSING_REV.  If not supported by the respective format,
+ * the latter two parameters will be ignored.  FS will be updated.
+ *
+ * The only file not being written is the 'format' file.  This allows
+ * callers such as hotcopy to modify the contents before turning the
+ * tree into an accessible repository.
+ *
+ * Use POOL for temporary allocations.
+ */
+svn_error_t *
+svn_fs_fs__create_file_tree(svn_fs_t *fs,
+                            const char *path,
+                            int format,
+                            int shard_size,
+                            apr_pool_t *pool);
+
 /* Create a fs_fs fileysystem referenced by FS at path PATH.  Get any
    temporary allocations from POOL.
 

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/hotcopy.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/hotcopy.c Tue Nov  4 11:40:16 2014
@@ -369,33 +369,30 @@ hotcopy_copy_packed_shard(svn_boolean_t 
   return SVN_NO_ERROR;
 }
 
-/* Remove FILE in SHARD folder.  Use POOL for temporary allocations. */
+/* Remove file PATH, if it exists - even if it is read-only. 
+ * Use POOL for temporary allocations. */
 static svn_error_t *
-hotcopy_remove_file(const char *shard,
-                    const char *file,
+hotcopy_remove_file(const char *path,
                     apr_pool_t *pool)
 {
-  const char *rev_path = svn_dirent_join(shard, file, pool);
-
   /* Make the rev file writable and remove it. */
-  SVN_ERR(svn_io_set_file_read_write(rev_path, TRUE, pool));
-  SVN_ERR(svn_io_remove_file2(rev_path, TRUE, pool));
+  SVN_ERR(svn_io_set_file_read_write(path, TRUE, pool));
+  SVN_ERR(svn_io_remove_file2(path, TRUE, pool));
 
   return SVN_NO_ERROR;
 }
 
 
 /* Remove revision or revprop files between START_REV (inclusive) and
- * END_REV (non-inclusive) from folder DST_SUBDIR in DST_FS.  Also,
- * remove index files if REMOVE_INDEXES is set.  Assume sharding as per
- * MAX_FILES_PER_DIR.  Use SCRATCH_POOL for temporary allocations. */
+ * END_REV (non-inclusive) from folder DST_SUBDIR in DST_FS.  Assume
+ * sharding as per MAX_FILES_PER_DIR.
+ * Use SCRATCH_POOL for temporary allocations. */
 static svn_error_t *
 hotcopy_remove_files(svn_fs_t *dst_fs,
                      const char *dst_subdir,
                      svn_revnum_t start_rev,
                      svn_revnum_t end_rev,
                      int max_files_per_dir,
-                     svn_boolean_t remove_indexes,
                      apr_pool_t *scratch_pool)
 {
   const char *shard;
@@ -420,8 +417,10 @@ hotcopy_remove_files(svn_fs_t *dst_fs,
         }
 
       /* remove files for REV */
-      SVN_ERR(hotcopy_remove_file(dst_subdir_shard,
-                                  apr_psprintf(iterpool, "%ld", rev),
+      SVN_ERR(hotcopy_remove_file(svn_dirent_join(dst_subdir_shard,
+                                                  apr_psprintf(iterpool,
+                                                               "%ld", rev),
+                                                  iterpool),
                                   iterpool));
     }
 
@@ -446,7 +445,7 @@ hotcopy_remove_rev_files(svn_fs_t *dst_f
                                                PATH_REVS_DIR,
                                                scratch_pool),
                                start_rev, end_rev,
-                               max_files_per_dir, TRUE, scratch_pool));
+                               max_files_per_dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -470,7 +469,7 @@ hotcopy_remove_revprop_files(svn_fs_t *d
                                                PATH_REVPROPS_DIR,
                                                scratch_pool),
                                start_rev ? start_rev : 1, end_rev,
-                               max_files_per_dir, FALSE, scratch_pool));
+                               max_files_per_dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -627,7 +626,7 @@ hotcopy_revisions(svn_fs_t *src_fs,
       if (pack_end_rev > dst_youngest)
         {
           SVN_ERR(svn_fs_fs__write_current(dst_fs, pack_end_rev, 0, 0,
-                                     iterpool));
+                                           iterpool));
         }
 
       /* When notifying about packed shards, make things simpler by either
@@ -994,17 +993,6 @@ hotcopy_body(void *baton, apr_pool_t *po
     SVN_ERR(svn_io_dir_file_copy(src_fs->path, dst_fs->path,
                                  PATH_TXN_CURRENT, pool));
 
-  /* If a revprop generation file exists in the source filesystem,
-   * reset it to zero (since this is on a different path, it will not
-   * overlap with data already in cache).  Also, clean up stale files
-   * used for the named atomics implementation. */
-  SVN_ERR(svn_io_check_path(svn_fs_fs__path_revprop_generation(src_fs, pool),
-                            &kind, pool));
-  if (kind == svn_node_file)
-    SVN_ERR(svn_fs_fs__write_revprop_generation_file(dst_fs, 0, pool));
-
-  SVN_ERR(svn_fs_fs__cleanup_revprop_namespace(dst_fs));
-
   return SVN_NO_ERROR;
 }
 
@@ -1033,75 +1021,25 @@ hotcopy_create_empty_dest(svn_fs_t *src_
                           apr_pool_t *pool)
 {
   fs_fs_data_t *src_ffd = src_fs->fsap_data;
-  fs_fs_data_t *dst_ffd = dst_fs->fsap_data;
-
-  dst_fs->path = apr_pstrdup(pool, dst_path);
 
-  dst_ffd->max_files_per_dir = src_ffd->max_files_per_dir;
-  dst_ffd->format = src_ffd->format;
-
-  /* Create the revision data directories. */
-  if (dst_ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(svn_fs_fs__path_rev_shard(dst_fs,
-                                                                  0, pool),
-                                        pool));
-  else
-    SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path,
-                                                        PATH_REVS_DIR, pool),
-                                        pool));
-
-  /* Create the revprops directory. */
-  if (src_ffd->max_files_per_dir)
-    SVN_ERR(svn_io_make_dir_recursively(
-                          svn_fs_fs__path_revprops_shard(dst_fs, 0, pool),
-                          pool));
-  else
-    SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path,
-                                                        PATH_REVPROPS_DIR,
-                                                        pool),
-                                        pool));
-
-  /* Create the transaction directory. */
-  SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path, PATH_TXNS_DIR,
-                                                      pool),
+  /* Create the DST_FS repository with the same layout as SRC_FS. */
+  SVN_ERR(svn_fs_fs__create_file_tree(dst_fs, dst_path, src_ffd->format,
+                                      src_ffd->max_files_per_dir,
                                       pool));
 
-  /* Create the protorevs directory. */
-  if (dst_ffd->format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT)
-    SVN_ERR(svn_io_make_dir_recursively(svn_dirent_join(dst_path,
-                                                        PATH_TXN_PROTOS_DIR,
-                                                        pool),
-                                        pool));
-
-  /* Create the 'current' file. */
-  SVN_ERR(svn_io_file_create(svn_fs_fs__path_current(dst_fs, pool),
-                             (dst_ffd->format >=
-                                SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT
-                                ? "0\n" : "0 1 1\n"),
-                             pool));
-
-  /* Create the lock and 'uuid' files.  Hotcopy destination receives a
-     new instance ID, but has the same filesystem UUID as the source. */
-  SVN_ERR(svn_io_file_create_empty(svn_fs_fs__path_lock(dst_fs, pool), pool));
+  /* Copy the UUID.  Hotcopy destination receives a new instance ID, but
+   * has the same filesystem UUID as the source. */
   SVN_ERR(svn_fs_fs__set_uuid(dst_fs, src_fs->uuid, NULL, pool));
 
-  /* Create the min unpacked rev file. */
-  if (dst_ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT)
-    SVN_ERR(svn_io_file_create(svn_fs_fs__path_min_unpacked_rev(dst_fs, pool),
-                                                                "0\n", pool));
-  /* Create the txn-current file if the repository supports
-     the transaction sequence file. */
-  if (dst_ffd->format >= SVN_FS_FS__MIN_TXN_CURRENT_FORMAT)
-    {
-      SVN_ERR(svn_io_file_create(svn_fs_fs__path_txn_current(dst_fs, pool),
-                                 "0\n", pool));
-      SVN_ERR(svn_io_file_create_empty(
-                          svn_fs_fs__path_txn_current_lock(dst_fs, pool),
-                          pool));
-    }
-
-  /* FS creation is complete. Stamp it with a format file. */
-  SVN_ERR(svn_fs_fs__write_format(dst_fs, TRUE, pool));
+  /* Remove revision 0 contents.  Otherwise, it may not get overwritten
+   * due to having a newer timestamp. */
+  SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_rev(dst_fs, 0, pool), pool));
+  SVN_ERR(hotcopy_remove_file(svn_fs_fs__path_revprops(dst_fs, 0, pool),
+                              pool));
+
+  /* This filesystem is ready.  Stamp it with a format number.  Fail if
+   * the 'format' file should already exist. */
+  SVN_ERR(svn_fs_fs__write_format(dst_fs, FALSE, pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/id.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/id.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/id.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/id.h Tue Nov  4 11:40:16 2014
@@ -24,32 +24,12 @@
 #define SVN_LIBSVN_FS_FS_ID_H
 
 #include "svn_fs.h"
+#include "private/svn_fs_fs_private.h"
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
-/* Node-revision IDs in FSFS consist of 3 of sub-IDs ("parts") that consist
- * of a creation REVISION number and some revision- / transaction-local
- * counter value (NUMBER).  Old-style ID parts use global counter values.
- *
- * The parts are: node_id, copy_id and txn_id for in-txn IDs as well as
- * node_id, copy_id and rev_offset for in-revision IDs.  This struct the
- * data structure used for each of those parts.
- */
-typedef struct svn_fs_fs__id_part_t
-{
-  /* SVN_INVALID_REVNUM for txns -> not a txn, COUNTER must be 0.
-     SVN_INVALID_REVNUM for others -> not assigned to a revision, yet.
-     0                  for others -> old-style ID or the root in rev 0. */
-  svn_revnum_t revision;
-
-  /* sub-id value relative to REVISION.  Its interpretation depends on
-     the part itself.  In rev_item, it is the index_index value, in others
-     it represents a unique counter value. */
-  apr_uint64_t number;
-} svn_fs_fs__id_part_t;
-
 
 /*** Operations on ID parts. ***/
 

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.c Tue Nov  4 11:40:16 2014
@@ -191,38 +191,71 @@ svn_fs_fs__unparse_revision_trailer(apr_
 
 svn_error_t *
 svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
+                        svn_checksum_t **l2p_checksum,
                         apr_off_t *p2l_offset,
+                        svn_checksum_t **p2l_checksum,
                         svn_stringbuf_t *footer,
-                        svn_revnum_t rev)
+                        svn_revnum_t rev,
+                        apr_pool_t *result_pool)
 {
   apr_int64_t val;
+  char *last_str = footer->data;
 
-  /* Split the footer into the 2 number strings. */
-  char *seperator = strchr(footer->data, ' ');
-  if (!seperator)
-    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Revision file (r%ld) has corrupt footer"),
-                             rev);
-  *seperator = '\0';
+  /* Get the L2P offset. */
+  const char *str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
 
-  /* Convert offset values. */
-  SVN_ERR(svn_cstring_atoi64(&val, footer->data));
+  SVN_ERR(svn_cstring_atoi64(&val, str));
   *l2p_offset = (apr_off_t)val;
-  SVN_ERR(svn_cstring_atoi64(&val, seperator + 1));
+
+  /* Get the L2P checksum. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
+
+  SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str,
+                                 result_pool));
+
+  /* Get the P2L offset. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
+
+  SVN_ERR(svn_cstring_atoi64(&val, str));
   *p2l_offset = (apr_off_t)val;
 
+  /* Get the P2L checksum. */
+  str = svn_cstring_tokenize(" ", &last_str);
+  if (str == NULL)
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid revision footer"));
+
+  SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str,
+                                 result_pool));
+
   return SVN_NO_ERROR;
 }
 
 svn_stringbuf_t *
 svn_fs_fs__unparse_footer(apr_off_t l2p_offset,
+                          svn_checksum_t *l2p_checksum,
                           apr_off_t p2l_offset,
-                          apr_pool_t *result_pool)
+                          svn_checksum_t *p2l_checksum,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool)
 {
   return svn_stringbuf_createf(result_pool,
-                               "%" APR_OFF_T_FMT " %" APR_OFF_T_FMT,
+                               "%" APR_OFF_T_FMT " %s %" APR_OFF_T_FMT " %s",
                                l2p_offset,
-                               p2l_offset);
+                               svn_checksum_to_cstring(l2p_checksum,
+                                                       scratch_pool),
+                               p2l_offset,
+                               svn_checksum_to_cstring(p2l_checksum,
+                                                       scratch_pool));
 }
 
 /* Read the next entry in the changes record from file FILE and store
@@ -355,7 +388,9 @@ read_change(change_t **change_p,
     }
 
   /* Get the mergeinfo-mod flag if given.  Otherwise, the next thing
-     is the path starting with a slash. */
+     is the path starting with a slash.  Also, we must initialize the
+     flag explicitly because 0 is not valid for a svn_tristate_t. */
+  info->mergeinfo_mod = svn_tristate_unknown;
   if (*last_str != '/')
     {
       str = svn_cstring_tokenize(" ", &last_str);
@@ -468,11 +503,11 @@ svn_fs_fs__read_changes_incrementally(sv
   return SVN_NO_ERROR;
 }
 
-/* Write a single change entry, path PATH, change CHANGE, and copyfrom
-   string COPYFROM, into the file specified by FILE.  Only include the
-   node kind field if INCLUDE_NODE_KIND is true.  Only include the
-   mergeinfo-mod field if INCLUDE_MERGEINFO_MODS is true.  All temporary
-   allocations are in SCRATCH_POOL. */
+/* Write a single change entry, path PATH, change CHANGE, to STREAM.
+
+   Only include the node kind field if INCLUDE_NODE_KIND is true.  Only
+   include the mergeinfo-mod field if INCLUDE_MERGEINFO_MODS is true.
+   All temporary allocations are in SCRATCH_POOL. */
 static svn_error_t *
 write_change_entry(svn_stream_t *stream,
                    const char *path,
@@ -565,13 +600,19 @@ svn_fs_fs__write_changes(svn_stream_t *s
   svn_boolean_t include_node_kinds =
       ffd->format >= SVN_FS_FS__MIN_KIND_IN_CHANGED_FORMAT;
   svn_boolean_t include_mergeinfo_mods =
-      ffd->format >= SVN_FS_FS__MIN_MERGEINFO_IN_CHANGES_FORMAT;
+      ffd->format >= SVN_FS_FS__MIN_MERGEINFO_IN_CHANGED_FORMAT;
   apr_array_header_t *sorted_changed_paths;
   int i;
 
   /* For the sake of the repository administrator sort the changes so
      that the final file is deterministic and repeatable, however the
-     rest of the FSFS code doesn't require any particular order here. */
+     rest of the FSFS code doesn't require any particular order here.
+
+     Also, this sorting is only effective in writing all entries with
+     a single call as write_final_changed_path_info() does.  For the
+     list being written incrementally during transaction, we actually
+     *must not* change the order of entries from different calls.
+   */
   sorted_changed_paths = svn_sort__hash(changes,
                                         svn_sort_compare_items_lexically,
                                         scratch_pool);

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/low_level.h Tue Nov  4 11:40:16 2014
@@ -64,25 +64,35 @@ svn_fs_fs__unparse_revision_trailer(apr_
 
 /* Given the format 7+ revision / pack FOOTER, parse it destructively
  * and return the start offsets of the index data in *L2P_OFFSET and
- * *P2L_OFFSET, respectively.
+ * *P2L_OFFSET, respectively.  Also, return the expected checksums in
+ * in *L2P_CHECKSUM and *P2L_CHECKSUM.
  * 
  * Note that REV is only used to construct nicer error objects that
- * mention this revision.
+ * mention this revision.  Allocate the checksums in RESULT_POOL.
  */
 svn_error_t *
 svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
+                        svn_checksum_t **l2p_checksum,
                         apr_off_t *p2l_offset,
+                        svn_checksum_t **p2l_checksum,
                         svn_stringbuf_t *footer,
-                        svn_revnum_t rev);
+                        svn_revnum_t rev,
+                        apr_pool_t *result_pool);
 
-/* Given the offset of the L2P index data in L2P_OFFSET and the offset of
- * the P2L index data in P2L_OFFSET,  return the corresponding format 7+
- * revision / pack file footer.  Allocate it in RESULT_POOL.
+/* Given the offset of the L2P index data in L2P_OFFSET, the content
+ * checksum in L2P_CHECKSUM and the offset plus checksum of the P2L
+ * index data in P2L_OFFSET and P2L_CHECKSUM.
+ *
+ * Return the corresponding format 7+ revision / pack file footer.
+ * Allocate it in RESULT_POOL and use SCRATCH_POOL for temporary.
  */
 svn_stringbuf_t *
 svn_fs_fs__unparse_footer(apr_off_t l2p_offset,
+                          svn_checksum_t *l2p_checksum,
                           apr_off_t p2l_offset,
-                          apr_pool_t *result_pool);
+                          svn_checksum_t *p2l_checksum,
+                          apr_pool_t *result_pool,
+                          apr_pool_t *scratch_pool);
 
 /* Read all the changes from STREAM and store them in *CHANGES,
    allocated in RESULT_POOL. Do temporary allocations in SCRATCH_POOL. */
@@ -112,8 +122,9 @@ svn_fs_fs__read_changes_incrementally(sv
 
 /* Write the changed path info from CHANGES in filesystem FS to the
    output stream STREAM.  You may call this function multiple time on
-   the same stream but the last call should set TERMINATE_LIST to write
-   an extra empty line that marks the end of the changed paths list.
+   the same stream.  If you are writing to a (proto-)revision file,
+   the last call must set TERMINATE_LIST to write an extra empty line
+   that marks the end of the changed paths list.
    Perform temporary allocations in SCRATCH_POOL.
  */
 svn_error_t *

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/recovery.c Tue Nov  4 11:40:16 2014
@@ -345,9 +345,6 @@ recover_body(void *baton, apr_pool_t *po
   svn_revnum_t youngest_rev;
   svn_node_kind_t youngest_revprops_kind;
 
-  /* Lose potentially corrupted data in temp files */
-  SVN_ERR(svn_fs_fs__cleanup_revprop_namespace(fs));
-
   /* The admin may have created a plain copy of this repo before attempting
      to recover it (hotcopy may or may not work with corrupted repos).
      Bump the instance ID. */

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.c Tue Nov  4 11:40:16 2014
@@ -41,12 +41,6 @@
    process got aborted and that we have re-read revprops. */
 #define REVPROP_CHANGE_TIMEOUT (10 * 1000000)
 
-/* The following are names of atomics that will be used to communicate
- * revprop updates across all processes on this machine. */
-#define ATOMIC_REVPROP_GENERATION "rev-prop-generation"
-#define ATOMIC_REVPROP_TIMEOUT    "rev-prop-timeout"
-#define ATOMIC_REVPROP_NAMESPACE  "rev-prop-atomics"
-
 svn_error_t *
 svn_fs_fs__upgrade_pack_revprops(svn_fs_t *fs,
                                  svn_fs_upgrade_notify_t notify_func,
@@ -141,401 +135,18 @@ svn_fs_fs__upgrade_cleanup_pack_revprops
   return SVN_NO_ERROR;
 }
 
-/* Revprop caching management.
- *
- * Mechanism:
- * ----------
- *
- * Revprop caching needs to be activated and will be deactivated for the
- * respective FS instance if the necessary infrastructure could not be
- * initialized.  In deactivated mode, there is almost no runtime overhead
- * associated with revprop caching.  As long as no revprops are being read
- * or changed, revprop caching imposes no overhead.
- *
- * When activated, we cache revprops using (revision, generation) pairs
- * as keys with the generation being incremented upon every revprop change.
- * Since the cache is process-local, the generation needs to be tracked
- * for at least as long as the process lives but may be reset afterwards.
- *
- * To track the revprop generation, we use two-layer approach. On the lower
- * level, we use named atomics to have a system-wide consistent value for
- * the current revprop generation.  However, those named atomics will only
- * remain valid for as long as at least one process / thread in the system
- * accesses revprops in the respective repository.  The underlying shared
- * memory gets cleaned up afterwards.
- *
- * On the second level, we will use a persistent file to track the latest
- * revprop generation.  It will be written upon each revprop change but
- * only be read if we are the first process to initialize the named atomics
- * with that value.
- *
- * The overhead for the second and following accesses to revprops is
- * almost zero on most systems.
- *
- *
- * Tech aspects:
- * -------------
- *
- * A problem is that we need to provide a globally available file name to
- * back the SHM implementation on OSes that need it.  We can only assume
- * write access to some file within the respective repositories.  Because
- * a given server process may access thousands of repositories during its
- * lifetime, keeping the SHM data alive for all of them is also not an
- * option.
- *
- * So, we store the new revprop generation on disk as part of each
- * setrevprop call, i.e. this write will be serialized and the write order
- * be guaranteed by the repository write lock.
- *
- * The only racy situation occurs when the data is being read again by two
- * processes concurrently but in that situation, the first process to
- * finish that procedure is guaranteed to be the only one that initializes
- * the SHM data.  Since even writers will first go through that
- * initialization phase, they will never operate on stale data.
- */
-
-/* Read revprop generation as stored on disk for repository FS. The result
- * is returned in *CURRENT. Default to 2 if no such file is available.
- */
-static svn_error_t *
-read_revprop_generation_file(apr_int64_t *current,
-                             svn_fs_t *fs,
-                             apr_pool_t *pool)
-{
-  svn_error_t *err;
-  apr_file_t *file;
-  char buf[80];
-  apr_size_t len;
-  const char *path = svn_fs_fs__path_revprop_generation(fs, pool);
-
-  err = svn_io_file_open(&file, path,
-                         APR_READ | APR_BUFFERED,
-                         APR_OS_DEFAULT, pool);
-  if (err && APR_STATUS_IS_ENOENT(err->apr_err))
-    {
-      svn_error_clear(err);
-      *current = 2;
-
-      return SVN_NO_ERROR;
-    }
-  SVN_ERR(err);
-
-  len = sizeof(buf);
-  SVN_ERR(svn_io_read_length_line(file, buf, &len, pool));
-
-  /* Check that the first line contains only digits. */
-  SVN_ERR(svn_fs_fs__check_file_buffer_numeric(buf, 0, path,
-                                               "Revprop Generation", pool));
-  SVN_ERR(svn_cstring_atoi64(current, buf));
-
-  return svn_io_file_close(file, pool);
-}
-
-/* Write the CURRENT revprop generation to disk for repository FS.
- */
-svn_error_t *
-svn_fs_fs__write_revprop_generation_file(svn_fs_t *fs,
-                                         apr_int64_t current,
-                                         apr_pool_t *pool)
-{
-  char buf[SVN_INT64_BUFFER_SIZE];
-  apr_size_t len = svn__i64toa(buf, current);
-  buf[len] = '\n';
-
-  SVN_ERR(svn_io_write_atomic(svn_fs_fs__path_revprop_generation(fs, pool),
-                              buf, len + 1,
-                              NULL /* copy_perms */, pool));
-
-  return SVN_NO_ERROR;
-}
-
-/* Make sure the revprop_namespace member in FS is set. */
-static svn_error_t *
-ensure_revprop_namespace(svn_fs_t *fs)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  return ffd->revprop_namespace == NULL
-    ? svn_atomic_namespace__create(&ffd->revprop_namespace,
-                                   svn_dirent_join(fs->path,
-                                                   ATOMIC_REVPROP_NAMESPACE,
-                                                   fs->pool),
-                                   fs->pool)
-    : SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_fs_fs__cleanup_revprop_namespace(svn_fs_t *fs)
-{
-  const char *name = svn_dirent_join(fs->path,
-                                     ATOMIC_REVPROP_NAMESPACE,
-                                     fs->pool);
-  return svn_error_trace(svn_atomic_namespace__cleanup(name, fs->pool));
-}
-
-/* Make sure the revprop_generation member in FS is set and, if necessary,
- * initialized with the latest value stored on disk.
- */
-static svn_error_t *
-ensure_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  SVN_ERR(ensure_revprop_namespace(fs));
-  if (ffd->revprop_generation == NULL)
-    {
-      apr_int64_t current;
-
-      SVN_ERR(svn_named_atomic__get(&ffd->revprop_generation,
-                                    ffd->revprop_namespace,
-                                    ATOMIC_REVPROP_GENERATION,
-                                    TRUE));
-
-      /* If the generation is at 0, we just created a new namespace
-       * (it would be at least 2 otherwise). Read the latest generation
-       * from disk and if we are the first one to initialize the atomic
-       * (i.e. is still 0), set it to the value just gotten.
-       */
-      SVN_ERR(svn_named_atomic__read(&current, ffd->revprop_generation));
-      if (current == 0)
-        {
-          SVN_ERR(read_revprop_generation_file(&current, fs, pool));
-          SVN_ERR(svn_named_atomic__cmpxchg(NULL, current, 0,
-                                            ffd->revprop_generation));
-        }
-    }
-
-  return SVN_NO_ERROR;
-}
-
-/* Make sure the revprop_timeout member in FS is set. */
-static svn_error_t *
-ensure_revprop_timeout(svn_fs_t *fs)
-{
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  SVN_ERR(ensure_revprop_namespace(fs));
-  return ffd->revprop_timeout == NULL
-    ? svn_named_atomic__get(&ffd->revprop_timeout,
-                            ffd->revprop_namespace,
-                            ATOMIC_REVPROP_TIMEOUT,
-                            TRUE)
-    : SVN_NO_ERROR;
-}
-
-/* Create an error object with the given MESSAGE and pass it to the
-   WARNING member of FS. Clears UNDERLYING_ERR. */
-static void
-log_revprop_cache_init_warning(svn_fs_t *fs,
-                               svn_error_t *underlying_err,
-                               const char *message,
-                               apr_pool_t *pool)
-{
-  svn_error_t *err = svn_error_createf(
-                       SVN_ERR_FS_REVPROP_CACHE_INIT_FAILURE,
-                       underlying_err, message,
-                       svn_dirent_local_style(fs->path, pool));
-
-  if (fs->warning)
-    (fs->warning)(fs->warning_baton, err);
-
-  svn_error_clear(err);
-}
-
 /* Test whether revprop cache and necessary infrastructure are
    available in FS. */
 static svn_boolean_t
 has_revprop_cache(svn_fs_t *fs, apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
-  svn_error_t *error;
 
   /* is the cache (still) enabled? */
   if (ffd->revprop_cache == NULL)
     return FALSE;
 
-  /* is it efficient? */
-  if (!svn_named_atomic__is_efficient())
-    {
-      /* access to it would be quite slow
-       * -> disable the revprop cache for good
-       */
-      ffd->revprop_cache = NULL;
-      log_revprop_cache_init_warning(fs, NULL,
-                                     "Revprop caching for '%s' disabled"
-                                     " because it would be inefficient.",
-                                     pool);
-
-      return FALSE;
-    }
-
-  /* try to access our SHM-backed infrastructure */
-  error = ensure_revprop_generation(fs, pool);
-  if (error)
-    {
-      /* failure -> disable revprop cache for good */
-
-      ffd->revprop_cache = NULL;
-      log_revprop_cache_init_warning(fs, error,
-                                     "Revprop caching for '%s' disabled "
-                                     "because SHM infrastructure for revprop "
-                                     "caching failed to initialize.",
-                                     pool);
-
-      return FALSE;
-    }
-
-  return TRUE;
-}
-
-/* Baton structure for revprop_generation_fixup. */
-typedef struct revprop_generation_fixup_t
-{
-  /* revprop generation to read */
-  apr_int64_t *generation;
-
-  /* containing the revprop_generation member to query */
-  fs_fs_data_t *ffd;
-} revprop_generation_upgrade_t;
-
-/* If the revprop generation has an odd value, it means the original writer
-   of the revprop got killed. We don't know whether that process as able
-   to change the revprop data but we assume that it was. Therefore, we
-   increase the generation in that case to basically invalidate everyone's
-   cache content.
-   Execute this only while holding the write lock to the repo in baton->FFD.
- */
-static svn_error_t *
-revprop_generation_fixup(void *void_baton,
-                         apr_pool_t *pool)
-{
-  revprop_generation_upgrade_t *baton = void_baton;
-  assert(baton->ffd->has_write_lock);
-
-  /* Maybe, either the original revprop writer or some other reader has
-     already corrected / bumped the revprop generation.  Thus, we need
-     to read it again. */
-  SVN_ERR(svn_named_atomic__read(baton->generation,
-                                 baton->ffd->revprop_generation));
-
-  /* Cause everyone to re-read revprops upon their next access, if the
-     last revprop write did not complete properly. */
-  while (*baton->generation % 2)
-    SVN_ERR(svn_named_atomic__add(baton->generation,
-                                  1,
-                                  baton->ffd->revprop_generation));
-
-  return SVN_NO_ERROR;
-}
-
-/* Read the current revprop generation and return it in *GENERATION.
-   Also, detect aborted / crashed writers and recover from that.
-   Use the access object in FS to set the shared mem values. */
-static svn_error_t *
-read_revprop_generation(apr_int64_t *generation,
-                        svn_fs_t *fs,
-                        apr_pool_t *pool)
-{
-  apr_int64_t current = 0;
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* read the current revprop generation number */
-  SVN_ERR(ensure_revprop_generation(fs, pool));
-  SVN_ERR(svn_named_atomic__read(&current, ffd->revprop_generation));
-
-  /* is an unfinished revprop write under the way? */
-  if (current % 2)
-    {
-      apr_int64_t timeout = 0;
-
-      /* read timeout for the write operation */
-      SVN_ERR(ensure_revprop_timeout(fs));
-      SVN_ERR(svn_named_atomic__read(&timeout, ffd->revprop_timeout));
-
-      /* has the writer process been aborted,
-       * i.e. has the timeout been reached?
-       */
-      if (apr_time_now() > timeout)
-        {
-          revprop_generation_upgrade_t baton;
-          baton.generation = &current;
-          baton.ffd = ffd;
-
-          /* Ensure that the original writer process no longer exists by
-           * acquiring the write lock to this repository.  Then, fix up
-           * the revprop generation.
-           */
-          if (ffd->has_write_lock)
-            SVN_ERR(revprop_generation_fixup(&baton, pool));
-          else
-            SVN_ERR(svn_fs_fs__with_write_lock(fs, revprop_generation_fixup,
-                                               &baton, pool));
-        }
-    }
-
-  /* return the value we just got */
-  *generation = current;
-  return SVN_NO_ERROR;
-}
-
-/* Set the revprop generation to the next odd number to indicate that
-   there is a revprop write process under way. If that times out,
-   readers shall recover from that state & re-read revprops.
-   Use the access object in FS to set the shared mem value. */
-static svn_error_t *
-begin_revprop_change(svn_fs_t *fs, apr_pool_t *pool)
-{
-  apr_int64_t current;
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* set the timeout for the write operation */
-  SVN_ERR(ensure_revprop_timeout(fs));
-  SVN_ERR(svn_named_atomic__write(NULL,
-                                  apr_time_now() + REVPROP_CHANGE_TIMEOUT,
-                                  ffd->revprop_timeout));
-
-  /* set the revprop generation to an odd value to indicate
-   * that a write is in progress
-   */
-  SVN_ERR(ensure_revprop_generation(fs, pool));
-  do
-    {
-      SVN_ERR(svn_named_atomic__add(&current,
-                                    1,
-                                    ffd->revprop_generation));
-    }
-  while (current % 2 == 0);
-
-  return SVN_NO_ERROR;
-}
-
-/* Set the revprop generation to the next even number to indicate that
-   a) readers shall re-read revprops, and
-   b) the write process has been completed (no recovery required)
-   Use the access object in FS to set the shared mem value. */
-static svn_error_t *
-end_revprop_change(svn_fs_t *fs, apr_pool_t *pool)
-{
-  apr_int64_t current = 1;
-  fs_fs_data_t *ffd = fs->fsap_data;
-
-  /* set the revprop generation to an even value to indicate
-   * that a write has been completed
-   */
-  SVN_ERR(ensure_revprop_generation(fs, pool));
-  do
-    {
-      SVN_ERR(svn_named_atomic__add(&current,
-                                    1,
-                                    ffd->revprop_generation));
-    }
-  while (current % 2);
-
-  /* Save the latest generation to disk. FS is currently in a "locked"
-   * state such that we can be sure the be the only ones to write that
-   * file.
-   */
-  return svn_fs_fs__write_revprop_generation_file(fs, current, pool);
+  return FALSE;
 }
 
 /* Container for all data required to access the packed revprop file
@@ -669,6 +280,19 @@ read_non_packed_revprop(apr_hash_t **pro
   return SVN_NO_ERROR;
 }
 
+/* Return the minimum length of any packed revprop file name in REVPROPS. */
+static apr_size_t
+get_min_filename_len(packed_revprops_t *revprops)
+{
+  char number_buffer[SVN_INT64_BUFFER_SIZE];
+
+  /* The revprop filenames have the format <REV>.<COUNT> - with <REV> being
+   * at least the first rev in the shard and <COUNT> having at least one
+   * digit.  Thus, the minimum is 2 + #decimal places in the start rev.
+   */
+  return svn__i64toa(number_buffer, revprops->manifest_start) + 2;
+}
+
 /* Given FS and REVPROPS->REVISION, fill the FILENAME, FOLDER and MANIFEST
  * members. Use POOL for allocating results and SCRATCH_POOL for temporaries.
  */
@@ -681,9 +305,27 @@ get_revprop_packname(svn_fs_t *fs,
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_stringbuf_t *content = NULL;
   const char *manifest_file_path;
-  int idx;
+  int idx, rev_count;
+  char *buffer, *buffer_end;
+  const char **filenames, **filenames_end;
+  apr_size_t min_filename_len;
+
+  /* Determine the dimensions. Rev 0 is excluded from the first shard. */
+  rev_count = ffd->max_files_per_dir;
+  revprops->manifest_start
+    = revprops->revision - (revprops->revision % rev_count);
+  if (revprops->manifest_start == 0)
+    {
+      ++revprops->manifest_start;
+      --rev_count;
+    }
+
+  revprops->manifest = apr_array_make(pool, rev_count, sizeof(const char*));
+
+  /* No line in the file can be less than this number of chars long. */
+  min_filename_len = get_min_filename_len(revprops);
 
-  /* read content of the manifest file */
+  /* Read the content of the manifest file */
   revprops->folder
     = svn_fs_fs__path_revprops_pack_shard(fs, revprops->revision, pool);
   manifest_file_path
@@ -691,37 +333,68 @@ get_revprop_packname(svn_fs_t *fs,
 
   SVN_ERR(svn_fs_fs__read_content(&content, manifest_file_path, pool));
 
-  /* parse the manifest. Every line is a file name */
-  revprops->manifest = apr_array_make(pool, ffd->max_files_per_dir,
-                                      sizeof(const char*));
-
-  /* Read all lines.  Since the last line ends with a newline, we will
-     end up with a valid but empty string after the last entry. */
-  while (content->data && *content->data)
-    {
-      APR_ARRAY_PUSH(revprops->manifest, const char*) = content->data;
-      content->data = strchr(content->data, '\n');
-      if (content->data)
-        {
-          *content->data = 0;
-          content->data++;
-        }
+  /* There CONTENT must have a certain minimal size and there no
+   * unterminated lines at the end of the file.  Both guarantees also
+   * simplify the parser loop below.
+   */
+  if (   content->len < rev_count * (min_filename_len + 1)
+      || content->data[content->len - 1] != '\n')
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Packed revprop manifest for r%ld not "
+                               "properly terminated"), revprops->revision);
+
+  /* Chop (parse) the manifest CONTENT into filenames, one per line.
+   * We only have to replace all newlines with NUL and add all line
+   * starts to REVPROPS->MANIFEST.
+   *
+   * There must be exactly REV_COUNT lines and that is the number of
+   * lines we parse from BUFFER to FILENAMES.  Set the end pointer for
+   * the source BUFFER such that BUFFER+MIN_FILENAME_LEN is still valid
+   * BUFFER_END is always valid due to CONTENT->LEN > MIN_FILENAME_LEN.
+   *
+   * Please note that this loop is performance critical for e.g. 'svn log'.
+   * It is run 1000x per revprop access, i.e. per revision and about
+   * 50 million times per sec (and CPU core).
+   */
+  for (filenames = (const char **)revprops->manifest->elts,
+       filenames_end = filenames + rev_count,
+       buffer = content->data,
+       buffer_end = buffer + content->len - min_filename_len;
+       (filenames < filenames_end) && (buffer < buffer_end);
+       ++filenames)
+    {
+      /* BUFFER always points to the start of the next line / filename. */
+      *filenames = buffer;
+
+      /* Find the next EOL.  This is guaranteed to stay within the CONTENT
+       * buffer because we left enough room after BUFFER_END and we know
+       * we will always see a newline as the last non-NUL char. */
+      buffer += min_filename_len;
+      while (*buffer != '\n')
+        ++buffer;
+
+      /* Found EOL.  Turn it into the filename terminator and move BUFFER
+       * to the start of the next line or CONTENT buffer end. */
+      *buffer = '\0';
+      ++buffer;
     }
-  content = NULL; /* No longer a valid stringbuf. */
 
-  /* Index for our revision. Rev 0 is excluded from the first shard. */
-  revprops->manifest_start = revprops->revision
-                           - (revprops->revision % ffd->max_files_per_dir);
-  if (revprops->manifest_start == 0)
-    ++revprops->manifest_start;
-  idx = (int)(revprops->revision - revprops->manifest_start);
+  /* We must have reached the end of both buffers. */
+  if (buffer < content->data + content->len)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             _("Packed revprop manifest for r%ld "
+                               "has too many entries"), revprops->revision);
 
-  if (revprops->manifest->nelts <= idx)
+  if (filenames < filenames_end)
     return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                             _("Packed revprop manifest for r%ld too "
-                               "small"), revprops->revision);
+                             _("Packed revprop manifest for r%ld "
+                               "has too few entries"), revprops->revision);
+
+  /* The target array has now exactly one entry per revision. */
+  revprops->manifest->nelts = rev_count;
 
   /* Now get the file name */
+  idx = (int)(revprops->revision - revprops->manifest_start);
   revprops->filename = APR_ARRAY_IDX(revprops->manifest, idx, const char*);
 
   return SVN_NO_ERROR;
@@ -739,8 +412,9 @@ same_shard(svn_fs_t *fs,
 }
 
 /* Given FS and the full packed file content in REVPROPS->PACKED_REVPROPS,
- * fill the START_REVISION, SIZES, OFFSETS members. Also, make
- * PACKED_REVPROPS point to the first serialized revprop.
+ * fill the START_REVISION member, and make PACKED_REVPROPS point to the
+ * first serialized revprop.  If READ_ALL is set, initialize the SIZES
+ * and OFFSETS members as well.
  *
  * Parse the revprops for REVPROPS->REVISION and set the PROPERTIES as
  * well as the SERIALIZED_SIZE member.  If revprop caching has been
@@ -749,6 +423,7 @@ same_shard(svn_fs_t *fs,
 static svn_error_t *
 parse_packed_revprops(svn_fs_t *fs,
                       packed_revprops_t *revprops,
+                      svn_boolean_t read_all,
                       apr_pool_t *pool,
                       apr_pool_t *scratch_pool)
 {
@@ -805,11 +480,14 @@ parse_packed_revprops(svn_fs_t *fs,
   revprops->packed_revprops->len = (apr_size_t)(uncompressed->len - offset);
   revprops->packed_revprops->blocksize = (apr_size_t)(uncompressed->blocksize - offset);
 
-  /* STREAM still points to the first entry in the sizes list.
-   * Init / construct REVPROPS members. */
+  /* STREAM still points to the first entry in the sizes list. */
   revprops->start_revision = (svn_revnum_t)first_rev;
-  revprops->sizes = apr_array_make(pool, (int)count, sizeof(offset));
-  revprops->offsets = apr_array_make(pool, (int)count, sizeof(offset));
+  if (read_all)
+    {
+      /* Init / construct REVPROPS members. */
+      revprops->sizes = apr_array_make(pool, (int)count, sizeof(offset));
+      revprops->offsets = apr_array_make(pool, (int)count, sizeof(offset));
+    }
 
   /* Now parse, revision by revision, the size and content of each
    * revisions' revprops. */
@@ -817,7 +495,6 @@ parse_packed_revprops(svn_fs_t *fs,
     {
       apr_int64_t size;
       svn_string_t serialized;
-      apr_hash_t *properties;
       svn_revnum_t revision = (svn_revnum_t)(first_rev + i);
       svn_pool_clear(iterpool);
 
@@ -838,20 +515,18 @@ parse_packed_revprops(svn_fs_t *fs,
                                 revprops->generation, &serialized,
                                 pool, iterpool));
           revprops->serialized_size = serialized.len;
+
+          /* If we only wanted the revprops for REVISION then we are done. */
+          if (!read_all)
+            break;
         }
-      else
+
+      if (read_all)
         {
-          /* If revprop caching is enabled, parse any revprops.
-           * They will get cached as a side-effect of this. */
-          if (has_revprop_cache(fs, pool))
-            SVN_ERR(parse_revprop(&properties, fs, revision,
-                                  revprops->generation, &serialized,
-                                  iterpool, iterpool));
+          /* fill REVPROPS data structures */
+          APR_ARRAY_PUSH(revprops->sizes, apr_off_t) = serialized.len;
+          APR_ARRAY_PUSH(revprops->offsets, apr_off_t) = offset;
         }
-
-      /* fill REVPROPS data structures */
-      APR_ARRAY_PUSH(revprops->sizes, apr_off_t) = serialized.len;
-      APR_ARRAY_PUSH(revprops->offsets, apr_off_t) = offset;
       revprops->total_size += serialized.len;
 
       offset += serialized.len;
@@ -862,6 +537,8 @@ parse_packed_revprops(svn_fs_t *fs,
 
 /* In filesystem FS, read the packed revprops for revision REV into
  * *REVPROPS.  Use GENERATION to populate the revprop cache, if enabled.
+ * If you want to modify revprop contents / update REVPROPS, READ_ALL
+ * must be set.  Otherwise, only the properties of REV are being provided.
  * Allocate data in POOL.
  */
 static svn_error_t *
@@ -869,6 +546,7 @@ read_pack_revprop(packed_revprops_t **re
                   svn_fs_t *fs,
                   svn_revnum_t rev,
                   apr_int64_t generation,
+                  svn_boolean_t read_all,
                   apr_pool_t *pool)
 {
   apr_pool_t *iterpool = svn_pool_create(pool);
@@ -911,14 +589,6 @@ read_pack_revprop(packed_revprops_t **re
                                 file_path,
                                 i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT,
                                 pool));
-
-      /* If we could not find the file, there was a write.
-       * So, we should refresh our revprop generation info as well such
-       * that others may find data we will put into the cache.  They would
-       * consider it outdated, otherwise.
-       */
-      if (missing && has_revprop_cache(fs, pool))
-        SVN_ERR(read_revprop_generation(&result->generation, fs, pool));
     }
 
   /* the file content should be available now */
@@ -927,7 +597,7 @@ read_pack_revprop(packed_revprops_t **re
                   _("Failed to read revprop pack file for r%ld"), rev);
 
   /* parse it. RESULT will be complete afterwards. */
-  err = parse_packed_revprops(fs, result, pool, iterpool);
+  err = parse_packed_revprops(fs, result, read_all, pool, iterpool);
   svn_pool_destroy(iterpool);
   if (err)
     return svn_error_createf(SVN_ERR_FS_CORRUPT, err,
@@ -957,22 +627,6 @@ svn_fs_fs__get_revision_proplist(apr_has
   /* should they be available at all? */
   SVN_ERR(svn_fs_fs__ensure_revision_exists(rev, fs, pool));
 
-  /* Try cache lookup first. */
-  if (has_revprop_cache(fs, pool))
-    {
-      svn_boolean_t is_cached;
-      pair_cache_key_t key = { 0 };
-
-      SVN_ERR(read_revprop_generation(&generation, fs, pool));
-
-      key.revision = rev;
-      key.second = generation;
-      SVN_ERR(svn_cache__get((void **) proplist_p, &is_cached,
-                             ffd->revprop_cache, &key, pool));
-      if (is_cached)
-        return SVN_NO_ERROR;
-    }
-
   /* if REV had not been packed when we began, try reading it from the
    * non-packed shard.  If that fails, we will fall through to packed
    * shard reads. */
@@ -997,7 +651,7 @@ svn_fs_fs__get_revision_proplist(apr_has
   if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT && !*proplist_p)
     {
       packed_revprops_t *revprops;
-      SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, pool));
+      SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, FALSE, pool));
       *proplist_p = revprops->properties;
     }
 
@@ -1058,18 +712,9 @@ switch_to_new_revprop(svn_fs_t *fs,
                       svn_boolean_t bump_generation,
                       apr_pool_t *pool)
 {
-  /* Now, we may actually be replacing revprops. Make sure that all other
-     threads and processes will know about this. */
-  if (bump_generation)
-    SVN_ERR(begin_revprop_change(fs, pool));
-
   SVN_ERR(svn_fs_fs__move_into_place(tmp_path, final_path, perms_reference,
                                      pool));
 
-  /* Indicate that the update (if relevant) has been completed. */
-  if (bump_generation)
-    SVN_ERR(end_revprop_change(fs, pool));
-
   /* Clean up temporary files, if necessary. */
   if (files_to_delete)
     {
@@ -1286,13 +931,8 @@ write_packed_revprop(const char **final_
   apr_off_t new_total_size;
   int changed_index;
 
-  /* read the current revprop generation. This value will not change
-   * while we hold the global write lock to this FS. */
-  if (has_revprop_cache(fs, pool))
-    SVN_ERR(read_revprop_generation(&generation, fs, pool));
-
   /* read contents of the current pack file */
-  SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, pool));
+  SVN_ERR(read_pack_revprop(&revprops, fs, rev, generation, TRUE, pool));
 
   /* serialize the new revprops */
   serialized = svn_stringbuf_create_empty(pool);

Modified: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.h
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.h?rev=1636544&r1=1636543&r2=1636544&view=diff
==============================================================================
--- subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.h (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/revprops.h Tue Nov  4 11:40:16 2014
@@ -22,17 +22,6 @@
 
 #include "svn_fs.h"
 
-/* Write the CURRENT revprop generation to disk for repository FS.
- */
-svn_error_t *
-svn_fs_fs__write_revprop_generation_file(svn_fs_t *fs,
-                                         apr_int64_t current,
-                                         apr_pool_t *pool);
-
-/* Make sure the revprop_namespace member in FS is set. */
-svn_error_t *
-svn_fs_fs__cleanup_revprop_namespace(svn_fs_t *fs);
-
 /* In the filesystem FS, pack all revprop shards up to min_unpacked_rev.
  * 
  * NOTE: Keep the old non-packed shards around until after the format bump.

Copied: subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c (from r1636534, subversion/trunk/subversion/libsvn_fs_fs/stats.c)
URL: http://svn.apache.org/viewvc/subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c?p2=subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c&p1=subversion/trunk/subversion/libsvn_fs_fs/stats.c&r1=1636534&r2=1636544&rev=1636544&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/remove-log-addressing/subversion/libsvn_fs_fs/stats.c Tue Nov  4 11:40:16 2014
@@ -544,6 +544,10 @@ parse_representation(rep_stats_t **repre
                                (apr_size_t)rep->item_index);
   if (!result)
     {
+      svn_fs_fs__rep_header_t *header;
+      svn_stream_t *stream;
+
+      svn_string_t content;
       /* not parsed, yet (probably a rep in the same revision).
        * Create a new rep object and determine its base rep as well.
        */
@@ -555,21 +559,14 @@ parse_representation(rep_stats_t **repre
       result->offset = (apr_size_t)rep->item_index;
       result->size = (apr_size_t)rep->size;
 
-      if (!svn_fs_fs__use_log_addressing(query->fs, rep->revision))
-        {
-          svn_fs_fs__rep_header_t *header;
-          svn_stream_t *stream;
+      content.data = file_content->data + (apr_size_t)rep->item_index;
+      content.len = file_content->len - (apr_size_t)rep->item_index;
 
-          svn_string_t content;
-          content.data = file_content->data + (apr_size_t)rep->item_index;
-          content.len = file_content->len - (apr_size_t)rep->item_index;
-
-          stream = svn_stream_from_string(&content, scratch_pool);
-          SVN_ERR(svn_fs_fs__read_rep_header(&header, stream,
-                                             scratch_pool, scratch_pool));
+      stream = svn_stream_from_string(&content, scratch_pool);
+      SVN_ERR(svn_fs_fs__read_rep_header(&header, stream,
+                                          scratch_pool, scratch_pool));
 
-          result->header_size = header->header_size;
-        }
+      result->header_size = header->header_size;
 
       svn_sort__array_insert(revision_info->representations, &result, idx);
     }
@@ -696,8 +693,7 @@ read_noderev(query_t *query,
 
   /* if this is a directory and has not been processed, yet, read and
    * process it recursively */
-  if (   noderev->kind == svn_node_dir && text && text->ref_count == 1
-      && !svn_fs_fs__use_log_addressing(query->fs, revision_info->revision))
+  if (   noderev->kind == svn_node_dir && text && text->ref_count == 1)
     SVN_ERR(parse_dir(query, file_content, noderev, revision_info,
                       pool, subpool));
 
@@ -875,171 +871,6 @@ read_phys_revision_file(query_t *query,
   return SVN_NO_ERROR;
 }
 
-/* Read the item described by ENTRY from the REV_FILE and return
- * the respective byte sequence in *CONTENTS allocated in POOL.
- */
-static svn_error_t *
-read_item(svn_stringbuf_t **contents,
-          svn_fs_fs__revision_file_t *rev_file,
-          svn_fs_fs__p2l_entry_t *entry,
-          apr_pool_t *pool)
-{
-  svn_stringbuf_t *item = svn_stringbuf_create_ensure(entry->size, pool);
-  item->len = entry->size;
-  item->data[item->len] = 0;
-
-  SVN_ERR(svn_io_file_aligned_seek(rev_file->file, rev_file->block_size,
-                                   NULL, entry->offset, pool));
-  SVN_ERR(svn_io_file_read_full2(rev_file->file, item->data, item->len,
-                                 NULL, NULL, pool));
-
-  *contents = item;
-
-  return SVN_NO_ERROR;
-}
-
-/* Process the logically addressed revision contents of revisions BASE to
- * BASE + COUNT - 1 in QUERY.  Use POOL for allocations.
- */
-static svn_error_t *
-read_log_rev_or_packfile(query_t *query,
-                         svn_revnum_t base,
-                         int count,
-                         apr_pool_t *pool)
-{
-  fs_fs_data_t *ffd = query->fs->fsap_data;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_pool_t *localpool = svn_pool_create(pool);
-  apr_off_t max_offset;
-  apr_off_t offset = 0;
-  int i;
-  svn_fs_fs__revision_file_t *rev_file;
-
-  /* we will process every revision in the rev / pack file */
-  for (i = 0; i < count; ++i)
-    {
-      /* create the revision info for the current rev */
-      revision_info_t *info = apr_pcalloc(pool, sizeof(*info));
-      info->representations = apr_array_make(pool, 4, sizeof(rep_stats_t*));
-      info->revision = base + i;
-
-      APR_ARRAY_PUSH(query->revisions, revision_info_t*) = info;
-    }
-
-  /* open the pack / rev file that is covered by the p2l index */
-  SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, base,
-                                           localpool, iterpool));
-  SVN_ERR(svn_fs_fs__p2l_get_max_offset(&max_offset, query->fs, rev_file,
-                                        base, localpool));
-
-  /* record the whole pack size in the first rev so the total sum will
-     still be correct */
-  APR_ARRAY_IDX(query->revisions, base, revision_info_t*)->end = max_offset;
-
-  /* for all offsets in the file, get the P2L index entries and process
-     the interesting items (change lists, noderevs) */
-  for (offset = 0; offset < max_offset; )
-    {
-      apr_array_header_t *entries;
-
-      svn_pool_clear(iterpool);
-
-      /* cancellation support */
-      if (query->cancel_func)
-        SVN_ERR(query->cancel_func(query->cancel_baton));
-
-      /* get all entries for the current block */
-      SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, query->fs, rev_file, base,
-                                          offset, ffd->p2l_page_size,
-                                          iterpool, iterpool));
-
-      /* process all entries (and later continue with the next block) */
-      for (i = 0; i < entries->nelts; ++i)
-        {
-          svn_fs_fs__p2l_entry_t *entry
-            = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
-
-          /* skip bits we previously processed */
-          if (i == 0 && entry->offset < offset)
-            continue;
-
-          /* skip zero-sized entries */
-          if (entry->size == 0)
-            continue;
-
-          /* read and process interesting items */
-          if (entry->type == SVN_FS_FS__ITEM_TYPE_NODEREV)
-            {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
-              SVN_ERR(read_item(&item, rev_file, entry, iterpool));
-              SVN_ERR(read_noderev(query, item, 0, info, pool, iterpool));
-            }
-          else if (entry->type == SVN_FS_FS__ITEM_TYPE_CHANGES)
-            {
-              svn_stringbuf_t *item;
-              revision_info_t *info = APR_ARRAY_IDX(query->revisions,
-                                                    entry->item.revision,
-                                                    revision_info_t*);
-              SVN_ERR(read_item(&item, rev_file, entry, iterpool));
-              info->change_count
-                = get_change_count(item->data + 0, item->len);
-              info->changes_len += entry->size;
-            }
-
-          /* advance offset */
-          offset += entry->size;
-        }
-    }
-
-  /* clean up and close file handles */
-  svn_pool_destroy(iterpool);
-  svn_pool_destroy(localpool);
-
-  return SVN_NO_ERROR;
-}
-
-/* Read the content of the pack file staring at revision BASE logical
- * addressing mode and store it in QUERY.  Use POOL for allocations.
- */
-static svn_error_t *
-read_log_pack_file(query_t *query,
-                   svn_revnum_t base,
-                   apr_pool_t *pool)
-{
-  SVN_ERR(read_log_rev_or_packfile(query, base, query->shard_size, pool));
-
-  /* one more pack file processed */
-  if (query->progress_func)
-    query->progress_func(base, query->progress_baton, pool);
-
-  return SVN_NO_ERROR;
-}
-
-/* Read the content of the file for REVISION in logical addressing mode
- * and store its contents in QUERY.  Use POOL for allocations.
- */
-static svn_error_t *
-read_log_revision_file(query_t *query,
-                       svn_revnum_t revision,
-                       apr_pool_t *pool)
-{
-  SVN_ERR(read_log_rev_or_packfile(query, revision, 1, pool));
-
-  /* show progress every 1000 revs or so */
-  if (query->progress_func)
-    {
-      if (query->shard_size && (revision % query->shard_size == 0))
-        query->progress_func(revision, query->progress_baton, pool);
-      if (!query->shard_size && (revision % 1000 == 0))
-        query->progress_func(revision, query->progress_baton, pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-
 /* Read the repository and collect the stats info in QUERY.
  * Use POOL for allocations.
  */
@@ -1050,20 +881,16 @@ read_revisions(query_t *query,
   svn_revnum_t revision;
 
   /* read all packed revs */
-  for ( revision = 0
+  for (revision = 0
       ; revision < query->min_unpacked_rev
       ; revision += query->shard_size)
-    if (svn_fs_fs__use_log_addressing(query->fs, revision))
-      SVN_ERR(read_log_pack_file(query, revision, pool));
-    else
+    {
       SVN_ERR(read_phys_pack_file(query, revision, pool));
+    }
 
   /* read non-packed revs */
   for ( ; revision <= query->head; ++revision)
-    if (svn_fs_fs__use_log_addressing(query->fs, revision))
-      SVN_ERR(read_log_revision_file(query, revision, pool));
-    else
-      SVN_ERR(read_phys_revision_file(query, revision, pool));
+    SVN_ERR(read_phys_revision_file(query, revision, pool));
 
   return SVN_NO_ERROR;
 }



Mime
View raw message