subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From julianf...@apache.org
Subject svn commit: r1634609 [4/11] - in /subversion/branches/move-tracking-2: ./ build/ notes/ subversion/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ subversion/libsvn_fs/ subversion/libsvn_fs_base/ subv...
Date Mon, 27 Oct 2014 17:28:16 GMT
Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/index.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/index.h?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/index.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/index.h Mon Oct 27 17:28:13 2014
@@ -48,43 +48,22 @@
 #define SVN_FS_FS__ITEM_TYPE_ANY_REP    7  /* item is any representation.
                                               Only used in pre-format7. */
 
-/* (user visible) entry in the phys-to-log index.  It describes a section
- * of some packed / non-packed rev file as containing a specific item.
- * There must be no overlapping / conflicting entries.
- */
-typedef struct svn_fs_fs__p2l_entry_t
-{
-  /* offset of the first byte that belongs to the item */
-  apr_off_t offset;
-  
-  /* length of the item in bytes */
-  apr_off_t size;
-
-  /* type of the item (see SVN_FS_FS__ITEM_TYPE_*) defines */
-  unsigned type;
-
-  /* modified FNV-1a checksum.  0 if unknown checksum */
-  apr_uint32_t fnv1_checksum;
-
-  /* item in that block */
-  svn_fs_fs__id_part_t item;
-} svn_fs_fs__p2l_entry_t;
-
 /* Open / create a log-to-phys index file with the full file path name
- * FILE_NAME.  Return the open file in *PROTO_INDEX and use POOL for
- * allocations.
+ * FILE_NAME.  Return the open file in *PROTO_INDEX allocated in
+ * RESULT_POOL.
  */
 svn_error_t *
 svn_fs_fs__l2p_proto_index_open(apr_file_t **proto_index,
                                 const char *file_name,
-                                apr_pool_t *pool);
+                                apr_pool_t *result_pool);
 
 /* Call this function before adding entries for the next revision to the
- * log-to-phys index file in PROTO_INDEX.  Use POOL for allocations.
+ * log-to-phys index file in PROTO_INDEX.  Use SCRATCH_POOL for temporary
+ * allocations.
  */
 svn_error_t *
 svn_fs_fs__l2p_proto_index_add_revision(apr_file_t *proto_index,
-                                        apr_pool_t *pool);
+                                        apr_pool_t *scratch_pool);
 
 /* Add a new mapping, ITEM_INDEX to the OFFSET, to log-to-phys index file
  * in PROTO_INDEX.  Please note that mappings may be added in any order
@@ -93,73 +72,83 @@ svn_fs_fs__l2p_proto_index_add_revision(
  * mark 'invalid' item indexes but that is already implied for all item
  * indexes not explicitly given a mapping.
  * 
- * Use POOL for allocations.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__l2p_proto_index_add_entry(apr_file_t *proto_index,
                                      apr_off_t offset,
                                      apr_uint64_t item_index,
-                                     apr_pool_t *pool);
+                                     apr_pool_t *scratch_pool);
 
 /* Use the proto index file stored at PROTO_FILE_NAME, construct the final
  * log-to-phys index and append it to INDEX_FILE.  The first revision will
  * be REVISION, entries to the next revision will be assigned to REVISION+1
- * and so forth.  Use POOL for allocations.
+ * and so forth.  
+ *
+ * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated
+ * in RESULT_POOL.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
-svn_fs_fs__l2p_index_append(svn_fs_t *fs,
+svn_fs_fs__l2p_index_append(svn_checksum_t **checksum,
+                            svn_fs_t *fs,
                             apr_file_t *index_file,
                             const char *proto_file_name,
                             svn_revnum_t revision,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* Open / create a phys-to-log index file with the full file path name
- * FILE_NAME.  Return the open file in *PROTO_INDEX and use POOL for
- * allocations.
+ * FILE_NAME.  Return the open file in *PROTO_INDEX allocated in
+ * RESULT_POOL.
  */
 svn_error_t *
 svn_fs_fs__p2l_proto_index_open(apr_file_t **proto_index,
                                 const char *file_name,
-                                apr_pool_t *pool);
+                                apr_pool_t *result_pool);
 
 /* Add a new mapping ENTRY to the phys-to-log index file in PROTO_INDEX.
  * The entries must be added in ascending offset order and must not leave
  * intermittent ranges uncovered.  The revision value in ENTRY may be
- * SVN_INVALID_REVISION.  Use POOL for allocations.
+ * SVN_INVALID_REVISION.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__p2l_proto_index_add_entry(apr_file_t *proto_index,
                                      svn_fs_fs__p2l_entry_t *entry,
-                                     apr_pool_t *pool);
+                                     apr_pool_t *scratch_pool);
 
 /* Set *NEXT_OFFSET to the first offset behind the last entry in the
  * phys-to-log proto index file PROTO_INDEX.  This will be 0 for empty
- * index files.  Use POOL for temporary allocations.
+ * index files.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__p2l_proto_index_next_offset(apr_off_t *next_offset,
                                        apr_file_t *proto_index,
-                                       apr_pool_t *pool);
+                                       apr_pool_t *scratch_pool);
 
 /* Use the proto index file stored at PROTO_FILE_NAME, construct the final
  * phys-to-log index and append it to INDEX_FILE.  Entries without a valid
  * revision will be assigned to the REVISION given here.
- * Use POOL for allocations.
+ *
+ * Return the MD5 checksum of the on-disk index data in *CHECKSUM, allocated
+ * in RESULT_POOL.  Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
-svn_fs_fs__p2l_index_append(svn_fs_t *fs,
+svn_fs_fs__p2l_index_append(svn_checksum_t **checksum,
+                            svn_fs_t *fs,
                             apr_file_t *index_file,
                             const char *proto_file_name,
                             svn_revnum_t revision,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* Use the phys-to-log mapping files in FS to build a list of entries
  * that (at least partly) overlap with the range given by BLOCK_START
  * offset and BLOCK_SIZE in the rep / pack file containing REVISION.
- * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements.
- * REV_FILE determines whether to access single rev or pack file data.
- * If that is not available anymore (neither in cache nor on disk),
- * return an error.  Use POOL for allocations.
+ * Return the array in *ENTRIES with svn_fs_fs__p2l_entry_t as elements,
+ * allocated in RESULT_POOL.  REV_FILE determines whether to access single
+ * rev or pack file data.  If that is not available anymore (neither in
+ * cache nor on disk), return an error.  Use SCRATCH_POOL for temporary
+ * allocations.
  *
  * Note that (only) the first and the last mapping may cross a cluster
  * boundary.
@@ -171,14 +160,16 @@ svn_fs_fs__p2l_index_lookup(apr_array_he
                             svn_revnum_t revision,
                             apr_off_t block_start,
                             apr_off_t block_size,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* Use the phys-to-log mapping files in FS to return the entry for the
  * item starting at global OFFSET in the rep file containing REVISION in
- * *ENTRY.  Sets *ENTRY to NULL if no item starts at exactly that offset.
- * REV_FILE determines whether to access single rev or pack file data.
- * If that is not available anymore (neither in cache nor on disk),
- * return an error.  Use POOL for allocations.
+ * *ENTRY, allocated in RESULT_POOL.  Sets *ENTRY to NULL if no item starts
+ * at exactly that offset.  REV_FILE determines whether to access single
+ * rev or pack file data.  If that is not available anymore (neither in
+ * cache nor on disk), return an error.  Use SCRATCH_POOL for temporary
+ * allocations.
  */
 svn_error_t *
 svn_fs_fs__p2l_entry_lookup(svn_fs_fs__p2l_entry_t **entry,
@@ -186,7 +177,8 @@ svn_fs_fs__p2l_entry_lookup(svn_fs_fs__p
                             svn_fs_fs__revision_file_t *rev_file,
                             svn_revnum_t revision,
                             apr_off_t offset,
-                            apr_pool_t *pool);
+                            apr_pool_t *result_pool,
+                            apr_pool_t *scratch_pool);
 
 /* For ITEM_INDEX within REV in FS, return the position in the respective
  * rev or pack file in *ABSOLUTE_POSITION.  If TXN_ID is not NULL, return
@@ -197,7 +189,7 @@ svn_fs_fs__p2l_entry_lookup(svn_fs_fs__p
  * If that is not available anymore (neither in cache nor on disk), re-open
  * the rev / pack file and retry to open the index file.  For anything but
  * committed log addressed revisions, REV_FILE may be NULL.
- * Use POOL for allocations.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__item_offset(apr_off_t *absolute_position,
@@ -206,32 +198,34 @@ svn_fs_fs__item_offset(apr_off_t *absolu
                        svn_revnum_t revision,
                        const svn_fs_fs__id_part_t *txn_id,
                        apr_uint64_t item_index,
-                       apr_pool_t *pool);
+                       apr_pool_t *scratch_pool);
 
 /* Use the log-to-phys indexes in FS to determine the maximum item indexes
  * assigned to revision START_REV to START_REV + COUNT - 1.  That is a
  * close upper limit to the actual number of items in the respective revs.
- * Return the results in *MAX_IDS,  allocated in POOL.
+ * Return the results in *MAX_IDS,  allocated in RESULT_POOL.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__l2p_get_max_ids(apr_array_header_t **max_ids,
                            svn_fs_t *fs,
                            svn_revnum_t start_rev,
                            apr_size_t count,
-                           apr_pool_t *pool);
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool);
 
 /* In *OFFSET, return the last OFFSET in the pack / rev file containing.
  * REV_FILE determines whether to access single rev or pack file data.
  * If that is not available anymore (neither in cache nor on disk), re-open
  * the rev / pack file and retry to open the index file.
- * Use POOL for allocations.
+ * Use SCRATCH_POOL for temporary allocations.
  */
 svn_error_t *
 svn_fs_fs__p2l_get_max_offset(apr_off_t *offset,
                               svn_fs_t *fs,
                               svn_fs_fs__revision_file_t *rev_file,
                               svn_revnum_t revision,
-                              apr_pool_t *pool);
+                              apr_pool_t *scratch_pool);
 
 /* Index (re-)creation utilities.
  */

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/lock.c Mon Oct 27 17:28:13 2014
@@ -386,7 +386,8 @@ add_to_digest(const char *fs_path,
   const char *index_digest_path;
   apr_hash_t *children;
   svn_lock_t *lock;
-  int i, original_count;
+  int i;
+  unsigned int original_count;
 
   SVN_ERR(digest_path_from_path(&index_digest_path, fs_path, index_path, pool));
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.c Mon Oct 27 17:28:13 2014
@@ -27,6 +27,7 @@
 #include "private/svn_sorts_private.h"
 #include "private/svn_string_private.h"
 #include "private/svn_subr_private.h"
+#include "private/svn_fspath.h"
 
 #include "../libsvn_fs/fs-loader.h"
 
@@ -69,6 +70,36 @@
  * various flags. */
 #define MAX_CHANGE_LINE_LEN FSFS_MAX_PATH_LEN + 256
 
+/* Convert the C string in *TEXT to a revision number and return it in *REV.
+ * Overflows, negative values other than -1 and terminating characters other
+ * than 0x20 or 0x0 will cause an error.  Set *TEXT to the first char after
+ * the initial separator or to EOS.
+ */
+static svn_error_t *
+parse_revnum(svn_revnum_t *rev,
+             const char **text)
+{
+  const char *string = *text;
+  if ((string[0] == '-') && (string[1] == '1'))
+    {
+      *rev = SVN_INVALID_REVNUM;
+      string += 2;
+    }
+  else
+    {
+      SVN_ERR(svn_revnum_parse(rev, string, &string));
+    }
+
+  if (*string == ' ')
+    ++string;
+  else if (*string != '\0')
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid character in revision number"));
+
+  *text = string;
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_fs__parse_revision_trailer(apr_off_t *root_offset,
                                   apr_off_t *changes_offset,
@@ -160,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
@@ -228,7 +292,7 @@ read_change(change_t **change_p,
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Invalid changes line in rev-file"));
 
-  info->node_rev_id = svn_fs_fs__id_parse(str, result_pool);
+  SVN_ERR(svn_fs_fs__id_parse(&info->node_rev_id, str, result_pool));
   if (info->node_rev_id == NULL)
     return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                             _("Invalid changes line in rev-file"));
@@ -324,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);
@@ -346,8 +412,12 @@ read_change(change_t **change_p,
                               _("Invalid mergeinfo-mod flag in rev-file"));
         }
     }
-  
+
   /* Get the changed path. */
+  if (!svn_fspath__is_canonical(last_str))
+    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Invalid path in changes line"));
+
   change->path.len = strlen(last_str);
   change->path.data = apr_pstrdup(result_pool, last_str);
 
@@ -362,15 +432,11 @@ read_change(change_t **change_p,
   else
     {
       last_str = line->data;
-      str = svn_cstring_tokenize(" ", &last_str);
-      if (! str)
-        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("Invalid changes line in rev-file"));
-      info->copyfrom_rev = SVN_STR_TO_REV(str);
+      SVN_ERR(parse_revnum(&info->copyfrom_rev, (const char **)&last_str));
 
-      if (! last_str)
+      if (!svn_fspath__is_canonical(last_str))
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                                _("Invalid changes line in rev-file"));
+                                _("Invalid copy-from path in changes line"));
 
       info->copyfrom_path = apr_pstrdup(result_pool, last_str);
     }
@@ -437,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,
@@ -534,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);
@@ -584,8 +656,8 @@ read_header_block(apr_hash_t **headers,
     {
       svn_stringbuf_t *header_str;
       const char *name, *value;
-      apr_ssize_t i = 0;
-      apr_ssize_t name_len;
+      apr_size_t i = 0;
+      apr_size_t name_len;
       svn_boolean_t eof;
 
       SVN_ERR(svn_stream_readline(stream, &header_str, "\n", &eof,
@@ -609,13 +681,10 @@ read_header_block(apr_hash_t **headers,
       name = header_str->data;
       name_len = i;
 
-      /* Skip over the NULL byte and the space following it. */
-      i += 2;
-
-      if (i > header_str->len)
+      /* Check if we have enough data to parse. */
+      if (i + 2 > header_str->len)
         {
           /* Restore the original line for the error. */
-          i -= 2;
           header_str->data[i] = ':';
           return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                    _("Found malformed header '%s' in "
@@ -623,6 +692,9 @@ read_header_block(apr_hash_t **headers,
                                    header_str->data);
         }
 
+      /* Skip over the NULL byte and the space following it. */
+      i += 2;
+
       value = header_str->data + i;
 
       /* header_str is safely in our pool, so we can use bits of it as
@@ -649,12 +721,7 @@ svn_fs_fs__parse_representation(represen
   rep = apr_pcalloc(result_pool, sizeof(*rep));
   *rep_p = rep;
 
-  str = svn_cstring_tokenize(" ", &string);
-  if (str == NULL)
-    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
-                            _("Malformed text representation offset line in node-rev"));
-
-  rep->revision = SVN_STR_TO_REV(str);
+  SVN_ERR(parse_revnum(&rep->revision, (const char **)&string));
 
   /* initialize transaction info (never stored) */
   svn_fs_fs__id_txn_reset(&rep->txn_id);
@@ -797,7 +864,7 @@ svn_fs_fs__read_noderev(node_revision_t 
 
   SVN_ERR(svn_stream_close(stream));
 
-  noderev->id = svn_fs_fs__id_parse(value, result_pool);
+  SVN_ERR(svn_fs_fs__id_parse(&noderev->id, value, result_pool));
   noderev_id = value; /* for error messages later */
 
   /* Read the type. */
@@ -848,13 +915,19 @@ svn_fs_fs__read_noderev(node_revision_t 
     }
   else
     {
+      if (!svn_fspath__is_canonical(value))
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                            _("Non-canonical cpath field in node-rev '%s'"),
+                            noderev_id);
+
       noderev->created_path = apr_pstrdup(result_pool, value);
     }
 
   /* Get the predecessor ID. */
   value = svn_hash_gets(headers, HEADER_PRED);
   if (value)
-    noderev->predecessor_id = svn_fs_fs__id_parse(value, result_pool);
+    SVN_ERR(svn_fs_fs__id_parse(&noderev->predecessor_id, value,
+                                result_pool));
 
   /* Get the copyroot. */
   value = svn_hash_gets(headers, HEADER_COPYROOT);
@@ -865,17 +938,9 @@ svn_fs_fs__read_noderev(node_revision_t 
     }
   else
     {
-      char *str;
-
-      str = svn_cstring_tokenize(" ", &value);
-      if (str == NULL)
-        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                 _("Malformed copyroot line in node-rev '%s'"),
-                                 noderev_id);
+      SVN_ERR(parse_revnum(&noderev->copyroot_rev, (const char **)&value));
 
-      noderev->copyroot_rev = SVN_STR_TO_REV(str);
-
-      if (*value == '\0')
+      if (!svn_fspath__is_canonical(value))
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Malformed copyroot line in node-rev '%s'"),
                                  noderev_id);
@@ -891,13 +956,7 @@ svn_fs_fs__read_noderev(node_revision_t 
     }
   else
     {
-      char *str = svn_cstring_tokenize(" ", &value);
-      if (str == NULL)
-        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                 _("Malformed copyfrom line in node-rev '%s'"),
-                                 noderev_id);
-
-      noderev->copyfrom_rev = SVN_STR_TO_REV(str);
+      SVN_ERR(parse_revnum(&noderev->copyfrom_rev, (const char **)&value));
 
       if (*value == 0)
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
@@ -1088,10 +1147,7 @@ svn_fs_fs__read_rep_header(svn_fs_fs__re
   if (! str || (strcmp(str, REP_DELTA) != 0))
     goto error;
 
-  str = svn_cstring_tokenize(" ", &last_str);
-  if (! str)
-    goto error;
-  (*header)->base_revision = SVN_STR_TO_REV(str);
+  SVN_ERR(parse_revnum(&(*header)->base_revision, (const char **)&last_str));
 
   str = svn_cstring_tokenize(" ", &last_str);
   if (! str)

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.h?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/low_level.h Mon Oct 27 17:28:13 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/move-tracking-2/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/pack.c Mon Oct 27 17:28:13 2014
@@ -479,7 +479,7 @@ copy_item_to_temp(pack_context_t *contex
   svn_fs_fs__p2l_entry_t *new_entry
     = apr_pmemdup(context->info_pool, entry, sizeof(*entry));
   new_entry->offset = 0;
-  SVN_ERR(svn_io_file_seek(temp_file, SEEK_CUR, &new_entry->offset, pool));
+  SVN_ERR(svn_io_file_seek(temp_file, APR_CUR, &new_entry->offset, pool));
   APR_ARRAY_PUSH(entries, svn_fs_fs__p2l_entry_t *) = new_entry;
   
   SVN_ERR(copy_file_data(context, temp_file, rev_file, entry->size, pool));
@@ -567,7 +567,7 @@ copy_rep_to_temp(pack_context_t *context
    * store it in CONTEXT */
   entry = apr_pmemdup(context->info_pool, entry, sizeof(*entry));
   entry->offset = 0;
-  SVN_ERR(svn_io_file_seek(context->reps_file, SEEK_CUR, &entry->offset,
+  SVN_ERR(svn_io_file_seek(context->reps_file, APR_CUR, &entry->offset,
                            pool));
   add_item_rep_mapping(context, entry);
 
@@ -589,7 +589,7 @@ copy_rep_to_temp(pack_context_t *context
     }
 
   /* copy the whole rep (including header!) to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file, SEEK_SET, &source_offset, pool));
+  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &source_offset, pool));
   SVN_ERR(copy_file_data(context, context->reps_file, rev_file, entry->size,
                          pool));
 
@@ -723,12 +723,12 @@ copy_node_to_temp(pack_context_t *contex
    * store it in CONTEXT */
   entry = apr_pmemdup(context->info_pool, entry, sizeof(*entry));
   entry->offset = 0;
-  SVN_ERR(svn_io_file_seek(context->reps_file, SEEK_CUR,
+  SVN_ERR(svn_io_file_seek(context->reps_file, APR_CUR,
                            &entry->offset, pool));
   add_item_rep_mapping(context, entry);
 
   /* copy the noderev to our temp file */
-  SVN_ERR(svn_io_file_seek(rev_file, SEEK_SET, &source_offset, pool));
+  SVN_ERR(svn_io_file_seek(rev_file, APR_SET, &source_offset, pool));
   SVN_ERR(copy_file_data(context, context->reps_file, rev_file, entry->size,
                          pool));
 
@@ -1112,7 +1112,7 @@ store_item(pack_context_t *context,
 
   /* select the item in the source file and copy it into the target
     * pack file */
-  SVN_ERR(svn_io_file_seek(temp_file, SEEK_SET, &item->offset, pool));
+  SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &item->offset, pool));
   SVN_ERR(copy_file_data(context, context->pack_file, temp_file,
                          item->size, pool));
 
@@ -1165,7 +1165,6 @@ copy_reps_from_temp(pack_context_t *cont
 {
   apr_pool_t *iterpool = svn_pool_create(pool);
   apr_array_header_t *path_order = context->path_order;
-  apr_array_header_t *parts = apr_array_make(pool, 16, sizeof(void*));
   int i;
 
   /* copy items in path order. */
@@ -1185,9 +1184,6 @@ copy_reps_from_temp(pack_context_t *cont
         SVN_ERR(store_item(context, temp_file, node_part, iterpool));
       if (rep_part)
         SVN_ERR(store_item(context, temp_file, rep_part, iterpool));
-
-      /* processed all items */
-      apr_array_clear(parts);
     }
 
   svn_pool_destroy(iterpool);
@@ -1311,7 +1307,8 @@ pack_range(pack_context_t *context,
 
           SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, context->fs,
                                               rev_file, revision, offset,
-                                              ffd->p2l_page_size, iterpool));
+                                              ffd->p2l_page_size, iterpool,
+                                              iterpool));
 
           for (i = 0; i < entries->nelts; ++i)
             {
@@ -1329,7 +1326,7 @@ pack_range(pack_context_t *context,
               offset = entry->offset;
               if (offset < rev_file->l2p_offset)
                 {
-                  SVN_ERR(svn_io_file_seek(rev_file->file, SEEK_SET, &offset,
+                  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset,
                                            iterpool2));
 
                   if (entry->type == SVN_FS_FS__ITEM_TYPE_CHANGES)
@@ -1445,7 +1442,8 @@ append_revision(pack_context_t *context,
       svn_pool_clear(iterpool);
       SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, context->fs, rev_file,
                                           context->start_rev, offset,
-                                          ffd->p2l_page_size, iterpool));
+                                          ffd->p2l_page_size, iterpool,
+                                          iterpool));
 
       for (i = 0; i < entries->nelts; ++i)
         {
@@ -1531,7 +1529,7 @@ pack_log_addressed(svn_fs_t *fs,
   /* phase 1: determine the size of the revisions to pack */
   SVN_ERR(svn_fs_fs__l2p_get_max_ids(&max_ids, fs, shard_rev,
                                      context.shard_end_rev - shard_rev,
-                                     pool));
+                                     pool, pool));
 
   /* pack revisions in ranges that don't exceed MAX_MEM */
   for (i = 0; i < max_ids->nelts; ++i)

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/recovery.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/recovery.c Mon Oct 27 17:28:13 2014
@@ -216,7 +216,7 @@ recover_find_max_ids(svn_fs_t *fs,
       char *str_val;
       char *str;
       svn_node_kind_t kind;
-      svn_fs_id_t *id;
+      const svn_fs_id_t *id;
       const svn_fs_fs__id_part_t *rev_item;
       apr_uint64_t node_id, copy_id;
       apr_off_t child_dir_offset;
@@ -246,7 +246,7 @@ recover_find_max_ids(svn_fs_t *fs,
         return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                 _("Directory entry corrupt"));
 
-      id = svn_fs_fs__id_parse(str, iterpool);
+      SVN_ERR(svn_fs_fs__id_parse(&id, str, iterpool));
 
       rev_item = svn_fs_fs__id_rev_item(id);
       if (rev_item->revision != rev)
@@ -345,8 +345,10 @@ 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. */
+  SVN_ERR(svn_fs_fs__set_uuid(fs, fs->uuid, NULL, pool));
 
   /* We need to know the largest revision in the filesystem. */
   SVN_ERR(recover_get_largest_revision(fs, &max_rev, pool));

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.c Mon Oct 27 17:28:13 2014
@@ -31,6 +31,8 @@
 #include "private/svn_io_private.h"
 #include "svn_private_config.h"
 
+/* Initialize the *FILE structure for REVISION in filesystem FS.  Set its
+ * pool member to the provided POOL. */
 static void
 init_revision_file(svn_fs_fs__revision_file_t *file,
                    svn_fs_t *fs,
@@ -40,9 +42,7 @@ init_revision_file(svn_fs_fs__revision_f
   fs_fs_data_t *ffd = fs->fsap_data;
 
   file->is_packed = svn_fs_fs__is_packed_rev(fs, revision);
-  file->start_revision = revision < ffd->min_unpacked_rev
-                       ? revision - (revision % ffd->max_files_per_dir)
-                       : revision;
+  file->start_revision = svn_fs_fs__packed_base_rev(fs, revision);
 
   file->file = NULL;
   file->stream = NULL;
@@ -50,7 +50,9 @@ init_revision_file(svn_fs_fs__revision_f
   file->l2p_stream = NULL;
   file->block_size = ffd->block_size;
   file->l2p_offset = -1;
+  file->l2p_checksum = NULL;
   file->p2l_offset = -1;
+  file->p2l_checksum = NULL;
   file->footer_offset = -1;
   file->pool = pool;
 }
@@ -176,6 +178,7 @@ open_pack_or_rev_file(svn_fs_fs__revisio
 
               /* We failed for the first time. Refresh cache & retry. */
               SVN_ERR(svn_fs_fs__update_min_unpacked_rev(fs, scratch_pool));
+              file->start_revision = svn_fs_fs__packed_base_rev(fs, rev);
 
               retry = TRUE;
             }
@@ -253,8 +256,10 @@ svn_fs_fs__auto_read_footer(svn_fs_fs__r
       footer->data[footer->len] = '\0';
 
       /* Extract index locations. */
-      SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->p2l_offset,
-                                      footer, file->start_revision));
+      SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->l2p_checksum,
+                                      &file->p2l_offset, &file->p2l_checksum,
+                                      footer, file->start_revision,
+                                      file->pool));
       file->footer_offset = filesize - footer_length - 1;
     }
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.h?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/rev_file.h Mon Oct 27 17:28:13 2014
@@ -72,11 +72,19 @@ typedef struct svn_fs_fs__revision_file_
    * has not been called, yet. */
   apr_off_t l2p_offset;
 
+  /* MD5 checksum on the whole on-disk representation of the L2P index.
+   * NULL if svn_fs_fs__auto_read_footer has not been called, yet. */
+  svn_checksum_t *l2p_checksum;
+
   /* Offset within FILE at which the L2P index ends and the P2L index
    * data starts. Greater than L2P_OFFSET. -1 if svn_fs_fs__auto_read_footer
    * has not been called, yet. */
   apr_off_t p2l_offset;
 
+  /* MD5 checksum on the whole on-disk representation of the P2L index.
+   * NULL if svn_fs_fs__auto_read_footer has not been called, yet. */
+  svn_checksum_t *p2l_checksum;
+
   /* Offset within FILE at which the P2L index ends and the footer starts.
    * Greater than P2L_OFFSET. -1 if svn_fs_fs__auto_read_footer has not
    * been called, yet. */

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.c Mon Oct 27 17:28:13 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
@@ -911,14 +522,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 */
@@ -957,22 +560,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. */
@@ -1058,18 +645,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,11 +864,6 @@ 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));
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.h
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.h?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.h (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/revprops.h Mon Oct 27 17:28:13 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.

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure Mon Oct 27 17:28:13 2014
@@ -43,8 +43,10 @@ repository) is:
     <shard>.pack/     Pack directory, if the repo has been packed (see below)
       <rev>.<count>   Pack file, if the repository has been packed (see below)
       manifest        Pack manifest file, if a pack file exists (see below)
-    revprops.db       SQLite database of the packed revision properties
-  transactions/       Subdirectory containing transactions
+    revprops.db       SQLite database of the packed revprops (format 5 only)
+  transactions/       Subdirectory containing transactions (format 1 to 6)
+    <txnid>.txn/      Directory containing transaction <txnid>
+  transactions-la/    Subdirectory containing transactions (format 7+)
     <txnid>.txn/      Directory containing transaction <txnid>
   txn-protorevs/      Subdirectory containing transaction proto-revision files
     <txnid>.rev       Proto-revision file for transaction <txnid>
@@ -64,7 +66,7 @@ repository) is:
   format              File containing the format number of this filesystem
   fsfs.conf           Configuration file
   min-unpacked-rev    File containing the oldest revision not in a pack file
-  min-unpacked-revprop File containing the oldest revision of unpacked revprop
+  min-unpacked-revprop Same for revision properties (format 5 only)
   rep-cache.db        SQLite database mapping rep checksums to locations
 
 Files in the revprops directory are in the hash dump format used by
@@ -613,11 +615,14 @@ lines containing "\n<root-offset> <cp-of
 the offset of the root directory node revision and <cp-offset> is the
 offset of the changed-path data.
 
-In logical addressing mode, the revision footer is pair of offsets,
-separated by a space and the whole is terminated a single byte.  That
-byte contains the length (as plain 8 bit value) of the footer excluding
-the length byte.  The first offset is the start of the log-to-phys index,
-the other is the start offset of the phys-to-log index.
+In logical addressing mode, the revision footer has the form
+
+  <l2p offset> <l2p checksum> <p2l offset> <p2l checksum><terminal byte>
+
+The terminal byte contains the length (as plain 8 bit value) of the footer
+excluding that length byte.  The first offset is the start of the log-to-
+phys index, followed by the digest of the MD5 checksum over its content.
+The other pair gives the same of for the phys-to-log index.
 
 All numbers in the rev file format are unsigned and are represented as
 ASCII decimal.

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure-indexes
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure-indexes?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure-indexes (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/structure-indexes Mon Oct 27 17:28:13 2014
@@ -80,6 +80,14 @@ Most data is unsigned by nature but will
 signed integers.
 
 
+Encoding in proto-index files
+-----------------------------
+
+These have a much simpler encoding.  Throughout the files, all records have
+the same length (but different between L2P and P2L).  All records contain
+unsigned 64 bit integers only, stored in little endian byte order.
+
+
 Log-to-phys index
 =================
 
@@ -143,7 +151,7 @@ page:
 Index on-disk format
 --------------------
 
-  index := header revisions pages offsets
+  index := "L2P-INDEX\n" header revisions pages offsets
 
   header := u(<header>.<first revision>) \
             u(<header>.<page size>) \
@@ -158,11 +166,13 @@ Index on-disk format
            u(<header>.<page table>[k].<entry count>),
            for k in 0 .. s(<header>.<page table>)-1
 
-  offsets := i(<header>.<page table>[k].<offsets>[0]) \
+  offsets := page(k),
+             for k in 0 .. s(<header>.<page table>)-1
+
+  page(k) := i(<header>.<page table>[k].<offsets>[0]) \
              i(  <header>.<page table>[k].<offsets>[l] \
                - <header>.<page table>[k].<offsets>[l - 1]),
-             for l in 1 .. s(<header>.<page table>[k].<entry count>)-1,
-             for k in 0 .. s(<header>.<page table>)-1
+             for l in 1 .. s(<header>.<page table>[k].<entry count>)-1
 
   u(x) ... unsigned int x in 7b/8b encoding
   i(x) ... signed int x in 7b/8b encoding
@@ -190,7 +200,7 @@ at the beginning of the file is optional
   ...
   <eof>         /* end of file. */
 
-All entries are pairs of 64 bit unsigned integers in machine endianess.
+All entries are pairs of 64 bit unsigned integers in little endian order.
 
 
 Phys-to-log index
@@ -256,7 +266,7 @@ entry:
 Index on-disk format
 --------------------
 
-  index := header pages items
+  index := "P2L-INDEX\n" header pages items
 
   header := u(<header>.<first revision>) \
             u(<header>.<file size>) \
@@ -286,14 +296,25 @@ Index on-disk format
   started after the begin of a given page and overlap with the next page
   will not be stored in the start page.  The runtime representation will
   duplicate items overlapping page boundaries; the on-disk representation
-  will not.
+  will not.  Thus, pages inside large items will have zero entries on disk.
 
 
 Proto index file format
 -----------------------
 
 The index will be created from a proto index file containing simple
-instances of the in-memory representation of svn_fs_fs__p2l_entry_t.
+instances of svn_fs_fs__p2l_entry_t with the following element order:
+
+  item offset               as uint64
+  item size                 as uint64
+  item type                 as uint64
+  modified FNV1a checksum   as uint64
+  revision                  as uint64, with SVN_INVALID_REVNUM mapped to 0
+                                       and revisions >= 0 stored as rev+1
+  item index                as uint64
+
+All values are stored in little endian order.
+
 Page table and header information, except start revision and page size,
 can easily be derived from that information.
 

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/temp_serializer.c Mon Oct 27 17:28:13 2014
@@ -205,7 +205,7 @@ static svn_temp_serializer__context_t *
 serialize_dir(apr_array_header_t *entries, apr_pool_t *pool)
 {
   dir_data_t dir_data;
-  apr_size_t i = 0;
+  int i = 0;
   svn_temp_serializer__context_t *context;
 
   /* calculate sizes */

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/transaction.c Mon Oct 27 17:28:13 2014
@@ -409,7 +409,7 @@ auto_truncate_proto_rev(svn_fs_t *fs,
       if (indexed_length < actual_length)
         SVN_ERR(svn_io_file_trunc(proto_rev, indexed_length, pool));
       else if (indexed_length > actual_length)
-        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_INCONSISTENT,
+        return svn_error_createf(SVN_ERR_FS_INDEX_INCONSISTENT,
                                  NULL,
                                  _("p2l proto index offset %s beyond proto"
                                    "rev file size %s for TXN %s"),
@@ -621,40 +621,29 @@ unparse_dir_entries(apr_array_header_t *
   return SVN_NO_ERROR;
 }
 
-/* Copy the contents of NEW_CHANGE into OLD_CHANGE assuming that both
-   belong to the same path.  Allocate copies in POOL.
+/* Return a deep copy of SOURCE and allocate it in RESULT_POOL.
  */
-static void
-replace_change(svn_fs_path_change2_t *old_change,
-               const svn_fs_path_change2_t *new_change,
-               apr_pool_t *pool)
-{
-  /* An add at this point must be following a previous delete,
-      so treat it just like a replace. */
-  old_change->node_kind = new_change->node_kind;
-  old_change->node_rev_id = svn_fs_fs__id_copy(new_change->node_rev_id,
-                                               pool);
-  old_change->text_mod = new_change->text_mod;
-  old_change->prop_mod = new_change->prop_mod;
-  old_change->mergeinfo_mod = new_change->mergeinfo_mod;
-  if (new_change->copyfrom_rev == SVN_INVALID_REVNUM)
-    {
-      old_change->copyfrom_rev = SVN_INVALID_REVNUM;
-      old_change->copyfrom_path = NULL;
-    }
-  else
-    {
-      old_change->copyfrom_rev = new_change->copyfrom_rev;
-      old_change->copyfrom_path = apr_pstrdup(pool,
-                                              new_change->copyfrom_path);
-    }
+static svn_fs_path_change2_t *
+path_change_dup(const svn_fs_path_change2_t *source,
+                apr_pool_t *result_pool)
+{
+  svn_fs_path_change2_t *result = apr_pmemdup(result_pool, source,
+                                              sizeof(*source));
+  result->node_rev_id = svn_fs_fs__id_copy(source->node_rev_id, result_pool);
+  if (source->copyfrom_path)
+    result->copyfrom_path = apr_pstrdup(result_pool, source->copyfrom_path);
+
+  return result;
 }
 
 /* Merge the internal-use-only CHANGE into a hash of public-FS
    svn_fs_path_change2_t CHANGED_PATHS, collapsing multiple changes into a
-   single summarical (is that real word?) change per path.  */
+   single summarical (is that real word?) change per path.  DELETIONS is
+   also a path->svn_fs_path_change2_t hash and contains all the deletions
+   that got turned into a replacement. */
 static svn_error_t *
 fold_change(apr_hash_t *changed_paths,
+            apr_hash_t *deletions,
             const change_t *change)
 {
   apr_pool_t *pool = apr_hash_pool_get(changed_paths);
@@ -686,7 +675,7 @@ fold_change(apr_hash_t *changed_paths,
            _("Invalid change ordering: new node revision ID "
              "without delete"));
 
-      /* Sanity check: an add, replacement, move, or reset must be the first
+      /* Sanity check: an add, replacement, or reset must be the first
          thing to follow a deletion. */
       if ((old_change->change_kind == svn_fs_path_change_delete)
           && (! ((info->change_kind == svn_fs_path_change_replace)
@@ -711,7 +700,7 @@ fold_change(apr_hash_t *changed_paths,
         case svn_fs_path_change_reset:
           /* A reset here will simply remove the path change from the
              hash. */
-          old_change = NULL;
+          apr_hash_set(changed_paths, path->data, path->len, NULL);
           break;
 
         case svn_fs_path_change_delete:
@@ -719,31 +708,48 @@ fold_change(apr_hash_t *changed_paths,
             {
               /* If the path was introduced in this transaction via an
                  add, and we are deleting it, just remove the path
-                 altogether. */
-              old_change = NULL;
+                 altogether.  (The caller will delete any child paths.) */
+              apr_hash_set(changed_paths, path->data, path->len, NULL);
+            }
+          else if (old_change->change_kind == svn_fs_path_change_replace)
+            {
+              /* A deleting a 'replace' restore the original deletion. */
+              new_change = apr_hash_get(deletions, path->data, path->len);
+              SVN_ERR_ASSERT(new_change);
+              apr_hash_set(changed_paths, path->data, path->len, new_change);
             }
           else
             {
-              /* A deletion overrules all previous changes. */
-              old_change->change_kind = svn_fs_path_change_delete;
-              old_change->text_mod = info->text_mod;
-              old_change->prop_mod = info->prop_mod;
-              old_change->mergeinfo_mod = info->mergeinfo_mod;
-              old_change->copyfrom_rev = SVN_INVALID_REVNUM;
-              old_change->copyfrom_path = NULL;
+              /* A deletion overrules a previous change (modify). */
+              new_change = path_change_dup(info, pool);
+              apr_hash_set(changed_paths, path->data, path->len, new_change);
             }
           break;
 
         case svn_fs_path_change_add:
         case svn_fs_path_change_replace:
           /* An add at this point must be following a previous delete,
-             so treat it just like a replace. */
-          replace_change(old_change, info, pool);
-          old_change->change_kind = svn_fs_path_change_replace;
+             so treat it just like a replace.  Remember the original
+             deletion such that we are able to delete this path again
+             (the replacement may have changed node kind and id). */
+          new_change = path_change_dup(info, pool);
+          new_change->change_kind = svn_fs_path_change_replace;
+
+          apr_hash_set(changed_paths, path->data, path->len, new_change);
+
+          /* Remember the original change.
+           * Make sure to allocate the hash key in a durable pool. */
+          apr_hash_set(deletions,
+                       apr_pstrmemdup(apr_hash_pool_get(deletions),
+                                      path->data, path->len),
+                       path->len, old_change);
           break;
 
         case svn_fs_path_change_modify:
         default:
+          /* If the new change modifies some attribute of the node, set
+             the corresponding flag, whether it already was set or not.
+             Note: We do not reset a flag to FALSE if a change is undone. */
           if (info->text_mod)
             old_change->text_mod = TRUE;
           if (info->prop_mod)
@@ -752,44 +758,44 @@ fold_change(apr_hash_t *changed_paths,
             old_change->mergeinfo_mod = svn_tristate_true;
           break;
         }
-
-      /* remove old_change from the cache if it is no longer needed. */
-      if (old_change == NULL)
-        apr_hash_set(changed_paths, path->data, path->len, NULL);
     }
   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 = apr_pmemdup(pool, info, sizeof(*new_change));
-      new_change->node_rev_id = svn_fs_fs__id_copy(info->node_rev_id, pool);
-      if (info->copyfrom_path)
-        new_change->copyfrom_path = apr_pstrdup(pool, info->copyfrom_path);
-
       /* Add this path.  The API makes no guarantees that this (new) key
-        will not be retained.  Thus, we copy the key into the target pool
-        to ensure a proper lifetime.  */
+         will not be retained.  Thus, we copy the key into the target pool
+         to ensure a proper lifetime.  */
       apr_hash_set(changed_paths,
                    apr_pstrmemdup(pool, path->data, path->len), path->len,
-                   new_change);
+                   path_change_dup(info, pool));
     }
 
   return SVN_NO_ERROR;
 }
 
+/* Baton type to be used with process_changes(). */
+typedef struct process_changes_baton_t
+{
+  /* Folded list of path changes. */
+  apr_hash_t *changed_paths;
+
+  /* Path changes that are deletions and have been turned into
+     replacements.  If those replacements get deleted again, this
+     container contains the record that we have to revert to. */
+  apr_hash_t *deletions;
+} process_changes_baton_t;
+
 /* An implementation of svn_fs_fs__change_receiver_t.
    Examine all the changed path entries in CHANGES and store them in
    *CHANGED_PATHS.  Folding is done to remove redundant or unnecessary
    data. Do all allocations in POOL. */
 static svn_error_t *
-process_changes(void *baton,
+process_changes(void *baton_p,
                 change_t *change,
                 apr_pool_t *scratch_pool)
 {
-  apr_hash_t *changed_paths = baton;
+  process_changes_baton_t *baton = baton_p;
 
-  SVN_ERR(fold_change(changed_paths, change));
+  SVN_ERR(fold_change(baton->changed_paths, baton->deletions, change));
 
   /* Now, if our change was a deletion or replacement, we have to
      blow away any changes thus far on paths that are (or, were)
@@ -820,14 +826,15 @@ process_changes(void *baton,
          The number of changes to process may be >> 1000.
          Therefore, keep the inner loop as tight as possible.
       */
-      for (hi = apr_hash_first(scratch_pool, changed_paths);
+      for (hi = apr_hash_first(scratch_pool, baton->changed_paths);
            hi;
            hi = apr_hash_next(hi))
         {
           /* KEY is the path. */
           const void *path;
           apr_ssize_t klen;
-          apr_hash_this(hi, &path, &klen, NULL);
+          svn_fs_path_change2_t *old_change;
+          apr_hash_this(hi, &path, &klen, (void**)&old_change);
 
           /* If we come across a child of our path, remove it.
              Call svn_fspath__skip_ancestor only if there is a chance that
@@ -839,7 +846,9 @@ process_changes(void *baton,
 
               child = svn_fspath__skip_ancestor(change->path.data, path);
               if (child && child[0] != '\0')
-                apr_hash_set(changed_paths, path, klen, NULL);
+                {
+                  apr_hash_set(baton->changed_paths, path, klen, NULL);
+                }
             }
         }
     }
@@ -856,6 +865,10 @@ svn_fs_fs__txn_changes_fetch(apr_hash_t 
   apr_file_t *file;
   apr_hash_t *changed_paths = apr_hash_make(pool);
   apr_pool_t *scratch_pool = svn_pool_create(pool);
+  process_changes_baton_t baton;
+
+  baton.changed_paths = changed_paths;
+  baton.deletions = apr_hash_make(scratch_pool);
 
   SVN_ERR(svn_io_file_open(&file,
                            path_txn_changes(fs, txn_id, scratch_pool),
@@ -865,7 +878,7 @@ svn_fs_fs__txn_changes_fetch(apr_hash_t 
   SVN_ERR(svn_fs_fs__read_changes_incrementally(
                                   svn_stream_from_aprfile2(file, TRUE,
                                                            scratch_pool),
-                                  process_changes, changed_paths,
+                                  process_changes, &baton,
                                   scratch_pool));
   svn_pool_destroy(scratch_pool);
 
@@ -998,12 +1011,7 @@ create_txn_dir(const char **id_p,
   txn_id->number = cb.txn_number;
 
   *id_p = svn_fs_fs__id_txn_unparse(txn_id, pool);
-  txn_dir = svn_dirent_join_many(pool,
-                                 fs->path,
-                                 PATH_TXNS_DIR,
-                                 apr_pstrcat(pool, *id_p, PATH_EXT_TXN,
-                                             SVN_VA_NULL),
-                                 SVN_VA_NULL);
+  txn_dir = svn_fs_fs__path_txn_dir(fs, txn_id, pool);
 
   return svn_io_dir_make(txn_dir, APR_OS_DEFAULT, pool);
 }
@@ -1026,8 +1034,8 @@ create_txn_dir_pre_1_5(const char **id_p
   const char *unique_path, *prefix;
 
   /* Try to create directories named "<txndir>/<rev>-<uniqueifier>.txn". */
-  prefix = svn_dirent_join_many(pool, fs->path, PATH_TXNS_DIR,
-                                apr_psprintf(pool, "%ld", rev), SVN_VA_NULL);
+  prefix = svn_dirent_join(svn_fs_fs__path_txns_dir(fs, pool),
+                           apr_psprintf(pool, "%ld", rev), pool);
 
   subpool = svn_pool_create(pool);
   for (i = 1; i <= 99999; i++)
@@ -1590,8 +1598,10 @@ svn_fs_fs__add_change(svn_fs_t *fs,
                         ? svn_tristate_true
                         : svn_tristate_false;
   change->node_kind = node_kind;
+  change->copyfrom_known = TRUE;
   change->copyfrom_rev = copyfrom_rev;
-  change->copyfrom_path = apr_pstrdup(pool, copyfrom_path);
+  if (copyfrom_path)
+    change->copyfrom_path = apr_pstrdup(pool, copyfrom_path);
 
   svn_hash_sets(changes, path, change);
   SVN_ERR(svn_fs_fs__write_changes(svn_stream_from_aprfile2(file, TRUE, pool),
@@ -1697,7 +1707,7 @@ allocate_item_index(apr_uint64_t *item_i
         *item_index = SVN_FS_FS__ITEM_INDEX_FIRST_USER;
 
       to_write = svn__ui64toa(buffer, *item_index + 1);
-      SVN_ERR(svn_io_file_seek(file, SEEK_SET, &offset, pool));
+      SVN_ERR(svn_io_file_seek(file, APR_SET, &offset, pool));
       SVN_ERR(svn_io_file_write_full(file, buffer, to_write, NULL, pool));
       SVN_ERR(svn_io_file_close(file, pool));
 
@@ -2519,7 +2529,7 @@ write_container_rep(representation_t *re
                     collection_writer_t writer,
                     svn_fs_t *fs,
                     apr_hash_t *reps_hash,
-                    int item_type,
+                    apr_uint32_t item_type,
                     svn_revnum_t final_revision,
                     apr_pool_t *scratch_pool)
 {
@@ -2618,7 +2628,7 @@ write_container_delta_rep(representation
                           svn_fs_t *fs,
                           node_revision_t *noderev,
                           apr_hash_t *reps_hash,
-                          int item_type,
+                          apr_uint32_t item_type,
                           svn_revnum_t final_revision,
                           apr_pool_t *scratch_pool)
 {
@@ -2956,9 +2966,9 @@ write_final_rev(const svn_fs_id_t **new_
   if (noderev->prop_rep && is_txn_rep(noderev->prop_rep))
     {
       apr_hash_t *proplist;
-      int item_type = noderev->kind == svn_node_dir
-                    ? SVN_FS_FS__ITEM_TYPE_DIR_PROPS
-                    : SVN_FS_FS__ITEM_TYPE_FILE_PROPS;
+      apr_uint32_t item_type = noderev->kind == svn_node_dir
+                             ? SVN_FS_FS__ITEM_TYPE_DIR_PROPS
+                             : SVN_FS_FS__ITEM_TYPE_FILE_PROPS;
       SVN_ERR(svn_fs_fs__get_proplist(&proplist, fs, noderev, pool));
 
       noderev->prop_rep->revision = rev;
@@ -3584,20 +3594,25 @@ svn_fs_fs__add_index_data(svn_fs_t *fs,
   apr_off_t p2l_offset;
   svn_stringbuf_t *footer;
   unsigned char footer_length;
+  svn_checksum_t *l2p_checksum;
+  svn_checksum_t *p2l_checksum;
 
   /* Append the actual index data to the pack file. */
   l2p_offset = 0;
   SVN_ERR(svn_io_file_seek(file, APR_END, &l2p_offset, pool));
-  SVN_ERR(svn_fs_fs__l2p_index_append(fs, file, l2p_proto_index, revision,
-                                      pool));
+  SVN_ERR(svn_fs_fs__l2p_index_append(&l2p_checksum, fs, file,
+                                      l2p_proto_index, revision,
+                                      pool, pool));
 
   p2l_offset = 0;
   SVN_ERR(svn_io_file_seek(file, APR_END, &p2l_offset, pool));
-  SVN_ERR(svn_fs_fs__p2l_index_append(fs, file, p2l_proto_index, revision,
-                                      pool));
+  SVN_ERR(svn_fs_fs__p2l_index_append(&p2l_checksum, fs, file,
+                                      p2l_proto_index, revision,
+                                      pool, pool));
 
   /* Append footer. */
-  footer = svn_fs_fs__unparse_footer(l2p_offset, p2l_offset, pool);
+  footer = svn_fs_fs__unparse_footer(l2p_offset, l2p_checksum, 
+                                     p2l_offset, p2l_checksum, pool, pool);
   SVN_ERR(svn_io_file_write_full(file, footer->data, footer->len, NULL,
                                  pool));
 
@@ -3638,6 +3653,22 @@ commit_body(void *baton, apr_pool_t *poo
   const svn_fs_fs__id_part_t *txn_id = svn_fs_fs__txn_get_id(cb->txn);
   apr_hash_t *changed_paths;
 
+  /* Re-Read the current repository format.  All our repo upgrade and
+     config evaluation strategies are such that existing information in
+     FS and FFD remains valid.
+
+     Although we don't recommend upgrading hot repositories, people may
+     still do it and we must make sure to either handle them gracefully
+     or to error out.
+
+     Committing pre-format 3 txns will fail after upgrade to format 3+
+     because the proto-rev cannot be found; no further action needed.
+     Upgrades from pre-f7 to f7+ means a potential change in addressing
+     mode for the final rev.  We must be sure to detect that cause because
+     the failure would only manifest once the new revision got committed.
+   */
+  SVN_ERR(svn_fs_fs__read_format_file(cb->fs, pool));
+
   /* Read the current youngest revision and, possibly, the next available
      node id and copy id (for old format filesystems).  Update the cached
      value for the youngest revision, because we have just checked it. */
@@ -3889,7 +3920,7 @@ svn_fs_fs__list_transactions(apr_array_h
   names = apr_array_make(pool, 1, sizeof(const char *));
 
   /* Get the transactions directory. */
-  txn_dir = svn_dirent_join(fs->path, PATH_TXNS_DIR, pool);
+  txn_dir = svn_fs_fs__path_txns_dir(fs, pool);
 
   /* Now find a listing of this directory. */
   SVN_ERR(svn_io_get_dirents3(&dirents, txn_dir, TRUE, pool, pool));

Modified: subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/tree.c?rev=1634609&r1=1634608&r2=1634609&view=diff
==============================================================================
--- subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/move-tracking-2/subversion/libsvn_fs_fs/tree.c Mon Oct 27 17:28:13 2014
@@ -1537,7 +1537,7 @@ fs_change_node_prop(svn_fs_root_t *root,
   parent_path_t *parent_path;
   apr_hash_t *proplist;
   const svn_fs_fs__id_part_t *txn_id;
-  svn_boolean_t modeinfo_mod = FALSE;
+  svn_boolean_t mergeinfo_mod = FALSE;
 
   if (! root->is_txn_root)
     return SVN_FS__NOT_TXN(root);
@@ -1582,7 +1582,7 @@ fs_change_node_prop(svn_fs_root_t *root,
                                                    (value != NULL), pool));
         }
 
-      modeinfo_mod = TRUE;
+      mergeinfo_mod = TRUE;
     }
 
   /* Set the property. */
@@ -1595,7 +1595,7 @@ fs_change_node_prop(svn_fs_root_t *root,
   /* Make a record of this modification in the changes table. */
   return add_change(root->fs, txn_id, path,
                     svn_fs_fs__dag_get_id(parent_path->node),
-                    svn_fs_path_change_modify, FALSE, TRUE, modeinfo_mod,
+                    svn_fs_path_change_modify, FALSE, TRUE, mergeinfo_mod,
                     svn_fs_fs__dag_node_kind(parent_path->node),
                     SVN_INVALID_REVNUM, NULL, pool);
 }
@@ -4338,10 +4338,12 @@ stringify_node(dag_node_t *node,
 
 /* Check metadata sanity on NODE, and on its children.  Manually verify
    information for DAG nodes in revision REV, and trust the metadata
-   accuracy for nodes belonging to older revisions. */
+   accuracy for nodes belonging to older revisions.  To detect cycles,
+   provide all parent dag_node_t * in PARENT_NODES. */
 static svn_error_t *
 verify_node(dag_node_t *node,
             svn_revnum_t rev,
+            apr_array_header_t *parent_nodes,
             apr_pool_t *pool)
 {
   svn_boolean_t has_mergeinfo;
@@ -4351,6 +4353,18 @@ verify_node(dag_node_t *node,
   int pred_count;
   svn_node_kind_t kind;
   apr_pool_t *iterpool = svn_pool_create(pool);
+  int i;
+
+  /* Detect (non-)DAG cycles. */
+  for (i = 0; i < parent_nodes->nelts; ++i)
+    {
+      dag_node_t *parent = APR_ARRAY_IDX(parent_nodes, i, dag_node_t *);
+      if (svn_fs_fs__id_eq(svn_fs_fs__dag_get_id(parent),
+                           svn_fs_fs__dag_get_id(node)))
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                                "Node is its own direct or indirect parent '%s'",
+                                stringify_node(node, iterpool));
+    }
 
   /* Fetch some data. */
   SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, node));
@@ -4402,8 +4416,8 @@ verify_node(dag_node_t *node,
   if (kind == svn_node_dir)
     {
       apr_array_header_t *entries;
-      int i;
       apr_int64_t children_mergeinfo = 0;
+      APR_ARRAY_PUSH(parent_nodes, dag_node_t*) = node;
 
       SVN_ERR(svn_fs_fs__dag_dir_entries(&entries, node, pool));
 
@@ -4422,7 +4436,7 @@ verify_node(dag_node_t *node,
             {
               SVN_ERR(svn_fs_fs__dag_get_node(&child, fs, dirent->id,
                                               iterpool));
-              SVN_ERR(verify_node(child, rev, iterpool));
+              SVN_ERR(verify_node(child, rev, parent_nodes, iterpool));
               SVN_ERR(svn_fs_fs__dag_get_mergeinfo_count(&child_mergeinfo,
                                                          child));
             }
@@ -4447,6 +4461,10 @@ verify_node(dag_node_t *node,
                                  stringify_node(node, iterpool),
                                  mergeinfo_count, has_mergeinfo,
                                  children_mergeinfo);
+
+      /* If we don't make it here, there was an error / corruption.
+       * In that case, nobody will need PARENT_NODES anymore. */
+      apr_array_pop(parent_nodes);
     }
 
   svn_pool_destroy(iterpool);
@@ -4459,6 +4477,7 @@ svn_fs_fs__verify_root(svn_fs_root_t *ro
 {
   svn_fs_t *fs = root->fs;
   dag_node_t *root_dir;
+  apr_array_header_t *parent_nodes;
 
   /* Issue #4129: bogus pred-counts and minfo-cnt's on the root node-rev
      (and elsewhere).  This code makes more thorough checks than the
@@ -4482,7 +4501,8 @@ svn_fs_fs__verify_root(svn_fs_root_t *ro
     }
 
   /* Recursively verify ROOT_DIR. */
-  SVN_ERR(verify_node(root_dir, root->rev, pool));
+  parent_nodes = apr_array_make(pool, 16, sizeof(dag_node_t *));
+  SVN_ERR(verify_node(root_dir, root->rev, parent_nodes, pool));
 
   /* Verify explicitly the predecessor of the root. */
   {



Mime
View raw message