You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by gb...@apache.org on 2013/11/17 11:02:41 UTC

svn commit: r1542685 [3/5] - in /subversion/branches/invoke-diff-cmd-feature: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/server-side/svncutter/ notes/ subversion/bindings/javahl/native/ subversion/bindin...

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/config_pool.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/config_pool.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/config_pool.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/config_pool.c Sun Nov 17 10:02:39 2013
@@ -24,8 +24,6 @@
 
 
 
-#include <assert.h>
-
 #include "svn_checksum.h"
 #include "svn_config.h"
 #include "svn_error.h"
@@ -34,22 +32,21 @@
 #include "svn_pools.h"
 #include "svn_repos.h"
 
-#include "private/svn_atomic.h"
+#include "private/svn_dep_compat.h"
 #include "private/svn_mutex.h"
 #include "private/svn_subr_private.h"
 #include "private/svn_repos_private.h"
+#include "private/svn_object_pool.h"
 
 #include "svn_private_config.h"
 
 
-/* A reference counting wrapper around a parsed svn_config_t* instance.  All
- * data in CFG is expanded (to make it thread-safe) and considered read-only.
+/* Our wrapper structure for parsed svn_config_t* instances.  All data in
+ * CS_CFG and CI_CFG is expanded (to make it thread-safe) and considered
+ * read-only.
  */
-typedef struct config_ref_t
+typedef struct config_object_t
 {
-  /* reference to the parent container */
-  svn_repos__config_pool_t *config_pool;
-
   /* UUID of the configuration contents.
    * This is a SHA1 checksum of the parsed textual representation of CFG. */
   svn_checksum_t *key;
@@ -62,14 +59,7 @@ typedef struct config_ref_t
 
   /* Case-insensitive config. May be NULL */
   svn_config_t *ci_cfg;
-
-  /* private pool. This instance and its other members got allocated in it.
-   * Will be destroyed when this instance is cleaned up. */
-  apr_pool_t *pool;
-
-  /* Number of references to this data struct */
-  volatile svn_atomic_t ref_count;
-} config_ref_t;
+} config_object_t;
 
 
 /* Data structure used to short-circuit the repository access for configs
@@ -78,8 +68,8 @@ typedef struct config_ref_t
  * the repository.
  *
  * As this is only an optimization and may create many entries in
- * svn_config_pool__t's IN_REPO_HASH_POOL index, we clean them up once in
- * a while.
+ * svn_repos__config_pool_t's IN_REPO_HASH_POOL index, we clean them up
+ * once in a while.
  */
 typedef struct in_repo_config_t
 {
@@ -97,10 +87,8 @@ typedef struct in_repo_config_t
 } in_repo_config_t;
 
 
-/* Core data structure.  All access to it must be serialized using MUTEX.
- *
- * CONFIGS maps a SHA1 checksum of the config text to the config_ref_t with
- * the parsed configuration in it.
+/* Core data structure extending the encapsulated OBJECT_POOL.  All access
+ * to it must be serialized using the OBJECT_POOL->MUTEX.
  *
  * To speed up URL@HEAD lookups, we maintain IN_REPO_CONFIGS as a secondary
  * hash index.  It maps URLs as provided by the caller onto in_repo_config_t
@@ -109,263 +97,97 @@ typedef struct in_repo_config_t
  * the respective repository.
  *
  * Unused configurations that are kept in the IN_REPO_CONFIGS hash and may
- * be cleaned up when the hash is about to grow.  We use various pools to
- * ensure that we can release unused memory for each data structure:
- *
- * - every config_ref_t uses its own pool
- *   (gets destroyed when config is removed from cache)
- * - CONFIGS_HASH_POOL is used for configs only
- * - IN_REPO_HASH_POOL is used for IN_REPO_CONFIGS and the in_repo_config_t
- *   structure in it
- *
- * References handed out to callers must remain valid until released.  In
- * that case, cleaning up the config pool will only set READY_FOR_CLEANUP
- * and the last reference being returned will actually trigger the
- * destruction.
+ * be cleaned up when the hash is about to grow.
  */
 struct svn_repos__config_pool_t
 {
-  /* serialization object for all non-atomic data in this struct */
-  svn_mutex__t *mutex;
-
-  /* set to TRUE when pool passed to svn_config_pool__create() gets cleaned
-   * up.  When set, the last config reference released must also destroy
-   * this config pool object. */
-  volatile svn_atomic_t ready_for_cleanup;
-
-  /* SHA1 -> config_ref_t* mapping */
-  apr_hash_t *configs;
-
-  /* number of entries in CONFIGS with a reference count > 0 */
-  volatile svn_atomic_t used_config_count;
+  svn_object_pool__t *object_pool;
 
   /* URL -> in_repo_config_t* mapping.
    * This is only a partial index and will get cleared regularly. */
   apr_hash_t *in_repo_configs;
 
-  /* the root pool owning this structure */
-  apr_pool_t *root_pool;
-
-  /* allocate the CONFIGS index here */
-  apr_pool_t *configs_hash_pool;
-
   /* allocate the IN_REPO_CONFIGS index and in_repo_config_t here */
   apr_pool_t *in_repo_hash_pool;
 };
 
 
-/* Destructor function for the whole config pool.
- */
-static apr_status_t
-destroy_config_pool(svn_repos__config_pool_t *config_pool)
-{
-  svn_mutex__lock(config_pool->mutex);
-
-  /* there should be no outstanding references to any config in this pool */
-  assert(svn_atomic_read(&config_pool->used_config_count) == 0);
-
-  /* make future attempts to access this pool cause definitive segfaults */
-  config_pool->configs = NULL;
-  config_pool->in_repo_configs = NULL;
-
-  /* This is the actual point of destruction. */
-  /* Destroying the pool will also release the lock. */
-  svn_pool_destroy(config_pool->root_pool);
-
-  return APR_SUCCESS;
-}
-
-/* Pool cleanup function for the whole config pool.  Actual destruction will
- * be deferred until no configurations are left in use.
- */
-static apr_status_t
-config_pool_cleanup(void *baton)
-{
-  svn_repos__config_pool_t *config_pool = baton;
-
-  /* from now on, anyone is allowed to destroy the config_pool */
-  svn_atomic_set(&config_pool->ready_for_cleanup, TRUE);
-
-  /* are there no more external references and can we grab the cleanup flag? */
-  if (   svn_atomic_read(&config_pool->used_config_count) == 0
-      && svn_atomic_cas(&config_pool->ready_for_cleanup, FALSE, TRUE) == TRUE)
-    {
-      /* Attempts to get a configuration from a pool whose cleanup has
-       * already started is illegal.
-       * So, used_config_count must not increase again.
-       */
-      destroy_config_pool(config_pool);
-    }
-
-  return APR_SUCCESS;
-}
-
-/* Cleanup function called when a config_ref_t gets released.
- */
-static apr_status_t
-config_ref_cleanup(void *baton)
-{
-  config_ref_t *config = baton;
-  svn_repos__config_pool_t *config_pool = config->config_pool;
-
-  /* Maintain reference counters and handle object cleanup */
-  if (   svn_atomic_dec(&config->ref_count) == 0
-      && svn_atomic_dec(&config_pool->used_config_count) == 0
-      && svn_atomic_cas(&config_pool->ready_for_cleanup, FALSE, TRUE) == TRUE)
-    {
-      /* There cannot be any future references to a config in this pool.
-       * So, we are the last one and need to finally clean it up.
-       */
-      destroy_config_pool(config_pool);
-    }
-
-  return APR_SUCCESS;
-}
-
 /* Return an automatic reference to the CFG member in CONFIG that will be
- * released when POOL gets cleaned up.  CASE_SENSITIVE controls option and
- * section name matching.
+ * released when POOL gets cleaned up.  The case sensitivity flag in *BATON
+ * selects the desired option and section name matching mode.
  */
-static svn_config_t *
-return_config_ref(config_ref_t *config,
-                  svn_boolean_t case_sensitive,
-                  apr_pool_t *pool)
+static void *
+getter(void *object,
+       void *baton,
+       apr_pool_t *pool)
 {
-  if (svn_atomic_inc(&config->ref_count) == 0)
-    svn_atomic_inc(&config->config_pool->used_config_count);
-
-  apr_pool_cleanup_register(pool, config, config_ref_cleanup,
-                            apr_pool_cleanup_null);
-  return svn_config__shallow_copy(case_sensitive ? config->cs_cfg
-                                                 : config->ci_cfg,
-                                  pool);
-}
-
-/* Set *CFG to the configuration with a parsed textual matching CHECKSUM.
- * Set *CFG to NULL if no such config can be found in CONFIG_POOL.
- * CASE_SENSITIVE controls option and section name matching.
- * 
- * RESULT_POOL determines the lifetime of the returned reference.
- *
- * Requires external serialization on CONFIG_POOL.
- */
-static svn_error_t *
-config_by_checksum(svn_config_t **cfg,
-                   svn_repos__config_pool_t *config_pool,
-                   svn_checksum_t *checksum,
-                   svn_boolean_t case_sensitive,
-                   apr_pool_t *result_pool)
-{
-  config_ref_t *config_ref = apr_hash_get(config_pool->configs,
-                                          checksum->digest,
-                                          svn_checksum_size(checksum));
-  *cfg = config_ref
-       ? return_config_ref(config_ref, case_sensitive, result_pool)
-       : NULL;
+  config_object_t *wrapper = object;
+  svn_boolean_t *case_sensitive = baton;
+  svn_config_t *config = *case_sensitive ? wrapper->cs_cfg : wrapper->ci_cfg;
 
-  return SVN_NO_ERROR;
+  /* we need to duplicate the root structure as it contains temp. buffers */
+  return config ? svn_config__shallow_copy(config, pool) : NULL;
 }
 
-/* Re-allocate CONFIGS in CONFIG_POOL and remove all unused configurations
- * to minimize memory consumption.
- *
- * Requires external serialization on CONFIG_POOL.
+/* Return a memory buffer structure allocated in POOL and containing the
+ * data from CHECKSUM.
  */
-static void
-remove_unused_configs(svn_repos__config_pool_t *config_pool)
+static svn_membuf_t *
+checksum_as_key(svn_checksum_t *checksum,
+                apr_pool_t *pool)
 {
-  apr_pool_t *new_pool = svn_pool_create(config_pool->root_pool);
-  apr_hash_t *new_hash = svn_hash__make(new_pool);
+  svn_membuf_t *result = apr_pcalloc(pool, sizeof(*result));
+  apr_size_t size = svn_checksum_size(checksum);
 
-  apr_hash_index_t *hi;
-  for (hi = apr_hash_first(config_pool->configs_hash_pool,
-                           config_pool->configs);
-       hi != NULL;
-       hi = apr_hash_next(hi))
-    {
-      config_ref_t *config_ref = svn__apr_hash_index_val(hi);
-      if (config_ref->ref_count == 0)
-        svn_pool_destroy(config_ref->pool);
-      else
-        apr_hash_set(new_hash, config_ref->key->digest,
-                     svn_checksum_size(config_ref->key), config_ref);
-    }
+  svn_membuf__create(result, size, pool);
+  result->size = size; /* exact length is required! */
+  memcpy(result->data, checksum->digest, size);
 
-  svn_pool_destroy(config_pool->configs_hash_pool);
-  config_pool->configs = new_hash;
-  config_pool->configs_hash_pool = new_pool;
+  return result;
 }
 
-/* Cache config_ref* in CONFIG_POOL and return a reference to it in *CFG.
- * RESULT_POOL determines the lifetime of that reference.
- * CASE_SENSITIVE controls option and section name matching.
- *
- * Requires external serialization on CONFIG_POOL.
+/* Copy the configuration from the wrapper in SOURCE to the wrapper in
+ * *TARGET with the case sensitivity flag in *BATON selecting the config
+ * to copy.  This is usually done to add the missing case-(in)-sensitive
+ * variant.  Since we must hold all data in *TARGET from the same POOL,
+ * a deep copy is required.
  */
 static svn_error_t *
-config_add(svn_config_t **cfg,
-           svn_repos__config_pool_t *config_pool,
-           config_ref_t *config_ref,
-           svn_boolean_t case_sensitive,
-           apr_pool_t *result_pool)
+setter(void **target,
+       void *source,
+       void *baton,
+       apr_pool_t *pool)
 {
-  config_ref_t *config = apr_hash_get(config_ref->config_pool->configs,
-                                      config_ref->key->digest,
-                                      svn_checksum_size(config_ref->key));
-  if (config)
-    {
-      /* entry already exists (e.g. race condition) */
-
-      /* Maybe, we created a variant with different case sensitivity? */
-      if (case_sensitive && config->cs_cfg == NULL)
-        {
-          SVN_ERR(svn_config_dup(&config->cs_cfg, config_ref->cs_cfg,
-                                 config->pool));
-          svn_config__set_read_only(config->cs_cfg, config_ref->pool);
-        }
-      else if (!case_sensitive && config->ci_cfg == NULL)
-        {
-          SVN_ERR(svn_config_dup(&config->ci_cfg, config_ref->ci_cfg,
-                                 config->pool));
-          svn_config__set_read_only(config->ci_cfg, config_ref->pool);
-        }
+  svn_boolean_t *case_sensitive = baton;
+  config_object_t *target_cfg = *(config_object_t **)target;
+  config_object_t *source_cfg = source;
 
-      /* Destroy the new one and return a reference to the existing one
-       * because the existing one may already have references on it.
-       */
-      svn_pool_destroy(config_ref->pool);
-      config_ref = config;
+  /* Maybe, we created a variant with different case sensitivity? */
+  if (*case_sensitive && target_cfg->cs_cfg == NULL)
+    {
+      SVN_ERR(svn_config_dup(&target_cfg->cs_cfg, source_cfg->cs_cfg, pool));
+      svn_config__set_read_only(target_cfg->cs_cfg, pool);
     }
-  else
+  else if (!*case_sensitive && target_cfg->ci_cfg == NULL)
     {
-      /* Release unused configurations if there are relatively frequent. */
-      if (  config_pool->used_config_count * 2 + 4
-          < apr_hash_count(config_pool->configs))
-        {
-          remove_unused_configs(config_pool);
-        }
-
-      /* add new index entry */
-      apr_hash_set(config_ref->config_pool->configs,
-                   config_ref->key->digest,
-                   svn_checksum_size(config_ref->key),
-                   config_ref);
+      SVN_ERR(svn_config_dup(&target_cfg->ci_cfg, source_cfg->ci_cfg, pool));
+      svn_config__set_read_only(target_cfg->ci_cfg, pool);
     }
 
-  *cfg = return_config_ref(config_ref, case_sensitive, result_pool);
-
   return SVN_NO_ERROR;
 }
 
-/* Set *CFG to the configuration passed in as text in CONTENTS.  If no such
- * configuration exists in CONFIG_POOL, yet, parse CONTENTS and cache the
- * result.  CASE_SENSITIVE controls option and section name matching.
- * 
+/* Set *CFG to the configuration passed in as text in CONTENTS and *KEY to
+ * the corresponding object pool key.  If no such configuration exists in
+ * CONFIG_POOL, yet, parse CONTENTS and cache the result.  CASE_SENSITIVE
+ * controls option and section name matching.
+ *
  * RESULT_POOL determines the lifetime of the returned reference and 
  * SCRATCH_POOL is being used for temporary allocations.
  */
 static svn_error_t *
 auto_parse(svn_config_t **cfg,
+           svn_membuf_t **key,
            svn_repos__config_pool_t *config_pool,
            svn_stringbuf_t *contents,
            svn_boolean_t case_sensitive,
@@ -373,7 +195,7 @@ auto_parse(svn_config_t **cfg,
            apr_pool_t *scratch_pool)
 {
   svn_checksum_t *checksum;
-  config_ref_t *config_ref;
+  config_object_t *config_object;
   apr_pool_t *cfg_pool;
 
   /* calculate SHA1 over the whole file contents */
@@ -383,50 +205,36 @@ auto_parse(svn_config_t **cfg,
                    &checksum, NULL, svn_checksum_sha1, TRUE, scratch_pool)));
 
   /* return reference to suitable config object if that already exists */
-  *cfg = NULL;
-  SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                       config_by_checksum(cfg, config_pool, checksum,
-                                          case_sensitive, result_pool));
-
+  *key = checksum_as_key(checksum, scratch_pool);
+  SVN_ERR(svn_object_pool__lookup((void **)cfg, config_pool->object_pool,
+                                  *key, &case_sensitive, result_pool));
   if (*cfg)
     return SVN_NO_ERROR;
 
   /* create a pool for the new config object and parse the data into it  */
+  cfg_pool = svn_pool_create(svn_object_pool__pool(config_pool->object_pool));
 
-  /* the following is thread-safe because the allocator is thread-safe */
-  cfg_pool = svn_pool_create(config_pool->root_pool);
+  config_object = apr_pcalloc(cfg_pool, sizeof(*config_object));
 
-  config_ref = apr_pcalloc(cfg_pool, sizeof(*config_ref));
-  config_ref->config_pool = config_pool;
-  config_ref->key = svn_checksum_dup(checksum, cfg_pool);
-  config_ref->pool = cfg_pool;
-  config_ref->ref_count = 0;
-
-  SVN_ERR(svn_config_parse(case_sensitive ? &config_ref->cs_cfg
-                                          : &config_ref->ci_cfg,
+  SVN_ERR(svn_config_parse(case_sensitive ? &config_object->cs_cfg
+                                          : &config_object->ci_cfg,
                            svn_stream_from_stringbuf(contents, scratch_pool),
                            case_sensitive, case_sensitive, cfg_pool));
 
   /* switch config data to r/o mode to guarantee thread-safe access */
-  svn_config__set_read_only(case_sensitive ? config_ref->cs_cfg
-                                           : config_ref->ci_cfg,
+  svn_config__set_read_only(case_sensitive ? config_object->cs_cfg
+                                           : config_object->ci_cfg,
                             cfg_pool);
 
   /* add config in pool, handle loads races and return the right config */
-  SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                       config_add(cfg, config_pool, config_ref,
-                                  case_sensitive, result_pool));
+  SVN_ERR(svn_object_pool__insert((void **)cfg, config_pool->object_pool,
+                                  *key, config_object, &case_sensitive,
+                                  cfg_pool, result_pool));
 
   return SVN_NO_ERROR;
 }
 
-/* Set *CFG to the configuration stored in URL@HEAD and cache it in 
- * CONFIG_POOL.
- * 
- * RESULT_POOL determines the lifetime of the returned reference and 
- * SCRATCH_POOL is being used for temporary allocations.
- *
- * Requires external serialization on CONFIG_POOL.
+/* Store a URL@REVISION to CHECKSUM, REPOS_ROOT in CONFIG_POOL.
  */
 static svn_error_t *
 add_checksum(svn_repos__config_pool_t *config_pool,
@@ -454,7 +262,7 @@ add_checksum(svn_repos__config_pool_t *c
     {
       /* insert a new entry.
        * Limit memory consumption by cyclically clearing pool and hash. */
-      if (2 * apr_hash_count(config_pool->configs)
+      if (2 * svn_object_pool__count(config_pool->object_pool)
           < apr_hash_count(config_pool->in_repo_configs))
         {
           svn_pool_clear(pool);
@@ -476,7 +284,7 @@ add_checksum(svn_repos__config_pool_t *c
 }
 
 /* Set *CFG to the configuration stored in URL@HEAD and cache it in 
- * CONFIG_POOL. ### Always returns a NULL CFG.  CASE_SENSITIVE controls
+ * CONFIG_POOL.  CASE_SENSITIVE controls
  * option and section name matching.  If PREFERRED_REPOS is given,
  * use that if it also matches URL.
  * 
@@ -485,6 +293,7 @@ add_checksum(svn_repos__config_pool_t *c
  */
 static svn_error_t *
 find_repos_config(svn_config_t **cfg,
+                  svn_membuf_t **key,
                   svn_repos__config_pool_t *config_pool,
                   const char *url,
                   svn_boolean_t case_sensitive,
@@ -544,9 +353,11 @@ find_repos_config(svn_config_t **cfg,
   SVN_ERR(svn_fs_file_checksum(&checksum, svn_checksum_sha1, root, fs_path,
                                FALSE, scratch_pool));
   if (checksum)
-    SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                         config_by_checksum(cfg, config_pool, checksum,
-                                            case_sensitive, result_pool));
+    {
+      *key = checksum_as_key(checksum, scratch_pool);
+      SVN_ERR(svn_object_pool__lookup((void **)cfg, config_pool->object_pool,
+                                      *key, &case_sensitive, result_pool));
+    }
 
   /* not parsed, yet? */
   if (!*cfg)
@@ -564,70 +375,57 @@ find_repos_config(svn_config_t **cfg,
                                         (apr_size_t)length, scratch_pool));
 
       /* handle it like ordinary file contents and cache it */
-      SVN_ERR(auto_parse(cfg, config_pool, contents, case_sensitive,
+      SVN_ERR(auto_parse(cfg, key, config_pool, contents, case_sensitive,
                          result_pool, scratch_pool));
     }
 
   /* store the (path,rev) -> checksum mapping as well */
   if (*cfg)
-    SVN_MUTEX__WITH_LOCK(config_pool->mutex,
+    SVN_MUTEX__WITH_LOCK(svn_object_pool__mutex(config_pool->object_pool),
                          add_checksum(config_pool, url, repos_root_dirent,
                                       youngest_rev, checksum));
 
   return SVN_NO_ERROR;
 }
 
-/* Set *CFG to the configuration cached in CONFIG_POOL for URL.  If no
- * suitable config has been cached or if it is potentially outdated, set
- * *CFG to NULL.  CASE_SENSITIVE controls option and section name matching.
- *
- * RESULT_POOL determines the lifetime of the returned reference and 
- * SCRATCH_POOL is being used for temporary allocations.
+/* Given the URL, search the CONFIG_POOL for an entry that maps it URL to
+ * a content checksum and is still up-to-date.  If this could be found,
+ * return the object's *KEY.  Use POOL for allocations.
  *
  * Requires external serialization on CONFIG_POOL.
+ *
+ * Note that this is only the URL(+rev) -> Checksum lookup and does not
+ * guarantee that there is actually a config object available for *KEY.
  */
 static svn_error_t *
-config_by_url(svn_config_t **cfg,
-              svn_repos__config_pool_t *config_pool,
-              const char *url,
-              svn_boolean_t case_sensitive,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
+key_by_url(svn_membuf_t **key,
+           svn_repos__config_pool_t *config_pool,
+           const char *url,
+           apr_pool_t *pool)
 {
   svn_error_t *err;
-  config_ref_t *config_ref = NULL;
   svn_stringbuf_t *contents;
   apr_int64_t current;
 
   /* hash lookup url -> sha1 -> config */
   in_repo_config_t *config = svn_hash_gets(config_pool->in_repo_configs, url);
-  *cfg = NULL;
-  if (config)
-    config_ref = apr_hash_get(config_pool->configs,
-                              config->key->digest,
-                              svn_checksum_size(config->key));
-  if (!config_ref)
-    return SVN_NO_ERROR;
-
-  /* available with the desired case sensitivity? */
-  if (case_sensitive && config_ref->cs_cfg == NULL)
-    return SVN_NO_ERROR;
-  if (!case_sensitive && config_ref->ci_cfg == NULL)
+  *key = NULL;
+  if (!config)
     return SVN_NO_ERROR;
 
-  /* found *some* configuration. 
+  /* found *some* reference to a configuration.
    * Verify that it is still current.  Will fail for BDB repos. */
   err = svn_stringbuf_from_file2(&contents, 
                                  svn_dirent_join(config->repo_root,
-                                                 "db/current", scratch_pool),
-                                 scratch_pool);
+                                                 "db/current", pool),
+                                 pool);
   if (!err)
     err = svn_cstring_atoi64(&current, contents->data);
 
   if (err)
     svn_error_clear(err);
   else if (current == config->revision)
-    *cfg = return_config_ref(config_ref, case_sensitive, result_pool);
+    *key = checksum_as_key(config->key, pool);
 
   return SVN_NO_ERROR;
 }
@@ -636,27 +434,25 @@ config_by_url(svn_config_t **cfg,
 
 svn_error_t *
 svn_repos__config_pool_create(svn_repos__config_pool_t **config_pool,
+                              svn_boolean_t thread_safe,
                               apr_pool_t *pool)
 {
-  /* our allocator must be thread-safe */
-  apr_pool_t *root_pool
-    = apr_allocator_owner_get(svn_pool_create_allocator(TRUE));
+  svn_repos__config_pool_t *result;
+  svn_object_pool__t *object_pool;
+  apr_pool_t *root_pool;
+
+  SVN_ERR(svn_object_pool__create(&object_pool, getter, setter,
+                                  4, APR_UINT32_MAX, TRUE, thread_safe,
+                                  pool));
+  root_pool = svn_object_pool__pool(object_pool);
 
   /* construct the config pool in our private ROOT_POOL to survive POOL
    * cleanup and to prevent threading issues with the allocator */
-  svn_repos__config_pool_t *result = apr_pcalloc(root_pool, sizeof(*result));
-  SVN_ERR(svn_mutex__init(&result->mutex, TRUE, root_pool));
+  result = apr_pcalloc(root_pool, sizeof(*result));
 
-  result->root_pool = root_pool;
-  result->configs_hash_pool = svn_pool_create(root_pool);
+  result->object_pool = object_pool;
   result->in_repo_hash_pool = svn_pool_create(root_pool);
-  result->configs = svn_hash__make(result->configs_hash_pool);
   result->in_repo_configs = svn_hash__make(result->in_repo_hash_pool);
-  result->ready_for_cleanup = FALSE;
-
-  /* make sure we clean up nicely */
-  apr_pool_cleanup_register(pool, result, config_pool_cleanup,
-                            apr_pool_cleanup_null);
 
   *config_pool = result;
   return SVN_NO_ERROR;
@@ -664,6 +460,7 @@ svn_repos__config_pool_create(svn_repos_
 
 svn_error_t *
 svn_repos__config_pool_get(svn_config_t **cfg,
+                           svn_membuf_t **key,
                            svn_repos__config_pool_t *config_pool,
                            const char *path,
                            svn_boolean_t must_exist,
@@ -674,22 +471,33 @@ svn_repos__config_pool_get(svn_config_t 
   svn_error_t *err = SVN_NO_ERROR;
   apr_pool_t *scratch_pool = svn_pool_create(pool);
 
+  /* make sure we always have a *KEY object */
+  svn_membuf_t *local_key = NULL;
+  if (key == NULL)
+    key = &local_key;
+  else
+    *key = NULL;
+
   if (svn_path_is_url(path))
     {
       /* Read config file from repository.
        * Attempt a quick lookup first. */
-      SVN_MUTEX__WITH_LOCK(config_pool->mutex,
-                           config_by_url(cfg, config_pool, path, 
-                                         case_sensitive, pool,
-                                         scratch_pool));
-      if (*cfg)
+      SVN_MUTEX__WITH_LOCK(svn_object_pool__mutex(config_pool->object_pool),
+                           key_by_url(key, config_pool, path, pool));
+      if (*key)
         {
-          svn_pool_destroy(scratch_pool);
-          return SVN_NO_ERROR;
+          SVN_ERR(svn_object_pool__lookup((void **)cfg,
+                                          config_pool->object_pool,
+                                          *key, &case_sensitive, pool));
+          if (*cfg)
+            {
+              svn_pool_destroy(scratch_pool);
+              return SVN_NO_ERROR;
+            }
         }
 
       /* Read and cache the configuration.  This may fail. */
-      err = find_repos_config(cfg, config_pool, path, case_sensitive,
+      err = find_repos_config(cfg, key, config_pool, path, case_sensitive,
                               preferred_repos, pool, scratch_pool);
       if (err || !*cfg)
         {
@@ -714,7 +522,7 @@ svn_repos__config_pool_get(svn_config_t 
       else
         {
           /* parsing and caching will always succeed */
-          err = auto_parse(cfg, config_pool, contents, case_sensitive,
+          err = auto_parse(cfg, key, config_pool, contents, case_sensitive,
                            pool, scratch_pool);
         }
     }

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/dump.c Sun Nov 17 10:02:39 2013
@@ -134,9 +134,9 @@ tracker_create(svn_revnum_t revision,
  * we encounter a new tree change.
  */
 static void
-tracker__trim(path_tracker_t *tracker,
-              const char *path,
-              svn_boolean_t allow_exact_match)
+tracker_trim(path_tracker_t *tracker,
+             const char *path,
+             svn_boolean_t allow_exact_match)
 {
   /* remove everything that is unrelated to PATH.
      Note that TRACKER->STACK is depth-ordered,
@@ -176,7 +176,7 @@ tracker_lookup(const char **orig_path,
                const char *path,
                apr_pool_t *pool)
 {
-  tracker__trim(tracker, path, TRUE);
+  tracker_trim(tracker, path, TRUE);
   if (tracker->depth == 0)
     {
       /* no tree changes -> paths are the same as in the previous rev. */
@@ -230,11 +230,11 @@ tracker_lookup(const char **orig_path,
    will have undefined values.
  */
 static path_tracker_entry_t *
-tracker__add_entry(path_tracker_t *tracker,
-                   const char *path)
+tracker_add_entry(path_tracker_t *tracker,
+                  const char *path)
 {
   path_tracker_entry_t *entry;
-  tracker__trim(tracker, path, FALSE);
+  tracker_trim(tracker, path, FALSE);
 
   if (tracker->depth == tracker->stack->nelts)
     {
@@ -263,7 +263,7 @@ tracker_path_copy(path_tracker_t *tracke
                   const char *copyfrom_path,
                   svn_revnum_t copyfrom_rev)
 {
-  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+  path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
 
   svn_stringbuf_set(entry->copyfrom_path, copyfrom_path);
   entry->copyfrom_rev = copyfrom_rev;
@@ -276,7 +276,7 @@ static void
 tracker_path_add(path_tracker_t *tracker,
                  const char *path)
 {
-  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+  path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
 
   svn_stringbuf_setempty(entry->copyfrom_path);
   entry->copyfrom_rev = SVN_INVALID_REVNUM;
@@ -301,7 +301,7 @@ static void
 tracker_path_delete(path_tracker_t *tracker,
                     const char *path)
 {
-  path_tracker_entry_t *entry = tracker__add_entry(tracker, path);
+  path_tracker_entry_t *entry = tracker_add_entry(tracker, path);
 
   svn_stringbuf_setempty(entry->copyfrom_path);
   entry->copyfrom_rev = SVN_INVALID_REVNUM;

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/repos.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/repos.h?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/repos.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_repos/repos.h Sun Nov 17 10:02:39 2013
@@ -382,6 +382,11 @@ svn_repos__authz_read(svn_authz_t **auth
                       svn_boolean_t accept_urls,
                       apr_pool_t *pool);
 
+/* Walk the configuration in AUTHZ looking for any errors. */
+svn_error_t *
+svn_repos__authz_validate(svn_authz_t *authz,
+                          apr_pool_t *pool);
+
 
 /*** Utility Functions ***/
 

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/config_file.c Sun Nov 17 10:02:39 2013
@@ -30,6 +30,7 @@
 #include "svn_types.h"
 #include "svn_dirent_uri.h"
 #include "svn_auth.h"
+#include "svn_hash.h"
 #include "svn_subst.h"
 #include "svn_utf.h"
 #include "svn_pools.h"
@@ -490,6 +491,18 @@ svn_config__shallow_copy(svn_config_t *s
   return cfg;
 }
 
+void
+svn_config__shallow_replace_section(svn_config_t *target,
+                                    svn_config_t *source,
+                                    const char *section)
+{
+  if (target->read_only)
+    target->sections = apr_hash_copy(target->pool, target->sections);
+
+  svn_hash_sets(target->sections, section,
+                svn_hash_gets(source->sections, section));
+}
+
 
 svn_error_t *
 svn_config__parse_file(svn_config_t *cfg, const char *file,

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/iter.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/iter.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/iter.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_subr/iter.c Sun Nov 17 10:02:39 2013
@@ -193,24 +193,36 @@ svn_iter__break(void)
 
 const void *svn__apr_hash_index_key(const apr_hash_index_t *hi)
 {
+#if APR_VERSION_AT_LEAST(1, 5, 0)
+  return apr_hash_this_key((apr_hash_index_t *)hi);
+#else
   const void *key;
 
   apr_hash_this((apr_hash_index_t *)hi, &key, NULL, NULL);
   return key;
+#endif
 }
 
 apr_ssize_t svn__apr_hash_index_klen(const apr_hash_index_t *hi)
 {
+#if APR_VERSION_AT_LEAST(1, 5, 0)
+  return apr_hash_this_key_len((apr_hash_index_t *)hi);
+#else
   apr_ssize_t klen;
 
   apr_hash_this((apr_hash_index_t *)hi, NULL, &klen, NULL);
   return klen;
+#endif
 }
 
 void *svn__apr_hash_index_val(const apr_hash_index_t *hi)
 {
+#if APR_VERSION_AT_LEAST(1, 5, 0)
+  return apr_hash_this_val((apr_hash_index_t *)hi);
+#else
   void *val;
 
   apr_hash_this((apr_hash_index_t *)hi, NULL, NULL, &val);
   return val;
+#endif
 }

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/diff_local.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/diff_local.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/diff_local.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/diff_local.c Sun Nov 17 10:02:39 2013
@@ -115,13 +115,20 @@ ensure_state(struct diff_baton *eb,
   apr_pool_t *ns_pool;
   if (!eb->cur)
     {
-      if (!svn_dirent_is_ancestor(eb->anchor_abspath, local_abspath))
+      const char *relpath;
+
+      relpath = svn_dirent_skip_ancestor(eb->anchor_abspath, local_abspath);
+      if (! relpath)
         return SVN_NO_ERROR;
 
-      SVN_ERR(ensure_state(eb,
-                           svn_dirent_dirname(local_abspath,scratch_pool),
-                           FALSE,
-                           scratch_pool));
+      /* Don't recurse on the anchor, as that might loop infinately because
+            svn_dirent_dirname("/",...)   -> "/"
+            svn_dirent_dirname("C:/",...) -> "C:/" (Windows) */
+      if (*relpath)
+        SVN_ERR(ensure_state(eb,
+                             svn_dirent_dirname(local_abspath,scratch_pool),
+                             FALSE,
+                             scratch_pool));
     }
   else if (svn_dirent_is_child(eb->cur->local_abspath, local_abspath, NULL))
     SVN_ERR(ensure_state(eb, svn_dirent_dirname(local_abspath,scratch_pool),

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/upgrade.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/upgrade.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/upgrade.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/upgrade.c Sun Nov 17 10:02:39 2013
@@ -755,13 +755,13 @@ migrate_single_tree_conflict_data(svn_sq
         {
           /* There is an existing ACTUAL row, so just update it. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_UPDATE_ACTUAL_CONFLICT_DATA));
+                                            STMT_UPDATE_ACTUAL_CONFLICT));
         }
       else
         {
           /* We need to insert an ACTUAL row with the tree conflict data. */
           SVN_ERR(svn_sqlite__get_statement(&stmt, sdb,
-                                            STMT_INSERT_ACTUAL_CONFLICT_DATA));
+                                            STMT_INSERT_ACTUAL_CONFLICT));
         }
 
       SVN_ERR(svn_sqlite__bindf(stmt, "iss", wc_id, conflict_relpath,

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc-queries.sql
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc-queries.sql?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc-queries.sql (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc-queries.sql Sun Nov 17 10:02:39 2013
@@ -325,7 +325,7 @@ WHERE wc_id = ?1 AND op_depth = ?3
 -- STMT_COMMIT_DESCENDANTS_TO_BASE
 UPDATE NODES SET op_depth = 0,
                  repos_id = ?4,
-                 repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1),
+                 repos_path = RELPATH_SKIP_JOIN(?2, ?5, local_relpath),
                  revision = ?6,
                  dav_cache = NULL,
                  moved_here = NULL,
@@ -425,24 +425,23 @@ WHERE work.wc_id = ?1 AND work.local_rel
 LIMIT 1
 
 -- STMT_SELECT_OP_DEPTH_MOVED_TO
-SELECT op_depth, moved_to, repos_path, revision
-FROM nodes
-WHERE wc_id = ?1 AND local_relpath = ?2
- AND op_depth <= (SELECT MIN(op_depth) FROM nodes
-                  WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth > ?3)
-ORDER BY op_depth DESC
+SELECT n.op_depth, n.moved_to, p.repos_path, p.revision
+FROM nodes p
+LEFT JOIN nodes n
+  ON p.wc_id=n.wc_id AND p.local_relpath = n.local_relpath
+ AND  n.op_depth = (SELECT MIN(d.op_depth)
+                    FROM nodes d
+                    WHERE d.wc_id = ?1
+                      AND d.local_relpath = n.local_relpath
+                      AND d.op_depth > ?3)
+WHERE p.wc_id = ?1 AND p.local_relpath = ?2 AND p.op_depth = ?3
+LIMIT 1
 
 -- STMT_SELECT_MOVED_TO
 SELECT moved_to
 FROM nodes
 WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth = ?3
 
--- STMT_SELECT_MOVED_HERE
-SELECT moved_here, presence, repos_path, revision
-FROM nodes
-WHERE wc_id = ?1 AND local_relpath = ?2 AND op_depth >= ?3
-ORDER BY op_depth
-
 -- STMT_SELECT_MOVED_BACK
 SELECT u.local_relpath,
        u.presence, u.repos_id, u.repos_path, u.revision,
@@ -468,13 +467,6 @@ WHERE u.wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(u.local_relpath, ?2)
   AND u.op_depth = ?4
 
--- STMT_DELETE_MOVED_BACK
-DELETE FROM nodes
-WHERE wc_id = ?1
-  AND (local_relpath = ?2
-       OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND op_depth = ?3
-
 -- STMT_DELETE_LOCK
 DELETE FROM lock
 WHERE repos_id = ?1 AND repos_relpath = ?2
@@ -925,7 +917,7 @@ VALUES (?1, ?2, 0,
             AND op_depth = 0))
 
 -- STMT_INSTALL_WORKING_NODE_FOR_DELETE
-INSERT OR REPLACE INTO nodes (
+INSERT INTO nodes (
     wc_id, local_relpath, op_depth,
     parent_relpath, presence, kind)
 VALUES(?1, ?2, ?3, ?4, MAP_BASE_DELETED, ?5)
@@ -1214,14 +1206,6 @@ VALUES (?1, ?2, ?3, ?4, ?5, ?6)
 
 /* these are used in upgrade.c  */
 
--- STMT_UPDATE_ACTUAL_CONFLICT_DATA
-UPDATE actual_node SET conflict_data = ?3
-WHERE wc_id = ?1 AND local_relpath = ?2
-
--- STMT_INSERT_ACTUAL_CONFLICT_DATA
-INSERT INTO actual_node (wc_id, local_relpath, conflict_data, parent_relpath)
-VALUES (?1, ?2, ?3, ?4)
-
 -- STMT_SELECT_ALL_FILES
 SELECT local_relpath FROM nodes_current
 WHERE wc_id = ?1 AND parent_relpath = ?2 AND kind = MAP_FILE
@@ -1574,21 +1558,6 @@ UPDATE nodes SET moved_to = NULL
  WHERE wc_id = ?1
    AND IS_STRICT_DESCENDANT_OF(moved_to, ?2)
 
-
-/* This statement returns pairs of move-roots below the path ?2 in WC_ID ?1,
- * where the original source of the move is within the subtree rooted at path
- * ?2 at op_depth ?3. (The move is recorded immediately above op_depth ?3) */
--- STMT_SELECT_MOVED_PAIRS_DEPTH
-SELECT local_relpath, moved_to, op_depth FROM nodes n
-WHERE wc_id = ?1
-  AND (local_relpath = ?2 OR IS_STRICT_DESCENDANT_OF(local_relpath, ?2))
-  AND moved_to IS NOT NULL
-  AND op_depth > ?3
-  AND op_depth = (SELECT MIN(op_depth) FROM nodes o
-                   WHERE o.wc_id = ?1
-                     AND o.local_relpath = n.local_relpath
-                     AND o.op_depth > ?3)
-
 -- STMT_SELECT_MOVED_PAIR3
 SELECT local_relpath, moved_to, op_depth, kind FROM nodes
 WHERE wc_id = ?1
@@ -1637,12 +1606,8 @@ WHERE n.wc_id = ?1
   AND h.moved_to IS NOT NULL
 
 -- STMT_COMMIT_UPDATE_ORIGIN
-/* Note that the only reason this SUBSTR() trick is valid is that you
-   can move neither the working copy nor the repository root.
-
-   SUBSTR(local_relpath, LENGTH(?2)+1) includes the '/' of the path */
 UPDATE nodes SET repos_id = ?4,
-                 repos_path = ?5 || SUBSTR(local_relpath, LENGTH(?2)+1),
+                 repos_path = RELPATH_SKIP_JOIN(?2, ?5, local_relpath),
                  revision = ?6
 WHERE wc_id = ?1
   AND (local_relpath = ?2
@@ -1662,14 +1627,16 @@ ORDER BY local_relpath
 
 -- STMT_SELECT_HAS_NON_FILE_CHILDREN
 SELECT 1 FROM nodes
-WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = 0 AND kind != MAP_FILE
+WHERE wc_id = ?1 AND parent_relpath = ?2 AND op_depth = ?3 AND kind != MAP_FILE
+LIMIT 1
 
 -- STMT_SELECT_HAS_GRANDCHILDREN
 SELECT 1 FROM nodes
 WHERE wc_id = ?1
   AND IS_STRICT_DESCENDANT_OF(parent_relpath, ?2)
-  AND op_depth = 0
+  AND op_depth = ?3
   AND file_external IS NULL
+LIMIT 1
 
 /* ------------------------------------------------------------------------- */
 

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db.c
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db.c?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db.c (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db.c Sun Nov 17 10:02:39 2013
@@ -661,21 +661,38 @@ svn_wc__db_retract_parent_delete(svn_wc_
 
   if (moved_to)
     {
-      /* ### TODO: Turn the move into a copy to keep the NODES table
-                   valid */
+      /* Turn the move into a copy to keep the NODES table valid */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_HERE_RECURSIVE));
+      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
+                                moved_to, relpath_depth(moved_to)));
+      SVN_ERR(svn_sqlite__step_done(stmt));
+
+      /* This leaves just the moved_to information on the origin,
+         which we will remove in the next step */
     }
 
   if (presence == svn_wc__db_status_base_deleted)
     {
+      /* Nothing left to shadow; remove the base-deleted node */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_DELETE_NODE));
-
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
-                                working_depth));
-
-      SVN_ERR(svn_sqlite__update(NULL, stmt));
+    }
+  else if (moved_to)
+    {
+      /* Clear moved to information, as this node is no longer base-deleted */
+      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
+                                        STMT_CLEAR_MOVED_TO_RELPATH));
+      }
+  else
+    {
+      /* Nothing to update */
+      return SVN_NO_ERROR;
     }
 
-  return SVN_NO_ERROR;
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
+                            working_depth));
+
+  return svn_error_trace(svn_sqlite__update(NULL, stmt));
 }
 
 
@@ -2084,28 +2101,29 @@ svn_wc__db_base_add_not_present_node(svn
 }
 
 /* Recursively clear moved-here information at the copy-half of the move
- * which moved the node at SRC_RELPATH away. This transforms the move into
- * a simple copy. */
+ * which moved a node to MOVED_TO_RELPATH. This transforms this side of the
+ * move into a simple copy.
+ */
 static svn_error_t *
-clear_moved_here(const char *src_relpath,
-                 svn_wc__db_wcroot_t *wcroot,
+clear_moved_here(svn_wc__db_wcroot_t *wcroot,
+                 const char *moved_to_relpath,
                  apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  const char *dst_relpath;
-
-  SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb, STMT_SELECT_MOVED_TO));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            src_relpath, relpath_depth(src_relpath)));
-  SVN_ERR(svn_sqlite__step_row(stmt));
-  dst_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
-  SVN_ERR(svn_sqlite__reset(stmt));
+  int affected_rows;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_CLEAR_MOVED_HERE_RECURSIVE));
-  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            dst_relpath, relpath_depth(dst_relpath)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+  SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, moved_to_relpath,
+                            relpath_depth(moved_to_relpath)));
+
+  SVN_ERR(svn_sqlite__update(&affected_rows, stmt));
+
+  if (affected_rows == 0)
+     return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                              _("The node '%s' was not found."),
+                              path_for_error_message(wcroot, moved_to_relpath,
+                                                     scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -2296,12 +2314,12 @@ db_base_remove(svn_wc__db_wcroot_t *wcro
       iterpool = svn_pool_create(scratch_pool);
       while (have_row)
         {
-          const char *child_relpath;
+          const char *moved_to_relpath;
           svn_error_t *err;
 
           svn_pool_clear(iterpool);
-          child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
-          err = clear_moved_here(child_relpath, wcroot, iterpool);
+          moved_to_relpath = svn_sqlite__column_text(stmt, 1, iterpool);
+          err = clear_moved_here(wcroot, moved_to_relpath, iterpool);
           if (err)
             return svn_error_compose_create(err, svn_sqlite__reset(stmt));
           SVN_ERR(svn_sqlite__step(&have_row, stmt));
@@ -4876,7 +4894,7 @@ handle_move_back(svn_boolean_t *moved_ba
              generally these values should be the same anyway as it was
              a no-op move. */
       SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_DELETE_MOVED_BACK));
+                                        STMT_DELETE_WORKING_OP_DEPTH));
 
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
                                              local_relpath,
@@ -5748,6 +5766,25 @@ set_actual_props(apr_int64_t wc_id,
   return svn_error_trace(svn_sqlite__step_done(stmt));
 }
 
+svn_error_t *
+svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 apr_hash_t *props,
+                                 svn_boolean_t clear_recorded_info,
+                                 apr_pool_t *scratch_pool)
+{
+  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
+                           props, wcroot->sdb, scratch_pool));
+
+  if (clear_recorded_info)
+    {
+      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
+                                 SVN_INVALID_FILESIZE, 0,
+                                 scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 /* The body of svn_wc__db_op_set_props().
 
@@ -5783,15 +5820,8 @@ set_props_txn(svn_wc__db_wcroot_t *wcroo
         props = NULL;
     }
 
-  SVN_ERR(set_actual_props(wcroot->wc_id, local_relpath,
-                           props, wcroot->sdb, scratch_pool));
-
-  if (clear_recorded_info)
-    {
-      SVN_ERR(db_record_fileinfo(wcroot, local_relpath,
-                                 SVN_INVALID_FILESIZE, 0,
-                                 scratch_pool));
-    }
+  SVN_ERR(svn_wc__db_op_set_props_internal(wcroot, local_relpath, props,
+                                           clear_recorded_info, scratch_pool));
 
   /* And finally.  */
   SVN_ERR(add_work_items(wcroot->sdb, work_items, scratch_pool));
@@ -6355,36 +6385,36 @@ svn_wc__db_op_mark_resolved(svn_wc__db_t
   return SVN_NO_ERROR;
 }
 
-/* Clear moved-to information at the delete-half of the move which
- * moved LOCAL_RELPATH here. This transforms the move into a simple delete. */
+/* Clear moved-to information at the delete-half of the move which moved
+ * MOVED_TO_RELPATH here. This transforms the delete part of the move into a
+ * normal delete.
+ *
+ * Note that the moved-to location is always an op-root, while this is not the
+ * case for a moved-from location.
+ */
 static svn_error_t *
-clear_moved_to(const char *local_relpath,
-               svn_wc__db_wcroot_t *wcroot,
+clear_moved_to(svn_wc__db_wcroot_t *wcroot,
+               const char *moved_to_relpath,
                apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
-  svn_boolean_t have_row;
   const char *moved_from_relpath;
+  int moved_from_op_depth;
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_MOVED_FROM_RELPATH));
-  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, local_relpath));
-  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-  if (!have_row)
-    {
-      SVN_ERR(svn_sqlite__reset(stmt));
-      return SVN_NO_ERROR;
-    }
+  SVN_ERR(svn_sqlite__bindf(stmt, "is", wcroot->wc_id, moved_to_relpath));
+  SVN_ERR(svn_sqlite__step_row(stmt));
 
   moved_from_relpath = svn_sqlite__column_text(stmt, 0, scratch_pool);
+  moved_from_op_depth = svn_sqlite__column_int(stmt, 1);
   SVN_ERR(svn_sqlite__reset(stmt));
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_CLEAR_MOVED_TO_RELPATH));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id,
-                            moved_from_relpath,
-                            relpath_depth(moved_from_relpath)));
-  SVN_ERR(svn_sqlite__step_done(stmt));
+                            moved_from_relpath, moved_from_op_depth));
+  SVN_ERR(svn_sqlite__update(NULL, stmt));
 
   return SVN_NO_ERROR;
 }
@@ -6540,7 +6570,7 @@ op_revert_txn(void *baton,
 
       /* If this node was moved-here, clear moved-to at the move source. */
       if (moved_here)
-        SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+        SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
     }
 
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
@@ -6683,7 +6713,7 @@ op_revert_recursive_txn(void *baton,
       svn_pool_clear(iterpool);
 
       moved_here_child_relpath = svn_sqlite__column_text(stmt, 0, iterpool);
-      err = clear_moved_to(moved_here_child_relpath, wcroot, iterpool);
+      err = clear_moved_to(wcroot, moved_here_child_relpath, iterpool);
       if (err)
         return svn_error_trace(svn_error_compose_create(
                                         err,
@@ -6697,7 +6727,7 @@ op_revert_recursive_txn(void *baton,
   /* Clear potential moved-to pointing at the target node itself. */
   if (op_depth > 0 && op_depth == relpath_depth(local_relpath)
       && moved_here)
-    SVN_ERR(clear_moved_to(local_relpath, wcroot, scratch_pool));
+    SVN_ERR(clear_moved_to(wcroot, local_relpath, scratch_pool));
 
   return SVN_NO_ERROR;
 }
@@ -9563,12 +9593,12 @@ svn_wc__db_read_props_streamily(svn_wc__
 
 /* Helper for svn_wc__db_read_props().
  */
-static svn_error_t *
-db_read_props(apr_hash_t **props,
-              svn_wc__db_wcroot_t *wcroot,
-              const char *local_relpath,
-              apr_pool_t *result_pool,
-              apr_pool_t *scratch_pool)
+svn_error_t *
+svn_wc__db_read_props_internal(apr_hash_t **props,
+                               svn_wc__db_wcroot_t *wcroot,
+                               const char *local_relpath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
@@ -9625,8 +9655,10 @@ svn_wc__db_read_props(apr_hash_t **props
                               local_abspath, scratch_pool, scratch_pool));
   VERIFY_USABLE_WCROOT(wcroot);
 
-  SVN_WC__DB_WITH_TXN(db_read_props(props, wcroot, local_relpath,
-                                    result_pool, scratch_pool),
+  SVN_WC__DB_WITH_TXN(svn_wc__db_read_props_internal(props, wcroot,
+                                                     local_relpath,
+                                                     result_pool,
+                                                     scratch_pool),
                       wcroot);
 
   return SVN_NO_ERROR;
@@ -12183,23 +12215,20 @@ svn_wc__db_scan_moved(const char **moved
 /* ###
  */
 static svn_error_t *
-follow_moved_to(apr_array_header_t **moved_tos,
-                int op_depth,
-                const char *repos_path,
-                svn_revnum_t revision,
-                svn_wc__db_wcroot_t *wcroot,
+follow_moved_to(svn_wc__db_wcroot_t *wcroot,
                 const char *local_relpath,
+                int op_depth,
+                apr_array_header_t **moved_tos,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
   svn_sqlite__stmt_t *stmt;
   svn_boolean_t have_row;
   int working_op_depth;
-  const char *ancestor_relpath, *node_moved_to = NULL;
+  const char *ancestor_relpath;
+  const char *node_moved_to = NULL;
   int i;
 
-  SVN_ERR_ASSERT((!op_depth && !repos_path) || (op_depth && repos_path));
-
   SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
                                     STMT_SELECT_OP_DEPTH_MOVED_TO));
   SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, local_relpath,
@@ -12209,50 +12238,26 @@ follow_moved_to(apr_array_header_t **mov
     {
       working_op_depth = svn_sqlite__column_int(stmt, 0);
       node_moved_to = svn_sqlite__column_text(stmt, 1, result_pool);
-      if (!repos_path)
-        {
-          SVN_ERR(svn_sqlite__step(&have_row, stmt));
-          if (!have_row || svn_sqlite__column_revnum(stmt, 0))
-            return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND,
-                                     svn_sqlite__reset(stmt),
-                                     _("The base node '%s' was not found."),
-                                     path_for_error_message(wcroot,
-                                                            local_relpath,
-                                                            scratch_pool));
-          repos_path = svn_sqlite__column_text(stmt, 2, scratch_pool);
-          revision = svn_sqlite__column_revnum(stmt, 3);
-        }
-    }
-  SVN_ERR(svn_sqlite__reset(stmt));
 
-  if (node_moved_to)
-    {
-      svn_boolean_t have_row2;
+      if (node_moved_to)
+        {
+          struct svn_wc__db_moved_to_t *moved_to;
 
-      SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                        STMT_SELECT_MOVED_HERE));
-      SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
-                                relpath_depth(node_moved_to)));
-      SVN_ERR(svn_sqlite__step(&have_row2, stmt));
-      if (!have_row2 || !svn_sqlite__column_int(stmt, 0)
-          || revision != svn_sqlite__column_revnum(stmt, 3)
-          || strcmp(repos_path, svn_sqlite__column_text(stmt, 2, NULL)))
-        node_moved_to = NULL;
-      SVN_ERR(svn_sqlite__reset(stmt));
+          moved_to = apr_palloc(result_pool, sizeof(*moved_to));
+          moved_to->op_depth = working_op_depth;
+          moved_to->local_relpath = node_moved_to;
+          APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
+        }
     }
 
-  if (node_moved_to)
-    {
-      struct svn_wc__db_moved_to_t *moved_to;
-
-      moved_to = apr_palloc(result_pool, sizeof(*moved_to));
-      moved_to->op_depth = working_op_depth;
-      moved_to->local_relpath = node_moved_to;
-      APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
-    }
+  SVN_ERR(svn_sqlite__reset(stmt));
 
-  /* A working row with moved_to, or no working row, and we are done. */
-  if (node_moved_to || !have_row)
+  if (!have_row)
+    return svn_error_createf(SVN_ERR_WC_PATH_NOT_FOUND, NULL,
+                             _("The node '%s' was not found."),
+                             path_for_error_message(wcroot, local_relpath,
+                                                    scratch_pool));
+  else if (node_moved_to)
     return SVN_NO_ERROR;
 
   /* Need to handle being moved via an ancestor. */
@@ -12267,55 +12272,29 @@ follow_moved_to(apr_array_header_t **mov
                                         STMT_SELECT_MOVED_TO));
       SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, ancestor_relpath,
                                 working_op_depth));
-      SVN_ERR(svn_sqlite__step(&have_row, stmt));
-      SVN_ERR_ASSERT(have_row);
+      SVN_ERR(svn_sqlite__step_row(stmt));
+
       ancestor_moved_to = svn_sqlite__column_text(stmt, 0, scratch_pool);
       SVN_ERR(svn_sqlite__reset(stmt));
       if (ancestor_moved_to)
         {
-          node_moved_to
-            = svn_relpath_join(ancestor_moved_to,
-                               svn_relpath_skip_ancestor(ancestor_relpath,
-                                                         local_relpath),
-                               result_pool);
-
-          SVN_ERR(svn_sqlite__get_statement(&stmt, wcroot->sdb,
-                                            STMT_SELECT_MOVED_HERE));
-          SVN_ERR(svn_sqlite__bindf(stmt, "isd", wcroot->wc_id, node_moved_to,
-                                    relpath_depth(ancestor_moved_to)));
-          SVN_ERR(svn_sqlite__step(&have_row, stmt));
-          if (!have_row)
-            ancestor_moved_to = NULL;
-          else if (!svn_sqlite__column_int(stmt, 0))
-            {
-              svn_wc__db_status_t presence
-                = svn_sqlite__column_token(stmt, 1, presence_map);
-              if (presence != svn_wc__db_status_not_present)
-                ancestor_moved_to = NULL;
-              else
-                {
-                  SVN_ERR(svn_sqlite__step(&have_row, stmt));
-                  if (!have_row && !svn_sqlite__column_int(stmt, 0))
-                    ancestor_moved_to = NULL;
-                }
-            }
-          SVN_ERR(svn_sqlite__reset(stmt));
-          if (!ancestor_moved_to)
-            break;
-          /* verify repos_path points back? */
-        }
-      if (ancestor_moved_to)
-        {
           struct svn_wc__db_moved_to_t *moved_to;
 
+          node_moved_to
+              = svn_relpath_join(ancestor_moved_to,
+                                 svn_relpath_skip_ancestor(ancestor_relpath,
+                                                           local_relpath),
+                                 result_pool);
+
           moved_to = apr_palloc(result_pool, sizeof(*moved_to));
           moved_to->op_depth = working_op_depth;
           moved_to->local_relpath = node_moved_to;
           APR_ARRAY_PUSH(*moved_tos, struct svn_wc__db_moved_to_t *) = moved_to;
 
-          SVN_ERR(follow_moved_to(moved_tos, relpath_depth(ancestor_moved_to),
-                                  repos_path, revision, wcroot, node_moved_to,
-                                  result_pool, scratch_pool));
+          SVN_ERR(follow_moved_to(wcroot, node_moved_to,
+                                  relpath_depth(ancestor_moved_to),
+                                  moved_tos, result_pool, scratch_pool));
+
           break;
         }
     }
@@ -12343,9 +12322,9 @@ svn_wc__db_follow_moved_to(apr_array_hea
                               sizeof(struct svn_wc__db_moved_to_t *));
 
   /* ### Wrap in a transaction */
-  SVN_ERR(follow_moved_to(moved_tos, 0, NULL, SVN_INVALID_REVNUM,
-                          wcroot, local_relpath,
-                          result_pool, scratch_pool));
+  SVN_WC__DB_WITH_TXN(follow_moved_to(wcroot, local_relpath, 0, moved_tos,
+                                      result_pool, scratch_pool),
+                      wcroot);
 
   /* ### Convert moved_to to abspath */
 

Modified: subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_private.h
URL: http://svn.apache.org/viewvc/subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_private.h?rev=1542685&r1=1542684&r2=1542685&view=diff
==============================================================================
--- subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_private.h (original)
+++ subversion/branches/invoke-diff-cmd-feature/subversion/libsvn_wc/wc_db_private.h Sun Nov 17 10:02:39 2013
@@ -466,6 +466,23 @@ svn_wc__db_op_depth_moved_to(const char 
                              apr_pool_t *result_pool,
                              apr_pool_t *scratch_pool);
 
+/* Like svn_wc__db_op_set_props, but updates ACTUAL_NODE directly without
+   comparing with the pristine properties, etc.
+*/
+svn_error_t *
+svn_wc__db_op_set_props_internal(svn_wc__db_wcroot_t *wcroot,
+                                 const char *local_relpath,
+                                 apr_hash_t *props,
+                                 svn_boolean_t clear_recorded_info,
+                                 apr_pool_t *scratch_pool);
+
+svn_error_t *
+svn_wc__db_read_props_internal(apr_hash_t **props,
+                               svn_wc__db_wcroot_t *wcroot,
+                               const char *local_relpath,
+                               apr_pool_t *result_pool,
+                               apr_pool_t *scratch_pool);
+
 /* Do a post-drive revision bump for the moved-away destination for
    any move sources under LOCAL_RELPATH.  This is called from within
    the revision bump transaction after the tree at LOCAL_RELPATH has