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 2010/11/17 01:09:55 UTC

svn commit: r1035869 [19/19] - in /subversion/branches/performance: ./ build/ build/generator/ build/generator/templates/ build/win32/ subversion/bindings/javahl/native/ subversion/bindings/javahl/src/org/apache/subversion/javahl/ subversion/bindings/j...

Modified: subversion/branches/performance/subversion/tests/libsvn_fs_fs/fs-pack-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_fs_fs/fs-pack-test.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_fs_fs/fs-pack-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_fs_fs/fs-pack-test.c Wed Nov 17 00:09:50 2010
@@ -34,16 +34,14 @@
 #include "../svn_test_fs.h"
 
 
-/*-----------------------------------------------------------------*/
 
-/** The actual fs-tests called by `make check` **/
+/*** Helper Functions ***/
 
 /* Write the format number and maximum number of files per directory
-   to a new format file in PATH, overwriting a previously existing file.
+   to a new format file in PATH, overwriting a previously existing
+   file.  Use POOL for temporary allocation.
 
-   Use POOL for temporary allocation.
-
-   This implementation is largely stolen from libsvn_fs_fs/fs_fs.c. */
+   (This implementation is largely stolen from libsvn_fs_fs/fs_fs.c.) */
 static svn_error_t *
 write_format(const char *path,
              int format,
@@ -97,12 +95,15 @@ get_rev_contents(svn_revnum_t rev, apr_p
   return apr_psprintf(pool, "%" APR_INT64_T_FMT "\n", num);
 }
 
-/* Create a packed filesystem in DIR.  Set the shard size to SHARD_SIZE
-   and create MAX_REV number of revisions.  Use POOL for allocations. */
+/* Create a packed filesystem in DIR.  Set the shard size to
+   SHARD_SIZE and create NUM_REVS number of revisions (in addition to
+   r0).  Use POOL for allocations.  After this function successfully
+   completes, the filesystem's youngest revision number will be the
+   same as NUM_REVS.  */
 static svn_error_t *
 create_packed_filesystem(const char *dir,
                          const svn_test_opts_t *opts,
-                         int max_rev,
+                         int num_revs,
                          int shard_size,
                          apr_pool_t *pool)
 {
@@ -133,9 +134,9 @@ create_packed_filesystem(const char *dir
   SVN_ERR(svn_test__create_greek_tree(txn_root, subpool));
   SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
 
-  /* Revisions 2-11: A bunch of random changes. */
+  /* Revisions 2 thru NUM_REVS-1: content tweaks to "iota". */
   iterpool = svn_pool_create(subpool);
-  while (after_rev < max_rev + 1)
+  while (after_rev < num_revs)
     {
       svn_pool_clear(iterpool);
       SVN_ERR(svn_fs_begin_txn(&txn, fs, after_rev, iterpool));
@@ -153,7 +154,10 @@ create_packed_filesystem(const char *dir
   return svn_fs_pack(dir, NULL, NULL, NULL, NULL, pool);
 }
 
-/* Pack a filesystem.  */
+
+/*** Tests ***/
+
+/* ------------------------------------------------------------------------ */
 #define REPO_NAME "test-repo-fsfs-pack"
 #define SHARD_SIZE 7
 #define MAX_REV 53
@@ -181,7 +185,8 @@ pack_filesystem(const svn_test_opts_t *o
   for (i = 0; i < (MAX_REV + 1) / SHARD_SIZE; i++)
     {
       path = svn_path_join_many(pool, REPO_NAME, "revs",
-            apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "pack", NULL);
+                                apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
+                                "pack", NULL);
 
       /* These files should exist. */
       SVN_ERR(svn_io_check_path(path, &kind, pool));
@@ -190,7 +195,8 @@ pack_filesystem(const svn_test_opts_t *o
                                  "Expected pack file '%s' not found", path);
 
       path = svn_path_join_many(pool, REPO_NAME, "revs",
-            apr_psprintf(pool, "%d.pack", i / SHARD_SIZE), "manifest", NULL);
+                                apr_psprintf(pool, "%d.pack", i / SHARD_SIZE),
+                                "manifest", NULL);
       SVN_ERR(svn_io_check_path(path, &kind, pool));
       if (kind != svn_node_file)
         return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
@@ -199,7 +205,8 @@ pack_filesystem(const svn_test_opts_t *o
 
       /* This directory should not exist. */
       path = svn_path_join_many(pool, REPO_NAME, "revs",
-            apr_psprintf(pool, "%d", i / SHARD_SIZE), NULL);
+                                apr_psprintf(pool, "%d", i / SHARD_SIZE),
+                                NULL);
       SVN_ERR(svn_io_check_path(path, &kind, pool));
       if (kind != svn_node_none)
         return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
@@ -220,12 +227,12 @@ pack_filesystem(const svn_test_opts_t *o
 
   /* Finally, make sure the final revision directory does exist. */
   path = svn_path_join_many(pool, REPO_NAME, "revs",
-        apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1), NULL);
+                            apr_psprintf(pool, "%d", (i / SHARD_SIZE) + 1),
+                            NULL);
   SVN_ERR(svn_io_check_path(path, &kind, pool));
   if (kind != svn_node_none)
     return svn_error_createf(SVN_ERR_FS_GENERAL, NULL,
-                             "Expected directory '%s' not found",
-                             path);
+                             "Expected directory '%s' not found", path);
 
 
   return SVN_NO_ERROR;
@@ -234,10 +241,10 @@ pack_filesystem(const svn_test_opts_t *o
 #undef SHARD_SIZE
 #undef MAX_REV
 
-/* Pack a filesystem.  */
+/* ------------------------------------------------------------------------ */
 #define REPO_NAME "test-repo-fsfs-pack-even"
 #define SHARD_SIZE 4
-#define MAX_REV 10
+#define MAX_REV 11
 static svn_error_t *
 pack_even_filesystem(const svn_test_opts_t *opts,
                      apr_pool_t *pool)
@@ -265,8 +272,10 @@ pack_even_filesystem(const svn_test_opts
 #undef SHARD_SIZE
 #undef MAX_REV
 
-/* Check reading from a packed filesystem. */
+/* ------------------------------------------------------------------------ */
 #define REPO_NAME "test-repo-read-packed-fs"
+#define SHARD_SIZE 5
+#define MAX_REV 11
 static svn_error_t *
 read_packed_fs(const svn_test_opts_t *opts,
                apr_pool_t *pool)
@@ -281,10 +290,10 @@ read_packed_fs(const svn_test_opts_t *op
       || (opts->server_minor_version && (opts->server_minor_version < 6)))
     return SVN_NO_ERROR;
 
-  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, 11, 5, pool));
+  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
   SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
 
-  for (i = 1; i < 12; i++)
+  for (i = 1; i < (MAX_REV + 1); i++)
     {
       svn_fs_root_t *rev_root;
       svn_stringbuf_t *sb;
@@ -306,9 +315,13 @@ read_packed_fs(const svn_test_opts_t *op
   return SVN_NO_ERROR;
 }
 #undef REPO_NAME
+#undef SHARD_SIZE
+#undef MAX_REV
 
-/* Check reading from a packed filesystem. */
+/* ------------------------------------------------------------------------ */
 #define REPO_NAME "test-repo-commit-packed-fs"
+#define SHARD_SIZE 5
+#define MAX_REV 10
 static svn_error_t *
 commit_packed_fs(const svn_test_opts_t *opts,
                  apr_pool_t *pool)
@@ -325,11 +338,11 @@ commit_packed_fs(const svn_test_opts_t *
     return SVN_NO_ERROR;
 
   /* Create the packed FS and open it. */
-  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, 11, 5, pool));
+  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, 5, pool));
   SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, pool));
 
   /* Now do a commit. */
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, 12, pool));
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, pool));
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
   SVN_ERR(svn_test__set_file_contents(txn_root, "iota",
           "How much better is it to get wisdom than gold! and to get "
@@ -339,9 +352,11 @@ commit_packed_fs(const svn_test_opts_t *
   return SVN_NO_ERROR;
 }
 #undef REPO_NAME
+#undef MAX_REV
+#undef SHARD_SIZE
 
-/* Get/set revprop while repository is being packed in background. */
-#define REPO_NAME "test-get-set-revprop-packed-fs"
+/* ------------------------------------------------------------------------ */
+#define REPO_NAME "test-repo-get-set-revprop-packed-fs"
 #define SHARD_SIZE 4
 #define MAX_REV 1
 static svn_error_t *
@@ -367,7 +382,7 @@ get_set_revprop_packed_fs(const svn_test
 
   subpool = svn_pool_create(pool);
   /* Do a commit to trigger packing. */
-  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV + 1, subpool));
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
   SVN_ERR(svn_test__set_file_contents(txn_root, "iota", "new-iota",  subpool));
   SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
@@ -377,14 +392,81 @@ get_set_revprop_packed_fs(const svn_test
   SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));
 
   /* Try to get revprop for revision 0. */
-  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR, pool));
+  SVN_ERR(svn_fs_revision_prop(&prop_value, fs, 0, SVN_PROP_REVISION_AUTHOR,
+                               pool));
 
   /* Try to change revprop for revision 0. */
   SVN_ERR(svn_fs_change_rev_prop(fs, 0, SVN_PROP_REVISION_AUTHOR,
-                                 svn_string_create("tweaked-author", pool), pool));
+                                 svn_string_create("tweaked-author", pool),
+                                 pool));
 
   return SVN_NO_ERROR;
 }
+#undef REPO_NAME
+#undef MAX_REV
+#undef SHARD_SIZE
+
+/* ------------------------------------------------------------------------ */
+/* Regression test for issue #3571 (fsfs 'svnadmin recover' expects
+   youngest revprop to be outside revprops.db). */
+#define REPO_NAME "test-repo-recover-fully-packed"
+#define SHARD_SIZE 4
+#define MAX_REV 7
+static svn_error_t *
+recover_fully_packed(const svn_test_opts_t *opts,
+                     apr_pool_t *pool)
+{
+  apr_pool_t *subpool;
+  svn_fs_t *fs;
+  svn_fs_txn_t *txn;
+  svn_fs_root_t *txn_root;
+  const char *conflict;
+  svn_revnum_t after_rev;
+  svn_error_t *err;
+
+  /* Bail (with success) on known-untestable scenarios */
+  if ((strcmp(opts->fs_type, "fsfs") != 0)
+      || (opts->server_minor_version && (opts->server_minor_version < 7)))
+    return SVN_NO_ERROR;
+
+  /* Create a packed FS for which every revision will live in a pack
+     digest file, and then recover it. */
+  SVN_ERR(create_packed_filesystem(REPO_NAME, opts, MAX_REV, SHARD_SIZE, pool));
+  SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
+
+  /* Add another revision, re-pack, re-recover. */
+  subpool = svn_pool_create(pool);
+  SVN_ERR(svn_fs_open(&fs, REPO_NAME, NULL, subpool));
+  SVN_ERR(svn_fs_begin_txn(&txn, fs, MAX_REV, subpool));
+  SVN_ERR(svn_fs_txn_root(&txn_root, txn, subpool));
+  SVN_ERR(svn_test__set_file_contents(txn_root, "A/mu", "new-mu", subpool));
+  SVN_ERR(svn_fs_commit_txn(&conflict, &after_rev, txn, subpool));
+  svn_pool_destroy(subpool);
+  SVN_ERR(svn_fs_pack(REPO_NAME, NULL, NULL, NULL, NULL, pool));
+  SVN_ERR(svn_fs_recover(REPO_NAME, NULL, NULL, pool));
+
+  /* Now, delete the youngest revprop file, and recover again.  This
+     time we want to see an error! */
+  SVN_ERR(svn_io_remove_file2(
+              svn_dirent_join_many(pool, REPO_NAME, PATH_REVPROPS_DIR,
+                                   apr_psprintf(pool, "%ld/%ld",
+                                                after_rev / SHARD_SIZE,
+                                                after_rev),
+                                   NULL),
+              FALSE, pool));
+  err = svn_fs_recover(REPO_NAME, NULL, NULL, pool);
+  if (! err)
+    return svn_error_create(SVN_ERR_TEST_FAILED, NULL,
+                            "Expected SVN_ERR_FS_CORRUPT error; got none");
+  if (err->apr_err != SVN_ERR_FS_CORRUPT)
+    return svn_error_create(SVN_ERR_TEST_FAILED, err,
+                            "Expected SVN_ERR_FS_CORRUPT error; got:");
+  svn_error_clear(err);
+  return SVN_NO_ERROR;
+}
+#undef REPO_NAME
+#undef MAX_REV
+#undef SHARD_SIZE
 
 /* ------------------------------------------------------------------------ */
 
@@ -403,5 +485,7 @@ struct svn_test_descriptor_t test_funcs[
                        "commit to a packed FSFS filesystem"),
     SVN_TEST_OPTS_PASS(get_set_revprop_packed_fs,
                        "get/set revprop while packing FSFS filesystem"),
+    SVN_TEST_OPTS_PASS(recover_fully_packed,
+                       "recover a fully packed filesystem"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/performance/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_wc/op-depth-test.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_wc/op-depth-test.c Wed Nov 17 00:09:50 2010
@@ -37,6 +37,8 @@
 
 #include "private/svn_wc_private.h"
 #include "private/svn_sqlite.h"
+#include "../../libsvn_wc/wc.h"
+#include "../../libsvn_wc/wc_db.h"
 
 #include "../svn_test.h"
 
@@ -170,11 +172,16 @@ static svn_error_t *
 wc_revert(wc_baton_t *b, const char *path, svn_depth_t depth)
 {
   const char *abspath = wc_path(b, path);
+  const char *lock_root_abspath;
 
-  return svn_wc_revert4(b->wc_ctx, abspath, depth, FALSE, NULL,
-                        NULL, NULL, /* cancel baton + func */
-                        NULL, NULL, /* notify baton + func */
-                        b->pool);
+  SVN_ERR(svn_wc__acquire_write_lock(&lock_root_abspath, b->wc_ctx, abspath,
+                                     TRUE /* lock_anchor */, b->pool, b->pool));
+  SVN_ERR(svn_wc_revert4(b->wc_ctx, abspath, depth, FALSE, NULL,
+                         NULL, NULL, /* cancel baton + func */
+                         NULL, NULL, /* notify baton + func */
+                         b->pool));
+  SVN_ERR(svn_wc__release_write_lock(b->wc_ctx, lock_root_abspath, b->pool));
+  return SVN_NO_ERROR;
 }
 
 static svn_error_t *
@@ -215,6 +222,15 @@ wc_update(wc_baton_t *b, const char *pat
                             TRUE, FALSE, FALSE, ctx, b->pool);
 }
 
+static svn_error_t *
+wc_resolved(wc_baton_t *b, const char *path)
+{
+  svn_client_ctx_t *ctx;
+
+  SVN_ERR(svn_client_create_context(&ctx, b->pool));
+  return svn_client_resolved(wc_path(b, path), TRUE, ctx, b->pool);
+}
+
 /* Create the Greek tree on disk in the WC, and commit it. */
 static svn_error_t *
 add_and_commit_greek_tree(wc_baton_t *b)
@@ -274,6 +290,10 @@ typedef struct nodes_row_t {
     const char *repo_relpath;
 } nodes_row_t;
 
+/* Macro for filling in the REPO_* fields of a non-base NODES_ROW_T
+ * that has no copy-from info. */
+#define NO_COPY_FROM SVN_INVALID_REVNUM, NULL
+
 /* Return a human-readable string representing ROW. */
 static const char *
 print_row(const nodes_row_t *row,
@@ -302,7 +322,7 @@ typedef struct {
  * Append an error message to BATON->errors if they differ or are not both
  * present.
  *
- * If the ACTUAL row has field values that should have been elided
+ * If the FOUND row has field values that should have been elided
  * (because they match the parent row), then do so now.  We want to ignore
  * any such lack of elision, for the purposes of these tests, because the
  * method of copying in use (at the time this tweak is introduced) does
@@ -317,8 +337,9 @@ compare_nodes_rows(const void *key, apr_
   comparison_baton_t *b = baton;
   nodes_row_t *expected = apr_hash_get(b->expected_hash, key, klen);
   nodes_row_t *found = apr_hash_get(b->found_hash, key, klen);
+  nodes_row_t elided;
 
-  /* If the ACTUAL row has field values that should have been elided
+  /* If the FOUND row has field values that should have been elided
    * (because they match the parent row), then do so now. */
   if (found && found->op_depth > 0 && found->repo_relpath)
     {
@@ -333,11 +354,16 @@ compare_nodes_rows(const void *key, apr_
                                   APR_HASH_KEY_STRING);
       if (parent_found && parent_found->op_depth > 0
           && parent_found->repo_relpath
+          && found->op_depth == parent_found->op_depth
+          && found->repo_revnum == parent_found->repo_revnum
           && strcmp(found->repo_relpath,
                     svn_relpath_join(parent_found->repo_relpath, name,
-                                     b->scratch_pool)) == 0
-          && found->repo_revnum == parent_found->repo_revnum)
+                                     b->scratch_pool)) == 0)
         {
+          /* Iterating in hash order, which is arbitrary, so only make
+             changes in a local copy */
+          elided = *found;
+          found = &elided;
           found->repo_relpath = NULL;
           found->repo_revnum = SVN_INVALID_REVNUM;
         }
@@ -397,7 +423,9 @@ check_db_rows(wc_baton_t *b,
   SVN_ERR(open_wc_db(&sdb, b->wc_abspath, b->pool, b->pool));
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_SELECT_NODES_INFO));
   SVN_ERR(svn_sqlite__bindf(stmt, "ss", base_relpath,
-                            apr_psprintf(b->pool, "%s/%%", base_relpath)));
+                            (base_relpath[0]
+                             ? apr_psprintf(b->pool, "%s/%%", base_relpath)
+                             : "_%")));
   SVN_ERR(svn_sqlite__step(&have_row, stmt));
   while (have_row)
     {
@@ -437,6 +465,17 @@ check_db_rows(wc_baton_t *b,
 /* ---------------------------------------------------------------------- */
 /* The test functions */
 
+/* Definition of a copy sub-test and its expected results. */
+struct copy_subtest_t
+{
+  /* WC-relative or repo-relative source and destination paths. */
+  const char *from_path;
+  const char *to_path;
+  /* All the expected nodes table rows within the destination sub-tree.
+   * Terminated by an all-zero row. */
+  nodes_row_t expected[20];
+};
+
 /* Check that all kinds of WC-to-WC copies give correct op_depth results:
  * create a Greek tree, make copies in it, and check the resulting DB rows. */
 static svn_error_t *
@@ -474,14 +513,7 @@ wc_wc_copies(wc_baton_t *b)
   /* Test copying various things */
 
   {
-#define NO_COPY_FROM SVN_INVALID_REVNUM, NULL
-    struct subtest_t
-      {
-        const char *from_path;
-        const char *to_path;
-        nodes_row_t expected[20];
-      }
-    subtests[] =
+    struct copy_subtest_t subtests[] =
       {
         /* base file */
         { source_base_file, "A/C/copy1", {
@@ -559,7 +591,7 @@ wc_wc_copies(wc_baton_t *b)
 
         { 0 }
       };
-    struct subtest_t *subtest;
+    struct copy_subtest_t *subtest;
 
     /* Fix up the expected->local_relpath fields in the subtest data to be
      * relative to the WC root rather than to the copy destination dir. */
@@ -591,63 +623,75 @@ wc_wc_copies(wc_baton_t *b)
 static svn_error_t *
 repo_wc_copies(wc_baton_t *b)
 {
-  const char source_base_file[]   = "A/B/lambda";
-  const char source_base_dir[]    = "A/B/E";
-
   SVN_ERR(add_and_commit_greek_tree(b));
 
   /* Delete some nodes so that we can test copying onto these paths */
 
+  SVN_ERR(wc_delete(b, "A/B/lambda"));
   SVN_ERR(wc_delete(b, "A/D/gamma"));
   SVN_ERR(wc_delete(b, "A/D/G"));
+  SVN_ERR(wc_delete(b, "A/D/H"));
 
   /* Test copying various things */
 
   {
-#define NO_COPY_FROM SVN_INVALID_REVNUM, NULL
-    struct subtest_t
-      {
-        const char *from_path;
-        const char *to_path;
-        nodes_row_t expected[20];
-      }
-    subtests[] =
+    struct copy_subtest_t subtests[] =
       {
-        /* file */
-        { source_base_file, "A/C/copy1", {
-            { 3, "",                "normal",   1, source_base_file }
+        /* file onto nothing */
+        { "iota", "A/C/copy1", {
+            { 3, "",                "normal",       1, "iota" },
           } },
 
-        /* dir */
-        { source_base_dir, "A/C/copy2", {
-            { 3, "",                "normal",   1, source_base_dir },
-            { 3, "alpha",           "normal",   NO_COPY_FROM },
-            { 3, "beta",            "normal",   NO_COPY_FROM }
+        /* dir onto nothing */
+        { "A/B/E", "A/C/copy2", {
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
+          } },
+
+        /* file onto a schedule-delete file */
+        { "iota", "A/B/lambda", {
+            { 0, "",                "normal",       1, "A/B/lambda" },
+            { 3, "",                "normal",       1, "iota" },
+          } },
+
+        /* dir onto a schedule-delete dir */
+        { "A/B/E", "A/D/G", {
+            { 0, "",                "normal",       1, "A/D/G" },
+            { 0, "pi",              "normal",       1, "A/D/G/pi" },
+            { 0, "rho",             "normal",       1, "A/D/G/rho" },
+            { 0, "tau",             "normal",       1, "A/D/G/tau" },
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "pi",              "base-deleted", NO_COPY_FROM },
+            { 3, "rho",             "base-deleted", NO_COPY_FROM },
+            { 3, "tau",             "base-deleted", NO_COPY_FROM },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
           } },
 
         /* dir onto a schedule-delete file */
-        { source_base_dir, "A/D/gamma", {
-            { 0, "",                "normal",   1, "A/D/gamma" },
-            { 3, "",                "normal",   1, source_base_dir },
-            { 3, "alpha",           "normal",   NO_COPY_FROM },
-            { 3, "beta",            "normal",   NO_COPY_FROM }
+        { "A/B/E", "A/D/gamma", {
+            { 0, "",                "normal",       1, "A/D/gamma" },
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
           } },
 
         /* file onto a schedule-delete dir */
-        { source_base_file, "A/D/G", {
-            { 0, "",                "normal",   1, "A/D/G" },
-            { 0, "pi",              "normal",   1, "A/D/G/pi" },
-            { 0, "rho",             "normal",   1, "A/D/G/rho" },
-            { 0, "tau",             "normal",   1, "A/D/G/tau" },
-            { 3, "",                "normal",   1, source_base_file },
-            { 3, "pi",              "base-deleted",   NO_COPY_FROM },
-            { 3, "rho",             "base-deleted",   NO_COPY_FROM },
-            { 3, "tau",             "base-deleted",   NO_COPY_FROM }
+        { "iota", "A/D/H", {
+            { 0, "",                "normal",       1, "A/D/H" },
+            { 0, "chi",             "normal",       1, "A/D/H/chi" },
+            { 0, "psi",             "normal",       1, "A/D/H/psi" },
+            { 0, "omega",           "normal",       1, "A/D/H/omega" },
+            { 3, "",                "normal",       1, "iota" },
+            { 3, "chi",             "base-deleted", NO_COPY_FROM },
+            { 3, "psi",             "base-deleted", NO_COPY_FROM },
+            { 3, "omega",           "base-deleted", NO_COPY_FROM },
           } },
 
         { 0 }
       };
-    struct subtest_t *subtest;
+    struct copy_subtest_t *subtest;
     svn_client_ctx_t *ctx;
 
     /* Fix up the expected->local_relpath fields in the subtest data to be
@@ -800,7 +844,100 @@ test_adds(const svn_test_opts_t *opts, a
   SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
                                         "adds", opts, pool));
   SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+  SVN_ERR(add_and_commit_greek_tree(&b));
 
+  /* add file */
+  file_write(&b, "new-file", "New file");
+  SVN_ERR(wc_add(&b, "new-file"));
+  {
+    nodes_row_t rows[] = {
+      { 1, "new-file",    "normal",       NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "new-file", rows));
+  }
+
+  /* add dir */
+  SVN_ERR(wc_mkdir(&b, "new-dir"));
+  SVN_ERR(wc_mkdir(&b, "new-dir/D2"));
+  {
+    nodes_row_t rows[] = {
+      { 1, "new-dir",     "normal",       NO_COPY_FROM     },
+      { 2, "new-dir/D2",  "normal",       NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "new-dir", rows));
+  }
+
+  /* replace file */
+  SVN_ERR(wc_delete(&b, "iota"));
+  file_write(&b, "iota", "New iota file");
+  SVN_ERR(wc_add(&b, "iota"));
+  {
+    nodes_row_t rows[] = {
+      { 0, "iota",        "normal",       1, "iota"        },
+      { 1, "iota",        "normal",       NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "iota", rows));
+  }
+
+  /* replace dir */
+  SVN_ERR(wc_delete(&b, "A/B/E"));
+  SVN_ERR(wc_mkdir(&b, "A/B/E"));
+  SVN_ERR(wc_mkdir(&b, "A/B/E/D2"));
+  {
+    nodes_row_t rows[] = {
+      { 0, "A/B/E",       "normal",       1, "A/B/E"       },
+      { 0, "A/B/E/alpha", "normal",       1, "A/B/E/alpha" },
+      { 0, "A/B/E/beta",  "normal",       1, "A/B/E/beta"  },
+      { 3, "A/B/E",       "normal",       NO_COPY_FROM     },
+      { 4, "A/B/E/D2",    "normal",       NO_COPY_FROM     },
+      { 3, "A/B/E/alpha", "base-deleted", NO_COPY_FROM     },
+      { 3, "A/B/E/beta",  "base-deleted", NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "A/B/E", rows));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_adds_change_kind(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "adds", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+  SVN_ERR(add_and_commit_greek_tree(&b));
+
+  /* replace dir with file */
+  SVN_ERR(wc_delete(&b, "A/B/E"));
+  file_write(&b, "A/B/E", "New E file");
+  SVN_ERR(wc_add(&b, "A/B/E"));
+  {
+    nodes_row_t rows[] = {
+      { 0, "A/B/E",       "normal",       1, "A/B/E"       },
+      { 0, "A/B/E/alpha", "normal",       1, "A/B/E/alpha" },
+      { 0, "A/B/E/beta",  "normal",       1, "A/B/E/beta"  },
+      { 3, "A/B/E",       "normal",       NO_COPY_FROM     },
+      { 3, "A/B/E/alpha", "base-deleted", NO_COPY_FROM     },
+      { 3, "A/B/E/beta",  "base-deleted", NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "A/B/E", rows));
+  }
+
+  /* replace file with dir */
+  SVN_ERR(wc_delete(&b, "iota"));
+  SVN_ERR(wc_mkdir(&b, "iota"));
+  SVN_ERR(wc_mkdir(&b, "iota/D2"));
+  {
+    nodes_row_t rows[] = {
+      { 0, "iota",        "normal",       1, "iota"        },
+      { 1, "iota",        "normal",       NO_COPY_FROM     },
+      { 2, "iota/D2",     "normal",       NO_COPY_FROM     },
+      { 0 } };
+    SVN_ERR(check_db_rows(&b, "iota", rows));
+  }
 
   return SVN_NO_ERROR;
 }
@@ -965,7 +1102,7 @@ test_repo_wc_copies(const svn_test_opts_
 
   b.pool = pool;
   SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
-                                        "wc_wc_copies", opts, pool));
+                                        "repo_wc_copies", opts, pool));
   SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
 
   return repo_wc_copies(&b);
@@ -1013,6 +1150,530 @@ test_delete_with_update(const svn_test_o
     };
     SVN_ERR(check_db_rows(&b, "A", rows));
   }
+  SVN_ERR(wc_resolved(&b, ""));
+  SVN_ERR(wc_update(&b, "", 1));
+  {
+    nodes_row_t rows[] = {
+      { 0, "A",       "normal",        1, "A"},
+      { 1, "A",       "normal",        NO_COPY_FROM},
+      { 2, "A/B",     "normal",        NO_COPY_FROM},
+      { 0 }
+    };
+    SVN_ERR(check_db_rows(&b, "A", rows));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+
+static svn_error_t *
+insert_dirs(wc_baton_t *b,
+            nodes_row_t *nodes)
+{
+  svn_sqlite__db_t *sdb;
+  svn_sqlite__stmt_t *stmt;
+  const char *dbpath = svn_dirent_join_many(b->pool,
+                                            b->wc_abspath, ".svn", "wc.db",
+                                            NULL);
+  const char * const statements[] = {
+    "DELETE FROM nodes;",
+    "INSERT INTO nodes (local_relpath, op_depth, presence, repos_path,"
+    "                   revision, wc_id, repos_id, kind, depth)"
+    "           VALUES (?1, ?2, ?3, ?4, ?5, 1, 1, 'dir', 'infinity');",
+    "INSERT INTO nodes (local_relpath, op_depth, presence, repos_path,"
+    "                   revision, parent_relpath, wc_id, repos_id, kind, depth)"
+    "           VALUES (?1, ?2, ?3, ?4, ?5, ?6, 1, 1, 'dir', 'infinity');",
+    NULL,
+  };
+
+  SVN_ERR(svn_sqlite__open(&sdb, dbpath, svn_sqlite__mode_readwrite,
+                           statements, 0, NULL,
+                           b->pool, b->pool));
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 0));
+  SVN_ERR(svn_sqlite__step_done(stmt));
+
+  while(nodes->local_relpath)
+    {
+      if (nodes->local_relpath[0])
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 2));
+          SVN_ERR(svn_sqlite__bindf(stmt, "sissrs",
+                                    nodes->local_relpath,
+                                    (apr_int64_t)nodes->op_depth,
+                                    nodes->presence,
+                                    nodes->repo_relpath,
+                                    nodes->repo_revnum,
+                                    svn_relpath_dirname(nodes->local_relpath,
+                                                        b->pool)));
+        }
+      else
+        {
+          SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, 1));
+          SVN_ERR(svn_sqlite__bindf(stmt, "sissr",
+                                    nodes->local_relpath,
+                                    (apr_int64_t)nodes->op_depth,
+                                    nodes->presence,
+                                    nodes->repo_relpath,
+                                    nodes->repo_revnum));
+        }
+
+      SVN_ERR(svn_sqlite__step_done(stmt));
+      ++nodes;
+    }
+
+  SVN_ERR(svn_sqlite__close(sdb));
+
+  return SVN_NO_ERROR;
+}
+
+static int count_rows(nodes_row_t *rows)
+{
+  nodes_row_t *first = rows;
+  while(rows->local_relpath)
+    ++rows;
+  return rows - first;
+}
+
+static svn_error_t *
+base_dir_insert_remove(wc_baton_t *b,
+                       const char *local_relpath,
+                       svn_revnum_t revision,
+                       nodes_row_t *before,
+                       nodes_row_t *added)
+{
+  nodes_row_t *after;
+  const char *dir_abspath = svn_path_join(b->wc_abspath, local_relpath,
+                                          b->pool);
+  int i, num_before = count_rows(before), num_added = count_rows(added);
+
+  SVN_ERR(insert_dirs(b, before));
+
+  SVN_ERR(svn_wc__db_base_add_directory(b->wc_ctx->db, dir_abspath,
+                                        local_relpath, b->repos_url,
+                                        "not-even-a-uuid", revision,
+                                        apr_hash_make(b->pool), revision,
+                                        0, NULL, NULL, svn_depth_infinity,
+                                        NULL, NULL, NULL, b->pool));
+
+  after = apr_palloc(b->pool, sizeof(*after) * (num_before + num_added + 1));
+  for (i = 0; i < num_before; ++i)
+    after[i] = before[i];
+  for (i = 0; i < num_added; ++i)
+    after[num_before+i] = added[i];
+  after[num_before+num_added].local_relpath = NULL;
+
+  SVN_ERR(check_db_rows(b, "", after));
+
+  SVN_ERR(svn_wc__db_base_remove(b->wc_ctx->db, dir_abspath, b->pool));
+
+  SVN_ERR(check_db_rows(b, "", before));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_base_dir_insert_remove(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "base_dir_insert_remove", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+
+  {
+    /* /  normal                     /    normal
+       A  normal                     A    normal
+                                     A/B  normal
+    */
+    nodes_row_t before[] = {
+      { 0, "",  "normal", 2, "" },
+      { 0, "A", "normal", 2, "A" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal", 2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /  normal                      /    normal
+       A  normal  base-del            A    normal  base-del
+                                      A/B  normal  base-del
+    */
+    nodes_row_t before[] = {
+      { 0, "",  "normal",       2, "" },
+      { 0, "A", "normal",       2, "A" },
+      { 1, "A", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /  normal                       /    normal
+       A  normal  normal               A    normal  normal
+                                       A/B  normal  base-del
+     */
+    nodes_row_t before[] = {
+      { 0, "",  "normal", 2, "" },
+      { 0, "A", "normal", 2, "A" },
+      { 1, "A", "normal", 1, "X" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                     /      normal
+       A    normal  normal             A      normal  normal
+       A/B  normal  not-pres           A/B    normal  not-pres
+                                       A/B/C  normal  base-del
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 0, "A/B", "normal",      2, "A/B" },
+      { 1, "A",   "normal",      1, "X" },
+      { 1, "A/B", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /    normal                      /    normal
+       A    normal  normal              A    normal  normal
+       A/B          normal              A/B  normal  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal", 2, "" },
+      { 0, "A",   "normal", 2, "A" },
+      { 1, "A",   "normal", 1, "X" },
+      { 1, "A/B", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                       /    normal
+       A    normal  normal               A    normal  normal
+       A/B          not-pres             A/B  normal  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 1, "A",   "normal",      1, "X" },
+      { 1, "A/B", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /    normal                       /    normal
+       A    normal  normal               A    normal  normal
+       A/B                  normal       A/B  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",      2, "" },
+      { 0, "A",   "normal",      2, "A" },
+      { 1, "A",   "normal",      1, "X" },
+      { 2, "A/B", "normal",      1, "Y" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B", 2, before, added));
+  }
+  {
+    /* /      normal                          /      normal
+       A      normal  normal                  A      normal  normal
+       A/B    normal  base-del  normal        A/B    normal  base-del  normal
+       A/B/C                    normal        A/B/C  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",    "normal",       2, "" },
+      { 0, "A",   "normal",       2, "A" },
+      { 0, "A/B", "normal",       2, "A/B" },
+      { 1, "A",   "normal",       1, "X" },
+      { 1, "A/B", "base-deleted", NO_COPY_FROM },
+      { 2, "A/B", "normal",       1, "Y" },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /      normal                          /      normal
+       A      normal  normal                  A      normal  normal
+       A/B    normal  not-pres  normal        A/B    normal  not-pres  normal
+       A/B/C                    normal        A/B/C  normal  base-del  normal
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 2, "A/B/C", "normal",      NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      normal                         /
+        A      normal  normal                 A      normal  normal
+        A/B    normal  base-del  normal       A/B    normal  base-del  normal
+        A/B/C                    not-pres     A/B/C  normal  base-del  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 1, "A",     "normal",       1, "X" },
+      { 1, "A/B",   "base-deleted", NO_COPY_FROM },
+      { 2, "A/B",   "normal",       1, "Y" },
+      { 2, "A/B/C", "not-present",  NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      normal                         /
+        A      normal  normal                 A      normal  normal
+        A/B    normal  not-pres  normal       A/B    normal  not-pres  normal
+        A/B/C                    not-pres     A/B/C  normal  base-del  not-pres
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 2, "A/B/C", "not-present", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /*  /      norm                       /
+        A      norm  norm                 A      norm  norm
+        A/B    norm  not-p  norm          A/B    norm  not-p  norm
+        A/B/C                     norm    A/B/C  norm  b-del        norm
+     */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",      2, "" },
+      { 0, "A",     "normal",      2, "A" },
+      { 0, "A/B",   "normal",      2, "A/B" },
+      { 1, "A",     "normal",      1, "X" },
+      { 1, "A/B",   "not-present", NO_COPY_FROM },
+      { 2, "A/B",   "normal",      1, "Y" },
+      { 3, "A/B/C", "normal",      NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C", 2, before, added));
+  }
+  {
+    /* /      norm                     /        norm
+       A      norm                     A        norm
+       A/B    norm                     A/B      norm
+       A/B/C  norm  -  -  norm         A/B/C    norm   -  -  norm
+                                       A/B/C/D  norm   -  -  b-del
+    */
+    nodes_row_t before[] = {
+      { 0, "",      "normal", 2, "" },
+      { 0, "A",     "normal", 2, "A" },
+      { 0, "A/B",   "normal", 2, "A/B" },
+      { 0, "A/B/C", "normal", 2, "A/B/C" },
+      { 3, "A/B/C", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C/D", "normal",       2, "A/B/C/D" },
+      { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C/D", 2, before, added));
+  }
+  {
+    /* /      norm                     /        norm
+       A      norm                     A        norm
+       A/B    norm                     A/B      norm
+       A/B/C  norm  -  -  norm         A/B/C    norm   -  -  norm
+       A/B/C/D                  norm   A/B/C/D  norm   -  -  b-del  norm
+    */
+    nodes_row_t before[] = {
+      { 0, "",        "normal", 2, "" },
+      { 0, "A",       "normal", 2, "A" },
+      { 0, "A/B",     "normal", 2, "A/B" },
+      { 0, "A/B/C",   "normal", 2, "A/B/C" },
+      { 3, "A/B/C",   "normal", NO_COPY_FROM },
+      { 4, "A/B/C/D", "normal", NO_COPY_FROM },
+      { 0 }
+    };
+    nodes_row_t added[] = {
+      { 0, "A/B/C/D", "normal",       2, "A/B/C/D" },
+      { 3, "A/B/C/D", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    SVN_ERR(base_dir_insert_remove(&b, "A/B/C/D", 2, before, added));
+  }
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+temp_op_make_copy(wc_baton_t *b,
+                  const char *local_relpath,
+                  nodes_row_t *before,
+                  nodes_row_t *after)
+{
+  const char *dir_abspath = svn_path_join(b->wc_abspath, local_relpath,
+                                          b->pool);
+
+  SVN_ERR(insert_dirs(b, before));
+
+  SVN_ERR(svn_wc__db_temp_op_make_copy(b->wc_ctx->db, dir_abspath, b->pool));
+
+  SVN_ERR(check_db_rows(b, "", after));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+test_temp_op_make_copy(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "base_dir_insert_remove", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+
+  {
+    /*  /           norm        -
+        A           norm        -
+        A/B         norm        -       norm
+        A/B/C       norm        -       base-del    norm
+        A/F         norm        -       norm
+        A/F/G       norm        -       norm
+        A/F/H       norm        -       not-pres
+        A/F/E       norm        -       base-del
+        A/X         norm        -
+        A/X/Y       incomplete  -
+    */
+    nodes_row_t before[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 0, "A/F",   "normal",       2, "A/F" },
+      { 0, "A/F/G", "normal",       2, "A/F/G" },
+      { 0, "A/F/H", "normal",       2, "A/F/H" },
+      { 0, "A/F/E", "normal",       2, "A/F/E" },
+      { 0, "A/X",   "normal",       2, "A/X" },
+      { 0, "A/X/Y", "incomplete",   2, "A/X/Y" },
+      { 2, "A/B",   "normal",       NO_COPY_FROM },
+      { 2, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 3, "A/B/C", "normal",       NO_COPY_FROM },
+      { 2, "A/F",   "normal",       1, "S2" },
+      { 2, "A/F/G", "normal",       NO_COPY_FROM },
+      { 2, "A/F/H", "not-present",  NO_COPY_FROM },
+      { 2, "A/F/E", "base-deleted", NO_COPY_FROM },
+      { 0 }
+    };
+    /*  /           norm        -
+        A           norm        norm
+        A/B         norm        base-del    norm
+        A/B/C       norm        base-del                norm
+        A/F         norm        base-del    norm
+        A/F/G       norm        base-del    norm
+        A/F/H       norm        base-del    not-pres
+        A/F/E       norm        base-del
+        A/X         norm        norm
+        A/X/Y       incomplete  incomplete
+    */
+    nodes_row_t after[] = {
+      { 0, "",      "normal",       2, "" },
+      { 0, "A",     "normal",       2, "A" },
+      { 0, "A/B",   "normal",       2, "A/B" },
+      { 0, "A/B/C", "normal",       2, "A/B/C" },
+      { 0, "A/F",   "normal",       2, "A/F" },
+      { 0, "A/F/G", "normal",       2, "A/F/G" },
+      { 0, "A/F/H", "normal",       2, "A/F/H" },
+      { 0, "A/F/E", "normal",       2, "A/F/E" },
+      { 0, "A/X",   "normal",       2, "A/X" },
+      { 0, "A/X/Y", "incomplete",   2, "A/X/Y" },
+      { 1, "A",     "normal",       2, "A" },
+      { 1, "A/B",   "base-deleted", NO_COPY_FROM },
+      { 1, "A/B/C", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F",   "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/G", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/H", "base-deleted", NO_COPY_FROM },
+      { 1, "A/F/E", "base-deleted", NO_COPY_FROM },
+      { 1, "A/X",   "normal",       NO_COPY_FROM },
+      { 1, "A/X/Y", "incomplete",   NO_COPY_FROM },
+      { 2, "A/B",   "normal",       NO_COPY_FROM },
+      { 3, "A/B/C", "normal",       NO_COPY_FROM },
+      { 2, "A/F",   "normal",       1, "S2" },
+      { 2, "A/F/G", "normal",       NO_COPY_FROM },
+      { 2, "A/F/H", "not-present",  NO_COPY_FROM },
+      { 0 }
+    };
+
+    SVN_ERR(temp_op_make_copy(&b, "A", before, after));
+  }
 
   return SVN_NO_ERROR;
 }
@@ -1024,7 +1685,7 @@ struct svn_test_descriptor_t test_funcs[
   {
     SVN_TEST_NULL,
     SVN_TEST_OPTS_WIMP(test_wc_wc_copies,
-                       "wc_wc_copies",
+                       "test_wc_wc_copies",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_reverts,
                        "test_reverts",
@@ -1039,13 +1700,22 @@ struct svn_test_descriptor_t test_funcs[
                        "test_delete_with_base",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_adds,
-                       "adds",
+                       "test_adds",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_repo_wc_copies,
                        "test_repo_wc_copies",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_delete_with_update,
-                       "test_test_delete_with_update",
+                       "test_delete_with_update",
+                       "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_adds_change_kind,
+                       "test_adds_change_kind",
+                       "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_base_dir_insert_remove,
+                       "test_base_dir_insert_remove",
+                       "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_temp_op_make_copy,
+                       "test_temp_op_make_copy",
                        "needs op_depth"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/performance/subversion/tests/libsvn_wc/tree-conflict-data-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/tests/libsvn_wc/tree-conflict-data-test.c?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/subversion/tests/libsvn_wc/tree-conflict-data-test.c (original)
+++ subversion/branches/performance/subversion/tests/libsvn_wc/tree-conflict-data-test.c Wed Nov 17 00:09:50 2010
@@ -53,15 +53,14 @@ fail(apr_pool_t *pool, const char *fmt, 
 static svn_error_t *
 test_read_tree_conflict(apr_pool_t *pool)
 {
-  svn_wc_conflict_description2_t *conflict;
-  apr_hash_t *conflicts;
+  const svn_wc_conflict_description2_t *conflict;
   svn_wc_conflict_description2_t *exp_conflict;
   const char *tree_conflict_data;
-  apr_hash_index_t *hi;
   const char *local_abspath;
+  const svn_skel_t *skel;
 
-  tree_conflict_data = "((conflict Foo.c file update deleted edited "
-                         "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
+  tree_conflict_data = "(conflict Foo.c file update deleted edited "
+                        "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 ))";
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
   exp_conflict = svn_wc_conflict_description_create_tree2(
@@ -70,11 +69,8 @@ test_read_tree_conflict(apr_pool_t *pool
   exp_conflict->action = svn_wc_conflict_action_delete;
   exp_conflict->reason = svn_wc_conflict_reason_edited;
 
-  SVN_ERR(svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                      pool));
-
-  hi = apr_hash_first(pool, conflicts);
-  conflict = svn__apr_hash_index_val(hi);
+  skel = svn_skel__parse(tree_conflict_data, strlen(tree_conflict_data), pool);
+  SVN_ERR(svn_wc__deserialize_conflict(&conflict, skel, "", pool, pool));
 
   if ((conflict->node_kind != exp_conflict->node_kind) ||
       (conflict->action    != exp_conflict->action) ||
@@ -87,120 +83,13 @@ test_read_tree_conflict(apr_pool_t *pool
 }
 
 static svn_error_t *
-test_read_2_tree_conflicts(apr_pool_t *pool)
-{
-  const char *tree_conflict_data;
-  svn_wc_conflict_description2_t *conflict1, *conflict2;
-  apr_hash_t *conflicts;
-  svn_wc_conflict_description2_t *exp_conflict1, *exp_conflict2;
-  apr_hash_index_t *hi;
-  const char *local_abspath;
-
-  tree_conflict_data =
-    "((conflict Foo.c file update deleted edited "
-      "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-     "(conflict Bar.h file update edited deleted "
-      "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
-  exp_conflict1 = svn_wc_conflict_description_create_tree2(
-                        local_abspath, svn_node_file, svn_wc_operation_update,
-                        NULL, NULL, pool);
-  exp_conflict1->action = svn_wc_conflict_action_delete;
-  exp_conflict1->reason = svn_wc_conflict_reason_edited;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Bar.h", pool));
-  exp_conflict2 = svn_wc_conflict_description_create_tree2(
-                        local_abspath, svn_node_file, svn_wc_operation_update,
-                         NULL, NULL, pool);
-  exp_conflict2->action = svn_wc_conflict_action_edit;
-  exp_conflict2->reason = svn_wc_conflict_reason_deleted;
-
-  SVN_ERR(svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                      pool));
-
-  hi = apr_hash_first(pool, conflicts);
-  conflict1 = svn__apr_hash_index_val(hi);
-  if ((conflict1->node_kind != exp_conflict1->node_kind) ||
-      (conflict1->action    != exp_conflict1->action) ||
-      (conflict1->reason    != exp_conflict1->reason) ||
-      (conflict1->operation != exp_conflict1->operation) ||
-      (strcmp(conflict1->local_abspath, exp_conflict1->local_abspath) != 0))
-    return fail(pool, "Tree conflict struct #1 has bad data");
-
-  hi = apr_hash_next(hi);
-  conflict2 = svn__apr_hash_index_val(hi);
-  if ((conflict2->node_kind != exp_conflict2->node_kind) ||
-      (conflict2->action    != exp_conflict2->action) ||
-      (conflict2->reason    != exp_conflict2->reason) ||
-      (conflict2->operation != exp_conflict2->operation) ||
-      (strcmp(conflict2->local_abspath, exp_conflict2->local_abspath) != 0))
-    return fail(pool, "Tree conflict struct #2 has bad data");
-
-  return SVN_NO_ERROR;
-}
-
-/* This needs to be adjusted in case the constants for the
- * delimiters change... */
-static const char* broken_tree_conflict_test_data[] = {
-  /* Missing descriptions */
-  "|Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c:file:update:deleted:edited::::::::|",
-  "|||||||",
-  "",
-  /* Missing fields */
-  "Foo.c:fileupdate:deleted:edited::::::::",
-  "Foo.c",
-  "::::",
-  ":::",
-  "Foo.c:::::::::::::;",
-  /* Bad separators */
-  "Foo.c:file:update:deleted:edited::::::::$Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c|file|update|deleted|edited:::::::::Bar.h|file|update|edited|deleted::::::::",
-  /* Missing separators */
-  "Foo.c:file:update:deleted:edited::::::::Bar.h:file:update:edited:deleted::::::::",
-  "Foo.c:fileupdate:deleted:edited::::::::",
-  /* Unescaped separators */
-  "F|oo.c:file:update:deleted:edited::::::::",
-  "F:oo.c:file:update:deleted:edited::::::::",
-  /* Unescaped escape */
-  "Foo.c\\:file:update:deleted:edited::::::::",
-  "Foo.c\\",
-  /* Illegally escaped char */
-  "\\Foo.c:file:update:deleted:edited::::::::",
-  NULL
-};
-
-static svn_error_t *
-test_read_invalid_tree_conflicts(apr_pool_t *pool)
-{
-  int i;
-  const char *tree_conflict_data;
-  apr_hash_t *conflicts;
-  svn_error_t *err;
-
-  for (i = 0; broken_tree_conflict_test_data[i] != NULL; i++)
-    {
-      tree_conflict_data = broken_tree_conflict_test_data[i];
-      err = svn_wc__read_tree_conflicts(&conflicts, tree_conflict_data, "",
-                                        pool);
-      if (err == SVN_NO_ERROR)
-        return fail(pool,
-                    "Error in broken tree conflict data was not detected:\n"
-                    "  %s", tree_conflict_data);
-      svn_error_clear(err);
-    }
-  return SVN_NO_ERROR;
-}
-
-static svn_error_t *
 test_write_tree_conflict(apr_pool_t *pool)
 {
   svn_wc_conflict_description2_t *conflict;
   const char *tree_conflict_data;
-  apr_hash_t *conflicts;
   const char *expected;
   const char *local_abspath;
+  svn_skel_t *skel;
 
   SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
 
@@ -210,14 +99,11 @@ test_write_tree_conflict(apr_pool_t *poo
   conflict->action = svn_wc_conflict_action_delete;
   conflict->reason = svn_wc_conflict_reason_edited;
 
-  conflicts = apr_hash_make(pool);
-  apr_hash_set(conflicts, conflict->local_abspath, APR_HASH_KEY_STRING,
-               conflict);
-
-  expected = "((conflict Foo.c file update deleted edited "
-               "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
+  SVN_ERR(svn_wc__serialize_conflict(&skel, conflict, pool, pool));
+  tree_conflict_data = svn_skel__unparse(skel, pool)->data;
 
-  SVN_ERR(svn_wc__write_tree_conflicts(&tree_conflict_data, conflicts, pool));
+  expected = "(conflict Foo.c file update deleted edited "
+             "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 ))";
 
   if (strcmp(expected, tree_conflict_data) != 0)
     return fail(pool, "Unexpected text from tree conflict\n"
@@ -227,60 +113,6 @@ test_write_tree_conflict(apr_pool_t *poo
   return SVN_NO_ERROR;
 }
 
-static svn_error_t *
-test_write_2_tree_conflicts(apr_pool_t *pool)
-{
-  svn_wc_conflict_description2_t *conflict1, *conflict2;
-  apr_hash_t *conflicts;
-  const char *tree_conflict_data;
-  const char *expected1;
-  const char *expected2;
-  const char *local_abspath;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Foo.c", pool));
-  conflict1 = svn_wc_conflict_description_create_tree2(
-                    local_abspath, svn_node_file, svn_wc_operation_update,
-                    NULL, NULL, pool);
-  conflict1->action = svn_wc_conflict_action_delete;
-  conflict1->reason = svn_wc_conflict_reason_edited;
-
-  SVN_ERR(svn_dirent_get_absolute(&local_abspath, "Bar.h", pool));
-  conflict2 = svn_wc_conflict_description_create_tree2(
-                    local_abspath, svn_node_file, svn_wc_operation_update,
-                    NULL, NULL, pool);
-  conflict2->action = svn_wc_conflict_action_edit;
-  conflict2->reason = svn_wc_conflict_reason_deleted;
-
-  conflicts = apr_hash_make(pool);
-  apr_hash_set(conflicts, conflict1->local_abspath, APR_HASH_KEY_STRING,
-               conflict1);
-  apr_hash_set(conflicts, conflict2->local_abspath, APR_HASH_KEY_STRING,
-               conflict2);
-
-  /* We don't know the order the hash will spit out the data, so just test
-     for both possibilities. */
-  expected1 = "((conflict Foo.c file update deleted edited "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-               "(conflict Bar.h file update edited deleted "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-  expected2 = "((conflict Bar.h file update edited deleted "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )) "
-               "(conflict Foo.c file update deleted edited "
-                 "(version 0  2 -1 0  0 ) (version 0  2 -1 0  0 )))";
-
-  SVN_ERR(svn_wc__write_tree_conflicts(&tree_conflict_data, conflicts, pool));
-
-  if (strcmp(expected1, tree_conflict_data) != 0
-        && strcmp(expected2, tree_conflict_data) != 0)
-    return fail(pool, "Unexpected text from tree conflict\n"
-                      "  Expected: %s\n"
-                      "         OR %s\n"
-                      "  Actual:   %s\n", expected1, expected2,
-                                          tree_conflict_data);
-
-  return SVN_NO_ERROR;
-}
-
 #ifdef THIS_TEST_RAISES_MALFUNCTION
 static svn_error_t *
 test_write_invalid_tree_conflicts(apr_pool_t *pool)
@@ -380,14 +212,8 @@ struct svn_test_descriptor_t test_funcs[
     SVN_TEST_NULL,
     SVN_TEST_PASS2(test_read_tree_conflict,
                    "read 1 tree conflict"),
-    SVN_TEST_PASS2(test_read_2_tree_conflicts,
-                   "read 2 tree conflicts"),
-    SVN_TEST_XFAIL2(test_read_invalid_tree_conflicts,
-                    "detect broken tree conflict data"),
     SVN_TEST_PASS2(test_write_tree_conflict,
                    "write 1 tree conflict"),
-    SVN_TEST_PASS2(test_write_2_tree_conflicts,
-                   "write 2 tree conflicts"),
 #ifdef THIS_TEST_RAISES_MALFUNCTION
     SVN_TEST_PASS2(test_write_invalid_tree_conflicts,
                    "detect broken tree conflict data while writing"),

Modified: subversion/branches/performance/tools/dev/unix-build/Makefile.svn
URL: http://svn.apache.org/viewvc/subversion/branches/performance/tools/dev/unix-build/Makefile.svn?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/tools/dev/unix-build/Makefile.svn (original)
+++ subversion/branches/performance/tools/dev/unix-build/Makefile.svn Wed Nov 17 00:09:50 2010
@@ -38,6 +38,7 @@ APR_UTIL_VER	= 1.3.9
 HTTPD_VER	= 2.2.15
 NEON_VER	= 0.29.3
 SERF_VER	= 0.7.x
+SERF_OLD_VER	= 0.6.x
 CYRUS_SASL_VER	= 2.1.23
 SQLITE_VER	= 3.6.23.1
 
@@ -45,7 +46,6 @@ BDB_DIST	= db-$(BDB_VER).tar.gz
 APR_ICONV_DIST	= apr-iconv-$(APR_ICONV_VER).tar.gz
 GNU_ICONV_DIST	= libiconv-$(GNU_ICONV_VER).tar.gz
 NEON_DIST	= neon-$(NEON_VER).tar.gz
-#SERF_DIST	= serf-$(SERF_VER).tar.gz
 SQLITE_DIST	= sqlite-$(SQLITE_VER).tar.gz
 CYRUS_SASL_DIST	= cyrus-sasl-$(CYRUS_SASL_VER).tar.gz
 HTTPD_DIST	= httpd-$(HTTPD_VER).tar.bz2
@@ -70,6 +70,7 @@ HTTPD_URL	= http://archive.apache.org/di
 NEON_URL	= http://webdav.org/neon/$(NEON_DIST)
 #SERF_URL	= http://serf.googlecode.com/files/$(SERF_DIST)
 SERF_URL	= http://serf.googlecode.com/svn/branches/$(SERF_VER)
+SERF_OLD_URL	= http://serf.googlecode.com/svn/branches/$(SERF_OLD_VER)
 SQLITE_URL	= http://www.sqlite.org/$(SQLITE_DIST)
 CYRUS_SASL_URL	= ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/$(CYRUS_SASL_DIST)
 
@@ -81,6 +82,7 @@ APR_UTIL_SRCDIR	= $(SRCDIR)/apr-util-$(A
 HTTPD_SRCDIR	= $(SRCDIR)/httpd-$(HTTPD_VER)
 NEON_SRCDIR	= $(SRCDIR)/neon-$(NEON_VER)
 SERF_SRCDIR	= $(SRCDIR)/serf-$(SERF_VER)
+SERF_OLD_SRCDIR	= $(SRCDIR)/serf-$(SERF_OLD_VER)
 SQLITE_SRCDIR	= $(SRCDIR)/sqlite-$(SQLITE_VER)
 CYRUS_SASL_SRCDIR	= $(SRCDIR)/cyrus-sasl-$(CYRUS_SASL_VER)
 SVN_SRCDIR	= $(SVN_WC)
@@ -93,6 +95,7 @@ APR_UTIL_OBJDIR	= $(OBJDIR)/apr-util-$(A
 HTTPD_OBJDIR	= $(OBJDIR)/httpd-$(HTTPD_VER)
 NEON_OBJDIR	= $(OBJDIR)/neon-$(NEON_VER)
 SERF_OBJDIR	= $(OBJDIR)/serf-$(SERF_VER)
+SERF_OLD_OBJDIR	= $(OBJDIR)/serf-$(SERF_OLD_VER)
 SQLITE_OBJDIR	= $(OBJDIR)/sqlite-$(SQLITE_VER)
 CYRUS_SASL_OBJDIR	= $(OBJDIR)/cyrus-sasl-$(CYRUS_SASL_VER)
 SVN_OBJDIR	= $(OBJDIR)/$(SVN_REL_WC)
@@ -109,8 +112,8 @@ svn_builddir	?=$(SVN_WC)
 .PHONY: all reset clean nuke
 
 all: dirs-create bdb-install apr-install iconv-install apr-util-install \
-	httpd-install neon-install serf-install sqlite-install \
-	cyrus-sasl-install svn-install svn-bindings-install
+	httpd-install neon-install serf-install serf-old-install \
+	sqlite-install cyrus-sasl-install svn-install svn-bindings-install
 
 # Use these to start a build from the beginning.
 reset: dirs-reset bdb-reset apr-reset iconv-reset apr-util-reset \
@@ -623,6 +626,47 @@ $(SERF_OBJDIR)/.installed: $(SERF_OBJDIR
 	touch $@
 
 #######################################################################
+# serf-old (compatible with Subversion 1.5)
+#######################################################################
+
+serf-old-retrieve:	$(SERF_OLD_OBJDIR)/.retrieved
+serf-old-configure:	$(SERF_OLD_OBJDIR)/.configured
+serf-old-compile:	$(SERF_OLD_OBJDIR)/.compiled
+serf-old-install:	$(SERF_OLD_OBJDIR)/.installed
+serf-old-reset:
+	$(foreach f, .retrieved .configured .compiled .installed, \
+		rm -f $(SERF_OLD_OBJDIR)/$(f);)
+
+serf-old-clean:
+	-(cd $(SERF_OLD_SRCDIR) && ./serfmake clean)
+
+# retrieve serf if not present yet
+$(SERF_OLD_OBJDIR)/.retrieved:
+	[ -d $(SERF_OLD_OBJDIR) ] || mkdir -p $(SERF_OLD_OBJDIR)
+	if [ ! -d $(SERF_OLD_SRCDIR) ]; then \
+		svn export $(SERF_OLD_URL) $(SERF_OLD_SRCDIR); \
+	fi
+	touch $@
+
+# compile serf (serf won't compile outside its source tree)
+$(SERF_OLD_OBJDIR)/.compiled: $(SERF_OLD_OBJDIR)/.retrieved
+	cd $(SERF_OLD_SRCDIR) && \
+		env CFLAGS="-O0 -g" ./serfmake --with-apr=$(PREFIX)/apr \
+			--prefix=$(PREFIX)/serf-old \
+			build
+	touch $@
+
+# install serf
+$(SERF_OLD_OBJDIR)/.installed: $(SERF_OLD_OBJDIR)/.compiled
+	cd $(SERF_OLD_SRCDIR) && \
+		./serfmake --with-apr=$(PREFIX)/apr \
+			--with-apr-util=$(PREFIX)/apr \
+			--prefix=$(PREFIX)/serf-old \
+			install
+	touch $@
+
+
+#######################################################################
 # sqlite
 #######################################################################
 
@@ -765,6 +809,7 @@ $(SVN_OBJDIR)/.retrieved:
 
 ifeq ($(BRANCH_MAJOR),1.5)
 BDB_FLAG=$(PREFIX)/bdb
+SERF_FLAG=--with-serf="$(PREFIX)/serf-old"
 else ifeq ($(BRANCH_MAJOR),1.4)
 BDB_FLAG=$(PREFIX)/bdb
 else ifeq ($(BRANCH_MAJOR),1.3)
@@ -777,6 +822,7 @@ else ifeq ($(BRANCH_MAJOR),1.0)
 BDB_FLAG=$(PREFIX)/bdb
 else
 BDB_FLAG=db.h:$(PREFIX)/bdb/include:$(PREFIX)/bdb/lib:db-$(BDB_MAJOR_VER)
+SERF_FLAG=--with-serf="$(PREFIX)/serf"
 endif
 
 ifeq ($(ENABLE_JAVA_BINDINGS),yes)
@@ -807,7 +853,7 @@ $(SVN_OBJDIR)/.configured: $(SVN_OBJDIR)
 			--with-apxs="$(PREFIX)/httpd/bin/apxs" \
 			--with-apache-libexecdir=$(PREFIX)/httpd/modules/svn-$(WC) \
 			--with-neon="$(PREFIX)/neon" \
-			--with-serf="$(PREFIX)/serf" \
+			$(SERF_FLAG) \
 			--with-sqlite="$(PREFIX)/sqlite" \
 			--with-berkeley-db="$(BDB_FLAG)" \
 			--with-sasl="$(PREFIX)/cyrus-sasl" \

Modified: subversion/branches/performance/tools/dist/construct-rolling-environment.sh
URL: http://svn.apache.org/viewvc/subversion/branches/performance/tools/dist/construct-rolling-environment.sh?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/tools/dist/construct-rolling-environment.sh (original)
+++ subversion/branches/performance/tools/dist/construct-rolling-environment.sh Wed Nov 17 00:09:50 2010
@@ -53,11 +53,11 @@ TEMPDIR=$BASEDIR/temp
 case $LOCATION in
     US)
     APACHE_MIRROR=http://www.pangex.com/pub/apache
-    SOURCEFORGE_MIRROR=http://internap.dl.sourceforge.net/sourceforge
+    SOURCEFORGE_MIRROR=softlayer
     ;;
     UK)
     APACHE_MIRROR=http://apache.rmplc.co.uk
-    SOURCEFORGE_MIRROR=http://kent.dl.sourceforge.net/sourceforge
+    SOURCEFORGE_MIRROR=kent
     ;;
     *)
     echo "Unknown LOCATION" >&2
@@ -77,7 +77,7 @@ setup() {
 create_prefix() {
     wget -nc http://ftp.gnu.org/gnu/autoconf/$AUTOCONF.tar.bz2
     wget -nc http://ftp.gnu.org/gnu/libtool/$LIBTOOL.tar.gz
-    wget -nc $SOURCEFORGE_MIRROR/swig/$SWIG.tar.gz
+    wget -nc "http://sourceforge.net/projects/swig/files/swig/$SWIG/$SWIG.tar.gz/download?use_mirror=$SOURCEFORGE_MIRROR"
 
     tar jxvf $AUTOCONF.tar.bz2
     cd $AUTOCONF

Modified: subversion/branches/performance/tools/hook-scripts/mailer/mailer.py
URL: http://svn.apache.org/viewvc/subversion/branches/performance/tools/hook-scripts/mailer/mailer.py?rev=1035869&r1=1035868&r2=1035869&view=diff
==============================================================================
--- subversion/branches/performance/tools/hook-scripts/mailer/mailer.py (original)
+++ subversion/branches/performance/tools/hook-scripts/mailer/mailer.py Wed Nov 17 00:09:50 2010
@@ -866,12 +866,16 @@ class DiffGenerator:
           content = src_fname = dst_fname = None
         else:
           src_fname, dst_fname = diff.get_files()
-          content = DiffContent(self.cfg.get_diff_cmd(self.group, {
-            'label_from' : label1,
-            'label_to' : label2,
-            'from' : src_fname,
-            'to' : dst_fname,
-            }))
+          try:
+            content = DiffContent(self.cfg.get_diff_cmd(self.group, {
+              'label_from' : label1,
+              'label_to' : label2,
+              'from' : src_fname,
+              'to' : dst_fname,
+              }))
+          except OSError:
+            # diff command does not exist, try difflib.unified_diff()
+            content = DifflibDiffContent(label1, label2, src_fname, dst_fname)
 
       # return a data item for this diff
       return _data(
@@ -890,6 +894,33 @@ class DiffGenerator:
         content=content,
         )
 
+def _classify_diff_line(line, seen_change):
+  # classify the type of line.
+  first = line[:1]
+  ltype = ''
+  if first == '@':
+    seen_change = True
+    ltype = 'H'
+  elif first == '-':
+    if seen_change:
+      ltype = 'D'
+    else:
+      ltype = 'F'
+  elif first == '+':
+    if seen_change:
+      ltype = 'A'
+    else:
+      ltype = 'T'
+  elif first == ' ':
+    ltype = 'C'
+  else:
+    ltype = 'U'
+
+  if line[-2] == '\r':
+    line=line[0:-2] + '\n' # remove carriage return
+
+  return line, ltype, seen_change
+
 
 class DiffContent:
   "This is a generator-like object returning annotated lines of a diff."
@@ -917,36 +948,42 @@ class DiffContent:
       self.pipe = None
       raise IndexError
 
-    # classify the type of line.
-    first = line[:1]
-    if first == '@':
-      self.seen_change = True
-      ltype = 'H'
-    elif first == '-':
-      if self.seen_change:
-        ltype = 'D'
-      else:
-        ltype = 'F'
-    elif first == '+':
-      if self.seen_change:
-        ltype = 'A'
-      else:
-        ltype = 'T'
-    elif first == ' ':
-      ltype = 'C'
-    else:
-      ltype = 'U'
+    line, ltype, self.seen_change = _classify_diff_line(line, self.seen_change)
+    return _data(
+      raw=line,
+      text=line[1:-1],  # remove indicator and newline
+      type=ltype,
+      )
 
-    if line[-2] == '\r':
-      line=line[0:-2] + '\n' # remove carriage return
+class DifflibDiffContent():
+  "This is a generator-like object returning annotated lines of a diff."
+
+  def __init__(self, label_from, label_to, from_file, to_file):
+    import difflib
+    self.seen_change = False
+    fromlines = open(from_file, 'U').readlines()
+    tolines = open(to_file, 'U').readlines()
+    self.diff = difflib.unified_diff(fromlines, tolines,
+                                     label_from, label_to)
+    
+  def __nonzero__(self):
+    # we always have some items
+    return True
 
+  def __getitem__(self, idx):
+
+    try:
+      line = self.diff.next()
+    except StopIteration:
+      raise IndexError
+
+    line, ltype, self.seen_change = _classify_diff_line(line, self.seen_change)
     return _data(
       raw=line,
       text=line[1:-1],  # remove indicator and newline
       type=ltype,
       )
 
-
 class TextCommitRenderer:
   "This class will render the commit mail in plain text."