Fix issue 2751: Lost prop-mods on overlapping commits.

Approved by: +1 cmpilato, jszakmeister, dlr, dionisos


git-svn-id: https://svn.apache.org/repos/asf/subversion/branches/1.1.x@864538 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/STATUS b/STATUS
index b65ed54..91a2fe9 100644
--- a/STATUS
+++ b/STATUS
@@ -82,14 +82,6 @@
       commands without this patch.
     Votes:
       +1: jszakmeister
-                                         
-Approved changes (further review is welcome, but not required):  
 
-  * r24073, r24126, r24128
-    Branch: 1.1.x-issue-2751
-    Fix rare FS corruption in both bdb and FSFS filesystem implementations
-    Justification:
-      Well, *corruption*...
-    Votes:
-      +1: dionisos, cmpilato, jszakmeister
+Approved changes (further review is welcome, but not required):
 
diff --git a/subversion/libsvn_fs_base/tree.c b/subversion/libsvn_fs_base/tree.c
index f264006..461becb 100644
--- a/subversion/libsvn_fs_base/tree.c
+++ b/subversion/libsvn_fs_base/tree.c
@@ -1,7 +1,7 @@
 /* tree.c : tree-like filesystem, built on DAG filesystem
  *
  * ====================================================================
- * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+ * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution.  The terms
@@ -2034,14 +2034,20 @@
   /* Possible early merge failure: if target and ancestor have
      different property lists, then the merge should fail.
      Propchanges can *only* be committed on an up-to-date directory.
+     ### TODO: see issue #418 about the inelegance of this. 
 
-     ### TODO: Please see issue #418 about the inelegance of this. */
+     Another possible, similar, early merge failure: if source and
+     ancestor have different property lists (meaning someone else
+     changed directory properties while our commit transaction was
+     happening), the merge should fail.  See issue #2751.
+  */
   {
-    node_revision_t *tgt_nr, *anc_nr;
+    node_revision_t *tgt_nr, *anc_nr, *src_nr;
 
     /* Get node revisions for our id's. */
     SVN_ERR (svn_fs_bdb__get_node_revision (&tgt_nr, fs, target_id, trail));
     SVN_ERR (svn_fs_bdb__get_node_revision (&anc_nr, fs, ancestor_id, trail));
+    SVN_ERR (svn_fs_bdb__get_node_revision (&src_nr, fs, source_id, trail));
 
     /* Now compare the prop-keys of the skels.  Note that just because
        the keys are different -doesn't- mean the proplists have
@@ -2050,9 +2056,9 @@
        it won't do that here either.  Checking to see if the propkey
        atoms are `equal' is enough. */
     if (! svn_fs_base__same_keys (tgt_nr->prop_key, anc_nr->prop_key))
-      {
-        return conflict_err (conflict_p, target_path);
-      }
+      return conflict_err (conflict_p, target_path);
+    if (! svn_fs_base__same_keys (src_nr->prop_key, anc_nr->prop_key))
+      return conflict_err (conflict_p, target_path);
   }
 
   /* ### todo: it would be more efficient to simply check for a NULL
diff --git a/subversion/libsvn_fs_fs/tree.c b/subversion/libsvn_fs_fs/tree.c
index 397b4f9..85b62ac 100644
--- a/subversion/libsvn_fs_fs/tree.c
+++ b/subversion/libsvn_fs_fs/tree.c
@@ -1,7 +1,7 @@
 /* tree.c : tree-like filesystem, built on DAG filesystem
  *
  * ====================================================================
- * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+ * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution.  The terms
@@ -1347,15 +1347,20 @@
   /* Possible early merge failure: if target and ancestor have
      different property lists, then the merge should fail.
      Propchanges can *only* be committed on an up-to-date directory.
+     ### TODO: see issue #418 about the inelegance of this. 
 
-     ### TODO: Please see issue #418 about the inelegance of this. */
+     Another possible, similar, early merge failure: if source and
+     ancestor have different property lists (meaning someone else
+     changed directory properties while our commit transaction was
+     happening), the merge should fail.  See issue #2751.
+  */
   {
-    node_revision_t *tgt_nr, *anc_nr;
+    node_revision_t *tgt_nr, *anc_nr, *src_nr;
 
     /* Get node revisions for our id's. */
-    
     SVN_ERR (svn_fs_fs__get_node_revision (&tgt_nr, fs, target_id, pool));
     SVN_ERR (svn_fs_fs__get_node_revision (&anc_nr, fs, ancestor_id, pool));
+    SVN_ERR (svn_fs_fs__get_node_revision (&src_nr, fs, source_id, pool));
     
     /* Now compare the prop-keys of the skels.  Note that just because
        the keys are different -doesn't- mean the proplists have
@@ -1364,9 +1369,9 @@
        it won't do that here either.  Checking to see if the propkey
        atoms are `equal' is enough. */
     if (! svn_fs_fs__noderev_same_rep_key (tgt_nr->prop_rep, anc_nr->prop_rep))
-      {
-        return conflict_err (conflict_p, target_path);
-      }
+      return conflict_err (conflict_p, target_path);
+    if (! svn_fs_fs__noderev_same_rep_key (src_nr->prop_rep, anc_nr->prop_rep))
+      return conflict_err (conflict_p, target_path);
   }
 
   /* ### todo: it would be more efficient to simply check for a NULL
diff --git a/subversion/tests/libsvn_fs_base/fs-test.c b/subversion/tests/libsvn_fs_base/fs-test.c
index 955b305..963940c 100644
--- a/subversion/tests/libsvn_fs_base/fs-test.c
+++ b/subversion/tests/libsvn_fs_base/fs-test.c
@@ -1,7 +1,7 @@
 /* fs-test.c --- tests for the filesystem
  *
  * ====================================================================
- * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
+ * Copyright (c) 2000-2007 CollabNet.  All rights reserved.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution.  The terms
@@ -5193,6 +5193,54 @@
 }
 
 
+static svn_error_t *
+unordered_txn_dirprops (const char **msg,
+                        svn_boolean_t msg_only,
+                        apr_pool_t *pool)
+{
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn, *txn2;
+  svn_fs_root_t *txn_root, *txn_root2;
+  svn_string_t pval;
+  svn_revnum_t new_rev;
+
+  /* This is a regression test for issue #2751. */
+  *msg = "test dir prop preservation in unordered txns";
+
+  if (msg_only)
+    return SVN_NO_ERROR;
+
+  /* Prepare a filesystem. */
+  SVN_ERR (svn_test__create_fs (&fs, "test-repo-root-revisions", pool));
+
+  /* Create and commit the greek tree. */
+  SVN_ERR (svn_fs_begin_txn (&txn, fs, 0, pool));
+  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
+  SVN_ERR (svn_test__create_greek_tree (txn_root, pool));
+  SVN_ERR (test_commit_txn (&new_rev, txn, NULL, pool));
+
+  /* Open two transactions */
+  SVN_ERR (svn_fs_begin_txn (&txn, fs, new_rev, pool));
+  SVN_ERR (svn_fs_txn_root (&txn_root, txn, pool));
+  SVN_ERR (svn_fs_begin_txn (&txn2, fs, new_rev, pool));
+  SVN_ERR (svn_fs_txn_root (&txn_root2, txn2, pool));
+
+  /* Change a child file in one. */
+  SVN_ERR (svn_test__set_file_contents (txn_root, "/A/B/E/alpha",
+                                        "New contents", pool));
+
+  /* Change dir props in the other. */
+  SET_STR (&pval, "value");
+  SVN_ERR (svn_fs_change_node_prop (txn_root2, "/A/B", "name", &pval, pool));
+
+  /* Commit the second one first. */
+  SVN_ERR (test_commit_txn (&new_rev, txn2, NULL, pool));
+  
+  /* Then commit the first -- but expect an conflict due to the
+     propchanges made by the other txn. */
+  return test_commit_txn (&new_rev, txn, "/A/B", pool);
+}
+
 /* ------------------------------------------------------------------------ */
 
 /* The test table.  */
@@ -5236,5 +5284,6 @@
     SVN_TEST_PASS (verify_checksum),
     SVN_TEST_PASS (skip_deltas),
     SVN_TEST_PASS (redundant_copy),
+    SVN_TEST_PASS (unordered_txn_dirprops),
     SVN_TEST_NULL
   };