Author: rhuijben
Date: Tue Apr 26 14:21:24 2011
New Revision: 1096759

URL: http://svn.apache.org/viewvc?rev=1096759&view=rev
Log:
Add a new libsvn_wc function that determines whether a node is obstructed
or missing. Using this from the merge code avoids a lot of separate wc_db
calls that were needed before this patch and then didn't provide an
accurate result anyway.

This patch replaces the exising usage of the obstruction check with this
new function, but doesn't use the real power yet.
(More patches on their way)

* subversion/include/private/svn_wc_private.h
  (svn_wc__check_for_obstructions): New function.

* subversion/libsvn_client/merge.c
  (obstructed_or_missing): Rename to ...
  (perform_obstruction_check): And use svn_wc__check_for_obstructions for
    doing the hard work. (But keeping the wrapper to handle current and
    future dry run scenarios).

  (merge_props_changed,
   merge_file_changed,
   merge_file_added,
   merge_file_deleted,
   merge_dir_added,
   merge_dir_deleted,
   merge_dir_opened): Update callers and remove some local hacks to detect
     obstruction working copies.

* subversion/libsvn_wc/node.c
  (svn_wc__check_for_obstructions): New function.

Modified:
    subversion/trunk/subversion/include/private/svn_wc_private.h
    subversion/trunk/subversion/libsvn_client/merge.c
    subversion/trunk/subversion/libsvn_wc/node.c

Modified: subversion/trunk/subversion/include/private/svn_wc_private.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/private/svn_wc_private.h?rev=1096759&r1=1096758&r2=1096759&view=diff
==============================================================================
--- subversion/trunk/subversion/include/private/svn_wc_private.h (original)
+++ subversion/trunk/subversion/include/private/svn_wc_private.h Tue Apr 26 
14:21:24 2011
@@ -946,6 +946,26 @@ svn_wc__node_get_commit_status(svn_node_
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
+/* Checks for obstructions for the merge processing
+ *
+ * ### Currently this API is work in progress and is designed for just this
+ * ### caller.
+ *
+ * All output arguments except OBSTRUCTION_STATE may be NULL.
+ */
+svn_error_t *
+svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
+                               svn_boolean_t *exists,
+                               svn_boolean_t *versioned,
+                               svn_boolean_t *added,
+                               svn_boolean_t *deleted,
+                               svn_node_kind_t *kind,
+                               svn_wc_context_t *wc_ctx,
+                               const char *local_abspath,
+                               svn_boolean_t no_wcroot_check,
+                               apr_pool_t *scratch_pool);
+
+
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */

Modified: subversion/trunk/subversion/libsvn_client/merge.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_client/merge.c?rev=1096759&r1=1096758&r2=1096759&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_client/merge.c (original)
+++ subversion/trunk/subversion/libsvn_client/merge.c Tue Apr 26 14:21:24 2011
@@ -372,76 +372,69 @@ is_path_conflicted_by_merge(merge_cmd_ba
  *   - Return 'obstructed' if there is a node on disk where none or a
  *     different kind is expected, or if the disk node cannot be read.
  *   - Return 'missing' if there is no node on disk but one is expected.
- *     Also return 'missing' for absent nodes (not here due to authz).*/
+ *     Also return 'missing' for absent nodes (not here due to authz).
+ *
+ * Optionally return a bit more info for interested users.
+ **/
 static svn_error_t *
-obstructed_or_missing(svn_wc_notify_state_t *obstr_state,
-                      const char *local_abspath,
-                      const char *local_dir_abspath,
-                      const merge_cmd_baton_t *merge_b,
-                      apr_pool_t *pool)
+perform_obstruction_check(svn_wc_notify_state_t *obstruction_state,
+                          svn_boolean_t *exists,
+                          svn_boolean_t *versioned,
+                          svn_boolean_t *added,
+                          svn_boolean_t *deleted,
+                          svn_node_kind_t *kind,
+                          const merge_cmd_baton_t *merge_b,
+                          const char *local_abspath,
+                          svn_node_kind_t expected_kind,
+                          apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
-  svn_node_kind_t kind_expected, kind_on_disk;
+  svn_wc_context_t *wc_ctx = merge_b->ctx->wc_ctx;
+  svn_node_kind_t wc_kind;
+  svn_boolean_t check_root;
+
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
+  *obstruction_state = svn_wc_notify_state_inapplicable;
 
-  SVN_ERR_ASSERT_NO_RETURN(svn_dirent_is_absolute(local_abspath));
+  if (exists)
+    *exists = FALSE;
+  if (versioned)
+    *versioned = FALSE;
+  if (added)
+    *added = FALSE;
+  if (deleted)
+    *deleted = FALSE;
 
   /* In a dry run, make as if nodes "deleted" by the dry run appear so. */
   if (merge_b->dry_run && dry_run_deleted_p(merge_b, local_abspath))
     {
-      *obstr_state = svn_wc_notify_state_inapplicable;
+      *obstruction_state = svn_wc_notify_state_inapplicable;
+      
       return SVN_NO_ERROR;
     }
 
-  SVN_ERR(svn_wc_read_kind(&kind_expected, merge_b->ctx->wc_ctx,
-                           local_abspath, FALSE, pool));
-
-  /* Report absent nodes as 'missing'. First of all, they count as 'hidden',
-   * and since we pass show_hidden == FALSE above, they will show up as
-   * 'none' here. */
-  if (kind_expected == svn_node_none)
-    {
-      svn_boolean_t is_absent;
-      err = svn_wc__node_is_status_absent(&is_absent, merge_b->ctx->wc_ctx,
-                                          local_abspath, pool);
-      if (err && err->apr_err != SVN_ERR_WC_PATH_NOT_FOUND)
-        return svn_error_return(err);
-      else if (!err && is_absent)
-        {
-          *obstr_state = svn_wc_notify_state_missing;
-          return SVN_NO_ERROR;
-        }
-
-      svn_error_clear(err);
-    }
-
-  SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, pool));
+  if (kind == NULL)
+    kind = &wc_kind;
 
-  /* If a node is deleted, the node might be gone in the working copy (and
-   * it probably is gone after we switch to single-db
-   *
-   * But to compare with disk state, we want to consider deleted nodes as
-   * svn_node_none instead of their original kind. */
+  check_root = ! strcmp(local_abspath, merge_b->target_abspath);
 
-  if (kind_expected == svn_node_file
-      || kind_expected == svn_node_dir)
+  SVN_ERR(svn_wc__check_for_obstructions(obstruction_state,
+                                         exists,
+                                         versioned,
+                                         added,
+                                         deleted,
+                                         kind,
+                                         wc_ctx, local_abspath,
+                                         check_root,
+                                         scratch_pool));
+
+  if (*obstruction_state == svn_wc_notify_state_inapplicable
+      && expected_kind != svn_node_unknown
+      && *kind != expected_kind)
     {
-      svn_boolean_t is_deleted;
-
-      SVN_ERR(svn_wc__node_is_status_deleted(&is_deleted,
-                                             merge_b->ctx->wc_ctx,
-                                             local_abspath,
-                                             pool));
-      if (is_deleted)
-        kind_expected = svn_node_none;
+      *obstruction_state = svn_wc_notify_state_obstructed;
     }
 
-  if (kind_expected == kind_on_disk)
-    *obstr_state = svn_wc_notify_state_inapplicable;
-  else if (kind_on_disk == svn_node_none)
-    *obstr_state = svn_wc_notify_state_missing;
-  else
-    *obstr_state = svn_wc_notify_state_obstructed;
-
   return SVN_NO_ERROR;
 }
 
@@ -1086,9 +1079,11 @@ merge_props_changed(const char *local_di
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  local_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      NULL,
+                                      merge_b, local_abspath, svn_node_unknown,
+                                      scratch_pool));
+
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -1356,9 +1351,10 @@ merge_file_changed(const char *local_dir
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  mine_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      NULL,
+                                      merge_b, mine_abspath, svn_node_unknown,
+                                      scratch_pool));
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (content_state)
@@ -1583,32 +1579,6 @@ merge_file_added(const char *local_dir_a
   if (tree_conflicted)
     *tree_conflicted = FALSE;
 
-  /* Easy out: not the same working copy.  (So, a disjoint working copy or
-     an external.) */
-  {
-    const char *mine_wcroot_abspath;
-
-    /* ### White-box optimization:
-
-       The code knows that MINE_ABSPATH is not a directory (it's an added
-       file), and we know that internally libsvn_wc queries are faster for
-       directories (this is an implementation detail).  Therefore, query for
-       the wcroot of the containing directory of MINE_ABSPATH.
-       
-       (We rely on the implementation detail only for performance, not for
-       correctness; under any implementation it would be valid to query for
-       the parent's wcroot.)
-     */
-    SVN_ERR(svn_wc_get_wc_root(&mine_wcroot_abspath, merge_b->ctx->wc_ctx,
-                               svn_dirent_dirname(mine_abspath, scratch_pool),
-                               scratch_pool, scratch_pool));
-    if (strcmp(mine_wcroot_abspath, merge_b->target_wcroot_abspath))
-      {
-        *content_state = svn_wc_notify_state_obstructed;
-        return SVN_NO_ERROR;
-      }
-  }
-
   /* Apply the prop changes to a new hash table. */
   file_props = apr_hash_copy(subpool, original_props);
   for (i = 0; i < prop_changes->nelts; ++i)
@@ -1665,9 +1635,11 @@ merge_file_added(const char *local_dir_a
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  mine_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      &kind,
+                                      merge_b, mine_abspath, svn_node_unknown,
+                                      scratch_pool));
+
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (content_state)
@@ -1960,9 +1932,11 @@ merge_file_deleted(const char *local_dir
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  mine_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      NULL,
+                                      merge_b, mine_abspath, svn_node_unknown,
+                                      scratch_pool));
+
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -2151,9 +2125,10 @@ merge_dir_added(const char *local_dir_ab
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  local_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      NULL,
+                                      merge_b, local_abspath, svn_node_unknown,
+                                      scratch_pool));
 
     /* In this case of adding a directory, we have an exception to the usual
      * "skip if it's inconsistent" rule. If the directory exists on disk
@@ -2347,9 +2322,11 @@ merge_dir_deleted(const char *local_dir_
   {
     svn_wc_notify_state_t obstr_state;
 
-    SVN_ERR(obstructed_or_missing(&obstr_state,
-                                  local_abspath, local_dir_abspath,
-                                  merge_b, subpool));
+    SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                      NULL,
+                                      merge_b, local_abspath, svn_node_unknown,
+                                      scratch_pool));
+
     if (obstr_state != svn_wc_notify_state_inapplicable)
       {
         if (state)
@@ -2445,14 +2422,13 @@ merge_dir_opened(const char *local_dir_a
                  svn_boolean_t *tree_conflicted,
                  svn_boolean_t *skip,
                  svn_boolean_t *skip_children,
-                 const char *path,
+                 const char *local_abspath,
                  svn_revnum_t rev,
                  void *baton,
                  apr_pool_t *scratch_pool)
 {
   merge_cmd_baton_t *merge_b = baton;
   apr_pool_t *subpool = svn_pool_create(merge_b->pool);
-  const char *local_abspath;
   svn_depth_t parent_depth;
   svn_node_kind_t kind;
   svn_node_kind_t kind_on_disk;
@@ -2460,6 +2436,8 @@ merge_dir_opened(const char *local_dir_a
   svn_boolean_t is_deleted;
   svn_error_t *err;
 
+  SVN_ERR_ASSERT(svn_dirent_is_absolute(local_abspath));
+
   if (tree_conflicted)
     *tree_conflicted = FALSE;
   if (skip_children)
@@ -2481,9 +2459,11 @@ merge_dir_opened(const char *local_dir_a
     }
 
   /* Check for an obstructed or missing node on disk. */
-  SVN_ERR(obstructed_or_missing(&obstr_state,
-                                path, local_dir_abspath,
-                                merge_b, subpool));
+  SVN_ERR(perform_obstruction_check(&obstr_state, NULL, NULL, NULL, NULL,
+                                    NULL,
+                                    merge_b, local_abspath, svn_node_unknown,
+                                    scratch_pool));
+
   if (obstr_state != svn_wc_notify_state_inapplicable)
     {
       if (skip_children)
@@ -2492,18 +2472,6 @@ merge_dir_opened(const char *local_dir_a
       return SVN_NO_ERROR;
     }
 
-  err = svn_dirent_get_absolute(&local_abspath, path, subpool);
-  if (err)
-    {
-      if (err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
-        svn_error_clear(err);
-      else
-        {
-          svn_pool_destroy(subpool);
-          return svn_error_return(err);
-        }
-    }
-
   SVN_ERR(svn_wc_read_kind(&kind, merge_b->ctx->wc_ctx,
                            local_abspath, TRUE, subpool));
   SVN_ERR(svn_io_check_path(local_abspath, &kind_on_disk, subpool));

Modified: subversion/trunk/subversion/libsvn_wc/node.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_wc/node.c?rev=1096759&r1=1096758&r2=1096759&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_wc/node.c (original)
+++ subversion/trunk/subversion/libsvn_wc/node.c Tue Apr 26 14:21:24 2011
@@ -1675,3 +1675,154 @@ svn_wc__rename_wc(svn_wc_context_t *wc_c
 
   return SVN_NO_ERROR;
 }
+
+svn_error_t *
+svn_wc__check_for_obstructions(svn_wc_notify_state_t *obstruction_state,
+                               svn_boolean_t *exists,
+                               svn_boolean_t *versioned,
+                               svn_boolean_t *added,
+                               svn_boolean_t *deleted,
+                               svn_node_kind_t *kind,
+                               svn_wc_context_t *wc_ctx,
+                               const char *local_abspath,
+                               svn_boolean_t no_wcroot_check,
+                               apr_pool_t *scratch_pool)
+{
+  svn_wc__db_status_t status;
+  svn_wc__db_kind_t db_kind;
+  svn_node_kind_t disk_kind;
+  svn_error_t *err;
+
+  *obstruction_state = svn_wc_notify_state_inapplicable;
+  if (exists)
+    *exists = FALSE;
+  if (versioned)
+    *versioned = FALSE;
+  if (added)
+    *versioned = FALSE;
+  if (deleted)
+    *versioned = FALSE;
+  if (kind)
+    *kind = svn_node_none;
+
+  SVN_ERR(svn_io_check_path(local_abspath, &disk_kind, scratch_pool));
+
+  err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                             NULL, NULL, NULL, NULL,
+                             wc_ctx->db, local_abspath,
+                             scratch_pool, scratch_pool);
+
+  if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+    {
+      svn_error_clear(err);
+
+      if (disk_kind != svn_node_none)
+        {
+          /* Nothing in the DB, but something on disk */
+          *obstruction_state = svn_wc_notify_state_obstructed;
+          return SVN_NO_ERROR;
+        }
+
+      err = svn_wc__db_read_info(&status, &db_kind, NULL, NULL, NULL, NULL, 
NULL,
+                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                 NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+                                 NULL, NULL, NULL, NULL, NULL, NULL,
+                                 wc_ctx->db, svn_dirent_dirname(local_abspath,
+                                                                scratch_pool),
+                                 scratch_pool, scratch_pool);
+
+      if (err && err->apr_err == SVN_ERR_WC_PATH_NOT_FOUND)
+        {
+          svn_error_clear(err);
+          /* No versioned parent; we can't add a node here */
+          *obstruction_state = svn_wc_notify_state_obstructed;
+          return SVN_NO_ERROR;
+        }
+      else
+        SVN_ERR(err);
+
+      if (db_kind != svn_wc__db_kind_dir
+          || (status != svn_wc__db_status_normal
+              && status != svn_wc__db_status_added))
+        {
+          /* The parent doesn't allow nodes to be added below it */
+          *obstruction_state = svn_wc_notify_state_obstructed;
+        }
+
+      return SVN_NO_ERROR;
+    }
+  else
+    SVN_ERR(err);
+
+  /* Check for obstructing working copies */
+  if (!no_wcroot_check
+      && db_kind == svn_wc__db_kind_dir
+      && status == svn_wc__db_status_normal)
+    {
+      svn_boolean_t is_root;
+      SVN_ERR(svn_wc__db_is_wcroot(&is_root, wc_ctx->db, local_abspath,
+                                   scratch_pool));
+
+      if (is_root)
+        {
+          /* Callers should handle this as unversioned */
+          *obstruction_state = svn_wc_notify_state_obstructed;
+          return SVN_NO_ERROR;
+        }
+    }
+
+  if (kind)
+    SVN_ERR(convert_db_kind_to_node_kind(kind, db_kind, status, FALSE));
+
+  switch (status)
+    {
+      case svn_wc__db_status_deleted:
+        if (versioned)
+          *versioned = TRUE;
+        if (deleted)
+          *deleted = TRUE;
+        /* Fall through to svn_wc__db_status_not_present */
+      case svn_wc__db_status_not_present:
+        if (disk_kind != svn_node_none)
+          *obstruction_state = svn_wc_notify_state_obstructed;
+        break;
+
+      case svn_wc__db_status_excluded:
+      case svn_wc__db_status_absent:
+      case svn_wc__db_status_incomplete:
+        if (versioned)
+          *versioned = TRUE;
+        *obstruction_state = svn_wc_notify_state_missing;
+        break;
+
+      case svn_wc__db_status_added:
+        if (added)
+          *added = TRUE;
+        /* Fall through to svn_wc__db_status_normal */
+      case svn_wc__db_status_normal:
+        if (versioned)
+          *versioned = TRUE;
+        if (exists)
+          *exists = TRUE;
+        if (disk_kind == svn_node_none)
+          *obstruction_state = svn_wc_notify_state_missing;
+        else
+          {
+            svn_node_kind_t expected_kind;
+
+            SVN_ERR(convert_db_kind_to_node_kind(&expected_kind, db_kind,
+                                                 status, FALSE));
+                                         
+            if (disk_kind != expected_kind)
+              *obstruction_state = svn_wc_notify_state_obstructed;
+          }
+        break;
+      default:
+        SVN_ERR_MALFUNCTION();
+    }
+
+  return SVN_NO_ERROR;
+}
+


Reply via email to