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/26 19:55:54 UTC

svn commit: r1039511 [3/5] - in /subversion/branches/performance: ./ build/ subversion/bindings/swig/perl/native/ subversion/bindings/swig/ruby/test/ subversion/include/ subversion/include/private/ subversion/libsvn_client/ subversion/libsvn_delta/ sub...

Modified: subversion/branches/performance/subversion/libsvn_subr/dirent_uri.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_subr/dirent_uri.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_subr/dirent_uri.c (original)
+++ subversion/branches/performance/subversion/libsvn_subr/dirent_uri.c Fri Nov 26 18:55:51 2010
@@ -63,7 +63,13 @@ typedef enum {
   type_relpath
 } path_type_t;
 
- 
+
+/**** Forward declarations *****/
+
+static svn_boolean_t
+relpath_is_canonical(const char *relpath);
+
+
 /**** Internal implementation functions *****/
 
 /* Return an internal-style new path based on PATH, allocated in POOL.
@@ -1189,8 +1195,8 @@ svn_relpath_join(const char *base,
   apr_size_t clen = strlen(component);
   char *path;
 
-  assert(svn_relpath_is_canonical(base, pool));
-  assert(svn_relpath_is_canonical(component, pool));
+  assert(relpath_is_canonical(base));
+  assert(relpath_is_canonical(component));
 
   /* If either is empty return the other */
   if (blen == 0)
@@ -1316,7 +1322,7 @@ svn_relpath_dirname(const char *relpath,
 {
   apr_size_t len = strlen(relpath);
 
-  assert(svn_relpath_is_canonical(relpath, pool));
+  assert(relpath_is_canonical(relpath));
 
   return apr_pstrmemdup(pool, relpath,
                         relpath_previous_segment(relpath, len));
@@ -1329,7 +1335,7 @@ svn_relpath_basename(const char *relpath
   apr_size_t len = strlen(relpath);
   apr_size_t start;
 
-  assert(!pool || svn_relpath_is_canonical(relpath, pool));
+  assert(relpath_is_canonical(relpath));
 
   start = len;
   while (start > 0 && relpath[start - 1] != '/')
@@ -1422,6 +1428,9 @@ svn_relpath_get_longest_ancestor(const c
                                  const char *relpath2,
                                  apr_pool_t *pool)
 {
+  assert(relpath_is_canonical(relpath1));
+  assert(relpath_is_canonical(relpath2));
+
   return apr_pstrndup(pool, relpath1,
                       get_longest_ancestor_length(type_relpath, relpath1,
                                                   relpath2, pool));
@@ -1497,6 +1506,9 @@ svn_relpath_is_child(const char *parent_
                      const char *child_relpath,
                      apr_pool_t *pool)
 {
+  /* assert(relpath_is_canonical(parent_relpath)); */
+  /* assert(relpath_is_canonical(child_relpath)); */
+
   return is_child(type_relpath, parent_relpath, child_relpath, pool);
 }
 
@@ -1517,6 +1529,9 @@ svn_dirent_is_ancestor(const char *paren
 svn_boolean_t
 svn_relpath_is_ancestor(const char *parent_relpath, const char *child_relpath)
 {
+  assert(relpath_is_canonical(parent_relpath));
+  assert(relpath_is_canonical(child_relpath));
+
   return is_ancestor(type_relpath, parent_relpath, child_relpath);
 }
 
@@ -1563,15 +1578,15 @@ svn_relpath_skip_ancestor(const char *pa
 {
   apr_size_t len = strlen(parent_relpath);
 
+  assert(relpath_is_canonical(parent_relpath));
+  assert(relpath_is_canonical(child_relpath));
+
   if (0 != memcmp(parent_relpath, child_relpath, len))
     return child_relpath; /* parent_relpath is no ancestor of child_relpath */
 
   if (child_relpath[len] == 0)
     return ""; /* parent_relpath == child_relpath */
 
-  if (len == 1 && child_relpath[0] == '/')
-    return child_relpath + 1;
-
   if (child_relpath[len] == '/')
     return child_relpath + len + 1;
 
@@ -1737,12 +1752,11 @@ svn_dirent_is_canonical(const char *dire
     }
 #endif /* SVN_USE_DOS_PATHS */
 
-  return svn_relpath_is_canonical(ptr, pool);
+  return relpath_is_canonical(ptr);
 }
 
-svn_boolean_t
-svn_relpath_is_canonical(const char *relpath,
-                         apr_pool_t *pool)
+static svn_boolean_t
+relpath_is_canonical(const char *relpath)
 {
   const char *ptr = relpath, *seg = relpath;
 
@@ -1787,6 +1801,13 @@ svn_relpath_is_canonical(const char *rel
 }
 
 svn_boolean_t
+svn_relpath_is_canonical(const char *relpath,
+                         apr_pool_t *pool)
+{
+  return relpath_is_canonical(relpath);
+}
+
+svn_boolean_t
 svn_uri_is_canonical(const char *uri, apr_pool_t *pool)
 {
   const char *ptr = uri, *seg = uri;
@@ -2444,3 +2465,167 @@ svn_uri_get_file_url_from_dirent(const c
 
   return SVN_NO_ERROR;
 }
+
+
+/* ------------------------ The fspath API ------------------------ */
+
+svn_boolean_t
+svn_fspath__is_canonical(const char *fspath)
+{
+  return fspath[0] == '/' && relpath_is_canonical(fspath + 1);
+}
+
+
+const char *
+svn_fspath__is_child(const char *parent_fspath,
+                     const char *child_fspath,
+                     apr_pool_t *pool)
+{
+  const char *result;
+  assert(svn_fspath__is_canonical(parent_fspath));
+  assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_is_child(parent_fspath, child_fspath, pool);
+#else
+  result = svn_relpath_is_child(parent_fspath + 1, child_fspath + 1, pool);
+#endif
+
+  assert(result == NULL || svn_relpath_is_canonical(result, pool));
+  return result;
+}
+
+const char *
+svn_fspath__skip_ancestor(const char *parent_fspath,
+                          const char *child_fspath)
+{
+  const char *result;
+  assert(svn_fspath__is_canonical(parent_fspath));
+  assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_skip_ancestor(parent_fspath, child_fspath);
+#else
+  if (svn_relpath_is_ancestor(parent_fspath + 1, child_fspath + 1))
+    result = svn_relpath_skip_ancestor(parent_fspath + 1, child_fspath + 1);
+  else
+    result = child_fspath;
+#endif
+
+  assert(svn_relpath_is_canonical(result, NULL)
+         || strcmp(result, child_fspath) == 0);
+  return result;
+}
+
+svn_boolean_t
+svn_fspath__is_ancestor(const char *parent_fspath,
+                        const char *child_fspath)
+{
+  assert(svn_fspath__is_canonical(parent_fspath));
+  assert(svn_fspath__is_canonical(child_fspath));
+
+#ifdef FSPATH_USE_URI
+  return svn_uri_is_ancestor(parent_fspath, child_fspath);
+#else
+  return svn_relpath_is_ancestor(parent_fspath + 1, child_fspath + 1);
+#endif
+}
+
+
+const char *
+svn_fspath__dirname(const char *fspath,
+                    apr_pool_t *pool)
+{
+  const char *result;
+  assert(svn_fspath__is_canonical(fspath));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_dirname(fspath, pool);
+#else
+  result = apr_pstrcat(pool, "/", svn_relpath_dirname(fspath + 1, pool),
+                       (char *)NULL);
+#endif
+
+  assert(svn_fspath__is_canonical(result));
+  return result;
+}
+
+
+const char *
+svn_fspath__basename(const char *fspath,
+                     apr_pool_t *pool)
+{
+  const char *result;
+  assert(svn_fspath__is_canonical(fspath));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_basename(fspath, pool);
+#else
+  result = svn_relpath_basename(fspath + 1, pool);
+#endif
+
+  assert(strchr(result, '/') == NULL);
+  return result;
+}
+
+void
+svn_fspath__split(const char **dirpath,
+                  const char **base_name,
+                  const char *fspath,
+                  apr_pool_t *result_pool)
+{
+  assert(dirpath != base_name);
+
+  if (dirpath)
+    *dirpath = svn_fspath__dirname(fspath, result_pool);
+
+  if (base_name)
+    *base_name = svn_fspath__basename(fspath, result_pool);
+}
+
+char *
+svn_fspath__join(const char *fspath,
+                 const char *relpath,
+                 apr_pool_t *result_pool)
+{
+  char *result;
+  assert(svn_fspath__is_canonical(fspath));
+  assert(svn_relpath_is_canonical(relpath, result_pool));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_join(fspath, relpath, result_pool);
+#else
+  if (relpath[0] == '\0')
+    result = apr_pstrdup(result_pool, fspath);
+  else if (fspath[1] == '\0')
+    result = apr_pstrcat(result_pool, "/", relpath, (char *)NULL);
+  else
+    result = apr_pstrcat(result_pool, fspath, "/", relpath, (char *)NULL);
+#endif
+
+  assert(svn_fspath__is_canonical(result));
+  return result;
+}
+
+char *
+svn_fspath__get_longest_ancestor(const char *fspath1,
+                                 const char *fspath2,
+                                 apr_pool_t *result_pool)
+{
+  char *result;
+  assert(svn_fspath__is_canonical(fspath1));
+  assert(svn_fspath__is_canonical(fspath2));
+
+#ifdef FSPATH_USE_URI
+  result = svn_uri_get_longest_ancestor(fspath1, fspath2, result_pool);
+#else
+  result = apr_pstrcat(result_pool, "/",
+                       svn_relpath_get_longest_ancestor(fspath1 + 1,
+                                                        fspath2 + 1,
+                                                        result_pool),
+                       NULL);
+#endif
+
+  assert(svn_fspath__is_canonical(result));
+  return result;
+}

Modified: subversion/branches/performance/subversion/libsvn_subr/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_subr/mergeinfo.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_subr/mergeinfo.c (original)
+++ subversion/branches/performance/subversion/libsvn_subr/mergeinfo.c Fri Nov 26 18:55:51 2010
@@ -1760,7 +1760,7 @@ svn_mergeinfo__remove_prefix_from_catalo
       apr_ssize_t padding = 0;
 
       SVN_ERR_ASSERT(klen >= prefix_len);
-      SVN_ERR_ASSERT(svn_uri_is_ancestor(prefix_path, original_path));
+      SVN_ERR_ASSERT(svn_fspath__is_ancestor(prefix_path, original_path));
 
       /* If the ORIGINAL_PATH doesn't match the PREFIX_PATH exactly
          and we're not simply removing a single leading slash (such as
@@ -1809,33 +1809,28 @@ svn_mergeinfo__add_prefix_to_catalog(svn
 svn_error_t *
 svn_mergeinfo__add_suffix_to_mergeinfo(svn_mergeinfo_t *out_mergeinfo,
                                        svn_mergeinfo_t mergeinfo,
-                                       const char *suffix,
+                                       const char *suffix_relpath,
                                        apr_pool_t *result_pool,
                                        apr_pool_t *scratch_pool)
 {
-  if (!suffix || svn_dirent_is_absolute(suffix))
-    {
-      *out_mergeinfo = svn_mergeinfo_dup(mergeinfo, result_pool);
-    }
-  else
-    {
-      apr_hash_index_t *hi;
-      const char *canonical_suffix = svn_uri_canonicalize(suffix,
-                                                          scratch_pool);
-      *out_mergeinfo = apr_hash_make(result_pool);
+  apr_hash_index_t *hi;
 
-      for (hi = apr_hash_first(scratch_pool, mergeinfo);
-           hi;
-           hi = apr_hash_next(hi))
-        {
-          const char *path = svn__apr_hash_index_key(hi);
-          apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+  SVN_ERR_ASSERT(suffix_relpath && svn_relpath_is_canonical(suffix_relpath,
+                                                            scratch_pool));
 
-          apr_hash_set(*out_mergeinfo,
-                       svn_dirent_join(path, canonical_suffix, result_pool),
-                       APR_HASH_KEY_STRING,
-                       svn_rangelist_dup(rangelist, result_pool));
-        }
+  *out_mergeinfo = apr_hash_make(result_pool);
+
+  for (hi = apr_hash_first(scratch_pool, mergeinfo);
+       hi;
+       hi = apr_hash_next(hi))
+    {
+      const char *path = svn__apr_hash_index_key(hi);
+      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+
+      apr_hash_set(*out_mergeinfo,
+                   svn_dirent_join(path, suffix_relpath, result_pool),
+                   APR_HASH_KEY_STRING,
+                   svn_rangelist_dup(rangelist, result_pool));
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/performance/subversion/libsvn_wc/copy.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/copy.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/copy.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/copy.c Fri Nov 26 18:55:51 2010
@@ -214,8 +214,6 @@ copy_versioned_file(svn_wc__db_t *db,
   svn_skel_t *work_items = NULL;
   const char *dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
   const char *tmpdir_abspath;
-  const char *tmp_dst_abspath;
-  svn_node_kind_t kind;
 
   SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db, dst_abspath,
                                          scratch_pool, scratch_pool));
@@ -230,7 +228,10 @@ copy_versioned_file(svn_wc__db_t *db,
      copy recursively if it's a dir. */
   if (!metadata_only)
     {
-      SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath,
+      const char *tmp_dst_abspath;
+      svn_node_kind_t disk_kind;
+
+      SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &disk_kind, src_abspath,
                              tmpdir_abspath,
                              TRUE, /* recursive */
                              cancel_func, cancel_baton, scratch_pool));
@@ -294,21 +295,22 @@ copy_versioned_dir(svn_wc__db_t *db,
   svn_skel_t *work_items = NULL;
   const char *dir_abspath = svn_dirent_dirname(dst_abspath, scratch_pool);
   const char *tmpdir_abspath;
-  const char *tmp_dst_abspath;
   const apr_array_header_t *versioned_children;
-  apr_hash_t *children;
-  svn_node_kind_t kind;
+  apr_hash_t *disk_children;
+  svn_node_kind_t disk_kind;
   apr_pool_t *iterpool;
   int i;
 
   /* Prepare a temp copy of the single filesystem node (usually a dir). */
   if (!metadata_only)
     {
+      const char *tmp_dst_abspath;
+
       SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db,
                                              dst_abspath,
                                              scratch_pool, scratch_pool));
 
-      SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath,
+      SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &disk_kind, src_abspath,
                              tmpdir_abspath, FALSE, /* recursive */
                              cancel_func, cancel_baton, scratch_pool));
       if (tmp_dst_abspath)
@@ -338,12 +340,14 @@ copy_versioned_dir(svn_wc__db_t *db,
       (*notify_func)(notify_baton, notify, scratch_pool);
     }
 
-  if (!metadata_only && kind == svn_node_dir)
+  if (!metadata_only && disk_kind == svn_node_dir)
     /* All filesystem children, versioned and unversioned.  We're only
        interested in their names, so we can pass TRUE as the only_check_type
        param. */
-    SVN_ERR(svn_io_get_dirents3(&children, src_abspath, TRUE,
+    SVN_ERR(svn_io_get_dirents3(&disk_children, src_abspath, TRUE,
                                 scratch_pool, scratch_pool));
+  else
+    disk_children = NULL;
 
   /* Copy all the versioned children */
   SVN_ERR(svn_wc__db_read_children(&versioned_children, db, src_abspath,
@@ -385,21 +389,22 @@ copy_versioned_dir(svn_wc__db_t *db,
                                  svn_dirent_local_style(child_src_abspath,
                                                         scratch_pool));
 
-      if (!metadata_only && kind == svn_node_dir)
+      if (disk_children)
         /* Remove versioned child as it has been handled */
-        apr_hash_set(children, child_name, APR_HASH_KEY_STRING, NULL);
+        apr_hash_set(disk_children, child_name, APR_HASH_KEY_STRING, NULL);
     }
 
   /* Copy all the remaining filesystem children, which are unversioned. */
-  if (!metadata_only && kind == svn_node_dir)
+  if (disk_children)
     {
       apr_hash_index_t *hi;
 
-      for (hi = apr_hash_first(scratch_pool, children); hi;
+      for (hi = apr_hash_first(scratch_pool, disk_children); hi;
            hi = apr_hash_next(hi))
         {
           const char *name = svn__apr_hash_index_key(hi);
           const char *unver_src_abspath, *unver_dst_abspath;
+          const char *tmp_dst_abspath;
 
           if (svn_wc_is_adm_dir(name, iterpool))
             continue;
@@ -411,8 +416,8 @@ copy_versioned_dir(svn_wc__db_t *db,
           unver_src_abspath = svn_dirent_join(src_abspath, name, iterpool);
           unver_dst_abspath = svn_dirent_join(dst_abspath, name, iterpool);
 
-          SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, unver_src_abspath,
-                                 tmpdir_abspath,
+          SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &disk_kind,
+                                 unver_src_abspath, tmpdir_abspath,
                                  TRUE, /* recursive */
                                  cancel_func, cancel_baton, iterpool));
           if (tmp_dst_abspath)
@@ -437,120 +442,6 @@ copy_versioned_dir(svn_wc__db_t *db,
 }
 
 
-#ifdef SVN_WC__OP_DEPTH
-/*
-A plan for copying a versioned node, recursively, with proper op-depths.
-
-Each DB change mentioned in a separate step is intended to change the WC
-from one valid state to another and must be exectuted within a DB txn.
-Several such changes can be batched together in a bigger txn if we don't
-want clients to be able to see intermediate states.
-
-TODO: We will probably want to notify all copied paths rather than just the
-  root path, some time in the future.  It may be difficult to get the list
-  of visited paths directly, because the metadata copying is performed
-  within a single SQL statement.  We could walk the destination tree after
-  copying, taking care to include any 'excluded' nodes but ignore any
-  'deleted' paths that may be left over from a replaced sub-tree.
-
-copy_versioned_tree:
-  # Copy a versioned file/dir SRC_PATH to DST_PATH, recursively.
-
-  # This function takes care to copy both the metadata tree and the disk
-  # tree as they are, even if they are different node kinds and so different
-  # tree shapes.
-
-  src_op_depth = working_op_depth_of(src_path)
-  src_depth = relpath_depth(src_path)
-  dst_depth = relpath_depth(dst_path)
-
-  # The source tree has in the NODES table, by design:
-  #   - zero or more rows below SRC_OP_DEPTH (these are uninteresting);
-  #   - one or more rows at SRC_OP_DEPTH;
-  #   - no rows with SRC_OP_DEPTH < row.op_depth <= SRC_DEPTH;
-  #   - zero or more rows above SRC_DEPTH (modifications);
-  # and SRC_OP_DEPTH <= SRC_DEPTH.
-
-  Copy single NODES row from src_path@src_op_depth to dst_path@dst_depth.
-  Copy all rows of descendent paths in == src_op_depth to == dst_depth.
-  Copy all rows of descendent paths in > src_depth to > dst_depth,
-    adjusting op_depth by (dst_depth - src_depth).
-
-  Copy disk node recursively (if it exists, and whatever its kind).
-  Copy ACTUAL_NODE rows (props and any other actual metadata).
-
-  # ### Are there no scenarios in which we would want to decrease dst_depth
-  #     and so subsume the destination into an existing op?  I guess not.
-
-*/
-
-/* Copy the working version of the versioned tree at SRC_ABSPATH to
- * DST_ABSPATH, recursively.  If METADATA_ONLY is true, then don't copy it
- * on disk, only in metadata, and don't care whether it already exists on
- * disk. */
-static svn_error_t *
-copy_versioned_tree(svn_wc__db_t *db,
-                    const char *src_abspath,
-                    const char *dst_abspath,
-                    svn_boolean_t metadata_only,
-                    svn_cancel_func_t cancel_func,
-                    void *cancel_baton,
-                    svn_wc_notify_func2_t notify_func,
-                    void *notify_baton,
-                    apr_pool_t *scratch_pool)
-{
-  svn_skel_t *work_item = NULL;
-
-  /* Prepare a copy of the on-disk tree (if it exists, and whatever its kind),
-   * in a temporary location. */
-  if (! metadata_only)
-    {
-      const char *tmpdir_abspath;
-      const char *tmp_dst_abspath;
-      svn_node_kind_t kind;
-
-      SVN_ERR(svn_wc__db_temp_wcroot_tempdir(&tmpdir_abspath, db, dst_abspath,
-                                             scratch_pool, scratch_pool));
-
-      SVN_ERR(copy_to_tmpdir(&tmp_dst_abspath, &kind, src_abspath,
-                             tmpdir_abspath,
-                             TRUE, /* recursive */
-                             cancel_func, cancel_baton,
-                             scratch_pool));
-      if (tmp_dst_abspath)
-        {
-          SVN_ERR(svn_wc__wq_build_file_move(&work_item, db,
-                                             tmp_dst_abspath, dst_abspath,
-                                             scratch_pool, scratch_pool));
-        }
-    }
-
-  /* Copy single NODES row from src_path@src_op_depth to dst_path@dst_depth. */
-  /* Copy all rows of descendent paths in == src_op_depth to == dst_depth. */
-  /* Copy all rows of descendent paths in > src_depth to > dst_depth,
-     adjusting op_depth by (dst_depth - src_depth). */
-  /* Copy ACTUAL_NODE rows (props and any other actual metadata). */
-  SVN_ERR(svn_wc__db_op_copy_tree(db, src_abspath, dst_abspath,
-                                  work_item, scratch_pool));
-
-  SVN_ERR(svn_wc__wq_run(db, dst_abspath, cancel_func, cancel_baton,
-                         scratch_pool));
-
-  /* Notify */
-  if (notify_func)
-    {
-      svn_wc_notify_t *notify
-        = svn_wc_create_notify(dst_abspath, svn_wc_notify_add,
-                               scratch_pool);
-      notify->kind = svn_node_dir;
-      (*notify_func)(notify_baton, notify, scratch_pool);
-    }
-
-  return SVN_NO_ERROR;
-}
-#endif
-
-
 /* Public Interface */
 
 svn_error_t *
@@ -718,17 +609,6 @@ svn_wc_copy3(svn_wc_context_t *wc_ctx,
                                                         scratch_pool));
     }
 
-#ifdef SVN_WC__OP_DEPTH
-  if (svn_wc__db_same_db(db, src_abspath, dst_abspath, scratch_pool))
-    {
-      SVN_ERR(copy_versioned_tree(db, src_abspath, dst_abspath,
-                                  metadata_only,
-                                  cancel_func, cancel_baton,
-                                  notify_func, notify_baton,
-                                  scratch_pool));
-    }
-  else
-#endif
   if (src_db_kind == svn_wc__db_kind_file
       || src_db_kind == svn_wc__db_kind_symlink)
     {

Modified: subversion/branches/performance/subversion/libsvn_wc/entries.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/entries.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/entries.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/entries.c Fri Nov 26 18:55:51 2010
@@ -74,6 +74,7 @@ typedef struct {
 typedef struct {
   apr_int64_t wc_id;
   const char *local_relpath;
+  apr_int64_t op_depth;
   const char *parent_relpath;
   svn_wc__db_status_t presence;
   svn_node_kind_t kind;  /* ### should switch to svn_wc__db_kind_t */
@@ -1620,8 +1621,7 @@ insert_working_node(svn_sqlite__db_t *sd
   SVN_ERR(svn_sqlite__get_statement(&stmt, sdb, STMT_INSERT_NODE));
   SVN_ERR(svn_sqlite__bindf(stmt, "isisnnnnsnrisnnni",
                             working_node->wc_id, working_node->local_relpath,
-                            (working_node->parent_relpath == NULL
-                             ? (apr_int64_t)1 : (apr_int64_t)2),
+                            working_node->op_depth,
                             working_node->parent_relpath,
                             /* Setting depth for files? */
                             svn_depth_to_word(working_node->depth),
@@ -1660,7 +1660,7 @@ insert_working_node(svn_sqlite__db_t *sd
     SVN_ERR(svn_sqlite__bind_checksum(stmt, 14, working_node->checksum,
                                       scratch_pool));
 
-  if (working_node->properties)
+  if (working_node->properties) /* ### Never set, props done later */
     SVN_ERR(svn_sqlite__bind_properties(stmt, 15, working_node->properties,
                                         scratch_pool));
 
@@ -1712,13 +1712,20 @@ insert_actual_node(svn_sqlite__db_t *sdb
   return svn_error_return(svn_sqlite__insert(NULL, stmt));
 }
 
+struct write_baton {
+  db_base_node_t *base;
+  db_working_node_t *work;
+};
+
 
 /* Write the information for ENTRY to WC_DB.  The WC_ID, REPOS_ID and
    REPOS_ROOT will all be used for writing ENTRY.
    ### transitioning from straight sql to using the wc_db APIs.  For the
    ### time being, we'll need both parameters. */
 static svn_error_t *
-write_entry(svn_wc__db_t *db,
+write_entry(struct write_baton **entry_node,
+            struct write_baton *parent_node,
+            svn_wc__db_t *db,
             svn_sqlite__db_t *sdb,
             apr_int64_t wc_id,
             apr_int64_t repos_id,
@@ -1727,6 +1734,7 @@ write_entry(svn_wc__db_t *db,
             const char *entry_abspath,
             const svn_wc_entry_t *this_dir,
             svn_boolean_t create_locks,
+            apr_pool_t *result_pool,
             apr_pool_t *scratch_pool)
 {
   db_base_node_t *base_node = NULL;
@@ -1739,34 +1747,118 @@ write_entry(svn_wc__db_t *db,
   else
     parent_relpath = svn_relpath_dirname(local_relpath, scratch_pool);
 
+  /* This is how it should work, it doesn't work like this yet because
+     we need proper op_depth to layer the working nodes.
+
+     Using "svn add", "svn rm", "svn cp" only files can be replaced
+     pre-wcng; directories can only be normal, deleted or added.
+     Files cannot be replaced within a deleted directory, so replaced
+     files can only exist in a normal directory, or a directory that
+     is added+copied.  In a normal directory a replaced file needs a
+     base node and a working node, in an added+copied directory a
+     replaced file needs two working nodes at different op-depths.
+
+     With just the above operations the conversion for files and
+     directories is straightforward:
+
+           pre-wcng                             wcng
+     parent         child                 parent     child
+
+     normal         normal                base       base
+     add+copied     normal+copied         work       work
+     normal+copied  normal+copied         work       work
+     normal         delete                base       base+work
+     delete         delete                base+work  base+work
+     add+copied     delete                work       work
+     normal         add                   base       work
+     add            add                   work       work
+     add+copied     add                   work       work
+     normal         add+copied            base       work
+     add            add+copied            work       work
+     add+copied     add+copied            work       work
+     normal         replace               base       base+work
+     add+copied     replace               work       work+work
+     normal         replace+copied        base       base+work
+     add+copied     replace+copied        work       work+work
+
+     However "svn merge" make this more complicated.  The pre-wcng
+     "svn merge" is capable of replacing a directory, that is it can
+     mark the whole tree deleted, and then copy another tree on top.
+     The entries then represent the replacing tree overlayed on the
+     deleted tree.
+
+       original       replace          schedule in
+       tree           tree             combined tree
+
+       A              A                replace+copied
+       A/f                             delete+copied
+       A/g            A/g              replace+copied
+                      A/h              add+copied
+       A/B            A/B              replace+copied
+       A/B/f                           delete+copied
+       A/B/g          A/B/g            replace+copied
+                      A/B/h            add+copied
+       A/C                             delete+copied
+       A/C/f                           delete+copied
+                      A/D              add+copied
+                      A/D/f            add+copied
+
+     The original tree could be normal tree, or an add+copied tree.
+     Committing such a merge generally worked, but making further tree
+     modifications before commit sometimes failed.
+
+     The root of the replace is handled like the file replace:
+
+           pre-wcng                             wcng
+     parent         child                 parent     child
+
+     normal         replace+copied        base       base+work
+     add+copied     replace+copied        work       work+work
+
+     although obviously the node is a directory rather then a file.
+     There are then more conversion states where the parent is
+     replaced.
+
+           pre-wcng                                wcng
+     parent           child              parent            child
+
+     replace+copied   add                [base|work]+work  work
+     replace+copied   add+copied         [base|work]+work  work
+     replace+copied   delete+copied      [base|work]+work  [base|work]+work
+     delete+copied    delete+copied      [base|work]+work  [base|work]+work
+     replace+copied   replace+copied     [base|work]+work  [base|work]+work
+  */
+
   switch (entry->schedule)
     {
       case svn_wc_schedule_normal:
         if (entry->copied)
-          working_node = MAYBE_ALLOC(working_node, scratch_pool);
+          working_node = MAYBE_ALLOC(working_node, result_pool);
         else
-          base_node = MAYBE_ALLOC(base_node, scratch_pool);
+          base_node = MAYBE_ALLOC(base_node, result_pool);
         break;
 
       case svn_wc_schedule_add:
-        working_node = MAYBE_ALLOC(working_node, scratch_pool);
+        working_node = MAYBE_ALLOC(working_node, result_pool);
         break;
 
       case svn_wc_schedule_delete:
-        working_node = MAYBE_ALLOC(working_node, scratch_pool);
+        working_node = MAYBE_ALLOC(working_node, result_pool);
         /* If the entry is part of a REPLACED (not COPIED) subtree,
            then it needs a BASE node. */
-       if (! (entry->copied
-               || (this_dir->copied
-                   && (this_dir->schedule == svn_wc_schedule_add ||
-                       this_dir->schedule == svn_wc_schedule_delete ||
-                       this_dir->schedule == svn_wc_schedule_replace))))
-          base_node = MAYBE_ALLOC(base_node, scratch_pool);
+        if (parent_node->base
+            && (! (entry->copied
+                   || (this_dir->copied
+                       && (this_dir->schedule == svn_wc_schedule_add ||
+                           this_dir->schedule == svn_wc_schedule_delete ||
+                           this_dir->schedule == svn_wc_schedule_replace)))))
+          base_node = MAYBE_ALLOC(base_node, result_pool);
         break;
 
       case svn_wc_schedule_replace:
-        working_node = MAYBE_ALLOC(working_node, scratch_pool);
-        base_node = MAYBE_ALLOC(base_node, scratch_pool);
+        working_node = MAYBE_ALLOC(working_node, result_pool);
+        if (parent_node->base)
+          base_node = MAYBE_ALLOC(base_node, result_pool);
         break;
     }
 
@@ -1774,14 +1866,14 @@ write_entry(svn_wc__db_t *db,
      BASE node to indicate the not-present node.  */
   if (entry->deleted)
     {
-      base_node = MAYBE_ALLOC(base_node, scratch_pool);
+      base_node = MAYBE_ALLOC(base_node, result_pool);
     }
 
   if (entry->copied)
     {
       /* Make sure we get a WORKING_NODE inserted. The copyfrom information
          will occur here or on a parent, as appropriate.  */
-      working_node = MAYBE_ALLOC(working_node, scratch_pool);
+      working_node = MAYBE_ALLOC(working_node, result_pool);
 
       if (entry->copyfrom_url)
         {
@@ -1796,60 +1888,31 @@ write_entry(svn_wc__db_t *db,
             {
               /* copyfrom_repos_path is NOT a URI. decode into repos path.  */
               working_node->copyfrom_repos_path =
-                svn_path_uri_decode(relative_url, scratch_pool);
+                svn_path_uri_decode(relative_url, result_pool);
             }
           working_node->copyfrom_revnum = entry->copyfrom_rev;
+#ifdef SVN_WC__OP_DEPTH
+          working_node->op_depth
+            = svn_wc__db_op_depth_for_upgrade(local_relpath);
+#else
+          working_node->op_depth = 2; /* ### temporary op_depth */
+#endif
         }
-      else
+      else if (parent_node->work && parent_node->work->copyfrom_repos_path)
         {
-          const char *parent_abspath = svn_dirent_dirname(entry_abspath,
-                                                          scratch_pool);
-          const char *op_root_abspath;
-          const char *original_repos_relpath;
-          svn_revnum_t original_revision;
-          svn_error_t *err;
-
-          /* The parent will *always* have info in the WORKING tree, since
-             we've been designated as COPIED but do not have our own
-             COPYFROM information. Therefore, our parent or a more distant
-             ancestor has that information. Grab the data.  */
-          err = svn_wc__db_scan_addition(
-                    NULL,
-                    &op_root_abspath,
-                    NULL, NULL, NULL,
-                    &original_repos_relpath, NULL, NULL, &original_revision,
-                    db,
-                    parent_abspath,
-                    scratch_pool, scratch_pool);
-
-          /* We could be reading the entries while in a transitional state
-             during an add/copy operation. The scan_addition *does* throw
-             errors sometimes. So clear anything that may come out of it,
-             and perform the copyfrom construction only when it looks like
-             we have a good/real set of return values.  */
-          svn_error_clear(err);
-
-          /* We may have been copied from a mixed-rev working copy. We need
-             to simulate additional copies around revision changes. The old
-             code could separately store the revision, but NG needs to create
-             copies at each change.  */
-          if (err == NULL
-              && op_root_abspath != NULL
-              && original_repos_relpath != NULL
-              && SVN_IS_VALID_REVNUM(original_revision)
-              /* above is valid result testing. below is the key test.  */
-              && original_revision != entry->revision)
-            {
-              const char *relpath_to_entry = svn_dirent_is_child(
-                op_root_abspath, entry_abspath, NULL);
-              const char *new_copyfrom_relpath = svn_relpath_join(
-                original_repos_relpath, relpath_to_entry, scratch_pool);
-
-              working_node->copyfrom_repos_id = repos_id;
-              working_node->copyfrom_repos_path = new_copyfrom_relpath;
-              working_node->copyfrom_revnum = entry->revision;
-            }
+          working_node->copyfrom_repos_id = repos_id;
+          working_node->copyfrom_repos_path
+            = svn_relpath_join(parent_node->work->copyfrom_repos_path,
+                               svn_relpath_basename(local_relpath, NULL),
+                               result_pool);
+          working_node->copyfrom_revnum = parent_node->work->copyfrom_revnum;
+          working_node->op_depth = parent_node->work->op_depth;
         }
+      else
+        return svn_error_createf(SVN_ERR_ENTRY_MISSING_URL, NULL,
+                                 _("No copyfrom URL for '%s'"),
+                                 svn_dirent_local_style(local_relpath,
+                                                        scratch_pool));
     }
 
   if (entry->keep_local)
@@ -1896,9 +1959,10 @@ write_entry(svn_wc__db_t *db,
 
   if (entry->file_external_path != NULL)
     {
-      base_node = MAYBE_ALLOC(base_node, scratch_pool);
+      base_node = MAYBE_ALLOC(base_node, result_pool);
     }
 
+
   /* Insert the base node. */
   if (base_node)
     {
@@ -1954,7 +2018,7 @@ write_entry(svn_wc__db_t *db,
         base_node->checksum = NULL;
       else
         SVN_ERR(svn_checksum_parse_hex(&base_node->checksum, svn_checksum_md5,
-                                       entry->checksum, scratch_pool));
+                                       entry->checksum, result_pool));
 
       if (this_dir->repos)
         {
@@ -1971,7 +2035,7 @@ write_entry(svn_wc__db_t *db,
                 base_node->repos_relpath = "";
               else
                 base_node->repos_relpath = svn_path_uri_decode(relative_url,
-                                                               scratch_pool);
+                                                               result_pool);
             }
           else
             {
@@ -1984,7 +2048,7 @@ write_entry(svn_wc__db_t *db,
                 base_node->repos_relpath =
                   svn_dirent_join(svn_path_uri_decode(base_path, scratch_pool),
                                   entry->name,
-                                  scratch_pool);
+                                  result_pool);
             }
         }
 
@@ -2061,7 +2125,7 @@ write_entry(svn_wc__db_t *db,
       else
         SVN_ERR(svn_checksum_parse_hex(&working_node->checksum,
                                        svn_checksum_md5,
-                                       entry->checksum, scratch_pool));
+                                       entry->checksum, result_pool));
 
       /* All subdirs start of incomplete, and stop being incomplete
          when the entries file in the subdir is upgraded. */
@@ -2087,7 +2151,8 @@ write_entry(svn_wc__db_t *db,
               /* If the entry is part of a COPIED (not REPLACED) subtree,
                  then the deletion is referring to the WORKING node, not
                  the BASE node. */
-              if (entry->copied
+              if (!base_node
+                  || entry->copied
                   || (this_dir->copied
                       && this_dir->schedule == svn_wc_schedule_add))
                 working_node->presence = svn_wc__db_status_not_present;
@@ -2122,6 +2187,19 @@ write_entry(svn_wc__db_t *db,
       working_node->changed_date = entry->cmt_date;
       working_node->changed_author = entry->cmt_author;
 
+      if (!entry->copied)
+        {
+          if (parent_node->work)
+            working_node->op_depth = parent_node->work->op_depth;
+          else
+#ifdef SVN_WC__OP_DEPTH
+            working_node->op_depth
+              = svn_wc__db_op_depth_for_upgrade(local_relpath);
+#else
+            working_node->op_depth = 2; /* ### temporary op_depth */
+#endif
+        }
+
       SVN_ERR(insert_working_node(sdb, working_node, scratch_pool));
     }
 
@@ -2137,6 +2215,13 @@ write_entry(svn_wc__db_t *db,
       SVN_ERR(insert_actual_node(sdb, actual_node, scratch_pool));
     }
 
+  if (entry_node)
+    {
+      *entry_node = apr_palloc(result_pool, sizeof(*entry_node));
+      (*entry_node)->base = base_node;
+      (*entry_node)->work = working_node;
+    }
+
   return SVN_NO_ERROR;
 }
 
@@ -2148,6 +2233,9 @@ struct entries_write_baton
   const char *dir_abspath;
   const char *new_root_abspath;
   apr_hash_t *entries;
+  struct write_baton *parent_node;
+  struct write_baton *dir_node;
+  apr_pool_t *result_pool;
 };
 
 /* Writes entries inside a sqlite transaction
@@ -2185,12 +2273,11 @@ entries_write_new_cb(void *baton,
   dir_relpath = svn_dirent_skip_ancestor(old_root_abspath, dir_abspath);
 
   /* Write out "this dir" */
-  SVN_ERR(write_entry(db, sdb, ewb->wc_id, ewb->repos_id,
-                      this_dir,
-                      dir_relpath,
+  SVN_ERR(write_entry(&ewb->dir_node, ewb->parent_node, db, sdb,
+                      ewb->wc_id, ewb->repos_id, this_dir, dir_relpath,
                       svn_dirent_join(new_root_abspath, dir_relpath,
                                       scratch_pool),
-                      this_dir, FALSE, iterpool));
+                      this_dir, FALSE, ewb->result_pool, iterpool));
 
   for (hi = apr_hash_first(scratch_pool, ewb->entries); hi;
        hi = apr_hash_next(hi))
@@ -2209,14 +2296,12 @@ entries_write_new_cb(void *baton,
          use this function for upgrading old working copies. */
       child_abspath = svn_dirent_join(dir_abspath, name, iterpool);
       child_relpath = svn_dirent_skip_ancestor(old_root_abspath, child_abspath);
-      SVN_ERR(write_entry(db, sdb, ewb->wc_id, ewb->repos_id,
-                          this_entry,
-                          child_relpath,
+      SVN_ERR(write_entry(NULL, ewb->dir_node, db, sdb,
+                          ewb->wc_id, ewb->repos_id,
+                          this_entry, child_relpath,
                           svn_dirent_join(new_root_abspath, child_relpath,
                                           scratch_pool),
-                          this_dir,
-                          TRUE,
-                          iterpool));
+                          this_dir, TRUE, iterpool, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -2225,13 +2310,16 @@ entries_write_new_cb(void *baton,
 
 
 svn_error_t *
-svn_wc__write_upgraded_entries(svn_wc__db_t *db,
+svn_wc__write_upgraded_entries(void **dir_baton,
+                               void *parent_baton,
+                               svn_wc__db_t *db,
                                svn_sqlite__db_t *sdb,
                                apr_int64_t repos_id,
                                apr_int64_t wc_id,
                                const char *dir_abspath,
                                const char *new_root_abspath,
                                apr_hash_t *entries,
+                               apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool)
 {
   struct entries_write_baton ewb;
@@ -2242,12 +2330,17 @@ svn_wc__write_upgraded_entries(svn_wc__d
   ewb.dir_abspath = dir_abspath;
   ewb.new_root_abspath = new_root_abspath;
   ewb.entries = entries;
+  ewb.parent_node = parent_baton;
+  ewb.result_pool = result_pool;
 
   /* Run this operation in a transaction to speed up SQLite.
      See http://www.sqlite.org/faq.html#q19 for more details */
-  return svn_error_return(
-      svn_sqlite__with_transaction(sdb, entries_write_new_cb, &ewb,
-                                   scratch_pool));
+  SVN_ERR(svn_sqlite__with_transaction(sdb, entries_write_new_cb, &ewb,
+                                       scratch_pool));
+
+  *dir_baton = ewb.dir_node;
+
+  return SVN_NO_ERROR;
 }
 
 

Modified: subversion/branches/performance/subversion/libsvn_wc/entries.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/entries.h?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/entries.h (original)
+++ subversion/branches/performance/subversion/libsvn_wc/entries.h Fri Nov 26 18:55:51 2010
@@ -87,15 +87,21 @@ svn_wc__read_entries_old(apr_hash_t **en
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool);
 
-/* For internal use by upgrade.c to write entries in the wc-ng format.  */
+/* For internal use by upgrade.c to write entries in the wc-ng format.
+   Return in DIR_BATON the baton to be passed as PARENT_BATON when
+   upgrading child directories. Pass a NULL PARENT_BATON when upgrading
+   the root directory. */
 svn_error_t *
-svn_wc__write_upgraded_entries(svn_wc__db_t *db,
+svn_wc__write_upgraded_entries(void **dir_baton,
+                               void *parent_baton,
+                               svn_wc__db_t *db,
                                svn_sqlite__db_t *sdb,
                                apr_int64_t repos_id,
                                apr_int64_t wc_id,
                                const char *dir_abspath,
                                const char *new_root_abspath,
                                apr_hash_t *entries,
+                               apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
 /* Parse a file external specification in the NULL terminated STR and

Modified: subversion/branches/performance/subversion/libsvn_wc/status.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/status.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/status.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/status.c Fri Nov 26 18:55:51 2010
@@ -782,8 +782,8 @@ send_status_structure(const struct walk_
           /* repos_lock still uses the deprecated filesystem absolute path
              format */
           repos_lock = apr_hash_get(wb->repos_locks,
-                                    svn_uri_join("/", repos_relpath,
-                                                 scratch_pool),
+                                    svn_fspath__join("/", repos_relpath,
+                                                     scratch_pool),
                                     APR_HASH_KEY_STRING);
         }
     }
@@ -2187,10 +2187,10 @@ close_file(void *file_baton,
               const char *repos_relpath = svn_relpath_join(dir_repos_relpath,
                                                            fb->name, pool);
 
-               repos_lock = apr_hash_get(fb->edit_baton->wb.repos_locks,
-                                         svn_uri_join("/", repos_relpath,
-                                                      pool),
-                                         APR_HASH_KEY_STRING);
+              repos_lock = apr_hash_get(fb->edit_baton->wb.repos_locks,
+                                        svn_fspath__join("/", repos_relpath,
+                                                         pool),
+                                        APR_HASH_KEY_STRING);
             }
         }
     }

Modified: subversion/branches/performance/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/upgrade.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/upgrade.c Fri Nov 26 18:55:51 2010
@@ -1156,7 +1156,9 @@ struct upgrade_data_t {
 
    Uses SCRATCH_POOL for all temporary allocation.  */
 static svn_error_t *
-upgrade_to_wcng(svn_wc__db_t *db,
+upgrade_to_wcng(void **dir_baton,
+                void *parent_baton,
+                svn_wc__db_t *db,
                 const char *dir_abspath,
                 int old_format,
                 svn_wc_upgrade_get_repos_info_t repos_info_func,
@@ -1258,11 +1260,11 @@ upgrade_to_wcng(svn_wc__db_t *db,
                                        scratch_pool));
     }
  
-  SVN_ERR(svn_wc__write_upgraded_entries(db, data->sdb,
+  SVN_ERR(svn_wc__write_upgraded_entries(dir_baton, parent_baton, db, data->sdb,
                                          data->repos_id, data->wc_id,
                                          dir_abspath, data->root_abspath,
                                          entries,
-                                         scratch_pool));
+                                         result_pool, scratch_pool));
 
   /***** WC PROPS *****/
 
@@ -1453,7 +1455,8 @@ svn_wc__upgrade_sdb(int *result_format,
 
 /* */
 static svn_error_t *
-upgrade_working_copy(svn_wc__db_t *db,
+upgrade_working_copy(void *parent_baton,
+                     svn_wc__db_t *db,
                      const char *dir_abspath,
                      svn_wc_upgrade_get_repos_info_t repos_info_func,
                      void *repos_info_baton,
@@ -1463,8 +1466,10 @@ upgrade_working_copy(svn_wc__db_t *db,
                      void *cancel_baton,
                      svn_wc_notify_func2_t notify_func,
                      void *notify_baton,
+                     apr_pool_t *result_pool,
                      apr_pool_t *scratch_pool)
 {
+  void *dir_baton;
   int old_format;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   apr_array_header_t *subdirs;
@@ -1507,7 +1512,7 @@ upgrade_working_copy(svn_wc__db_t *db,
     }
 
 
-  SVN_ERR(upgrade_to_wcng(db, dir_abspath, old_format,
+  SVN_ERR(upgrade_to_wcng(&dir_baton, parent_baton, db, dir_abspath, old_format,
                           repos_info_func, repos_info_baton,
                           repos_cache, data, scratch_pool, iterpool));
 
@@ -1523,12 +1528,12 @@ upgrade_working_copy(svn_wc__db_t *db,
 
       svn_pool_clear(iterpool);
 
-      SVN_ERR(upgrade_working_copy(db, child_abspath,
+      SVN_ERR(upgrade_working_copy(dir_baton, db, child_abspath,
                                    repos_info_func, repos_info_baton,
                                    repos_cache, data,
                                    cancel_func, cancel_baton,
                                    notify_func, notify_baton,
-                                   iterpool));
+                                   iterpool, iterpool));
     }
 
   svn_pool_destroy(iterpool);
@@ -1611,12 +1616,12 @@ svn_wc_upgrade(svn_wc_context_t *wc_ctx,
                           scratch_pool, scratch_pool));
 
   /* Upgrade the pre-wcng into a wcng in a temporary location. */
-  SVN_ERR(upgrade_working_copy(db, local_abspath,
+  SVN_ERR(upgrade_working_copy(NULL, db, local_abspath,
                                repos_info_func, repos_info_baton,
                                apr_hash_make(scratch_pool), &data,
                                cancel_func, cancel_baton,
                                notify_func, notify_baton,
-                               scratch_pool));
+                               scratch_pool, scratch_pool));
 
   /* A workqueue item to move the pristine dir into place */
   pristine_from = svn_wc__adm_child(data.root_abspath, PRISTINE_STORAGE_RELPATH,

Modified: subversion/branches/performance/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/wc-queries.sql?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/performance/subversion/libsvn_wc/wc-queries.sql Fri Nov 26 18:55:51 2010
@@ -132,9 +132,9 @@ INSERT OR REPLACE INTO nodes (
 VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14,
         ?15, ?16, ?17, ?18, ?19);
 
--- STMT_SELECT_BASE_NODE_CHILDREN
+-- STMT_SELECT_OP_DEPTH_CHILDREN
 SELECT local_relpath FROM nodes
-WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0;
+WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = ?3;
 
 -- STMT_SELECT_NODE_CHILDREN
 SELECT local_relpath FROM nodes

Modified: subversion/branches/performance/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/wc_db.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/wc_db.c Fri Nov 26 18:55:51 2010
@@ -128,6 +128,11 @@ APR_INLINE static int relpath_depth(cons
   return n;
 }
 
+int svn_wc__db_op_depth_for_upgrade(const char *local_relpath)
+{
+  return relpath_depth(local_relpath);
+}
+
 typedef struct insert_base_baton_t {
   /* common to all insertions into BASE */
   svn_wc__db_status_t status;
@@ -274,10 +279,12 @@ read_info(svn_wc__db_status_t *status,
           apr_pool_t *result_pool,
           apr_pool_t *scratch_pool);
 
+#ifndef SVN_WC__OP_DEPTH
 static svn_error_t *
 elide_copyfrom(svn_wc__db_pdh_t *pdh,
                const char *local_relpath,
                apr_pool_t *scratch_pool);
+#endif
 
 static svn_error_t *
 scan_addition(svn_wc__db_status_t *status,
@@ -302,6 +309,9 @@ scan_deletion(const char **base_del_relp
               apr_pool_t *result_pool,
               apr_pool_t *scratch_pool);
 
+static svn_error_t *
+convert_to_working_status(svn_wc__db_status_t *working_status,
+                          svn_wc__db_status_t status);
 
 /* Return the absolute path, in local path style, of LOCAL_RELPATH in WCROOT. */
 static const char *
@@ -1055,13 +1065,10 @@ add_children_to_hash(apr_hash_t *childre
 }
 
 
-/* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH.
-   If BASE_ONLY is true, then *only* the children from BASE_NODE are
-   returned (those in WORKING_NODE are ignored). The result children are
-   allocated in RESULT_POOL.  */
+/* Return in *CHILDREN all of the children of the directory LOCAL_RELPATH,
+   of any status, in all op-depths in the NODES table. */
 static svn_error_t *
 gather_children(const apr_array_header_t **children,
-                svn_boolean_t base_only,
                 svn_wc__db_pdh_t *pdh,
                 const char *local_relpath,
                 apr_pool_t *result_pool,
@@ -1070,23 +1077,55 @@ gather_children(const apr_array_header_t
   apr_hash_t *names_hash = apr_hash_make(scratch_pool);
   apr_array_header_t *names_array;
 
-  /* All of the names get allocated in RESULT_POOL.  For !base_only it
+  /* All of the names get allocated in RESULT_POOL.  It
      appears to be faster to use the hash to remove duplicates than to
      use DISTINCT in the SQL query. */
-  if (base_only)
-    SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_BASE_NODE_CHILDREN,
-                                 pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                 local_relpath, result_pool));
-  else
-    SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN,
-                                 pdh->wcroot->sdb, pdh->wcroot->wc_id,
-                                 local_relpath, result_pool));
+  SVN_ERR(add_children_to_hash(names_hash, STMT_SELECT_NODE_CHILDREN,
+                               pdh->wcroot->sdb, pdh->wcroot->wc_id,
+                               local_relpath, result_pool));
 
   SVN_ERR(svn_hash_keys(&names_array, names_hash, result_pool));
   *children = names_array;
   return SVN_NO_ERROR;
 }
 
+/* Set *CHILDREN to a new array of (const char *) names of the repository
+   children of the directory PDH:LOCAL_RELPATH - that is, the children at
+   the same op-depth. */
+static svn_error_t *
+gather_repo_children(const apr_array_header_t **children,
+                     svn_wc__db_pdh_t *pdh,
+                     const char *local_relpath,
+                     apr_int64_t op_depth,
+                     apr_pool_t *result_pool,
+                     apr_pool_t *scratch_pool)
+{
+  apr_array_header_t *result
+    = apr_array_make(result_pool, 0, sizeof(const char *));
+  svn_sqlite__stmt_t *stmt;
+  svn_boolean_t have_row;
+
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_OP_DEPTH_CHILDREN));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isi", pdh->wcroot->wc_id, local_relpath,
+                            op_depth));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  while (have_row)
+    {
+      const char *child_relpath = svn_sqlite__column_text(stmt, 0, NULL);
+
+      /* Allocate the name in RESULT_POOL so we won't have to copy it. */
+      APR_ARRAY_PUSH(result, const char *)
+        = svn_relpath_basename(child_relpath, result_pool);
+
+      SVN_ERR(svn_sqlite__step(&have_row, stmt));
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+
+  *children = result;
+  return SVN_NO_ERROR;
+}
+
 
 /* */
 static svn_error_t *
@@ -2156,8 +2195,8 @@ svn_wc__db_base_get_children(const apr_a
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  return gather_children(children, TRUE,
-                         pdh, local_relpath, result_pool, scratch_pool);
+  return gather_repo_children(children, pdh, local_relpath, 0,
+                              result_pool, scratch_pool);
 }
 
 
@@ -2916,9 +2955,9 @@ get_info_for_copy(apr_int64_t *copyfrom_
     }
   else if (*status == svn_wc__db_status_deleted)
     {
-      const char *work_del_relpath;
+      const char *base_del_relpath, *work_del_relpath;
 
-      SVN_ERR(scan_deletion(NULL, NULL, NULL, &work_del_relpath,
+      SVN_ERR(scan_deletion(&base_del_relpath, NULL, NULL, &work_del_relpath,
                             pdh, local_relpath, scratch_pool, scratch_pool));
       if (work_del_relpath)
         {
@@ -2939,19 +2978,21 @@ get_info_for_copy(apr_int64_t *copyfrom_
                                                         local_relpath),
                                result_pool);
         }
-      else
+      else if (base_del_relpath)
         {
-          *copyfrom_relpath = repos_relpath;
-          *copyfrom_rev = revision;
-          if (!repos_root_url || !repos_uuid)
-            SVN_ERR(scan_upwards_for_repos(copyfrom_id, NULL,
-                                           pdh->wcroot, local_relpath,
-                                           result_pool, scratch_pool));
-          else
-            SVN_ERR(fetch_repos_id(copyfrom_id,
-                                   repos_root_url, repos_uuid,
-                                   pdh->wcroot->sdb, scratch_pool));
+          SVN_ERR(base_get_info(NULL, NULL, copyfrom_rev, copyfrom_relpath,
+                                &repos_root_url, &repos_uuid,
+                                NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                NULL, NULL,
+                                pdh, base_del_relpath,
+                                result_pool, scratch_pool));
+
+          SVN_ERR(fetch_repos_id(copyfrom_id,
+                                 repos_root_url, repos_uuid,
+                                 pdh->wcroot->sdb, scratch_pool));
         }
+      else
+        SVN_ERR_MALFUNCTION();
     }
   else
     {
@@ -2965,6 +3006,20 @@ get_info_for_copy(apr_int64_t *copyfrom_
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+op_depth_of(apr_int64_t *op_depth,
+            svn_wc__db_pdh_t *pdh,
+            const char *local_relpath);
+
+static svn_error_t *
+op_depth_for_copy(apr_int64_t *op_depth,
+                  apr_int64_t copyfrom_repos_id,
+                  const char *copyfrom_relpath,
+                  svn_revnum_t copyfrom_revision,
+                  svn_wc__db_pdh_t *pdh,
+                  const char *local_relpath,
+                  apr_pool_t *scratch_pool);
+
 /* Like svn_wc__db_op_copy(), but with PDH+LOCAL_RELPATH instead of
  * DB+LOCAL_ABSPATH. */
 static svn_error_t *
@@ -2972,7 +3027,6 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
            const char *src_relpath,
            svn_wc__db_pdh_t *dst_pdh,
            const char *dst_relpath,
-           apr_int64_t dst_op_depth,
            const svn_skel_t *work_items,
            apr_pool_t *scratch_pool)
 {
@@ -2981,6 +3035,7 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
   svn_wc__db_status_t status, dst_status;
   svn_boolean_t have_work;
   apr_int64_t copyfrom_id;
+  apr_int64_t dst_op_depth;
   svn_wc__db_kind_t kind;
   const apr_array_header_t *children;
 
@@ -2988,6 +3043,10 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
                             &status, &kind, &have_work,
                             src_pdh, src_relpath, scratch_pool, scratch_pool));
 
+  SVN_ERR(op_depth_for_copy(&dst_op_depth, copyfrom_id,
+                            copyfrom_relpath, copyfrom_rev,
+                            dst_pdh, dst_relpath, scratch_pool));
+
   SVN_ERR_ASSERT(kind == svn_wc__db_kind_file || kind == svn_wc__db_kind_dir);
 
   /* ### New status, not finished, see notes/wc-ng/copying */
@@ -3021,8 +3080,13 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
     }
 
   if (kind == svn_wc__db_kind_dir)
-    SVN_ERR(gather_children(&children, FALSE, src_pdh, src_relpath,
-                            scratch_pool, scratch_pool));
+    {
+      apr_int64_t src_op_depth;
+
+      SVN_ERR(op_depth_of(&src_op_depth, src_pdh, src_relpath));
+      SVN_ERR(gather_repo_children(&children, src_pdh, src_relpath,
+                                   src_op_depth, scratch_pool, scratch_pool));
+    }
   else
     children = NULL;
 
@@ -3062,6 +3126,10 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
                                 dst_relpath, dst_parent_relpath));
       SVN_ERR(svn_sqlite__step_done(stmt));
 
+      /* Insert incomplete children, if relevant.
+         The children are part of the same op and so have the same op_depth.
+         (The only time we'd want a different depth is during a recursive
+         simple add, but we never insert children here during a simple add.) */
       if (kind == svn_wc__db_kind_dir)
         SVN_ERR(insert_incomplete_children(dst_pdh->wcroot->sdb,
                                            dst_pdh->wcroot->wc_id,
@@ -3082,8 +3150,10 @@ db_op_copy(svn_wc__db_pdh_t *src_pdh,
                             scratch_pool));
     }
 
+#ifndef SVN_WC__OP_DEPTH
   /* ### Should do this earlier and insert the node with the right values. */
   SVN_ERR(elide_copyfrom(dst_pdh, dst_relpath, scratch_pool));
+#endif
 
   SVN_ERR(add_work_items(dst_pdh->wcroot->sdb, work_items, scratch_pool));
 
@@ -3100,10 +3170,6 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
 {
   svn_wc__db_pdh_t *src_pdh, *dst_pdh;
   const char *src_relpath, *dst_relpath;
-#ifdef SVN_WC__OP_DEPTH
-  const char *dst_op_root_relpath;
-#endif
-  apr_int64_t dst_op_depth;
 
   SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
   SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
@@ -3120,55 +3186,13 @@ svn_wc__db_op_copy(svn_wc__db_t *db,
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(dst_pdh);
 
-#ifdef SVN_WC__OP_DEPTH
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&dst_pdh, &dst_op_root_relpath,
-                                             db, dst_op_root_abspath,
-                                             svn_sqlite__mode_readwrite,
-                                             scratch_pool, scratch_pool));
-  dst_op_depth = relpath_depth(dst_op_root_relpath);
-#else
-  dst_op_depth = 2;  /* ### temporary op_depth */
-#endif
-
   /* ### This should all happen in one transaction. */
   SVN_ERR(db_op_copy(src_pdh, src_relpath, dst_pdh, dst_relpath,
-                     dst_op_depth, work_items, scratch_pool));
+                     work_items, scratch_pool));
 
   return SVN_NO_ERROR;
 }
 
-svn_boolean_t
-svn_wc__db_same_db(svn_wc__db_t *db,
-                   const char *src_abspath,
-                   const char *dst_abspath,
-                   apr_pool_t *scratch_pool)
-{
-  svn_error_t *err;
-  svn_wc__db_pdh_t *src_pdh, *dst_pdh;
-  const char *src_relpath, *dst_relpath;
-
-  err = svn_wc__db_pdh_parse_local_abspath(&src_pdh, &src_relpath, db,
-                                           src_abspath,
-                                           svn_sqlite__mode_readonly,
-                                           scratch_pool, scratch_pool);
-  if (err)
-    {
-      src_pdh = NULL;
-      svn_error_clear(err);
-    }
-  err = svn_wc__db_pdh_parse_local_abspath(&dst_pdh, &dst_relpath, db,
-                                           dst_abspath,
-                                           svn_sqlite__mode_readonly,
-                                           scratch_pool, scratch_pool);
-  if (err)
-    {
-      dst_pdh = NULL;
-      svn_error_clear(err);
-    }
-
-  return (src_pdh && dst_pdh && src_pdh->wcroot == dst_pdh->wcroot);
-}
-
 /* Set *OP_DEPTH to the highest op depth of PDH:LOCAL_RELPATH. */
 static svn_error_t *
 op_depth_of(apr_int64_t *op_depth,
@@ -3222,169 +3246,65 @@ catch_copy_of_absent(svn_wc__db_pdh_t *p
 }
 
 
-/*
- * Copy single NODES row from src_path@src_op_depth to dst_path@dst_depth.
- * Copy all rows of descendent paths in == src_op_depth to == dst_depth.
- * Copy all rows of descendent paths in > src_depth to > dst_depth,
- * adjusting op_depth by (dst_depth - src_depth).
- *
- * ### TODO: Return a list of copied nodes. */
-static svn_error_t *
-copy_nodes_rows(svn_wc__db_pdh_t *src_pdh,
-                const char *src_relpath,
-                svn_wc__db_pdh_t *dst_pdh,
-                const char *dst_relpath,
-                apr_pool_t *scratch_pool)
-{
-  apr_int64_t src_op_depth;
-  apr_int64_t src_depth = relpath_depth(src_relpath);
-  apr_int64_t dst_depth = relpath_depth(dst_relpath);
-  svn_sqlite__stmt_t *stmt;
-  const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath,
-                                                       scratch_pool);
-
-  SVN_ERR(op_depth_of(&src_op_depth, src_pdh, src_relpath));
-
-  if (src_op_depth == 0)
-    SVN_ERR(catch_copy_of_absent(src_pdh, src_relpath, scratch_pool));
-
-  /* Root node */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
-                                    STMT_COPY_NODES_ROW));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isissi",
-                            src_pdh->wcroot->wc_id,
-                            src_relpath,
-                            src_op_depth,
-                            dst_relpath,
-                            dst_parent_relpath,
-                            dst_depth));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  /* Descendants at same depth */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
-                                    STMT_COPY_NODES_AT_SAME_OP_DEPTH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isisii",
-                            src_pdh->wcroot->wc_id,
-                            construct_like_arg(src_relpath, scratch_pool),
-                            src_op_depth,
-                            dst_relpath,
-                            dst_depth,
-                            (apr_int64_t)(strlen(src_relpath) + 1)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  /* Descendants at greater depths */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, src_pdh->wcroot->sdb,
-                                    STMT_COPY_NODES_AT_GREATER_OP_DEPTH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isisii",
-                            src_pdh->wcroot->wc_id,
-                            construct_like_arg(src_relpath, scratch_pool),
-                            src_depth,
-                            dst_relpath,
-                            dst_depth,
-                            (apr_int64_t)(strlen(src_relpath) + 1)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  return SVN_NO_ERROR;
-}
-
-/* */
-static svn_error_t *
-copy_actual_rows(svn_wc__db_pdh_t *src_pdh,
-                 const char *src_relpath,
-                 svn_wc__db_pdh_t *dst_pdh,
-                 const char *dst_relpath,
-                 apr_pool_t *scratch_pool)
+/* If COPYFROM_REPOS_ID+COPYFROM_RELPATH+COPYFROM_REVISION "match" the copyfrom
+   information for the parent of LOCAL_RELPATH then set *OP_DEPTH to
+   the op_depth of the parent, otherwise set *OP_DEPTH to the op_depth
+   of LOCAL_RELPATH. */
+static svn_error_t *
+op_depth_for_copy(apr_int64_t *op_depth,
+                  apr_int64_t copyfrom_repos_id,
+                  const char *copyfrom_relpath,
+                  svn_revnum_t copyfrom_revision,
+                  svn_wc__db_pdh_t *pdh,
+                  const char *local_relpath,
+                  apr_pool_t *scratch_pool)
 {
+#ifdef SVN_WC__OP_DEPTH
+  const char *parent_relpath, *name;
   svn_sqlite__stmt_t *stmt;
-  const char *src_parent_relpath = svn_relpath_dirname(src_relpath,
-                                                       scratch_pool);
-  const char *dst_parent_relpath = svn_relpath_dirname(dst_relpath,
-                                                       scratch_pool);
-
-  /* ### Copying changelist is OK for a move but what about a copy? */
-  SVN_ERR(svn_sqlite__get_statement(&stmt, dst_pdh->wcroot->sdb,
-                                    STMT_COPY_ACTUAL_NODE_ROWS));
-  SVN_ERR(svn_sqlite__bindf(stmt, "issssii",
-                            src_pdh->wcroot->wc_id, src_relpath,
-                            construct_like_arg(src_relpath, scratch_pool),
-                            dst_relpath, dst_parent_relpath,
-                            (apr_int64_t)(strlen(src_relpath) + 1),
-                            (apr_int64_t)(strlen(src_parent_relpath) + 1)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
-
-  return SVN_NO_ERROR;
-}
-
-
-struct copy_tree_baton_t
-{
-  svn_wc__db_pdh_t *src_pdh, *dst_pdh;
-  const char *src_relpath, *dst_relpath;
-  const svn_skel_t *work_items;
-};
-
-/* */
-static svn_error_t *
-db_op_copy_tree(void *baton,
-                svn_sqlite__db_t *sdb,
-                apr_pool_t *scratch_pool)
-{
-  struct copy_tree_baton_t *b = baton;
-
-  SVN_ERR(copy_nodes_rows(b->src_pdh, b->src_relpath,
-                          b->dst_pdh, b->dst_relpath,
-                          scratch_pool));
-
-  SVN_ERR(copy_actual_rows(b->src_pdh, b->src_relpath,
-                           b->dst_pdh, b->dst_relpath,
-                           scratch_pool));
-
-  SVN_ERR(add_work_items(b->dst_pdh->wcroot->sdb, b->work_items, scratch_pool));
-
-  return SVN_NO_ERROR;
-}
-
-svn_error_t *
-svn_wc__db_op_copy_tree(svn_wc__db_t *db,
-                        const char *src_abspath,
-                        const char *dst_abspath,
-                        const svn_skel_t *work_items,
-                        apr_pool_t *scratch_pool)
-{
-  struct copy_tree_baton_t b;
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(src_abspath));
-  SVN_ERR_ASSERT(svn_dirent_is_absolute(dst_abspath));
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&b.src_pdh, &b.src_relpath, db,
-                                             src_abspath,
-                                             svn_sqlite__mode_readwrite,
-                                             scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(b.src_pdh);
-
-  SVN_ERR(svn_wc__db_pdh_parse_local_abspath(&b.dst_pdh, &b.dst_relpath, db,
-                                             dst_abspath,
-                                             svn_sqlite__mode_readwrite,
-                                             scratch_pool, scratch_pool));
-  VERIFY_USABLE_PDH(b.dst_pdh);
-
-  b.work_items = work_items;
-
-  SVN_ERR_ASSERT(b.src_pdh->wcroot == b.dst_pdh->wcroot);
-  /* ASSERT(presence == normal) */
+  svn_boolean_t have_row;
 
-  SVN_ERR(svn_sqlite__with_transaction(b.dst_pdh->wcroot->sdb,
-                                       db_op_copy_tree, &b, scratch_pool));
+  *op_depth = relpath_depth(local_relpath);
 
-  /* ### Do we sometimes need to elide copy-from info and/or other fields on
-   * the destination root node? See elide_copyfrom(). */
+  if (!copyfrom_relpath)
+    return SVN_NO_ERROR;
 
-  /* ### Do we need to flush entries?
-   * SVN_ERR(flush_entries(db, b.dst_pdh, dst_abspath, scratch_pool)); */
+  svn_relpath_split(&parent_relpath, &name, local_relpath, scratch_pool);
 
+  SVN_ERR(svn_sqlite__get_statement(&stmt, pdh->wcroot->sdb,
+                                    STMT_SELECT_WORKING_NODE));
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", pdh->wcroot->wc_id, parent_relpath));
+  SVN_ERR(svn_sqlite__step(&have_row, stmt));
+  if (have_row)
+    {
+      svn_wc__db_status_t status = svn_sqlite__column_token(stmt, 1,
+                                                            presence_map);
+      SVN_ERR(convert_to_working_status(&status, status));
+      if (status == svn_wc__db_status_added)
+        {
+          apr_int64_t parent_copyfrom_repos_id
+            = svn_sqlite__column_int64(stmt, 10);
+          const char *parent_copyfrom_relpath
+            = svn_sqlite__column_text(stmt, 11, NULL);
+          svn_revnum_t parent_copyfrom_revision
+            = svn_sqlite__column_revnum(stmt, 12);
+
+          if (parent_copyfrom_repos_id == copyfrom_repos_id
+              && copyfrom_revision == parent_copyfrom_revision
+              && !strcmp(svn_relpath_join(parent_copyfrom_relpath, name,
+                                          scratch_pool),
+                         copyfrom_relpath))
+            *op_depth = svn_sqlite__column_int64(stmt, 0);
+        }
+    }
+  SVN_ERR(svn_sqlite__reset(stmt));
+  
+#else
+  *op_depth = 2; /* temporary op_depth */
+#endif
   return SVN_NO_ERROR;
 }
 
-
 svn_error_t *
 svn_wc__db_op_copy_dir(svn_wc__db_t *db,
                        const char *local_abspath,
@@ -3442,7 +3362,10 @@ svn_wc__db_op_copy_dir(svn_wc__db_t *db,
       iwb.original_revnum = original_revision;
     }
 
-  iwb.op_depth = 2;  /* ### temporary op_depth */
+  /* ### Should we do this inside the transaction? */
+  SVN_ERR(op_depth_for_copy(&iwb.op_depth, iwb.original_repos_id,
+                            original_repos_relpath, original_revision,
+                            pdh, local_relpath, scratch_pool));
 
   iwb.children = children;
   iwb.depth = depth;
@@ -3516,16 +3439,10 @@ svn_wc__db_op_copy_file(svn_wc__db_t *db
       iwb.original_revnum = original_revision;
     }
 
-#ifdef SVN_WC__OP_DEPTH
-  iwb.op_depth = relpath_depth(local_relpath);
-
-  /* ### TODO? If the WC parent dir is already a copy from
-   * dirname(original_repos_relpath)@original_revision, then this is a
-   * redundant copy as far is the repos is concerned, so it should share
-   * the same op_depth.  But that's a degenerate case.  Is it needed? */
-#else
-  iwb.op_depth = 2;  /* ### temporary op_depth */
-#endif
+  /* ### Should we do this inside the transaction? */
+  SVN_ERR(op_depth_for_copy(&iwb.op_depth, iwb.original_repos_id,
+                            original_repos_relpath, original_revision,
+                            pdh, local_relpath, scratch_pool));
 
   iwb.checksum = checksum;
 
@@ -3594,7 +3511,10 @@ svn_wc__db_op_copy_symlink(svn_wc__db_t 
       iwb.original_revnum = original_revision;
     }
 
-  iwb.op_depth = 2;  /* ### temporary op_depth */
+  /* ### Should we do this inside the transaction? */
+  SVN_ERR(op_depth_for_copy(&iwb.op_depth, iwb.original_repos_id,
+                            original_repos_relpath, original_revision,
+                            pdh, local_relpath, scratch_pool));
 
   iwb.target = target;
 
@@ -5773,7 +5693,7 @@ svn_wc__db_read_children(const apr_array
                                              scratch_pool, scratch_pool));
   VERIFY_USABLE_PDH(pdh);
 
-  return gather_children(children, FALSE,
+  return gather_children(children,
                          pdh, local_relpath, result_pool, scratch_pool);
 }
 
@@ -8836,8 +8756,8 @@ make_copy_txn(void *baton,
     SVN_ERR(svn_sqlite__reset(stmt));
 
   /* Get the BASE children, as WORKING children don't need modifications */
-  SVN_ERR(svn_wc__db_base_get_children(&children, mcb->db, mcb->local_abspath,
-                                       scratch_pool, iterpool));
+  SVN_ERR(gather_repo_children(&children, mcb->pdh, mcb->local_relpath, 0,
+                               scratch_pool, iterpool));
 
   for (i = 0; i < children->nelts; i++)
     {
@@ -8955,6 +8875,7 @@ svn_wc__db_temp_op_make_copy(svn_wc__db_
   return SVN_NO_ERROR;
 }
 
+#ifndef SVN_WC__OP_DEPTH
 /* Return the copyfrom info for LOCAL_ABSPATH resolving inheritance. */
 static svn_error_t *
 get_copyfrom(apr_int64_t *copyfrom_repos_id,
@@ -9007,8 +8928,10 @@ get_copyfrom(apr_int64_t *copyfrom_repos
 
   return SVN_NO_ERROR;
 }
+#endif
 
 
+#ifndef SVN_WC__OP_DEPTH
 static svn_error_t *
 elide_copyfrom(svn_wc__db_pdh_t *pdh,
                const char *local_relpath,
@@ -9112,6 +9035,7 @@ svn_wc__db_temp_elide_copyfrom(svn_wc__d
 
   return SVN_NO_ERROR;
 }
+#endif
 
 
 svn_error_t *

Modified: subversion/branches/performance/subversion/libsvn_wc/wc_db.h
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/wc_db.h?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/wc_db.h (original)
+++ subversion/branches/performance/subversion/libsvn_wc/wc_db.h Fri Nov 26 18:55:51 2010
@@ -1011,35 +1011,6 @@ svn_wc__db_pristine_repair(svn_wc__db_t 
    @{
 */
 
-/* Return TRUE if SRC_ABSPATH and DST_ABSPATH are versioned paths in the
- * same DB; FALSE otherwise. */
-svn_boolean_t
-svn_wc__db_same_db(svn_wc__db_t *db,
-                   const char *src_abspath,
-                   const char *dst_abspath,
-                   apr_pool_t *scratch_pool);
-
-/* Copy the tree at SRC_ABSPATH (in NODES and ACTUAL_NODE tables) to
- * DST_ABSPATH.
- *
- * SRC_ABSPATH and DST_ABSPATH must be in the same WC.  SRC_ABSPATH must
- * exist, and must not be excluded/absent/not-present.  The parent of
- * DST_ABSPATH must be a versioned directory.  DST_ABSPATH must be in a
- * state suitable for creating a new node: nonexistent or deleted.
- *
- * Preserve changelist associations in the copy.  Preserve all node states
- * including excluded/absent/not-present.
- *
- * Copy the metadata only: do not look at or copy the nodes on disk.
- *
- * Add WORK_ITEMS to the work queue. */
-svn_error_t *
-svn_wc__db_op_copy_tree(svn_wc__db_t *db,
-                        const char *src_abspath,
-                        const char *dst_abspath,
-                        const svn_skel_t *work_items,
-                        apr_pool_t *scratch_pool);
-
 /* Copy the node at SRC_ABSPATH (in NODES and ACTUAL_NODE tables) to
  * DST_ABSPATH, both in DB but not necessarily in the same WC.  The parent
  * of DST_ABSPATH must be a versioned directory.
@@ -2388,12 +2359,14 @@ svn_wc__db_temp_op_make_copy(svn_wc__db_
                              apr_pool_t *scratch_pool);
 
 
+#ifndef SVN_WC__OP_DEPTH
 /* Elide the copyfrom information for LOCAL_ABSPATH if it can be derived
    from the parent node.  */
 svn_error_t *
 svn_wc__db_temp_elide_copyfrom(svn_wc__db_t *db,
                                const char *local_abspath,
                                apr_pool_t *scratch_pool);
+#endif
 
 
 /* Return the serialized file external info (from BASE) for LOCAL_ABSPATH.
@@ -2477,6 +2450,9 @@ svn_wc__db_drop_root(svn_wc__db_t *db,
                      const char *local_abspath,
                      apr_pool_t *scratch_pool);
 
+/* Return the OP_DEPTH for LOCAL_RELPATH. */
+int svn_wc__db_op_depth_for_upgrade(const char *local_relpath);
+
 /* @} */
 
 

Modified: subversion/branches/performance/subversion/libsvn_wc/workqueue.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/libsvn_wc/workqueue.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/libsvn_wc/workqueue.c (original)
+++ subversion/branches/performance/subversion/libsvn_wc/workqueue.c Fri Nov 26 18:55:51 2010
@@ -1516,12 +1516,14 @@ run_file_install(svn_wc__db_t *db,
                                       FALSE /* ignore_enoent */,
                                       scratch_pool));
 
+#ifndef SVN_WC__OP_DEPTH
       /* ### there used to be a call to entry_modify() above, to set the
          ### TRANSLATED_SIZE and LAST_MOD_TIME values. that function elided
          ### copyfrom information that snuck into the database. it should
          ### not be there in the first place, but we can manually get rid
          ### of the erroneous, inheritable copyfrom data.  */
       SVN_ERR(svn_wc__db_temp_elide_copyfrom(db, local_abspath, scratch_pool));
+#endif
     }
 
   return SVN_NO_ERROR;

Modified: subversion/branches/performance/subversion/mod_dav_svn/reports/mergeinfo.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/mod_dav_svn/reports/mergeinfo.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/mod_dav_svn/reports/mergeinfo.c (original)
+++ subversion/branches/performance/subversion/mod_dav_svn/reports/mergeinfo.c Fri Nov 26 18:55:51 2010
@@ -50,6 +50,7 @@ dav_svn__get_mergeinfo_report(const dav_
   dav_error *derr = NULL;
   apr_xml_elem *child;
   svn_mergeinfo_catalog_t catalog;
+  svn_boolean_t validate_inherited_mergeinfo = FALSE;
   svn_boolean_t include_descendants = FALSE;
   dav_svn__authz_read_baton arb;
   const dav_svn_repos *repos = resource->info->repos;
@@ -99,6 +100,12 @@ dav_svn__get_mergeinfo_report(const dav_
                                  resource->pool);
           (*((const char **)(apr_array_push(paths)))) = target;
         }
+      else if (strcmp(child->name, SVN_DAV__VALIDATE_INHERITED) == 0)
+        {
+          const char *word = dav_xml_get_cdata(child, resource->pool, 1);
+          if (strcmp(word, "yes") == 0)
+            validate_inherited_mergeinfo = TRUE;
+        }
       else if (strcmp(child->name, SVN_DAV__INCLUDE_DESCENDANTS) == 0)
         {
           const char *word = dav_xml_get_cdata(child, resource->pool, 1);
@@ -117,10 +124,11 @@ dav_svn__get_mergeinfo_report(const dav_
   /* Build mergeinfo brigade */
   bb = apr_brigade_create(resource->pool, output->c->bucket_alloc);
 
-  serr = svn_repos_fs_get_mergeinfo(&catalog, repos->repos, paths, rev,
-                                    inherit, include_descendants,
-                                    dav_svn__authz_read_func(&arb),
-                                    &arb, resource->pool);
+  serr = svn_repos_fs_get_mergeinfo2(&catalog, repos->repos, paths, rev,
+                                     inherit, validate_inherited_mergeinfo,
+                                     include_descendants,
+                                     dav_svn__authz_read_func(&arb),
+                                     &arb, resource->pool);
   if (serr)
     {
       derr = dav_svn__convert_err(serr, HTTP_BAD_REQUEST, serr->message,
@@ -197,6 +205,22 @@ dav_svn__get_mergeinfo_report(const dav_
         }
     }
 
+  if (validate_inherited_mergeinfo)
+    {
+      serr = dav_svn__brigade_puts(bb, output,
+                                   "<S:" SVN_DAV__VALIDATE_INHERITED ">"
+                                   "yes"
+                                   "</S:" SVN_DAV__VALIDATE_INHERITED ">"
+                                   DEBUG_CR);
+      if (serr)
+        {
+          derr = dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR,
+                                      "Error ending REPORT response.",
+                                      resource->pool);
+          goto cleanup;
+        }
+    }
+
   if ((serr = dav_svn__brigade_puts(bb, output,
                                     "</S:" SVN_DAV__MERGEINFO_REPORT ">"
                                     DEBUG_CR)))

Modified: subversion/branches/performance/subversion/mod_dav_svn/repos.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/mod_dav_svn/repos.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/mod_dav_svn/repos.c (original)
+++ subversion/branches/performance/subversion/mod_dav_svn/repos.c Fri Nov 26 18:55:51 2010
@@ -1420,7 +1420,6 @@ cleanup_fs_access(void *data)
 /* Helper func to construct a special 'parentpath' private resource. */
 static dav_error *
 get_parentpath_resource(request_rec *r,
-                        const char *root_path,
                         dav_resource **resource)
 {
   const char *new_uri;
@@ -1915,7 +1914,7 @@ get_resource(request_rec *r,
 
       if (strcmp(parentpath, uri) == 0)
         {
-          err = get_parentpath_resource(r, root_path, resource);
+          err = get_parentpath_resource(r, resource);
           if (err)
             return err;
           return NULL;

Modified: subversion/branches/performance/subversion/svn/add-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/add-cmd.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/add-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/add-cmd.c Fri Nov 26 18:55:51 2010
@@ -71,10 +71,8 @@ svn_cl__add(apr_getopt_t *os,
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
 
       if (svn_path_is_url(target))
-        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                                  NULL,
-                                                  _("'%s' is not a local path"),
-                                                  target));
+        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                 _("'%s' is not a local path"), target);
     }
 
   iterpool = svn_pool_create(pool);

Modified: subversion/branches/performance/subversion/svn/changelist-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/changelist-cmd.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/changelist-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/changelist-cmd.c Fri Nov 26 18:55:51 2010
@@ -76,10 +76,8 @@ svn_cl__changelist(apr_getopt_t *os,
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
 
       if (svn_path_is_url(target))
-        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                                  NULL,
-                                                  _("'%s' is not a local path"),
-                                                  target));
+        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                 _("'%s' is not a local path"), target);
     }
 
   if (opt_state->quiet)

Modified: subversion/branches/performance/subversion/svn/cleanup-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/cleanup-cmd.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/cleanup-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/cleanup-cmd.c Fri Nov 26 18:55:51 2010
@@ -64,10 +64,8 @@ svn_cl__cleanup(apr_getopt_t *os,
       const char *target = APR_ARRAY_IDX(targets, i, const char *);
 
       if (svn_path_is_url(target))
-        return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                                  NULL,
-                                                  _("'%s' is not a local path"),
-                                                  target));
+        return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                                 _("'%s' is not a local path"), target);
     }
 
   SVN_ERR(svn_cl__eat_peg_revisions(&targets, targets, pool));

Modified: subversion/branches/performance/subversion/svn/export-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/export-cmd.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/export-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/export-cmd.c Fri Nov 26 18:55:51 2010
@@ -86,10 +86,9 @@ svn_cl__export(apr_getopt_t *os,
     }
 
   if (svn_path_is_url(to))
-    return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                              NULL,
-                                              _("'%s' is not a local path"),
-                                              to));
+    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("'%s' is not a local path"), to);
+
   if (! opt_state->quiet)
     SVN_ERR(svn_cl__notifier_mark_export(ctx->notify_baton2));
 

Modified: subversion/branches/performance/subversion/svn/import-cmd.c
URL: http://svn.apache.org/viewvc/subversion/branches/performance/subversion/svn/import-cmd.c?rev=1039511&r1=1039510&r2=1039511&view=diff
==============================================================================
--- subversion/branches/performance/subversion/svn/import-cmd.c (original)
+++ subversion/branches/performance/subversion/svn/import-cmd.c Fri Nov 26 18:55:51 2010
@@ -101,10 +101,9 @@ svn_cl__import(apr_getopt_t *os,
     }
 
   if (svn_path_is_url(path))
-    return svn_error_return(svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR,
-                                              NULL,
-                                              _("'%s' is not a local path"),
-                                              path));
+    return svn_error_createf(SVN_ERR_CL_ARG_PARSING_ERROR, NULL,
+                             _("'%s' is not a local path"), path);
+
   if (! svn_path_is_url(url))
     return svn_error_createf
       (SVN_ERR_CL_ARG_PARSING_ERROR, NULL,