subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From stef...@apache.org
Subject svn commit: r1687045 [8/31] - in /subversion/branches/svn-mergeinfo-normalizer: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ doc/ subversion/bindings/javahl/ subversion/bindings/javahl/native/ subversion/bindings/javahl/native...
Date Tue, 23 Jun 2015 12:55:47 GMT
Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.c Tue Jun 23 12:55:43 2015
@@ -286,6 +286,114 @@ use_block_read(svn_fs_t *fs)
   return svn_fs_fs__use_log_addressing(fs) && ffd->use_block_read;
 }
 
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+                               representation_t *rep,
+                               apr_pool_t *scratch_pool)
+{
+  svn_checksum_t checksum;
+  svn_checksum_t *empty_md5;
+  svn_fs_fs__revision_file_t *revision_file;
+  svn_fs_fs__rep_header_t *rep_header;
+
+  /* Anything to do at all?
+   *
+   * Note that a 0 SIZE is only possible for PLAIN reps due to the SVN\1
+   * magic prefix in any DELTA rep. */
+  if (!rep || rep->expanded_size != 0 || rep->size == 0)
+    return SVN_NO_ERROR;
+
+  /* This function may only be called for committed data. */
+  assert(!svn_fs_fs__id_txn_used(&rep->txn_id));
+
+  /* EXPANDED_SIZE is 0. If the MD5 does not match the one for empty
+   * contents, we know that EXPANDED_SIZE == 0 is wrong and needs to
+   * be set to the actual value given by SIZE.
+   *
+   * Using svn_checksum_match() will also accept all-zero values for
+   * the MD5 digest and only report a mismatch if the MD5 has actually
+   * been given. */
+  empty_md5 = svn_checksum_empty_checksum(svn_checksum_md5, scratch_pool);
+
+  checksum.digest = rep->md5_digest;
+  checksum.kind = svn_checksum_md5;
+  if (!svn_checksum_match(empty_md5, &checksum))
+    {
+      rep->expanded_size = rep->size;
+      return SVN_NO_ERROR;
+    }
+
+  /* Data in the rep-cache.db does not have MD5 checksums (all zero) on it.
+   * Compare SHA1 instead. */
+  if (rep->has_sha1)
+    {
+      svn_checksum_t *empty_sha1
+        = svn_checksum_empty_checksum(svn_checksum_sha1, scratch_pool);
+
+      checksum.digest = rep->sha1_digest;
+      checksum.kind = svn_checksum_sha1;
+      if (!svn_checksum_match(empty_sha1, &checksum))
+        {
+          rep->expanded_size = rep->size;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  /* Only two cases are left here.
+   * (1) A non-empty PLAIN rep with a MD5 collision on EMPTY_MD5.
+   * (2) A DELTA rep with zero-length output. */
+
+  /* SVN always stores a DELTA rep with zero-length output as an empty
+   * sequence of txdelta windows, i.e. as "SVN\1".  In that case, SIZE is
+   * 4 bytes.  There is no other possible DELTA rep of that size and any
+   * PLAIN rep of 4 bytes would produce a different MD5.  Hence, if SIZE is
+   * actually 4 here, we know that this is an empty DELTA rep.
+   *
+   * Note that it is technically legal to have DELTA reps with a 0 length
+   * output window.  Their on-disk size would be longer.  We handle that
+   * case later together with the equally unlikely MD5 collision. */
+  if (rep->size == 4)
+    {
+      /* EXPANDED_SIZE is already 0. */
+      return SVN_NO_ERROR;
+    }
+
+  /* We still have the two options, PLAIN or DELTA rep.  At this point, we
+   * are in an extremely unlikely case and can spend some time to figure it
+   * out.  So, let's just look at the representation header. */
+  SVN_ERR(open_and_seek_revision(&revision_file, fs, rep->revision,
+                                 rep->item_index, scratch_pool));
+  SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, revision_file->stream,
+                                     scratch_pool, scratch_pool));
+  SVN_ERR(svn_fs_fs__close_revision_file(revision_file));
+
+  /* Only for PLAIN reps do we have to correct EXPANDED_SIZE. */
+  if (rep_header->type == svn_fs_fs__rep_plain)
+    rep->expanded_size = rep->size;
+
+  return SVN_NO_ERROR;
+}
+
+/* Correct known issues with committed NODEREV in FS.
+ * Uses SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+fixup_node_revision(svn_fs_t *fs,
+                    node_revision_t *noderev,
+                    apr_pool_t *scratch_pool)
+{
+  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
+  noderev->is_fresh_txn_root = FALSE;
+
+  /* Make sure EXPANDED_SIZE has the correct value for every rep. */
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->data_rep,
+                                         scratch_pool));
+  SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, noderev->prop_rep,
+                                         scratch_pool));
+
+  return SVN_NO_ERROR;
+}
+
 /* Get the node-revision for the node ID in FS.
    Set *NODEREV_P to the new node-revision structure, allocated in POOL.
    See svn_fs_fs__get_node_revision, which wraps this and adds another
@@ -376,9 +484,7 @@ get_node_revision_body(node_revision_t *
                                           revision_file->stream,
                                           result_pool,
                                           scratch_pool));
-
-          /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-          (*noderev_p)->is_fresh_txn_root = FALSE;
+          SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
 
           /* The noderev is not in cache, yet. Add it, if caching has been enabled. */
           if (ffd->node_revision_cache)
@@ -765,9 +871,7 @@ create_rep_state_body(rep_state_t **rep_
      Since we don't know the depth of the delta chain, let's assume, the
      whole contents get rewritten 3 times.
    */
-  estimated_window_storage
-    = 4 * (  (rep->expanded_size ? rep->expanded_size : rep->size)
-           + SVN_DELTA_WINDOW_SIZE);
+  estimated_window_storage = 4 * (rep->expanded_size + SVN_DELTA_WINDOW_SIZE);
   estimated_window_storage = MIN(estimated_window_storage, APR_SIZE_MAX);
 
   rs->window_cache =    ffd->txdelta_window_cache
@@ -952,7 +1056,7 @@ svn_fs_fs__check_rep(representation_t *r
       if (   entry == NULL
           || entry->type < SVN_FS_FS__ITEM_TYPE_FILE_REP
           || entry->type > SVN_FS_FS__ITEM_TYPE_DIR_PROPS)
-        return svn_error_createf(SVN_ERR_REPOS_CORRUPTED, NULL,
+        return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  _("No representation found at offset %s "
                                    "for item %s in revision %ld"),
                                  apr_off_t_toa(scratch_pool, offset),
@@ -1322,15 +1426,11 @@ set_cached_combined_window(svn_stringbuf
    ID, and representation REP.
    Also, set *WINDOW_P to the base window content for *LIST, if it
    could be found in cache. Otherwise, *LIST will contain the base
-   representation for the whole delta chain.
-   Finally, return the expanded size of the representation in
-   *EXPANDED_SIZE. It will take care of cases where only the on-disk
-   size is known.  */
+   representation for the whole delta chain. */
 static svn_error_t *
 build_rep_list(apr_array_header_t **list,
                svn_stringbuf_t **window_p,
                rep_state_t **src_state,
-               svn_filesize_t *expanded_size,
                svn_fs_t *fs,
                representation_t *first_rep,
                apr_pool_t *pool)
@@ -1345,24 +1445,9 @@ build_rep_list(apr_array_header_t **list
   *list = apr_array_make(pool, 1, sizeof(rep_state_t *));
   rep = *first_rep;
 
-  /* The value as stored in the data struct.
-     0 is either for unknown length or actually zero length. */
-  *expanded_size = first_rep->expanded_size;
-
   /* for the top-level rep, we need the rep_args */
   SVN_ERR(create_rep_state(&rs, &rep_header, &shared_file, &rep, fs, pool,
                            iterpool));
-
-  /* Unknown size or empty representation?
-     That implies the this being the first iteration.
-     Usually size equals on-disk size, except for empty,
-     compressed representations (delta, size = 4).
-     Please note that for all non-empty deltas have
-     a 4-byte header _plus_ some data. */
-  if (*expanded_size == 0)
-    if (rep_header->type == svn_fs_fs__rep_plain || first_rep->size != 4)
-      *expanded_size = first_rep->size;
-
   while (1)
     {
       svn_pool_clear(iterpool);
@@ -1624,9 +1709,11 @@ get_combined_window(svn_stringbuf_t **re
       /* Maybe, we've got a PLAIN start representation.  If we do, read
          as much data from it as the needed for the txdelta window's source
          view.
-         Note that BUF / SOURCE may only be NULL in the first iteration. */
+         Note that BUF / SOURCE may only be NULL in the first iteration.
+         Also note that we may have short-cut reading the delta chain --
+         in which case SRC_OPS is 0 and it might not be a PLAIN rep. */
       source = buf;
-      if (source == NULL && rb->src_state != NULL)
+      if (source == NULL && rb->src_state != NULL && window->src_ops)
         SVN_ERR(read_plain_window(&source, rb->src_state, window->sview_len,
                                   pool, iterpool));
 
@@ -1664,7 +1751,7 @@ get_combined_window(svn_stringbuf_t **re
 }
 
 /* Returns whether or not the expanded fulltext of the file is cachable
- * based on its size SIZE.  The decision depends on the cache used by RB.
+ * based on its size SIZE.  The decision depends on the cache used by FFD.
  */
 static svn_boolean_t
 fulltext_size_is_cachable(fs_fs_data_t *ffd, svn_filesize_t size)
@@ -1997,8 +2084,9 @@ rep_read_contents(void *baton,
   if (!rb->rs_list)
     {
       /* Window stream not initialized, yet.  Do it now. */
+      rb->len = rb->rep.expanded_size;
       SVN_ERR(build_rep_list(&rb->rs_list, &rb->base_window,
-                             &rb->src_state, &rb->len, rb->fs, &rb->rep,
+                             &rb->src_state, rb->fs, &rb->rep,
                              rb->filehandle_pool));
 
       /* In case we did read from the fulltext cache before, make the
@@ -2065,7 +2153,6 @@ svn_fs_fs__get_contents(svn_stream_t **c
   else
     {
       fs_fs_data_t *ffd = fs->fsap_data;
-      svn_filesize_t len = rep->expanded_size ? rep->expanded_size : rep->size;
       struct rep_read_baton *rb;
 
       pair_cache_key_t fulltext_cache_key = { 0 };
@@ -2081,7 +2168,7 @@ svn_fs_fs__get_contents(svn_stream_t **c
        * cache it. */
       if (ffd->fulltext_cache && cache_fulltext
           && SVN_IS_VALID_REVNUM(rep->revision)
-          && fulltext_size_is_cachable(ffd, len))
+          && fulltext_size_is_cachable(ffd, rep->expanded_size))
         {
           rb->fulltext_cache = ffd->fulltext_cache;
         }
@@ -2437,11 +2524,41 @@ read_dir_entries(apr_array_header_t *ent
   return SVN_NO_ERROR;
 }
 
-/* Fetch the contents of a directory into ENTRIES.  Values are stored
+/* For directory NODEREV in FS, return the *FILESIZE of its in-txn
+ * representation.  If the directory representation is comitted data,
+ * set *FILESIZE to SVN_INVALID_FILESIZE. Use SCRATCH_POOL for temporaries.
+ */
+static svn_error_t *
+get_txn_dir_info(svn_filesize_t *filesize,
+                 svn_fs_t *fs,
+                 node_revision_t *noderev,
+                 apr_pool_t *scratch_pool)
+{
+  if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
+    {
+      const svn_io_dirent2_t *dirent;
+      const char *filename;
+
+      filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+                                                   scratch_pool);
+
+      SVN_ERR(svn_io_stat_dirent2(&dirent, filename, FALSE, FALSE,
+                                  scratch_pool, scratch_pool));
+      *filesize = dirent->filesize;
+    }
+  else
+    {
+      *filesize = SVN_INVALID_FILESIZE;
+    }
+
+  return SVN_NO_ERROR;
+}
+
+/* Fetch the contents of a directory into DIR.  Values are stored
    as filename to string mappings; further conversion is necessary to
    convert them into svn_fs_dirent_t values. */
 static svn_error_t *
-get_dir_contents(apr_array_header_t **entries,
+get_dir_contents(svn_fs_fs__dir_data_t *dir,
                  svn_fs_t *fs,
                  node_revision_t *noderev,
                  apr_pool_t *result_pool,
@@ -2449,18 +2566,31 @@ get_dir_contents(apr_array_header_t **en
 {
   svn_stream_t *contents;
 
-  *entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
+  /* Initialize the result. */
+  dir->entries = apr_array_make(result_pool, 16, sizeof(svn_fs_dirent_t *));
+  dir->txn_filesize = SVN_INVALID_FILESIZE;
+
+  /* Read dir contents - unless there is none in which case we are done. */
   if (noderev->data_rep && svn_fs_fs__id_txn_used(&noderev->data_rep->txn_id))
     {
-      const char *filename
-        = svn_fs_fs__path_txn_node_children(fs, noderev->id, scratch_pool);
+      /* Get location & current size of the directory representation. */
+      const char *filename;
+      apr_file_t *file;
+
+      filename = svn_fs_fs__path_txn_node_children(fs, noderev->id,
+                                                   scratch_pool);
 
       /* The representation is mutable.  Read the old directory
          contents from the mutable children file, followed by the
          changes we've made in this transaction. */
-      SVN_ERR(svn_stream_open_readonly(&contents, filename, scratch_pool,
-                                       scratch_pool));
-      SVN_ERR(read_dir_entries(*entries, contents, TRUE, noderev->id,
+      SVN_ERR(svn_io_file_open(&file, filename, APR_READ | APR_BUFFERED,
+                               APR_OS_DEFAULT, scratch_pool));
+
+      /* Obtain txn children file size. */
+      SVN_ERR(svn_io_file_size_get(&dir->txn_filesize, file, scratch_pool));
+
+      contents = svn_stream_from_aprfile2(file, FALSE, scratch_pool);
+      SVN_ERR(read_dir_entries(dir->entries, contents, TRUE, noderev->id,
                                result_pool, scratch_pool));
       SVN_ERR(svn_stream_close(contents));
     }
@@ -2469,9 +2599,7 @@ get_dir_contents(apr_array_header_t **en
       /* Undeltify content before parsing it. Otherwise, we could only
        * parse it byte-by-byte.
        */
-      apr_size_t len = noderev->data_rep->expanded_size
-                     ? (apr_size_t)noderev->data_rep->expanded_size
-                     : (apr_size_t)noderev->data_rep->size;
+      apr_size_t len = noderev->data_rep->expanded_size;
       svn_stringbuf_t *text;
 
       /* The representation is immutable.  Read it normally. */
@@ -2482,7 +2610,7 @@ get_dir_contents(apr_array_header_t **en
 
       /* de-serialize hash */
       contents = svn_stream_from_stringbuf(text, scratch_pool);
-      SVN_ERR(read_dir_entries(*entries, contents, FALSE,  noderev->id,
+      SVN_ERR(read_dir_entries(dir->entries, contents, FALSE, noderev->id,
                                result_pool, scratch_pool));
     }
 
@@ -2538,6 +2666,7 @@ svn_fs_fs__rep_contents_dir(apr_array_he
 {
   pair_cache_key_t pair_key = { 0 };
   const void *key;
+  svn_fs_fs__dir_data_t *dir;
 
   /* find the cache we may use */
   svn_cache__t *cache = locate_dir_cache(fs, &key, &pair_key, noderev,
@@ -2546,19 +2675,32 @@ svn_fs_fs__rep_contents_dir(apr_array_he
     {
       svn_boolean_t found;
 
-      SVN_ERR(svn_cache__get((void **)entries_p, &found, cache, key,
+      SVN_ERR(svn_cache__get((void **)&dir, &found, cache, key,
                              result_pool));
       if (found)
-        return SVN_NO_ERROR;
+        {
+          /* Verify that the cached dir info is not stale
+           * (no-op for committed data). */
+          svn_filesize_t filesize;
+          SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
+          if (filesize == dir->txn_filesize)
+            {
+              /* Still valid. Done. */
+              *entries_p = dir->entries;
+              return SVN_NO_ERROR;
+            }
+        }
     }
 
   /* Read in the directory contents. */
-  SVN_ERR(get_dir_contents(entries_p, fs, noderev, result_pool,
-                           scratch_pool));
+  dir = apr_pcalloc(scratch_pool, sizeof(*dir));
+  SVN_ERR(get_dir_contents(dir, fs, noderev, result_pool, scratch_pool));
+  *entries_p = dir->entries;
 
   /* Update the cache, if we are to use one. */
   if (cache)
-    SVN_ERR(svn_cache__set(cache, key, *entries_p, scratch_pool));
+    SVN_ERR(svn_cache__set(cache, key, dir, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2590,30 +2732,40 @@ svn_fs_fs__rep_contents_dir_entry(svn_fs
                                          scratch_pool);
   if (cache)
     {
+      extract_dir_entry_baton_t baton;
+
+      svn_filesize_t filesize;
+      SVN_ERR(get_txn_dir_info(&filesize, fs, noderev, scratch_pool));
+
       /* Cache lookup. */
+      baton.txn_filesize = filesize;
+      baton.name = name;
       SVN_ERR(svn_cache__get_partial((void **)dirent,
                                      &found,
                                      cache,
                                      key,
                                      svn_fs_fs__extract_dir_entry,
-                                     (void*)name,
+                                     &baton,
                                      result_pool));
     }
 
   /* fetch data from disk if we did not find it in the cache */
   if (! found)
     {
-      apr_array_header_t *entries;
       svn_fs_dirent_t *entry;
       svn_fs_dirent_t *entry_copy = NULL;
+      svn_fs_fs__dir_data_t dir;
 
-      /* read the dir from the file system. It will probably be put it
-         into the cache for faster lookup in future calls. */
-      SVN_ERR(svn_fs_fs__rep_contents_dir(&entries, fs, noderev,
-                                          scratch_pool, scratch_pool));
+      /* Read in the directory contents. */
+      SVN_ERR(get_dir_contents(&dir, fs, noderev, scratch_pool,
+                               scratch_pool));
+
+      /* Update the cache, if we are to use one. */
+      if (cache)
+        SVN_ERR(svn_cache__set(cache, key, &dir, scratch_pool));
 
       /* find desired entry and return a copy in POOL, if found */
-      entry = svn_fs_fs__find_dir_entry(entries, name, NULL);
+      entry = svn_fs_fs__find_dir_entry(dir.entries, name, NULL);
       if (entry)
         {
           entry_copy = apr_palloc(result_pool, sizeof(*entry_copy));
@@ -2639,16 +2791,27 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
 
   if (noderev->prop_rep && svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
     {
+      svn_error_t *err;
       const char *filename
         = svn_fs_fs__path_txn_node_props(fs, noderev->id, pool);
       proplist = apr_hash_make(pool);
 
       SVN_ERR(svn_stream_open_readonly(&stream, filename, pool, pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+      err = svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool);
+      if (err)
+        {
+          svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+          err = svn_error_compose_create(err, svn_stream_close(stream));
+          return svn_error_quick_wrapf(err,
+                   _("malformed property list for node-revision '%s' in '%s'"),
+                   id_str->data, filename);
+        }
       SVN_ERR(svn_stream_close(stream));
     }
   else if (noderev->prop_rep)
     {
+      svn_error_t *err;
       fs_fs_data_t *ffd = fs->fsap_data;
       representation_t *rep = noderev->prop_rep;
       pair_cache_key_t key = { 0 };
@@ -2667,7 +2830,16 @@ svn_fs_fs__get_proplist(apr_hash_t **pro
       proplist = apr_hash_make(pool);
       SVN_ERR(svn_fs_fs__get_contents(&stream, fs, noderev->prop_rep, FALSE,
                                       pool));
-      SVN_ERR(svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool));
+      err = svn_hash_read2(proplist, stream, SVN_HASH_TERMINATOR, pool);
+      if (err)
+        {
+          svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+          err = svn_error_compose_create(err, svn_stream_close(stream));
+          return svn_error_quick_wrapf(err,
+                   _("malformed property list for node-revision '%s'"),
+                   id_str->data);
+        }
       SVN_ERR(svn_stream_close(stream));
 
       if (ffd->properties_cache && SVN_IS_VALID_REVNUM(rep->revision))
@@ -3200,9 +3372,7 @@ block_read_noderev(node_revision_t **nod
   /* read node rev from revision file */
   SVN_ERR(svn_fs_fs__read_noderev(noderev_p, stream,
                                   result_pool, scratch_pool));
-
-  /* Workaround issue #4031: is-fresh-txn-root in revision files. */
-  (*noderev_p)->is_fresh_txn_root = FALSE;
+  SVN_ERR(fixup_node_revision(fs, *noderev_p, scratch_pool));
 
   if (ffd->node_revision_cache)
     SVN_ERR(svn_cache__set(ffd->node_revision_cache, &key, *noderev_p,

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/cached_data.h Tue Jun 23 12:55:43 2015
@@ -30,6 +30,18 @@
 
 
 
+/* Resolve a FSFS quirk: if REP in FS is a "PLAIN" representation, its
+ * EXPANDED_SIZE element may be 0, in which case its value has to be taken
+ * from SIZE.
+ *
+ * This function ensures that EXPANDED_SIZE in REP always contains the
+ * actual value. No-op if REP is NULL.  Uses SCRATCH_POOL for temporaries.
+ */
+svn_error_t *
+svn_fs_fs__fixup_expanded_size(svn_fs_t *fs,
+                               representation_t *rep,
+                               apr_pool_t *scratch_pool);
+
 /* Set *NODEREV_P to the node-revision for the node ID in FS.  Do any
    allocations in POOL. */
 svn_error_t *

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.c Tue Jun 23 12:55:43 2015
@@ -498,6 +498,40 @@ svn_fs_fs__dag_get_proplist(apr_hash_t *
   return SVN_NO_ERROR;
 }
 
+svn_error_t *
+svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+                         dag_node_t *node,
+                         apr_pool_t *scratch_pool)
+{
+  node_revision_t *noderev;
+
+  SVN_ERR(get_node_revision(&noderev, node));
+
+  if (! noderev->prop_rep)
+    {
+      *has_props = FALSE; /* Easy out */
+      return SVN_NO_ERROR;
+    }
+
+  if (svn_fs_fs__id_txn_used(&noderev->prop_rep->txn_id))
+    {
+      /* We are in a commit or something. Check actual properties */
+      apr_hash_t *proplist;
+
+      SVN_ERR(svn_fs_fs__get_proplist(&proplist, node->fs,
+                                      noderev, scratch_pool));
+
+      *has_props = proplist ? (0 < apr_hash_count(proplist)) : FALSE;
+    }
+  else
+    {
+      /* Properties are stored as a standard hash stream,
+         always ending with "END\n" (4 bytes) */
+      *has_props = noderev->prop_rep->expanded_size > 4;
+    }
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_fs_fs__dag_set_proplist(dag_node_t *node,

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/dag.h Tue Jun 23 12:55:43 2015
@@ -177,6 +177,12 @@ svn_error_t *svn_fs_fs__dag_get_proplist
                                          dag_node_t *node,
                                          apr_pool_t *pool);
 
+/* Set *HAS_PROPS to TRUE if NODE has properties. Use SCRATCH_POOL
+   for temporary allocations */
+svn_error_t *svn_fs_fs__dag_has_props(svn_boolean_t *has_props,
+                                      dag_node_t *node,
+                                      apr_pool_t *scratch_pool);
+
 /* Set the property list of NODE to PROPLIST, allocating from POOL.
    The node being changed must be mutable.
 

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.c Tue Jun 23 12:55:43 2015
@@ -27,7 +27,6 @@
 #include <apr_general.h>
 #include <apr_pools.h>
 #include <apr_file_io.h>
-#include <apr_thread_mutex.h>
 
 #include "svn_fs.h"
 #include "svn_delta.h"
@@ -163,9 +162,11 @@ fs_freeze_body(void *baton,
 
   SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, b->fs, pool));
   if (exists)
-    SVN_ERR(svn_fs_fs__lock_rep_cache(b->fs, pool));
-
-  SVN_ERR(b->freeze_func(b->freeze_baton, pool));
+    SVN_ERR(svn_fs_fs__with_rep_cache_lock(b->fs,
+                                           b->freeze_func, b->freeze_baton,
+                                           pool));
+  else
+    SVN_ERR(b->freeze_func(b->freeze_baton, pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs.h Tue Jun 23 12:55:43 2015
@@ -527,7 +527,14 @@ typedef struct representation_t
   svn_filesize_t size;
 
   /* The size of the fulltext of the representation. If this is 0,
-   * the fulltext size is equal to representation size in the rev file, */
+   * for a plain rep, the real fulltext size is equal to the SIZE field.
+   * For a delta rep, this field is always the real fulltext size.
+   *
+   * Note that svn_fs_fs__fixup_expanded_size() checks for these special
+   * cases and ensures that this field contains the actual value.  We call
+   * it early after reading a representation struct, so most code does not
+   * have to worry about it.
+   */
   svn_filesize_t expanded_size;
 
   /* Is this a representation (still) within a transaction? */
@@ -616,6 +623,18 @@ typedef struct change_t
   svn_fs_path_change2_t info;
 } change_t;
 
+
+/*** Directory (only used at the cache interface) ***/
+typedef struct svn_fs_fs__dir_data_t
+{
+  /* Contents, i.e. all directory entries, sorted by name. */
+  apr_array_header_t *entries;
+
+  /* SVN_INVALID_FILESIZE for committed data, otherwise the length of the
+   * in-txn on-disk representation of that directory. */
+  svn_filesize_t txn_filesize;
+} svn_fs_fs__dir_data_t;
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs_fs.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/fs_fs.c Tue Jun 23 12:55:43 2015
@@ -1126,7 +1126,9 @@ 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), fs, pool);
+  ffd->youngest_rev_cache = 0;
+
+  return SVN_NO_ERROR;
 }
 
 /* Wrapper around svn_io_file_create which ignores EEXIST. */
@@ -1377,38 +1379,9 @@ svn_fs_fs__file_length(svn_filesize_t *l
       /* Treat "no representation" as "empty file". */
       *length = 0;
     }
-  else if (data_rep->expanded_size)
-    {
-      /* Standard case: a non-empty file. */
-      *length = data_rep->expanded_size;
-    }
   else
     {
-      /* Work around a FSFS format quirk (see issue #4554).
-
-         A plain representation may specify its EXPANDED LENGTH as "0"
-         in which case, the SIZE value is what we want.
-
-         Because EXPANDED_LENGTH will also be 0 for empty files, while
-         SIZE is non-null, we need to check wether the content is
-         actually empty.  We simply compare with the MD5 checksum of
-         empty content (sha-1 is not always available).
-       */
-      svn_checksum_t *empty_md5
-        = svn_checksum_empty_checksum(svn_checksum_md5, pool);
-
-      if (memcmp(empty_md5->digest, data_rep->md5_digest,
-                 sizeof(data_rep->md5_digest)))
-        {
-          /* Contents is not empty, i.e. EXPANDED_LENGTH cannot be the
-             actual file length. */
-          *length = data_rep->size;
-        }
-      else
-        {
-          /* Contents is empty. */
-          *length = 0;
-        }
+      *length = data_rep->expanded_size;
     }
 
   return SVN_NO_ERROR;
@@ -1944,7 +1917,10 @@ get_node_origins_from_file(svn_fs_t *fs,
 
   stream = svn_stream_from_aprfile2(fd, FALSE, pool);
   *node_origins = apr_hash_make(pool);
-  SVN_ERR(svn_hash_read2(*node_origins, stream, SVN_HASH_TERMINATOR, pool));
+  err = svn_hash_read2(*node_origins, stream, SVN_HASH_TERMINATOR, pool);
+  if (err)
+    return svn_error_quick_wrapf(err, _("malformed node origin data in '%s'"),
+                                 node_origins_file);
   return svn_stream_close(stream);
 }
 

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/hotcopy.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/hotcopy.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/hotcopy.c Tue Jun 23 12:55:43 2015
@@ -855,7 +855,6 @@ hotcopy_body(void *baton, apr_pool_t *po
                * ### so we have no way of just printing a warning via
                * ### the fs->warning() callback. */
 
-              const char *msg;
               const char *src_abspath;
               const char *dst_abspath;
               const char *config_relpath;
@@ -874,13 +873,12 @@ hotcopy_body(void *baton, apr_pool_t *po
               src_abspath = svn_dirent_dirname(src_abspath, pool);
               dst_abspath = svn_dirent_dirname(dst_abspath, pool);
 
-              msg = apr_psprintf(pool,
+              return svn_error_quick_wrapf(err,
                                  _("Failed to create hotcopy at '%s'. "
                                    "The file '%s' is missing from the source "
                                    "repository. Please create this file, for "
                                    "instance by running 'svnadmin upgrade %s'"),
                                  dst_abspath, config_relpath, src_abspath);
-              return svn_error_quick_wrap(err, msg);
             }
           else
             return svn_error_trace(err);
@@ -984,6 +982,10 @@ hotcopy_body(void *baton, apr_pool_t *po
       if (kind == svn_node_file)
         {
           SVN_ERR(svn_sqlite__hotcopy(src_subdir, dst_subdir, pool));
+
+          /* The source might have r/o flags set on it - which would be
+             carried over to the copy. */
+          SVN_ERR(svn_io_set_file_read_write(dst_subdir, FALSE, pool));
           SVN_ERR(svn_fs_fs__del_rep_reference(dst_fs, src_youngest, pool));
         }
     }
@@ -996,21 +998,6 @@ hotcopy_body(void *baton, apr_pool_t *po
   return SVN_NO_ERROR;
 }
 
-/* Wrapper around hotcopy_body taking out all necessary source repository
- * locks.
- */
-static svn_error_t *
-hotcopy_locking_src_body(void *baton, apr_pool_t *pool)
-{
-  struct hotcopy_body_baton *hbb = baton;
-  fs_fs_data_t *src_ffd = hbb->src_fs->fsap_data;
-
-  return src_ffd->format >= SVN_FS_FS__MIN_PACK_LOCK_FORMAT
-    ? svn_error_trace(svn_fs_fs__with_pack_lock(hbb->src_fs, hotcopy_body,
-                                                baton, pool))
-    : hotcopy_body(baton, pool);
-}
-
 /* Create an empty filesystem at DST_FS at DST_PATH with the same
  * configuration as SRC_FS (uuid, format, and other parameters).
  * After creation DST_FS has no revisions, not even revision zero. */
@@ -1104,8 +1091,7 @@ svn_fs_fs__hotcopy(svn_fs_t *src_fs,
   hbb.notify_baton = notify_baton;
   hbb.cancel_func = cancel_func;
   hbb.cancel_baton = cancel_baton;
-  SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_locking_src_body, &hbb,
-                                    pool));
+  SVN_ERR(svn_fs_fs__with_all_locks(dst_fs, hotcopy_body, &hbb, pool));
 
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/id.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/id.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/id.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/id.c Tue Jun 23 12:55:43 2015
@@ -365,14 +365,21 @@ svn_fs_fs__id_check_related(const svn_fs
   if (a == b)
     return TRUE;
 
-  /* If both node_ids start with _ and they have differing transaction
-     IDs, then it is impossible for them to be related. */
-  if (id_a->private_id.node_id.revision == SVN_INVALID_REVNUM)
+  /* If both node_ids have been created within _different_ transactions
+     (and are still uncommitted), then it is impossible for them to be
+     related.
+
+     Due to our txn-local temporary IDs, however, they might have been
+     given the same temporary node ID.  We need to detect that case.
+   */
+  if (   id_a->private_id.node_id.revision == SVN_INVALID_REVNUM
+      && id_b->private_id.node_id.revision == SVN_INVALID_REVNUM)
     {
-      if (   !svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
-                                    &id_b->private_id.txn_id)
-          || !svn_fs_fs__id_txn_used(&id_a->private_id.txn_id))
+      if (!svn_fs_fs__id_part_eq(&id_a->private_id.txn_id,
+                                 &id_b->private_id.txn_id))
         return FALSE;
+
+      /* At this point, matching node_ids implies relatedness. */
     }
 
   return svn_fs_fs__id_part_eq(&id_a->private_id.node_id,
@@ -385,7 +392,7 @@ svn_fs_fs__id_compare(const svn_fs_id_t
                       const svn_fs_id_t *b)
 {
   if (svn_fs_fs__id_eq(a, b))
-    return svn_fs_node_same;
+    return svn_fs_node_unchanged;
   return (svn_fs_fs__id_check_related(a, b) ? svn_fs_node_common_ancestor
                                             : svn_fs_node_unrelated);
 }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/lock.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/lock.c Tue Jun 23 12:55:43 2015
@@ -222,7 +222,7 @@ write_digest_file(apr_hash_t *children,
                                  svn_io_file_del_none, pool, pool));
   if ((err = svn_hash_write2(hash, stream, SVN_HASH_TERMINATOR, pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Cannot write lock/entries hashfile '%s'"),
@@ -273,7 +273,7 @@ read_digest_file(apr_hash_t **children_p
   hash = apr_hash_make(pool);
   if ((err = svn_hash_read2(hash, stream, SVN_HASH_TERMINATOR, pool)))
     {
-      svn_error_clear(svn_stream_close(stream));
+      err = svn_error_compose_create(err, svn_stream_close(stream));
       return svn_error_createf(err->apr_err,
                                err,
                                _("Can't parse lock/entries hashfile '%s'"),
@@ -715,6 +715,7 @@ check_lock(svn_error_t **fs_err,
            const svn_fs_lock_target_t *target,
            struct lock_baton *lb,
            svn_fs_root_t *root,
+           svn_revnum_t youngest_rev,
            apr_pool_t *pool)
 {
   svn_node_kind_t kind;
@@ -751,6 +752,15 @@ check_lock(svn_error_t **fs_err,
   if (SVN_IS_VALID_REVNUM(target->current_rev))
     {
       svn_revnum_t created_rev;
+
+      if (target->current_rev > youngest_rev)
+        {
+          *fs_err = svn_error_createf(SVN_ERR_FS_NO_SUCH_REVISION, NULL,
+                                      _("No such revision %ld"),
+                                      target->current_rev);
+          return SVN_NO_ERROR;
+        }
+
       SVN_ERR(svn_fs_fs__node_created_rev(&created_rev, root, path,
                                           pool));
 
@@ -856,7 +866,7 @@ lock_body(void *baton, apr_pool_t *pool)
       info.fs_err = SVN_NO_ERROR;
 
       SVN_ERR(check_lock(&info.fs_err, info.path, item->value, lb, root,
-                         iterpool));
+                         youngest, iterpool));
 
       /* If no error occurred while pre-checking, schedule the index updates for
          this path. */
@@ -1099,6 +1109,7 @@ svn_fs_fs__lock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1139,11 +1150,13 @@ svn_fs_fs__lock(svn_fs_t *fs,
   lb.steal_lock = steal_lock;
   lb.result_pool = result_pool;
 
-  err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_fs__with_write_lock(fs, lock_body, &lb, iterpool);
   for (i = 0; i < lb.infos->nelts; ++i)
     {
       struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
                                                 struct lock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->lock && !info->fs_err)
@@ -1152,10 +1165,11 @@ svn_fs_fs__lock(svn_fs_t *fs,
                                              info->path);
 
           cb_err = lock_callback(lock_baton, info->path, info->lock,
-                                 info->fs_err, scratch_pool);
+                                 info->fs_err, iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);
@@ -1195,6 +1209,7 @@ svn_fs_fs__unlock(svn_fs_t *fs,
   apr_array_header_t *sorted_targets;
   apr_hash_t *canonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
+  apr_pool_t *iterpool;
   svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
@@ -1229,11 +1244,13 @@ svn_fs_fs__unlock(svn_fs_t *fs,
   ub.break_lock = break_lock;
   ub.result_pool = result_pool;
 
-  err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, scratch_pool);
+  iterpool = svn_pool_create(scratch_pool);
+  err = svn_fs_fs__with_write_lock(fs, unlock_body, &ub, iterpool);
   for (i = 0; i < ub.infos->nelts; ++i)
     {
       struct unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i,
                                                   struct unlock_info_t);
+      svn_pool_clear(iterpool);
       if (!cb_err && lock_callback)
         {
           if (!info->done && !info->fs_err)
@@ -1241,10 +1258,11 @@ svn_fs_fs__unlock(svn_fs_t *fs,
                                              0, _("Failed to unlock '%s'"),
                                              info->path);
           cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
-                                 scratch_pool);
+                                 iterpool);
         }
       svn_error_clear(info->fs_err);
     }
+  svn_pool_destroy(iterpool);
 
   if (err && cb_err)
     svn_error_compose(err, cb_err);

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.c Tue Jun 23 12:55:43 2015
@@ -189,6 +189,19 @@ svn_fs_fs__unparse_revision_trailer(apr_
                                changes_offset);
 }
 
+/* If ERR is not NULL, wrap it MESSAGE.  The latter must have an %ld
+ * format parameter that will be filled with REV. */
+static svn_error_t *
+wrap_footer_error(svn_error_t *err,
+                  const char *message,
+                  svn_revnum_t rev)
+{
+  if (err)
+    return svn_error_quick_wrapf(err, message, rev);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_fs__parse_footer(apr_off_t *l2p_offset,
                         svn_checksum_t **l2p_checksum,
@@ -196,6 +209,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
                         svn_checksum_t **p2l_checksum,
                         svn_stringbuf_t *footer,
                         svn_revnum_t rev,
+                        apr_off_t footer_offset,
                         apr_pool_t *result_pool)
 {
   apr_int64_t val;
@@ -204,17 +218,20 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
   /* 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"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
-  SVN_ERR(svn_cstring_atoi64(&val, str));
+  SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+                                                 footer_offset - 1, 10),
+                            "Invalid L2P offset in r%ld footer",
+                            rev));
   *l2p_offset = (apr_off_t)val;
 
   /* 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"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
   SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str,
                                  result_pool));
@@ -222,17 +239,33 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
   /* 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"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
-  SVN_ERR(svn_cstring_atoi64(&val, str));
+  SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0,
+                                                 footer_offset - 1, 10),
+                            "Invalid P2L offset in r%ld footer",
+                            rev));
   *p2l_offset = (apr_off_t)val;
 
+  /* The P2L indes follows the L2P index */
+  if (*p2l_offset <= *l2p_offset)
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "P2L offset %s must be larger than L2P offset %s"
+                             " in r%ld footer",
+                             apr_psprintf(result_pool,
+                                          "%" APR_UINT64_T_HEX_FMT,
+                                          (apr_uint64_t)*p2l_offset),
+                             apr_psprintf(result_pool,
+                                          "%" APR_UINT64_T_HEX_FMT,
+                                          (apr_uint64_t)*l2p_offset),
+                             rev);
+
   /* 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"));
+    return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                             "Invalid r%ld footer", rev);
 
   SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str,
                                  result_pool));

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/low_level.h Tue Jun 23 12:55:43 2015
@@ -67,6 +67,8 @@ svn_fs_fs__unparse_revision_trailer(apr_
  * *P2L_OFFSET, respectively.  Also, return the expected checksums in
  * in *L2P_CHECKSUM and *P2L_CHECKSUM.
  *
+ * FOOTER_OFFSET is used for validation.
+ *
  * Note that REV is only used to construct nicer error objects that
  * mention this revision.  Allocate the checksums in RESULT_POOL.
  */
@@ -77,6 +79,7 @@ svn_fs_fs__parse_footer(apr_off_t *l2p_o
                         svn_checksum_t **p2l_checksum,
                         svn_stringbuf_t *footer,
                         svn_revnum_t rev,
+                        apr_off_t footer_offset,
                         apr_pool_t *result_pool);
 
 /* Given the offset of the L2P index data in L2P_OFFSET, the content

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.c Tue Jun 23 12:55:43 2015
@@ -384,6 +384,8 @@ close_pack_context(pack_context_t *conte
   SVN_ERR(svn_io_remove_file2(proto_l2p_index_path, FALSE, pool));
   SVN_ERR(svn_io_remove_file2(proto_p2l_index_path, FALSE, pool));
 
+  /* Ensure that packed file is written to disk.*/
+  SVN_ERR(svn_io_file_flush_to_disk(context->pack_file, pool));
   SVN_ERR(svn_io_file_close(context->pack_file, pool));
 
   return SVN_NO_ERROR;
@@ -572,7 +574,7 @@ copy_rep_to_temp(pack_context_t *context
   /* read & parse the representation header */
   stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
   SVN_ERR(svn_fs_fs__read_rep_header(&rep_header, stream, pool, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* if the representation is a delta against some other rep, link the two */
   if (   rep_header->type == svn_fs_fs__rep_delta
@@ -643,17 +645,18 @@ compare_dir_entries_format6(const svn_so
 apr_array_header_t *
 svn_fs_fs__order_dir_entries(svn_fs_t *fs,
                              apr_hash_t *directory,
-                             apr_pool_t *pool)
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool)
 {
   apr_array_header_t *ordered
     = svn_sort__hash(directory,
                      svn_fs_fs__use_log_addressing(fs)
                        ? compare_dir_entries_format7
                        : compare_dir_entries_format6,
-                     pool);
+                     scratch_pool);
 
   apr_array_header_t *result
-    = apr_array_make(pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
+    = apr_array_make(result_pool, ordered->nelts, sizeof(svn_fs_dirent_t *));
 
   int i;
   for (i = 0; i < ordered->nelts; ++i)
@@ -714,7 +717,7 @@ copy_node_to_temp(pack_context_t *contex
   /* read & parse noderev */
   stream = svn_stream_from_aprfile2(rev_file, TRUE, pool);
   SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool, pool));
-  svn_stream_close(stream);
+  SVN_ERR(svn_stream_close(stream));
 
   /* create a copy of ENTRY, make it point to the copy destination and
    * store it in CONTEXT */
@@ -736,9 +739,7 @@ copy_node_to_temp(pack_context_t *contex
     {
       path_order->rep_id.revision = noderev->data_rep->revision;
       path_order->rep_id.number = noderev->data_rep->item_index;
-      path_order->expanded_size = noderev->data_rep->expanded_size
-                                ? noderev->data_rep->expanded_size
-                                : noderev->data_rep->size;
+      path_order->expanded_size = noderev->data_rep->expanded_size;
     }
 
   /* Sort path is the key used for ordering noderevs and associated reps.
@@ -1655,7 +1656,9 @@ pack_phys_addressed(const char *pack_fil
                     apr_pool_t *pool)
 {
   const char *pack_file_path, *manifest_file_path;
-  svn_stream_t *pack_stream, *manifest_stream;
+  apr_file_t *pack_file;
+  apr_file_t *manifest_file;
+  svn_stream_t *manifest_stream;
   svn_revnum_t end_rev, rev;
   apr_off_t next_offset;
   apr_pool_t *iterpool;
@@ -1664,13 +1667,18 @@ pack_phys_addressed(const char *pack_fil
   pack_file_path = svn_dirent_join(pack_file_dir, PATH_PACKED, pool);
   manifest_file_path = svn_dirent_join(pack_file_dir, PATH_MANIFEST, pool);
 
-  /* Create the new directory and pack file. */
-  SVN_ERR(svn_stream_open_writable(&pack_stream, pack_file_path, pool,
-                                    pool));
+  /* Create the new directory and pack file.
+   * Use unbuffered apr_file_t since we're going to write using 16kb
+   * chunks. */
+  SVN_ERR(svn_io_file_open(&pack_file, pack_file_path,
+                           APR_WRITE | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, pool));
 
   /* Create the manifest file. */
-  SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
-                                   pool, pool));
+  SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+                           APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, pool));
+  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE, pool);
 
   end_rev = start_rev + max_files_per_dir - 1;
   next_offset = 0;
@@ -1697,16 +1705,24 @@ pack_phys_addressed(const char *pack_fil
 
       /* Copy all the bits from the rev file to the end of the pack file. */
       SVN_ERR(svn_stream_open_readonly(&rev_stream, path, iterpool, iterpool));
-      SVN_ERR(svn_stream_copy3(rev_stream, svn_stream_disown(pack_stream,
-                                                             iterpool),
+      SVN_ERR(svn_stream_copy3(rev_stream,
+                               svn_stream_from_aprfile2(pack_file, TRUE, pool),
                                cancel_func, cancel_baton, iterpool));
     }
 
-  /* disallow write access to the manifest file */
+  /* Close stream over APR file. */
   SVN_ERR(svn_stream_close(manifest_stream));
+
+  /* Ensure that pack file is written to disk. */
+  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, pool));
+  SVN_ERR(svn_io_file_close(manifest_file, pool));
+
+  /* disallow write access to the manifest file */
   SVN_ERR(svn_io_set_file_read_only(manifest_file_path, FALSE, iterpool));
 
-  SVN_ERR(svn_stream_close(pack_stream));
+  /* Ensure that pack file is written to disk. */
+  SVN_ERR(svn_io_file_flush_to_disk(pack_file, pool));
+  SVN_ERR(svn_io_file_close(pack_file, pool));
 
   svn_pool_destroy(iterpool);
 
@@ -1915,6 +1931,34 @@ pack_shard(struct pack_baton *baton,
   return SVN_NO_ERROR;
 }
 
+/* Read the youngest rev and the first non-packed rev info for FS from disk.
+   Set *FULLY_PACKED when there is no completed unpacked shard.
+   Use SCRATCH_POOL for temporary allocations.
+ */
+static svn_error_t *
+get_pack_status(svn_boolean_t *fully_packed,
+                svn_fs_t *fs,
+                apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+  apr_int64_t completed_shards;
+  svn_revnum_t youngest;
+
+  SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs,
+                                           scratch_pool));
+
+  SVN_ERR(svn_fs_fs__youngest_rev(&youngest, fs, scratch_pool));
+  completed_shards = (youngest + 1) / ffd->max_files_per_dir;
+
+  /* See if we've already completed all possible shards thus far. */
+  if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
+    *fully_packed = TRUE;
+  else
+    *fully_packed = FALSE;
+
+  return SVN_NO_ERROR;
+}
+
 /* The work-horse for svn_fs_fs__pack, called with the FS write lock.
    This implements the svn_fs_fs__with_write_lock() 'body' callback
    type.  BATON is a 'struct pack_baton *'.
@@ -1936,30 +1980,16 @@ pack_body(void *baton,
   struct pack_baton *pb = baton;
   fs_fs_data_t *ffd = pb->fs->fsap_data;
   apr_int64_t completed_shards;
-  svn_revnum_t youngest;
   apr_pool_t *iterpool;
+  svn_boolean_t fully_packed;
 
-  /* If the repository isn't a new enough format, we don't support packing.
-     Return a friendly error to that effect. */
-  if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT)
-    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
-      _("FSFS format (%d) too old to pack; please upgrade the filesystem."),
-      ffd->format);
-
-  /* If we aren't using sharding, we can't do any packing, so quit. */
-  if (!ffd->max_files_per_dir)
-    return SVN_NO_ERROR;
-
-  SVN_ERR(svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, pb->fs,
-                                           pool));
-
-  SVN_ERR(svn_fs_fs__youngest_rev(&youngest, pb->fs, pool));
-  completed_shards = (youngest + 1) / ffd->max_files_per_dir;
-
-  /* See if we've already completed all possible shards thus far. */
-  if (ffd->min_unpacked_rev == (completed_shards * ffd->max_files_per_dir))
+  /* Since another process might have already packed the repo,
+     we need to re-read the pack status. */
+  SVN_ERR(get_pack_status(&fully_packed, pb->fs, pool));
+  if (fully_packed)
     return SVN_NO_ERROR;
 
+  completed_shards = (ffd->youngest_rev_cache + 1) / ffd->max_files_per_dir;
   pb->revs_dir = svn_dirent_join(pb->fs->path, PATH_REVS_DIR, pool);
   if (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT)
     pb->revsprops_dir = svn_dirent_join(pb->fs->path, PATH_REVPROPS_DIR,
@@ -1993,7 +2023,25 @@ svn_fs_fs__pack(svn_fs_t *fs,
   struct pack_baton pb = { 0 };
   fs_fs_data_t *ffd = fs->fsap_data;
   svn_error_t *err;
+  svn_boolean_t fully_packed;
+
+  /* If the repository isn't a new enough format, we don't support packing.
+     Return a friendly error to that effect. */
+  if (ffd->format < SVN_FS_FS__MIN_PACKED_FORMAT)
+    return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+      _("FSFS format (%d) too old to pack; please upgrade the filesystem."),
+      ffd->format);
+
+  /* If we aren't using sharding, we can't do any packing, so quit. */
+  if (!ffd->max_files_per_dir)
+    return SVN_NO_ERROR;
+
+  /* Is there we even anything to do?. */
+  SVN_ERR(get_pack_status(&fully_packed, fs, pool));
+  if (fully_packed)
+    return SVN_NO_ERROR;
 
+  /* Lock the repo and start the pack process. */
   pb.fs = fs;
   pb.notify_func = notify_func;
   pb.notify_baton = notify_baton;

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/pack.h Tue Jun 23 12:55:43 2015
@@ -51,13 +51,14 @@ svn_fs_fs__get_packed_offset(apr_off_t *
                              apr_pool_t *pool);
 
 /* Return the svn_dir_entry_t* objects of DIRECTORY in an APR array
- * allocated in POOL with entries added in storage (on-disk) order.
- * FS format will be used to pick the optimal ordering strategy.
+ * allocated in RESULT_POOL with entries added in storage (on-disk) order.
+ * FS' format will be used to pick the optimal ordering strategy.  Use
+ * SCRATCH_POOL for temporary allocations.
  */
 apr_array_header_t *
 svn_fs_fs__order_dir_entries(svn_fs_t *fs,
                              apr_hash_t *directory,
-                             apr_pool_t *pool);
-
+                             apr_pool_t *result_pool,
+                             apr_pool_t *scratch_pool);
 
 #endif

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/recovery.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/recovery.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/recovery.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/recovery.c Tue Jun 23 12:55:43 2015
@@ -160,6 +160,7 @@ recover_find_max_ids(svn_fs_t *fs,
   apr_hash_index_t *hi;
   apr_pool_t *iterpool;
   node_revision_t *noderev;
+  svn_error_t *err;
 
   baton.stream = rev_file->stream;
   SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
@@ -196,16 +197,23 @@ recover_find_max_ids(svn_fs_t *fs,
      stored in the representation.  Note that this is a directory, i.e.
      represented using the hash format on disk and can never have 0 length. */
   baton.pool = pool;
-  baton.remaining = noderev->data_rep->expanded_size
-                  ? noderev->data_rep->expanded_size
-                  : noderev->data_rep->size;
+  baton.remaining = noderev->data_rep->expanded_size;
   stream = svn_stream_create(&baton, pool);
   svn_stream_set_read2(stream, NULL /* only full read support */,
                        read_handler_recover);
 
   /* Now read the entries from that stream. */
   entries = apr_hash_make(pool);
-  SVN_ERR(svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool));
+  err = svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool);
+  if (err)
+    {
+      svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
+
+      err = svn_error_compose_create(err, svn_stream_close(stream));
+      return svn_error_quick_wrapf(err,
+                _("malformed representation for node-revision '%s'"),
+                id_str->data);
+    }
   SVN_ERR(svn_stream_close(stream));
 
   /* Now check each of the entries in our directory to find new node and

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache-db.sql Tue Jun 23 12:55:43 2015
@@ -63,3 +63,6 @@ WHERE revision > ?1
 -- STMT_LOCK_REP
 BEGIN TRANSACTION;
 INSERT INTO rep_cache VALUES ('dummy', 0, 0, 0, 0)
+
+-- STMT_UNLOCK_REP
+ROLLBACK TRANSACTION;

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.c Tue Jun 23 12:55:43 2015
@@ -24,6 +24,7 @@
 
 #include "svn_private_config.h"
 
+#include "cached_data.h"
 #include "fs_fs.h"
 #include "fs.h"
 #include "rep-cache.h"
@@ -273,6 +274,8 @@ svn_fs_fs__get_rep_reference(representat
       (*rep)->item_index = svn_sqlite__column_int64(stmt, 1);
       (*rep)->size = svn_sqlite__column_int64(stmt, 2);
       (*rep)->expanded_size = svn_sqlite__column_int64(stmt, 3);
+
+      SVN_ERR(svn_fs_fs__fixup_expanded_size(fs, *rep, pool));
     }
   else
     *rep = NULL;
@@ -371,9 +374,13 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
-                          apr_pool_t *pool)
+/* Start a transaction to take an SQLite reserved lock that prevents
+   other writes.
+
+   See unlock_rep_cache(). */
+static svn_error_t *
+lock_rep_cache(svn_fs_t *fs,
+               apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
 
@@ -384,3 +391,31 @@ svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
 
   return SVN_NO_ERROR;
 }
+
+/* End the transaction started by lock_rep_cache(). */
+static svn_error_t *
+unlock_rep_cache(svn_fs_t *fs,
+                 apr_pool_t *pool)
+{
+  fs_fs_data_t *ffd = fs->fsap_data;
+
+  SVN_ERR_ASSERT(ffd->rep_cache_db); /* was opened by lock_rep_cache() */
+
+  SVN_ERR(svn_sqlite__exec_statements(ffd->rep_cache_db, STMT_UNLOCK_REP));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__with_rep_cache_lock(svn_fs_t *fs,
+                               svn_error_t *(*body)(void *,
+                                                    apr_pool_t *),
+                               void *baton,
+                               apr_pool_t *pool)
+{
+  svn_error_t *err;
+
+  SVN_ERR(lock_rep_cache(fs, pool));
+  err = body(baton, pool);
+  return svn_error_compose_create(err, unlock_rep_cache(fs, pool));
+}

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.h
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.h?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.h (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rep-cache.h Tue Jun 23 12:55:43 2015
@@ -87,10 +87,14 @@ svn_fs_fs__del_rep_reference(svn_fs_t *f
                              apr_pool_t *pool);
 
 /* Start a transaction to take an SQLite reserved lock that prevents
-   other writes. */
+   other writes, call BODY, end the transaction, and return what BODY returned.
+ */
 svn_error_t *
-svn_fs_fs__lock_rep_cache(svn_fs_t *fs,
-                          apr_pool_t *pool);
+svn_fs_fs__with_rep_cache_lock(svn_fs_t *fs,
+                               svn_error_t *(*body)(void *baton,
+                                                    apr_pool_t *pool),
+                               void *baton,
+                               apr_pool_t *pool);
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rev_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rev_file.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rev_file.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/rev_file.c Tue Jun 23 12:55:43 2015
@@ -259,6 +259,7 @@ svn_fs_fs__auto_read_footer(svn_fs_fs__r
       SVN_ERR(svn_fs_fs__parse_footer(&file->l2p_offset, &file->l2p_checksum,
                                       &file->p2l_offset, &file->p2l_checksum,
                                       footer, file->start_revision,
+                                      filesize - footer_length - 1,
                                       file->pool));
       file->footer_offset = filesize - footer_length - 1;
     }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/revprops.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/revprops.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/revprops.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/revprops.c Tue Jun 23 12:55:43 2015
@@ -36,11 +36,6 @@
 
 #include "svn_private_config.h"
 
-/* Give writing processes 10 seconds to replace an existing revprop
-   file with a new one. After that time, we assume that the writing
-   process got aborted and that we have re-read revprops. */
-#define REVPROP_CHANGE_TIMEOUT (10 * 1000000)
-
 svn_error_t *
 svn_fs_fs__upgrade_pack_revprops(svn_fs_t *fs,
                                  svn_fs_upgrade_notify_t notify_func,
@@ -415,7 +410,8 @@ parse_packed_revprops(svn_fs_t *fs,
    * length header to remove) */
   svn_stringbuf_t *compressed = revprops->packed_revprops;
   svn_stringbuf_t *uncompressed = svn_stringbuf_create_empty(pool);
-  SVN_ERR(svn__decompress(compressed, uncompressed, APR_SIZE_MAX));
+  SVN_ERR(svn__decompress(compressed->data, compressed->len,
+                          uncompressed, APR_SIZE_MAX));
 
   /* read first revision number and number of revisions in the pack */
   stream = svn_stream_from_stringbuf(uncompressed, scratch_pool);
@@ -657,17 +653,23 @@ write_non_packed_revprop(const char **fi
                          apr_hash_t *proplist,
                          apr_pool_t *pool)
 {
+  apr_file_t *file;
   svn_stream_t *stream;
   *final_path = svn_fs_fs__path_revprops(fs, rev, pool);
 
   /* ### do we have a directory sitting around already? we really shouldn't
      ### have to get the dirname here. */
-  SVN_ERR(svn_stream_open_unique(&stream, tmp_path,
-                                 svn_dirent_dirname(*final_path, pool),
-                                 svn_io_file_del_none, pool, pool));
+  SVN_ERR(svn_io_open_unique_file3(&file, tmp_path,
+                                   svn_dirent_dirname(*final_path, pool),
+                                   svn_io_file_del_none, pool, pool));
+  stream = svn_stream_from_aprfile2(file, TRUE, pool);
   SVN_ERR(svn_hash_write2(proplist, stream, SVN_HASH_TERMINATOR, pool));
   SVN_ERR(svn_stream_close(stream));
 
+  /* Flush temporary file to disk and close it. */
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
+
   return SVN_NO_ERROR;
 }
 
@@ -750,7 +752,7 @@ serialize_revprops_header(svn_stream_t *
   return SVN_NO_ERROR;
 }
 
-/* Writes the a pack file to FILE_STREAM.  It copies the serialized data
+/* Writes the a pack file to FILE.  It copies the serialized data
  * from REVPROPS for the indexes [START,END) except for index CHANGED_INDEX.
  *
  * The data for the latter is taken from NEW_SERIALIZED.  Note, that
@@ -768,7 +770,7 @@ repack_revprops(svn_fs_t *fs,
                 int changed_index,
                 svn_stringbuf_t *new_serialized,
                 apr_off_t new_total_size,
-                svn_stream_t *file_stream,
+                apr_file_t *file,
                 apr_pool_t *pool)
 {
   fs_fs_data_t *ffd = fs->fsap_data;
@@ -810,15 +812,17 @@ repack_revprops(svn_fs_t *fs,
   SVN_ERR(svn_stream_close(stream));
 
   /* compress / store the data */
-  SVN_ERR(svn__compress(uncompressed,
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
                         compressed,
                         ffd->compress_packed_revprops
                           ? SVN_DELTA_COMPRESSION_LEVEL_DEFAULT
                           : SVN_DELTA_COMPRESSION_LEVEL_NONE));
 
-  /* finally, write the content to the target stream and close it */
-  SVN_ERR(svn_stream_write(file_stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(file_stream));
+  /* finally, write the content to the target file, flush and close it */
+  SVN_ERR(svn_io_file_write_full(file, compressed->data, compressed->len,
+                                 NULL, pool));
+  SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+  SVN_ERR(svn_io_file_close(file, pool));
 
   return SVN_NO_ERROR;
 }
@@ -826,23 +830,22 @@ repack_revprops(svn_fs_t *fs,
 /* Allocate a new pack file name for revisions
  *     [REVPROPS->START_REVISION + START, REVPROPS->START_REVISION + END - 1]
  * of REVPROPS->MANIFEST.  Add the name of old file to FILES_TO_DELETE,
- * auto-create that array if necessary.  Return an open file stream to
- * the new file in *STREAM allocated in POOL.
+ * auto-create that array if necessary.  Return an open file *FILE that is
+ * allocated in POOL.
  */
 static svn_error_t *
-repack_stream_open(svn_stream_t **stream,
-                   svn_fs_t *fs,
-                   packed_revprops_t *revprops,
-                   int start,
-                   int end,
-                   apr_array_header_t **files_to_delete,
-                   apr_pool_t *pool)
+repack_file_open(apr_file_t **file,
+                 svn_fs_t *fs,
+                 packed_revprops_t *revprops,
+                 int start,
+                 int end,
+                 apr_array_header_t **files_to_delete,
+                 apr_pool_t *pool)
 {
   apr_int64_t tag;
   const char *tag_string;
   svn_string_t *new_filename;
   int i;
-  apr_file_t *file;
   int manifest_offset
     = (int)(revprops->start_revision - revprops->manifest_start);
 
@@ -874,12 +877,11 @@ repack_stream_open(svn_stream_t **stream
     APR_ARRAY_IDX(revprops->manifest, i + manifest_offset, const char*)
       = new_filename->data;
 
-  /* create a file stream for the new file */
-  SVN_ERR(svn_io_file_open(&file, svn_dirent_join(revprops->folder,
-                                                  new_filename->data,
-                                                  pool),
+  /* open the file */
+  SVN_ERR(svn_io_file_open(file, svn_dirent_join(revprops->folder,
+                                                 new_filename->data,
+                                                 pool),
                            APR_WRITE | APR_CREATE, APR_OS_DEFAULT, pool));
-  *stream = svn_stream_from_aprfile2(file, FALSE, pool);
 
   return SVN_NO_ERROR;
 }
@@ -903,6 +905,7 @@ write_packed_revprop(const char **final_
   packed_revprops_t *revprops;
   apr_int64_t generation = 0;
   svn_stream_t *stream;
+  apr_file_t *file;
   svn_stringbuf_t *serialized;
   apr_off_t new_total_size;
   int changed_index;
@@ -933,11 +936,11 @@ write_packed_revprop(const char **final_
 
       *final_path = svn_dirent_join(revprops->folder, revprops->filename,
                                     pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
       SVN_ERR(repack_revprops(fs, revprops, 0, revprops->sizes->nelts,
                               changed_index, serialized, new_total_size,
-                              stream, pool));
+                              file, pool));
     }
   else
     {
@@ -983,50 +986,51 @@ write_packed_revprop(const char **final_
       /* write the new, split files */
       if (left_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, 0,
-                                     left_count, files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, 0,
+                                   left_count, files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops, 0, left_count,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (left_count + right_count < revprops->sizes->nelts)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops, changed_index,
-                                     changed_index + 1, files_to_delete,
-                                     pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops, changed_index,
+                                   changed_index + 1, files_to_delete,
+                                   pool));
           SVN_ERR(repack_revprops(fs, revprops, changed_index,
                                   changed_index + 1,
                                   changed_index, serialized, new_total_size,
-                                  stream, pool));
+                                  file, pool));
         }
 
       if (right_count)
         {
-          SVN_ERR(repack_stream_open(&stream, fs, revprops,
-                                     revprops->sizes->nelts - right_count,
-                                     revprops->sizes->nelts,
-                                     files_to_delete, pool));
+          SVN_ERR(repack_file_open(&file, fs, revprops,
+                                   revprops->sizes->nelts - right_count,
+                                   revprops->sizes->nelts,
+                                   files_to_delete, pool));
           SVN_ERR(repack_revprops(fs, revprops,
                                   revprops->sizes->nelts - right_count,
                                   revprops->sizes->nelts, changed_index,
-                                  serialized, new_total_size, stream,
+                                  serialized, new_total_size, file,
                                   pool));
         }
 
       /* write the new manifest */
       *final_path = svn_dirent_join(revprops->folder, PATH_MANIFEST, pool);
-      SVN_ERR(svn_stream_open_unique(&stream, tmp_path, revprops->folder,
-                                     svn_io_file_del_none, pool, pool));
-
+      SVN_ERR(svn_io_open_unique_file3(&file, tmp_path, revprops->folder,
+                                       svn_io_file_del_none, pool, pool));
+      stream = svn_stream_from_aprfile2(file, TRUE, pool);
       for (i = 0; i < revprops->manifest->nelts; ++i)
         {
           const char *filename = APR_ARRAY_IDX(revprops->manifest, i,
                                                const char*);
           SVN_ERR(svn_stream_printf(stream, pool, "%s\n", filename));
         }
-
       SVN_ERR(svn_stream_close(stream));
+      SVN_ERR(svn_io_file_flush_to_disk(file, pool));
+      SVN_ERR(svn_io_file_close(file, pool));
     }
 
   return SVN_NO_ERROR;
@@ -1165,7 +1169,6 @@ svn_fs_fs__copy_revprops(const char *pac
   apr_file_t *pack_file;
   svn_revnum_t rev;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
-  svn_stream_t *stream;
 
   /* create empty data buffer and a write stream on top of it */
   svn_stringbuf_t *uncompressed
@@ -1189,6 +1192,7 @@ svn_fs_fs__copy_revprops(const char *pac
   for (rev = start_rev; rev <= end_rev; rev++)
     {
       const char *path;
+      svn_stream_t *stream;
 
       svn_pool_clear(iterpool);
 
@@ -1207,12 +1211,14 @@ svn_fs_fs__copy_revprops(const char *pac
   SVN_ERR(svn_stream_close(pack_stream));
 
   /* compress the content (or just store it for COMPRESSION_LEVEL 0) */
-  SVN_ERR(svn__compress(uncompressed, compressed, compression_level));
+  SVN_ERR(svn__compress(uncompressed->data, uncompressed->len,
+                        compressed, compression_level));
 
   /* write the pack file content to disk */
-  stream = svn_stream_from_aprfile2(pack_file, FALSE, scratch_pool);
-  SVN_ERR(svn_stream_write(stream, compressed->data, &compressed->len));
-  SVN_ERR(svn_stream_close(stream));
+  SVN_ERR(svn_io_file_write_full(pack_file, compressed->data, compressed->len,
+                                 NULL, scratch_pool));
+  SVN_ERR(svn_io_file_flush_to_disk(pack_file, scratch_pool));
+  SVN_ERR(svn_io_file_close(pack_file, scratch_pool));
 
   svn_pool_destroy(iterpool);
 
@@ -1231,6 +1237,7 @@ svn_fs_fs__pack_revprops_shard(const cha
                                apr_pool_t *scratch_pool)
 {
   const char *manifest_file_path, *pack_filename = NULL;
+  apr_file_t *manifest_file;
   svn_stream_t *manifest_stream;
   svn_revnum_t start_rev, end_rev, rev;
   apr_off_t total_size;
@@ -1247,8 +1254,12 @@ svn_fs_fs__pack_revprops_shard(const cha
 
   /* Create the new directory and manifest file stream. */
   SVN_ERR(svn_io_dir_make(pack_file_dir, APR_OS_DEFAULT, scratch_pool));
-  SVN_ERR(svn_stream_open_writable(&manifest_stream, manifest_file_path,
-                                   scratch_pool, scratch_pool));
+
+  SVN_ERR(svn_io_file_open(&manifest_file, manifest_file_path,
+                           APR_WRITE | APR_BUFFERED | APR_CREATE | APR_EXCL,
+                           APR_OS_DEFAULT, scratch_pool));
+  manifest_stream = svn_stream_from_aprfile2(manifest_file, TRUE,
+                                             scratch_pool);
 
   /* revisions to handle. Special case: revision 0 */
   start_rev = (svn_revnum_t) (shard * max_files_per_dir);
@@ -1315,8 +1326,10 @@ svn_fs_fs__pack_revprops_shard(const cha
                                      compression_level, cancel_func,
                                      cancel_baton, iterpool));
 
-  /* flush the manifest file and update permissions */
+  /* flush the manifest file to disk and update permissions */
   SVN_ERR(svn_stream_close(manifest_stream));
+  SVN_ERR(svn_io_file_flush_to_disk(manifest_file, iterpool));
+  SVN_ERR(svn_io_file_close(manifest_file, iterpool));
   SVN_ERR(svn_io_copy_perms(shard_path, pack_file_dir, iterpool));
 
   svn_pool_destroy(iterpool);
@@ -1347,7 +1360,7 @@ svn_fs_fs__delete_revprops_shard(const c
                                  apr_psprintf(iterpool, "%d", i),
                                  iterpool);
           if (cancel_func)
-            SVN_ERR((*cancel_func)(cancel_baton));
+            SVN_ERR(cancel_func(cancel_baton));
 
           SVN_ERR(svn_io_remove_file2(path, TRUE, iterpool));
         }

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/stats.c
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/stats.c?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/stats.c (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/stats.c Tue Jun 23 12:55:43 2015
@@ -176,23 +176,6 @@ typedef struct query_t
   void *cancel_baton;
 } query_t;
 
-/* Return the length of REV_FILE in *FILE_SIZE.
- * Use SCRATCH_POOL for temporary allocations.
- */
-static svn_error_t *
-get_file_size(apr_off_t *file_size,
-              svn_fs_fs__revision_file_t *rev_file,
-              apr_pool_t *scratch_pool)
-{
-  apr_finfo_t finfo;
-
-  SVN_ERR(svn_io_file_info_get(&finfo, APR_FINFO_SIZE, rev_file->file,
-                               scratch_pool));
-
-  *file_size = finfo.size;
-  return SVN_NO_ERROR;
-}
-
 /* Initialize the LARGEST_CHANGES member in STATS with a capacity of COUNT
  * entries.  Allocate the result in RESULT_POOL.
  */
@@ -436,8 +419,7 @@ parse_representation(rep_stats_t **repre
        */
       result = apr_pcalloc(result_pool, sizeof(*result));
       result->revision = rep->revision;
-      result->expanded_size = (rep->expanded_size ? rep->expanded_size
-                                                  : rep->size);
+      result->expanded_size = rep->expanded_size;
       result->offset = (apr_off_t)rep->item_index;
       result->size = rep->size;
 
@@ -729,12 +711,12 @@ read_phys_pack_file(query_t *query,
 {
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, base,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* process each revision in the pack file */
   for (i = 0; i < query->shard_size; ++i)
@@ -798,7 +780,7 @@ read_phys_revision_file(query_t *query,
                         apr_pool_t *scratch_pool)
 {
   revision_info_t *info = apr_pcalloc(result_pool, sizeof(*info));
-  apr_off_t file_size = 0;
+  svn_filesize_t file_size = 0;
   svn_fs_fs__revision_file_t *rev_file;
 
   /* cancellation support */
@@ -808,7 +790,7 @@ read_phys_revision_file(query_t *query,
   /* read the whole pack file into memory */
   SVN_ERR(svn_fs_fs__open_pack_or_rev_file(&rev_file, query->fs, revision,
                                            scratch_pool, scratch_pool));
-  SVN_ERR(get_file_size(&file_size, rev_file, scratch_pool));
+  SVN_ERR(svn_io_file_size_get(&file_size, rev_file->file, scratch_pool));
 
   /* create the revision info for the current rev */
   info->representations = apr_array_make(result_pool, 4, sizeof(rep_stats_t*));

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure Tue Jun 23 12:55:43 2015
@@ -198,9 +198,9 @@ Shard packing:
     (i.e. same min packed revision)
 
 Addressing:
-  Format 1-6: Physical addressing; uses fixed positions within a rev file
+  Format 1+: Physical addressing; uses fixed positions within a rev file
   Format 7+:  Logical addressing; uses item index that will be translated
-    on-the-fly to the actual rev / pack file location
+    on-the-fly to the actual rev / pack file location (default for 7+ created)
 
 Repository IDs:
   Format 1+:  The first line of db/uuid contains the repository UUID
@@ -525,6 +525,7 @@ A revision file contains a concatenation
   * Text and property representations
   * Node-revisions
   * The changed-path data
+  * Two offsets at the very end (physical addressing only)
   * Index data (logical addressing only)
   * Revision / pack file footer (logical addressing only)
 
@@ -578,8 +579,9 @@ defined:
     representations may not be handled correctly by SVN before 1.7.20,
     1.8.12 and 1.9.0, if they have 0 <size> fields for non-empty contents.
     Releases 1.8.0 through 1.8.11 may have falsely created instances of
-    that (see issue #4554).  Finally, 0 <size> fields are NEVER legal for
-    DELTA representations.
+    that (see issue #4554).  Finally, 0 <size> fields are only ever legal
+    for DELTA representations if the reconstructed full-text is actually
+    empty.
 
 The predecessor of a node-rev crosses both soft and true copies;
 together with the count field, it allows efficient determination of
@@ -756,6 +758,9 @@ Format 7 introduces logical addressing t
 to be translated / mapped to physical rev / pack file offsets.
 These indexes are appended to the respective rev / pack file.
 
+The indexes map (revision number, item-index) pairs to absolute file offsets
+and absolute file offsets to (revision number, item-index, item metadata).
+
 Details of the binary format used by these index files can be
 found in structure-indexes.
 

Modified: subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure-indexes
URL: http://svn.apache.org/viewvc/subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure-indexes?rev=1687045&r1=1687044&r2=1687045&view=diff
==============================================================================
--- subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure-indexes (original)
+++ subversion/branches/svn-mergeinfo-normalizer/subversion/libsvn_fs_fs/structure-indexes Tue Jun 23 12:55:43 2015
@@ -13,10 +13,10 @@ to read and cache any data without trave
 
 Rev and pack files are immutable, so the same is true for index data.
 During a transaction or while packing a file, a proto index file gets
-written (actually, one log-to-phys and one phys-to-log).  Its format is
-a simple concatenation of runtime structs and as such, an implementation
-detail subject to change.  A proto index basically aggregates all the
-information that must later be transformed into the final index.
+written (actually, one log-to-phys and one phys-to-log).  They use a
+simpler, less compact format with fixed record lengths.  A proto index
+basically aggregates all the information that must later be transformed
+into the final index.
 
 
 General design concerns
@@ -192,11 +192,11 @@ at the beginning of the file is optional
 
   <bof>         /* begin of proto index file for revision r and following */
   (0, 0)        /* mark start of revision r, optional for first rev */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 1 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   (0, 0)        /* mark start of revision r + 2 */
-  (off, item)*  /* zero to many mappings in random order */
+  (off, item)*  /* zero or more mappings in random order */
   ...
   <eof>         /* end of file. */
 
@@ -343,10 +343,12 @@ For performance reasons we use a modifie
 
   h0 = fnv_1a([b0 b4 b8 ..]), ..., h3 = fnv_1a([b3 b7 b11 ..])
 
-* combine the big endian representation of these checksums plus the
-  remnant of the original stream into a 12 to 15 byte long intermediate
+* concatenate the big endian representation of these checksums (4 bytes
+  each) plus the remnant of the original stream into a 16 to 19 byte long
+  intermediate:
 
-  [i0 .. iK], 12 <= K+1 <= 15
+  [i0 .. iK] = [big-endian(h0) ... big-endian(h3) remnant ], 16 <= K+1 <= 19
 
-* FNV checksum = fnv_1a([i0 .. iK]) in big endian representation
+* fold the variable-length intermediate into a compact 32 bit checksum:
 
+  FNV checksum = fnv_1a([i0 .. iK])



Mime
View raw message