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

svn commit: r1302987 - in /subversion/branches/1.6.x-issue4129: ./ subversion/libsvn_fs_fs/fs_fs.c subversion/libsvn_fs_fs/tree.c subversion/libsvn_fs_fs/tree.h

Author: stsp
Date: Tue Mar 20 16:38:17 2012
New Revision: 1302987

URL: http://svn.apache.org/viewvc?rev=1302987&view=rev
Log:
On the 1.6.x-issue4129 branch, merge r1178280, r1178282, r1186121,
and r1186231 from trunk. The regression test added for issue #4129
relies on these changes.

Modified:
    subversion/branches/1.6.x-issue4129/   (props changed)
    subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/fs_fs.c
    subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.c
    subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.h

Propchange: subversion/branches/1.6.x-issue4129/
------------------------------------------------------------------------------
  Merged /subversion/trunk:r1178280,1178282,1186121,1186231

Modified: subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/fs_fs.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/fs_fs.c?rev=1302987&r1=1302986&r2=1302987&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/fs_fs.c (original)
+++ subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/fs_fs.c Tue Mar 20 16:38:17 2012
@@ -5345,6 +5345,62 @@ write_hash_rep(svn_filesize_t *size,
   return svn_stream_printf(whb->stream, pool, "ENDREP\n");
 }
 
+/* Sanity check ROOT_NODEREV, a candidate for being the root node-revision
+   of (not yet committed) revision REV in FS.  Use POOL for temporary
+   allocations.
+ */
+static svn_error_t *
+validate_root_noderev(svn_fs_t *fs,
+                      node_revision_t *root_noderev,
+                      svn_revnum_t rev,
+                      apr_pool_t *pool)
+{
+  svn_revnum_t head_revnum = rev-1;
+  int head_predecessor_count;
+
+  SVN_ERR_ASSERT(rev > 0);
+
+  /* Compute HEAD_PREDECESSOR_COUNT. */
+  {
+    svn_fs_root_t *head_revision;
+    const svn_fs_id_t *head_root_id;
+    node_revision_t *head_root_noderev;
+
+    /* Get /@HEAD's noderev. */
+    SVN_ERR(svn_fs_fs__revision_root(&head_revision, fs, head_revnum, pool));
+    SVN_ERR(svn_fs_fs__node_id(&head_root_id, head_revision, "/", pool));
+    SVN_ERR(svn_fs_fs__get_node_revision(&head_root_noderev, fs, head_root_id,
+                                         pool));
+
+    head_predecessor_count = head_root_noderev->predecessor_count;
+  }
+
+  /* Check that the root noderev's predecessor count equals REV.
+
+     This kind of corruption was seen on svn.apache.org (both on
+     the root noderev and on other fspaths' noderevs); see
+       http://mid.gmane.org/20111002202833.GA12373@daniel3.local
+
+     Normally (rev == root_noderev->predecessor_count), but here we
+     use a more roundabout check that should only trigger on new instances
+     of the corruption, rather then trigger on each and every new commit
+     to a repository that has triggered the bug somewhere in its root
+     noderev's history.
+   */
+  if (root_noderev->predecessor_count != -1
+      && (root_noderev->predecessor_count - head_predecessor_count)
+         != (rev - head_revnum))
+    {
+      return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
+                               _("predecessor count for "
+                                 "the root node-revision is wrong: "
+                                 "found %d, committing r%ld"),
+                                 root_noderev->predecessor_count, rev);
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Copy a node-revision specified by id ID in fileystem FS from a
    transaction into the proto-rev-file FILE.  Return the offset of
    the new node-revision in *OFFSET.  If this is a directory, all
@@ -5360,7 +5416,11 @@ write_hash_rep(svn_filesize_t *size,
    If REPS_TO_CACHE is not NULL, append to it a copy (allocated in
    REPS_POOL) of each data rep that is new in this revision.
 
-   Temporary allocations are from POOL.  */
+   AT_ROOT is true if the node revision being written is the root
+   node-revision.  It is only controls additional sanity checking
+   logic.
+
+   Temporary allocations are also from POOL. */
 static svn_error_t *
 write_final_rev(const svn_fs_id_t **new_id_p,
                 apr_file_t *file,
@@ -5372,6 +5432,7 @@ write_final_rev(const svn_fs_id_t **new_
                 apr_off_t initial_offset,
                 apr_array_header_t *reps_to_cache,
                 apr_pool_t *reps_pool,
+                svn_boolean_t at_root,
                 apr_pool_t *pool)
 {
   node_revision_t *noderev;
@@ -5410,7 +5471,7 @@ write_final_rev(const svn_fs_id_t **new_
           dirent = val;
           SVN_ERR(write_final_rev(&new_id, file, rev, fs, dirent->id,
                                   start_node_id, start_copy_id, initial_offset,
-                                  reps_to_cache, reps_pool,
+                                  reps_to_cache, reps_pool, FALSE,
                                   subpool));
           if (new_id && (svn_fs_fs__id_rev(new_id) == rev))
             dirent->id = svn_fs_fs__id_copy(new_id, pool);
@@ -5508,6 +5569,8 @@ write_final_rev(const svn_fs_id_t **new_
   noderev->id = new_id;
 
   /* Write out our new node-revision. */
+  if (at_root)
+    SVN_ERR(validate_root_noderev(fs, noderev, rev, pool));
   SVN_ERR(svn_fs_fs__write_noderev(svn_stream_from_aprfile2(file, TRUE, pool),
                                    noderev, ffd->format,
                                    svn_fs_fs__fs_supports_mergeinfo(fs),
@@ -5818,7 +5881,7 @@ commit_body(void *baton, apr_pool_t *poo
   root_id = svn_fs_fs__id_txn_create("0", "0", cb->txn->id, pool);
   SVN_ERR(write_final_rev(&new_root_id, proto_file, new_rev, cb->fs, root_id,
                           start_node_id, start_copy_id, initial_offset,
-                          cb->reps_to_cache, cb->reps_pool,
+                          cb->reps_to_cache, cb->reps_pool, TRUE,
                           pool));
 
   /* Write the changed-path information. */

Modified: subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.c?rev=1302987&r1=1302986&r2=1302987&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.c Tue Mar 20 16:38:17 2012
@@ -866,11 +866,11 @@ add_change(svn_fs_t *fs,
 
 /* Get the id of a node referenced by path PATH in ROOT.  Return the
    id in *ID_P allocated in POOL. */
-static svn_error_t *
-fs_node_id(const svn_fs_id_t **id_p,
-           svn_fs_root_t *root,
-           const char *path,
-           apr_pool_t *pool)
+svn_error_t *
+svn_fs_fs__node_id(const svn_fs_id_t **id_p,
+                   svn_fs_root_t *root,
+                   const char *path,
+                   apr_pool_t *pool)
 {
   if ((! root->is_txn_root)
       && (path[0] == '\0' || ((path[0] == '/') && (path[1] == '\0'))))
@@ -935,7 +935,7 @@ node_kind(svn_node_kind_t *kind_p,
   dag_node_t *node;
 
   /* Get the node id. */
-  SVN_ERR(fs_node_id(&node_id, root, path, pool));
+  SVN_ERR(svn_fs_fs__node_id(&node_id, root, path, pool));
 
   /* Use the node id to get the real kind. */
   SVN_ERR(svn_fs_fs__dag_get_node(&node, root->fs, node_id, pool));
@@ -2956,7 +2956,7 @@ fs_node_origin_rev(svn_revnum_t *revisio
   path = svn_fs__canonicalize_abspath(path, pool);
 
   /* Check the cache first. */
-  SVN_ERR(fs_node_id(&given_noderev_id, root, path, pool));
+  SVN_ERR(svn_fs_fs__node_id(&given_noderev_id, root, path, pool));
   node_id = svn_fs_fs__id_node_id(given_noderev_id);
 
   /* Is it a brand new uncommitted node? */
@@ -3028,7 +3028,7 @@ fs_node_origin_rev(svn_revnum_t *revisio
       }
 
     /* Walk the predecessor links back to origin. */
-    SVN_ERR(fs_node_id(&pred_id, curroot, lastpath->data, predidpool));
+    SVN_ERR(svn_fs_fs__node_id(&pred_id, curroot, lastpath->data, predidpool));
     while (pred_id)
       {
         svn_pool_clear(subpool);
@@ -3654,7 +3654,7 @@ static root_vtable_t root_vtable = {
   fs_paths_changed,
   svn_fs_fs__check_path,
   fs_node_history,
-  fs_node_id,
+  svn_fs_fs__node_id,
   svn_fs_fs__node_created_rev,
   fs_node_origin_rev,
   fs_node_created_path,

Modified: subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.h?rev=1302987&r1=1302986&r2=1302987&view=diff
==============================================================================
--- subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.h (original)
+++ subversion/branches/1.6.x-issue4129/subversion/libsvn_fs_fs/tree.h Tue Mar 20 16:38:17 2012
@@ -55,6 +55,13 @@ svn_fs_fs__check_path(svn_node_kind_t *k
                       const char *path,
                       apr_pool_t *pool);
 
+/* Implement root_vtable_t.node_id(). */
+svn_error_t *
+svn_fs_fs__node_id(const svn_fs_id_t **id_p,
+                   svn_fs_root_t *root,
+                   const char *path,
+                   apr_pool_t *pool);
+
 /* Set *REVISION to the revision in which PATH under ROOT was created.
    Use POOL for any temporary allocations.  If PATH is in an
    uncommitted transaction, *REVISION will be set to