subversion-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cmpil...@apache.org
Subject svn commit: r1403849 [8/19] - in /subversion/branches/master-passphrase: ./ build/ build/ac-macros/ build/hudson/ contrib/server-side/fsfsfixer/ notes/ notes/api-errata/1.8/ notes/directory-index/ notes/obliterate/ notes/tree-conflicts/ subversion/bind...
Date Tue, 30 Oct 2012 20:03:39 GMT
Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.c Tue Oct 30 20:03:28 2012
@@ -1211,3 +1211,152 @@ svn_fs_fs__deserialize_changes(void **ou
 
   return SVN_NO_ERROR;
 }
+
+/* Auxiliary structure representing the content of a svn_mergeinfo_t hash.
+   This structure is much easier to (de-)serialize than an APR array.
+ */
+typedef struct mergeinfo_data_t
+{
+  /* number of paths in the hash */
+  unsigned count;
+  
+  /* COUNT keys (paths) */
+  const char **keys;
+  
+  /* COUNT keys lengths (strlen of path) */
+  apr_ssize_t *key_lengths;
+  
+  /* COUNT entries, each giving the number of ranges for the key */
+  int *range_counts;
+
+  /* all ranges in a single, concatenated buffer */
+  svn_merge_range_t *ranges;
+} mergeinfo_data_t;
+
+svn_error_t *
+svn_fs_fs__serialize_mergeinfo(void **data,
+                               apr_size_t *data_len,
+                               void *in,
+                               apr_pool_t *pool)
+{
+  svn_mergeinfo_t mergeinfo = in;
+  mergeinfo_data_t merges;
+  svn_temp_serializer__context_t *context;
+  svn_stringbuf_t *serialized;
+  apr_hash_index_t *hi;
+  unsigned i;
+  int k;
+  apr_size_t range_count;
+
+  /* initialize our auxiliary data structure */
+  merges.count = apr_hash_count(mergeinfo);
+  merges.keys = apr_palloc(pool, sizeof(*merges.keys) * merges.count);
+  merges.key_lengths = apr_palloc(pool, sizeof(*merges.key_lengths) *
+                                        merges.count);
+  merges.range_counts = apr_palloc(pool, sizeof(*merges.range_counts) *
+                                         merges.count);
+
+  i = 0;
+  range_count = 0;
+  for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi), ++i)
+    {
+      svn_rangelist_t *ranges;
+      apr_hash_this(hi, (const void**)&merges.keys[i],
+                        &merges.key_lengths[i],
+                        (void **)&ranges);
+      merges.range_counts[i] = ranges->nelts;
+      range_count += ranges->nelts;
+    }
+
+  merges.ranges = apr_palloc(pool, sizeof(*merges.ranges) * range_count);
+
+  i = 0;
+  for (hi = apr_hash_first(pool, mergeinfo); hi; hi = apr_hash_next(hi))
+    {
+      svn_rangelist_t *ranges = svn__apr_hash_index_val(hi);
+      for (k = 0; k < ranges->nelts; ++k, ++i)
+        merges.ranges[i] = *APR_ARRAY_IDX(ranges, k, svn_merge_range_t*);
+    }
+  
+  /* serialize it and all its elements */
+  context = svn_temp_serializer__init(&merges,
+                                      sizeof(merges),
+                                      range_count * 30,
+                                      pool);
+
+  /* keys array */
+  svn_temp_serializer__push(context,
+                            (const void * const *)&merges.keys,
+                            merges.count * sizeof(*merges.keys));
+
+  for (i = 0; i < merges.count; ++i)
+    svn_temp_serializer__add_string(context, &merges.keys[i]);
+
+  svn_temp_serializer__pop(context);
+
+  /* key lengths array */
+  svn_temp_serializer__push(context,
+                            (const void * const *)&merges.key_lengths,
+                            merges.count * sizeof(*merges.key_lengths));
+  svn_temp_serializer__pop(context);
+
+  /* range counts array */
+  svn_temp_serializer__push(context,
+                            (const void * const *)&merges.range_counts,
+                            merges.count * sizeof(*merges.range_counts));
+  svn_temp_serializer__pop(context);
+
+  /* ranges */
+  svn_temp_serializer__push(context,
+                            (const void * const *)&merges.ranges,
+                            range_count * sizeof(*merges.ranges));
+  svn_temp_serializer__pop(context);
+
+  /* return the serialized result */
+  serialized = svn_temp_serializer__get(context);
+
+  *data = serialized->data;
+  *data_len = serialized->len;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__deserialize_mergeinfo(void **out,
+                                 void *data,
+                                 apr_size_t data_len,
+                                 apr_pool_t *pool)
+{
+  unsigned i;
+  int k, n;
+  mergeinfo_data_t *merges = (mergeinfo_data_t *)data;
+  svn_mergeinfo_t mergeinfo;
+  
+  /* de-serialize our auxiliary data structure */
+  svn_temp_deserializer__resolve(merges, (void**)&merges->keys);
+  svn_temp_deserializer__resolve(merges, (void**)&merges->key_lengths);
+  svn_temp_deserializer__resolve(merges, (void**)&merges->range_counts);
+  svn_temp_deserializer__resolve(merges, (void**)&merges->ranges);
+
+  /* de-serialize keys and add entries to the result */
+  n = 0;
+  mergeinfo = svn_hash__make(pool);
+  for (i = 0; i < merges->count; ++i)
+    {
+      svn_rangelist_t *ranges = apr_array_make(pool,
+                                               merges->range_counts[i],
+                                               sizeof(svn_merge_range_t*));
+      for (k = 0; k < merges->range_counts[i]; ++k, ++n)
+        APR_ARRAY_PUSH(ranges, svn_merge_range_t*) = &merges->ranges[n];
+      
+      svn_temp_deserializer__resolve((void*)merges->keys,
+                                     (void**)&merges->keys[i]);
+      apr_hash_set(mergeinfo, merges->keys[i], merges->key_lengths[i], ranges);
+    }
+
+  /* done */
+  *out = mergeinfo;
+
+  return SVN_NO_ERROR;
+}
+

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/temp_serializer.h Tue Oct 30 20:03:28 2012
@@ -255,4 +255,22 @@ svn_fs_fs__deserialize_changes(void **ou
                                apr_size_t data_len,
                                apr_pool_t *pool);
 
+/**
+ * Implements #svn_cache__serialize_func_t for #svn_mergeinfo_t objects.
+ */
+svn_error_t *
+svn_fs_fs__serialize_mergeinfo(void **data,
+                               apr_size_t *data_len,
+                               void *in,
+                               apr_pool_t *pool);
+
+/**
+ * Implements #svn_cache__deserialize_func_t for #svn_mergeinfo_t objects.
+ */
+svn_error_t *
+svn_fs_fs__deserialize_mergeinfo(void **out,
+                                 void *data,
+                                 apr_size_t data_len,
+                                 apr_pool_t *pool);
+
 #endif

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.c Tue Oct 30 20:03:28 2012
@@ -59,6 +59,7 @@
 #include "temp_serializer.h"
 
 #include "private/svn_mergeinfo_private.h"
+#include "private/svn_subr_private.h"
 #include "private/svn_fs_util.h"
 #include "private/svn_fspath.h"
 #include "../libsvn_fs/fs-loader.h"
@@ -120,8 +121,11 @@ typedef struct fs_txn_root_data_t
 } fs_txn_root_data_t;
 
 /* Declared here to resolve the circular dependencies. */
-static svn_error_t * get_dag(dag_node_t **dag_node_p, svn_fs_root_t *root,
-                             const char *path, apr_pool_t *pool);
+static svn_error_t * get_dag(dag_node_t **dag_node_p,
+                             svn_fs_root_t *root,
+                             const char *path,
+                             svn_boolean_t needs_lock_cache,
+                             apr_pool_t *pool);
 
 static svn_fs_root_t *make_revision_root(svn_fs_t *fs, svn_revnum_t rev,
                                          dag_node_t *root_dir,
@@ -135,6 +139,254 @@ static svn_error_t *make_txn_root(svn_fs
 
 /*** Node Caching ***/
 
+/* 1st level cache */
+
+/* An entry in the first-level cache.  REVISION and PATH form the key that
+   will ultimately be matched.
+ */
+typedef struct cache_entry_t
+{
+  /* hash value derived from PATH, REVISION.
+     Used to short-circuit failed lookups. */
+  long int hash_value;
+
+  /* revision to which the NODE belongs */
+  svn_revnum_t revision;
+
+  /* path of the NODE */
+  char *path;
+
+  /* cached value of strlen(PATH). */
+  apr_size_t path_len;
+
+  /* the node allocated in the cache's pool. NULL for empty entries. */
+  dag_node_t *node;
+} cache_entry_t;
+
+/* Number of entries in the cache.  Keep this low to keep pressure on the
+   CPU caches low as well.  A binary value is most efficient.  If we walk
+   a directory tree, we want enough entries to store nodes for all files
+   without overwriting the nodes for the parent folder.  That way, there
+   will be no unnecessary misses (except for a few random ones caused by
+   hash collision).
+
+   The actual number of instances may be higher but entries that got
+   overwritten are no longer visible.
+ */
+enum { BUCKET_COUNT = 256 };
+
+/* Each pool that has received a DAG node, will hold at least on lock on
+   our cache to ensure that the node remains valid despite being allocated
+   in the cache's pool.  This is the structure to represent the lock.
+ */
+typedef struct cache_lock_t
+{
+  /* pool holding the lock */
+  apr_pool_t *pool;
+  
+  /* cache being locked */
+  fs_fs_dag_cache_t *cache;
+
+  /* next lock. NULL at EOL */
+  struct cache_lock_t *next;
+
+  /* previous lock. NULL at list head. Only then this==cache->first_lock */
+  struct cache_lock_t *prev;
+} cache_lock_t;
+
+/* The actual cache structure.  All nodes will be allocated in POOL.
+   When the number of INSERTIONS (i.e. objects created form that pool)
+   exceeds a certain threshold, the pool will be cleared and the cache
+   with it.
+   
+   To ensure that nodes returned from this structure remain valid, the
+   cache will get locked for the lifetime of the _receiving_ pools (i.e.
+   those in which we would allocate the node if there was no cache.).
+   The cache will only be cleared FIRST_LOCK is 0.
+ */
+struct fs_fs_dag_cache_t
+{
+  /* fixed number of (possibly empty) cache entries */
+  cache_entry_t buckets[BUCKET_COUNT];
+
+  /* pool used for all node allocation */
+  apr_pool_t *pool;
+
+  /* number of entries created from POOL since the last cleanup */
+  apr_size_t insertions;
+
+  /* Property lookups etc. have a very high locality (75% re-hit).
+     Thus, remember the last hit location for optimistic lookup. */
+  apr_size_t last_hit;
+
+  /* List of receiving pools that are still alive. */
+  cache_lock_t *first_lock;
+};
+
+/* Cleanup function to be called when a receiving pool gets cleared.
+   Unlocks the cache once.
+ */
+static apr_status_t
+unlock_cache(void *baton_void)
+{
+  cache_lock_t *lock = baton_void;
+
+  /* remove lock from chain. Update the head */
+  if (lock->next)
+    lock->next->prev = lock->prev;
+  if (lock->prev)
+    lock->prev->next = lock->next;
+  else
+    lock->cache->first_lock = lock->next;
+
+  return APR_SUCCESS;
+}
+
+/* Cleanup function to be called when the cache itself gets destroyed.
+   In that case, we must unregister all unlock requests.
+ */
+static apr_status_t
+unregister_locks(void *baton_void)
+{
+  fs_fs_dag_cache_t *cache = baton_void;
+  cache_lock_t *lock;
+
+  for (lock = cache->first_lock; lock; lock = lock->next)
+    apr_pool_cleanup_kill(lock->pool,
+                          lock,
+                          unlock_cache);
+
+  return APR_SUCCESS;
+}
+
+fs_fs_dag_cache_t*
+svn_fs_fs__create_dag_cache(apr_pool_t *pool)
+{
+  fs_fs_dag_cache_t *result = apr_pcalloc(pool, sizeof(*result));
+  result->pool = svn_pool_create(pool);
+
+  apr_pool_cleanup_register(pool,
+                            result,
+                            unregister_locks,
+                            apr_pool_cleanup_null);
+  
+  return result;
+}
+
+/* Prevent the entries in CACHE from being destroyed, for as long as the
+   POOL lives.
+ */
+static void
+lock_cache(fs_fs_dag_cache_t* cache, apr_pool_t *pool)
+{
+  /* we only need to lock / unlock once per pool.  Since we will often ask
+     for multiple nodes with the same pool, we can reduce the overhead.
+     However, if e.g. pools are being used in an alternating pattern,
+     we may lock the cache more than once for the same pool (and register
+     just as many cleanup actions).
+   */
+  cache_lock_t *lock = cache->first_lock;
+
+  /* try to find an existing lock for POOL.
+     But limit the time spent on chasing pointers.  */
+  int limiter = 8;
+  while (lock && --limiter)
+      if (lock->pool == pool)
+        return;
+
+  /* create a new lock and put it at the beginning of the lock chain */
+  lock = apr_palloc(pool, sizeof(*lock));
+  lock->cache = cache;
+  lock->pool = pool;
+  lock->next = cache->first_lock;
+  lock->prev = NULL;
+
+  if (cache->first_lock)
+    cache->first_lock->prev = lock;
+  cache->first_lock = lock;
+
+  /* instruct POOL to remove the look upon cleanup */
+  apr_pool_cleanup_register(pool,
+                            lock,
+                            unlock_cache,
+                            apr_pool_cleanup_null);
+}
+
+/* Clears the CACHE at regular intervals (destroying all cached nodes)
+ */
+static void
+auto_clear_dag_cache(fs_fs_dag_cache_t* cache)
+{
+  if (cache->first_lock == NULL && cache->insertions > BUCKET_COUNT)
+    {
+      apr_pool_clear(cache->pool);
+
+      memset(cache->buckets, 0, sizeof(cache->buckets));
+      cache->insertions = 0;
+    }
+}
+
+/* For the given REVISION and PATH, return the respective entry in CACHE.
+   If the entry is empty, its NODE member will be NULL and the caller
+   may then set it to the corresponding DAG node allocated in CACHE->POOL.
+ */
+static cache_entry_t *
+cache_lookup( fs_fs_dag_cache_t *cache
+            , svn_revnum_t revision
+            , const char *path)
+{
+  apr_size_t i, bucket_index;
+  apr_size_t path_len = strlen(path);
+  long int hash_value = revision;
+
+  /* optimistic lookup: hit the same bucket again? */
+  cache_entry_t *result = &cache->buckets[cache->last_hit];
+  if (   (result->revision == revision)
+      && (result->path_len == path_len)
+      && !memcmp(result->path, path, path_len))
+    {
+      return result;
+    }
+
+  /* need to do a full lookup.  Calculate the hash value
+     (HASH_VALUE has been initialized to REVISION). */
+  for (i = 0; i + 4 <= path_len; i += 4)
+    hash_value = hash_value * 0xd1f3da69 + *(const apr_uint32_t*)(path + i);
+  
+  for (; i < path_len; ++i)
+    hash_value = hash_value * 33 + path[i];
+
+  bucket_index = hash_value + (hash_value >> 16);
+  bucket_index = (bucket_index + (bucket_index >> 8)) % BUCKET_COUNT;
+
+  /* access the corresponding bucket and remember its location */
+  result = &cache->buckets[bucket_index];
+  cache->last_hit = bucket_index;
+
+  /* if it is *NOT* a match,  clear the bucket, expect the caller to fill
+     in the node and count it as an insertion */
+  if (   (result->hash_value != hash_value)
+      || (result->revision != revision)
+      || (result->path_len != path_len)
+      || memcmp(result->path, path, path_len))
+    {
+      result->hash_value = hash_value;
+      result->revision = revision;
+      if (result->path_len < path_len)
+        result->path = apr_palloc(cache->pool, path_len + 1);
+      result->path_len = path_len;
+      memcpy(result->path, path, path_len + 1);
+
+      result->node = NULL;
+
+      cache->insertions++;
+    }
+
+  return result;
+}
+
+/* 2nd level cache */
+
 /* Find and return the DAG node cache for ROOT and the key that
    should be used for PATH. */
 static void
@@ -160,32 +412,75 @@ locate_cache(svn_cache__t **cache,
 }
 
 /* Return NODE for PATH from ROOT's node cache, or NULL if the node
-   isn't cached; the node is copied into POOL. */
+   isn't cached; read it from the FS. *NODE remains valid until either
+   POOL or the FS gets cleared or destroyed (whichever comes first). 
+
+   Since locking can be expensive and POOL may be long-living, for
+   nodes that will not need to survive the next call to this function,
+   set NEEDS_LOCK_CACHE to FALSE. */
 static svn_error_t *
 dag_node_cache_get(dag_node_t **node_p,
                    svn_fs_root_t *root,
                    const char *path,
+                   svn_boolean_t needs_lock_cache,
                    apr_pool_t *pool)
 {
   svn_boolean_t found;
-  dag_node_t *node;
+  dag_node_t *node = NULL;
   svn_cache__t *cache;
   const char *key;
 
   SVN_ERR_ASSERT(*path == '/');
 
-  locate_cache(&cache, &key, root, path, pool);
-
-  SVN_ERR(svn_cache__get((void **) &node, &found, cache, key, pool));
-  if (found && node)
+  if (!root->is_txn_root)
     {
-      /* Patch up the FS, since this might have come from an old FS
-       * object. */
-      svn_fs_fs__dag_set_fs(node, root->fs);
-      *node_p = node;
+      /* immutable DAG node. use the global caches for it */
+      
+      fs_fs_data_t *ffd = root->fs->fsap_data;
+      cache_entry_t *bucket;
+
+      auto_clear_dag_cache(ffd->dag_node_cache);
+      bucket = cache_lookup(ffd->dag_node_cache, root->rev, path);
+      if (bucket->node == NULL)
+        {
+          locate_cache(&cache, &key, root, path, pool);
+          SVN_ERR(svn_cache__get((void **)&node, &found, cache, key,
+                                 ffd->dag_node_cache->pool));
+          if (found && node)
+            {
+              /* Patch up the FS, since this might have come from an old FS
+              * object. */
+              svn_fs_fs__dag_set_fs(node, root->fs);
+              bucket->node = node;
+            }
+        }
+      else
+        {
+          node = bucket->node;
+        }
+
+      /* if we found a node, make sure it remains valid at least as long
+         as it would when allocated in POOL. */
+      if (node && needs_lock_cache)
+        lock_cache(ffd->dag_node_cache, pool);
     }
   else
-    *node_p = NULL;
+    {
+      /* DAG is mutable / may become invalid. Use the TXN-local cache */
+      
+      locate_cache(&cache, &key, root, path, pool);
+
+      SVN_ERR(svn_cache__get((void **) &node, &found, cache, key, pool));
+      if (found && node)
+        {
+          /* Patch up the FS, since this might have come from an old FS
+          * object. */
+          svn_fs_fs__dag_set_fs(node, root->fs);
+        }
+    }
+
+  *node_p = node;
+
   return SVN_NO_ERROR;
 }
 
@@ -504,7 +799,7 @@ get_copy_inheritance(copy_id_inherit_t *
   SVN_ERR(svn_fs_fs__dag_get_copyroot(&copyroot_rev, &copyroot_path,
                                       child->node));
   SVN_ERR(svn_fs_fs__revision_root(&copyroot_root, fs, copyroot_rev, pool));
-  SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, pool));
+  SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, FALSE, pool));
   copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
 
   if (svn_fs_fs__id_compare(copyroot_id, child_id) == -1)
@@ -592,7 +887,9 @@ open_path(parent_path_t **parent_path_p,
   dag_node_t *here; /* The directory we're currently looking at.  */
   parent_path_t *parent_path; /* The path from HERE up to the root.  */
   const char *rest; /* The portion of PATH we haven't traversed yet.  */
-  const char *canon_path = svn_fs__canonicalize_abspath(path, pool);
+  const char *canon_path = svn_fs__is_canonical_abspath(path)
+                         ? path
+                         : svn_fs__canonicalize_abspath(path, pool);
   const char *path_so_far = "/";
   apr_pool_t *iterpool = svn_pool_create(pool);
 
@@ -641,7 +938,8 @@ open_path(parent_path_t **parent_path_p,
           /* If we found a directory entry, follow it.  First, we
              check our node cache, and, failing that, we hit the DAG
              layer. */
-          SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far, pool));
+          SVN_ERR(dag_node_cache_get(&cached_node, root, path_so_far, TRUE,
+                                     pool));
           if (cached_node)
             child = cached_node;
           else
@@ -770,7 +1068,8 @@ make_path_mutable(svn_fs_root_t *root,
                                           parent_path->node));
       SVN_ERR(svn_fs_fs__revision_root(&copyroot_root, root->fs,
                                        copyroot_rev, pool));
-      SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path, pool));
+      SVN_ERR(get_dag(&copyroot_node, copyroot_root, copyroot_path,
+                      FALSE, pool));
 
       child_id = svn_fs_fs__dag_get_id(parent_path->node);
       copyroot_id = svn_fs_fs__dag_get_id(copyroot_node);
@@ -807,29 +1106,47 @@ make_path_mutable(svn_fs_root_t *root,
 
 /* Open the node identified by PATH in ROOT.  Set DAG_NODE_P to the
    node we find, allocated in POOL.  Return the error
-   SVN_ERR_FS_NOT_FOUND if this node doesn't exist. */
+   SVN_ERR_FS_NOT_FOUND if this node doesn't exist.
+
+   Since locking can be expensive and POOL may be long-living, for
+   nodes that will not need to survive the next call to this function,
+   set NEEDS_LOCK_CACHE to FALSE. */
 static svn_error_t *
 get_dag(dag_node_t **dag_node_p,
         svn_fs_root_t *root,
         const char *path,
+        svn_boolean_t needs_lock_cache,
         apr_pool_t *pool)
 {
   parent_path_t *parent_path;
-  dag_node_t *node;
+  dag_node_t *node = NULL;
 
-  /* Canonicalize the input PATH. */
-  path = svn_fs__canonicalize_abspath(path, pool);
+  /* First we look for the DAG in our cache
+     (if the path may be canonical). */
+  if (*path == '/')
+    SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache, pool));
 
-  /* First we look for the DAG in our cache. */
-  SVN_ERR(dag_node_cache_get(&node, root, path, pool));
   if (! node)
     {
-      /* Call open_path with no flags, as we want this to return an error
-         if the node for which we are searching doesn't exist. */
-      SVN_ERR(open_path(&parent_path, root, path, 0, NULL, pool));
-      node = parent_path->node;
+      /* Canonicalize the input PATH. */
+      if (!svn_fs__is_canonical_abspath(path))
+        {
+          path = svn_fs__canonicalize_abspath(path, pool);
+
+          /* Try again with the corrected path. */
+          SVN_ERR(dag_node_cache_get(&node, root, path, needs_lock_cache,
+                                     pool));
+        }
+
+      if (! node)
+        {
+          /* Call open_path with no flags, as we want this to return an
+           * error if the node for which we are searching doesn't exist. */
+          SVN_ERR(open_path(&parent_path, root, path, 0, NULL, pool));
+          node = parent_path->node;
 
-      /* No need to cache our find -- open_path() will do that for us. */
+          /* No need to cache our find -- open_path() will do that for us. */
+        }
     }
 
   *dag_node_p = node;
@@ -894,7 +1211,7 @@ svn_fs_fs__node_id(const svn_fs_id_t **i
     {
       dag_node_t *node;
 
-      SVN_ERR(get_dag(&node, root, path, pool));
+      SVN_ERR(get_dag(&node, root, path, FALSE, pool));
       *id_p = svn_fs_fs__id_copy(svn_fs_fs__dag_get_id(node), pool);
     }
   return SVN_NO_ERROR;
@@ -909,7 +1226,7 @@ svn_fs_fs__node_created_rev(svn_revnum_t
 {
   dag_node_t *node;
 
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
   return svn_fs_fs__dag_get_revision(revision, node, pool);
 }
 
@@ -924,7 +1241,7 @@ fs_node_created_path(const char **create
 {
   dag_node_t *node;
 
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, TRUE, pool));
   *created_path = svn_fs_fs__dag_get_created_path(node);
 
   return SVN_NO_ERROR;
@@ -988,7 +1305,7 @@ fs_node_prop(svn_string_t **value_p,
   dag_node_t *node;
   apr_hash_t *proplist;
 
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
   SVN_ERR(svn_fs_fs__dag_get_proplist(&proplist, node, pool));
   *value_p = NULL;
   if (proplist)
@@ -1011,7 +1328,7 @@ fs_node_proplist(apr_hash_t **table_p,
   apr_hash_t *table;
   dag_node_t *node;
 
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
   SVN_ERR(svn_fs_fs__dag_get_proplist(&table, node, pool));
   *table_p = table ? table : apr_hash_make(pool);
 
@@ -1127,8 +1444,8 @@ fs_props_changed(svn_boolean_t *changed_
       (SVN_ERR_FS_GENERAL, NULL,
        _("Cannot compare property value between two different filesystems"));
 
-  SVN_ERR(get_dag(&node1, root1, path1, pool));
-  SVN_ERR(get_dag(&node2, root2, path2, pool));
+  SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
+  SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
   return svn_fs_fs__dag_things_different(changed_p, NULL,
                                          node1, node2);
 }
@@ -1141,7 +1458,7 @@ fs_props_changed(svn_boolean_t *changed_
 static svn_error_t *
 get_root(dag_node_t **node, svn_fs_root_t *root, apr_pool_t *pool)
 {
-  return get_dag(node, root, "", pool);
+  return get_dag(node, root, "/", TRUE, pool);
 }
 
 
@@ -1805,7 +2122,7 @@ fs_dir_entries(apr_hash_t **table_p,
   dag_node_t *node;
 
   /* Get the entries for this path in the caller's pool. */
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
   return svn_fs_fs__dag_dir_entries(table_p, node, pool);
 }
 
@@ -1959,7 +2276,7 @@ copy_helper(svn_fs_root_t *from_root,
        _("Copy from mutable tree not currently supported"));
 
   /* Get the NODE for FROM_PATH in FROM_ROOT.*/
-  SVN_ERR(get_dag(&from_node, from_root, from_path, pool));
+  SVN_ERR(get_dag(&from_node, from_root, from_path, TRUE, pool));
 
   /* Build up the parent path from TO_PATH in TO_ROOT.  If the last
      component does not exist, it's not that big a deal.  We'll just
@@ -2036,7 +2353,7 @@ copy_helper(svn_fs_root_t *from_root,
                                             pool));
 
       /* Make a record of this modification in the changes table. */
-      SVN_ERR(get_dag(&new_node, to_root, to_path, pool));
+      SVN_ERR(get_dag(&new_node, to_root, to_path, TRUE, pool));
       SVN_ERR(add_change(to_root->fs, txn_id, to_path,
                          svn_fs_fs__dag_get_id(new_node), kind, FALSE, FALSE,
                          svn_fs_fs__dag_node_kind(from_node),
@@ -2139,7 +2456,7 @@ fs_copied_from(svn_revnum_t *rev_p,
     {
       /* There is no cached entry, look it up the old-fashioned
          way. */
-      SVN_ERR(get_dag(&node, root, path, pool));
+      SVN_ERR(get_dag(&node, root, path, TRUE, pool));
       SVN_ERR(svn_fs_fs__dag_get_copyfrom_rev(&copyfrom_rev, node));
       SVN_ERR(svn_fs_fs__dag_get_copyfrom_path(&copyfrom_path, node));
     }
@@ -2211,7 +2528,7 @@ fs_file_length(svn_filesize_t *length_p,
   dag_node_t *file;
 
   /* First create a dag_node_t from the root/path pair. */
-  SVN_ERR(get_dag(&file, root, path, pool));
+  SVN_ERR(get_dag(&file, root, path, FALSE, pool));
 
   /* Now fetch its length */
   return svn_fs_fs__dag_file_length(length_p, file, pool);
@@ -2230,7 +2547,7 @@ fs_file_checksum(svn_checksum_t **checks
 {
   dag_node_t *file;
 
-  SVN_ERR(get_dag(&file, root, path, pool));
+  SVN_ERR(get_dag(&file, root, path, FALSE, pool));
   return svn_fs_fs__dag_file_checksum(checksum, file, kind, pool);
 }
 
@@ -2249,7 +2566,7 @@ fs_file_contents(svn_stream_t **contents
   svn_stream_t *file_stream;
 
   /* First create a dag_node_t from the root/path pair. */
-  SVN_ERR(get_dag(&node, root, path, pool));
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
 
   /* Then create a readable stream from the dag_node_t. */
   SVN_ERR(svn_fs_fs__dag_get_contents(&file_stream, node, pool));
@@ -2261,6 +2578,25 @@ fs_file_contents(svn_stream_t **contents
 /* --- End machinery for svn_fs_file_contents() ---  */
 
 
+/* --- Machinery for svn_fs_try_process_file_contents() ---  */
+
+static svn_error_t *
+fs_try_process_file_contents(svn_boolean_t *success,
+                             svn_fs_root_t *root,
+                             const char *path,
+                             svn_fs_process_contents_func_t processor,
+                             void* baton,
+                             apr_pool_t *pool)
+{
+  dag_node_t *node;
+  SVN_ERR(get_dag(&node, root, path, FALSE, pool));
+
+  return svn_fs_fs__dag_try_process_file_contents(success, node,
+                                                  processor, baton, pool);
+}
+
+/* --- End machinery for svn_fs_try_process_file_contents() ---  */
+
 
 /* --- Machinery for svn_fs_apply_textdelta() ---  */
 
@@ -2635,8 +2971,8 @@ fs_contents_changed(svn_boolean_t *chang
         (SVN_ERR_FS_GENERAL, NULL, _("'%s' is not a file"), path2);
   }
 
-  SVN_ERR(get_dag(&node1, root1, path1, pool));
-  SVN_ERR(get_dag(&node2, root2, path2, pool));
+  SVN_ERR(get_dag(&node1, root1, path1, TRUE, pool));
+  SVN_ERR(get_dag(&node2, root2, path2, TRUE, pool));
   return svn_fs_fs__dag_things_different(NULL, changed_p,
                                          node1, node2);
 }
@@ -2656,10 +2992,10 @@ fs_get_file_delta_stream(svn_txdelta_str
   dag_node_t *source_node, *target_node;
 
   if (source_root && source_path)
-    SVN_ERR(get_dag(&source_node, source_root, source_path, pool));
+    SVN_ERR(get_dag(&source_node, source_root, source_path, TRUE, pool));
   else
     source_node = NULL;
-  SVN_ERR(get_dag(&target_node, target_root, target_path, pool));
+  SVN_ERR(get_dag(&target_node, target_root, target_path, TRUE, pool));
 
   /* Create a delta stream that turns the source into the target.  */
   return svn_fs_fs__dag_get_file_delta_stream(stream_p, source_node,
@@ -3143,7 +3479,7 @@ history_prev(void *baton, apr_pool_t *po
 
       SVN_ERR(svn_fs_fs__revision_root(&copyroot_root, fs, copyroot_rev,
                                        pool));
-      SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, pool));
+      SVN_ERR(get_dag(&node, copyroot_root, copyroot_path, FALSE, pool));
       copy_dst = svn_fs_fs__dag_get_created_path(node);
 
       /* If our current path was the very destination of the copy,
@@ -3340,7 +3676,7 @@ crawl_directory_dag_for_mergeinfo(svn_fs
       svn_pool_clear(iterpool);
 
       kid_path = svn_fspath__join(this_path, dirent->name, iterpool);
-      SVN_ERR(get_dag(&kid_dag, root, kid_path, iterpool));
+      SVN_ERR(get_dag(&kid_dag, root, kid_path, TRUE, iterpool));
 
       SVN_ERR(svn_fs_fs__dag_has_mergeinfo(&has_mergeinfo, kid_dag));
       SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down, kid_dag));
@@ -3400,6 +3736,24 @@ crawl_directory_dag_for_mergeinfo(svn_fs
   return SVN_NO_ERROR;
 }
 
+/* Return the cache key as a combination of REV_ROOT->REV, the inheritance
+   flags INHERIT and ADJUST_INHERITED_MERGEINFO, and the PATH.  The result
+   will be allocated in POOL..
+ */
+static const char *
+mergeinfo_cache_key(const char *path,
+                    svn_fs_root_t *rev_root,
+                    svn_mergeinfo_inheritance_t inherit,
+                    svn_boolean_t adjust_inherited_mergeinfo,
+                    apr_pool_t *pool)
+{
+  apr_int64_t number = rev_root->rev;
+  number = number * 4
+         + (inherit == svn_mergeinfo_nearest_ancestor ? 2 : 0)
+         + (adjust_inherited_mergeinfo ? 1 : 0);
+  
+  return svn_fs_fs__combine_number_and_string(number, path, pool);
+}
 
 /* Calculates the mergeinfo for PATH under REV_ROOT using inheritance
    type INHERIT.  Returns it in *MERGEINFO, or NULL if there is none.
@@ -3407,20 +3761,18 @@ crawl_directory_dag_for_mergeinfo(svn_fs
    used for temporary allocations.
  */
 static svn_error_t *
-get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
-                       svn_fs_root_t *rev_root,
-                       const char *path,
-                       svn_mergeinfo_inheritance_t inherit,
-                       svn_boolean_t adjust_inherited_mergeinfo,
-                       apr_pool_t *result_pool,
-                       apr_pool_t *scratch_pool)
+get_mergeinfo_for_path_internal(svn_mergeinfo_t *mergeinfo,
+                                svn_fs_root_t *rev_root,
+                                const char *path,
+                                svn_mergeinfo_inheritance_t inherit,
+                                svn_boolean_t adjust_inherited_mergeinfo,
+                                apr_pool_t *result_pool,
+                                apr_pool_t *scratch_pool)
 {
   parent_path_t *parent_path, *nearest_ancestor;
   apr_hash_t *proplist;
   svn_string_t *mergeinfo_string;
 
-  *mergeinfo = NULL;
-
   path = svn_fs__canonicalize_abspath(path, scratch_pool);
 
   SVN_ERR(open_path(&parent_path, rev_root, path, 0, NULL, scratch_pool));
@@ -3509,6 +3861,58 @@ get_mergeinfo_for_path(svn_mergeinfo_t *
   return SVN_NO_ERROR;
 }
 
+/* Caching wrapper around get_mergeinfo_for_path_internal().
+ */
+static svn_error_t *
+get_mergeinfo_for_path(svn_mergeinfo_t *mergeinfo,
+                       svn_fs_root_t *rev_root,
+                       const char *path,
+                       svn_mergeinfo_inheritance_t inherit,
+                       svn_boolean_t adjust_inherited_mergeinfo,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
+{
+  fs_fs_data_t *ffd = rev_root->fs->fsap_data;
+  const char *cache_key;
+  svn_boolean_t found = FALSE;
+  svn_stringbuf_t *mergeinfo_exists;
+
+  *mergeinfo = NULL;
+
+  cache_key = mergeinfo_cache_key(path, rev_root, inherit,
+                                  adjust_inherited_mergeinfo, scratch_pool);
+  if (ffd->mergeinfo_existence_cache)
+    {
+      SVN_ERR(svn_cache__get((void **)&mergeinfo_exists, &found,
+                             ffd->mergeinfo_existence_cache,
+                             cache_key, result_pool));
+      if (found && mergeinfo_exists->data[0] == '1')
+        SVN_ERR(svn_cache__get((void **)mergeinfo, &found,
+                              ffd->mergeinfo_cache,
+                              cache_key, result_pool));
+    }
+    
+  if (! found)
+    {
+      SVN_ERR(get_mergeinfo_for_path_internal(mergeinfo, rev_root, path,
+                                              inherit,
+                                              adjust_inherited_mergeinfo,
+                                              result_pool, scratch_pool));
+      if (ffd->mergeinfo_existence_cache)
+        {
+          mergeinfo_exists = svn_stringbuf_create(*mergeinfo ? "1" : "0",
+                                                  scratch_pool);
+          SVN_ERR(svn_cache__set(ffd->mergeinfo_existence_cache,
+                                 cache_key, mergeinfo_exists, scratch_pool));
+          if (*mergeinfo)
+            SVN_ERR(svn_cache__set(ffd->mergeinfo_cache,
+                                  cache_key, *mergeinfo, scratch_pool));
+        }
+    }
+
+  return SVN_NO_ERROR;
+}
+
 /* Adds mergeinfo for each descendant of PATH (but not PATH itself)
    under ROOT to RESULT_CATALOG.  Returned values are allocated in
    RESULT_POOL; temporary values in POOL. */
@@ -3522,7 +3926,7 @@ add_descendant_mergeinfo(svn_mergeinfo_c
   dag_node_t *this_dag;
   svn_boolean_t go_down;
 
-  SVN_ERR(get_dag(&this_dag, root, path, scratch_pool));
+  SVN_ERR(get_dag(&this_dag, root, path, TRUE, scratch_pool));
   SVN_ERR(svn_fs_fs__dag_has_descendants_with_mergeinfo(&go_down,
                                                         this_dag));
   if (go_down)
@@ -3549,7 +3953,7 @@ get_mergeinfos_for_paths(svn_fs_root_t *
                          apr_pool_t *result_pool,
                          apr_pool_t *scratch_pool)
 {
-  svn_mergeinfo_catalog_t result_catalog = apr_hash_make(result_pool);
+  svn_mergeinfo_catalog_t result_catalog = svn_hash__make(result_pool);
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
   int i;
 
@@ -3649,6 +4053,7 @@ static root_vtable_t root_vtable = {
   fs_file_length,
   fs_file_checksum,
   fs_file_contents,
+  fs_try_process_file_contents,
   fs_make_file,
   fs_apply_textdelta,
   fs_apply_text,
@@ -3688,7 +4093,7 @@ make_revision_root(svn_fs_t *fs,
   root->rev = rev;
 
   frd->root_dir = root_dir;
-  frd->copyfrom_cache = apr_hash_make(root->pool);
+  frd->copyfrom_cache = svn_hash__make(root->pool);
 
   root->fsap_data = frd;
 

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_fs/tree.h Tue Oct 30 20:03:28 2012
@@ -23,12 +23,19 @@
 #ifndef SVN_LIBSVN_FS_TREE_H
 #define SVN_LIBSVN_FS_TREE_H
 
+#include "fs.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 
 
+/* In POOL, create an instance of a DAG node 1st level cache.
+   The POOL will be cleared at regular intervals. */
+fs_fs_dag_cache_t*
+svn_fs_fs__create_dag_cache(apr_pool_t *pool);
+
 /* Set *ROOT_P to the root directory of revision REV in filesystem FS.
    Allocate the structure in POOL. */
 svn_error_t *svn_fs_fs__revision_root(svn_fs_root_t **root_p, svn_fs_t *fs,

Modified: subversion/branches/master-passphrase/subversion/libsvn_fs_util/fs-util.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_fs_util/fs-util.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_fs_util/fs-util.c Tue Oct 30 20:03:28 2012
@@ -35,6 +35,40 @@
 #include "private/svn_fspath.h"
 #include "../libsvn_fs/fs-loader.h"
 
+svn_boolean_t
+svn_fs__is_canonical_abspath(const char *path)
+{
+  size_t path_len;
+  const char *end;
+
+  /* No PATH?  No problem. */
+  if (! path)
+    return TRUE;
+
+  /* Empty PATH?  That's just "/". */
+  if (! *path)
+    return FALSE;
+
+  /* No leading slash?  Fix that. */
+  if (*path != '/')
+    return FALSE;
+
+  /* check for trailing '/' */
+  path_len = strlen(path);
+  if (path_len == 1)
+    return TRUE;
+  if (path[path_len - 1] == '/')
+    return FALSE;
+
+  /* check for "//" */
+  end = path + path_len - 1;
+  for (; path != end; ++path)
+    if ((path[0] == '/') && (path[1] == '/'))
+      return FALSE;
+
+  return TRUE;
+}
+
 const char *
 svn_fs__canonicalize_abspath(const char *path, apr_pool_t *pool)
 {

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra/compat.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra/compat.c Tue Oct 30 20:03:28 2012
@@ -871,3 +871,90 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
   *revision_deleted = log_path_deleted_baton.revision_deleted;
   return SVN_NO_ERROR;
 }
+
+
+svn_error_t *
+svn_ra__get_inherited_props_walk(svn_ra_session_t *session,
+                                 const char *path,
+                                 svn_revnum_t revision,
+                                 apr_array_header_t **inherited_props,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool)
+{
+  const char *repos_root_url;
+  const char *session_url;
+  const char *parent_url;
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+
+  *inherited_props =
+    apr_array_make(result_pool, 1, sizeof(svn_prop_inherited_item_t *));
+
+  /* Walk to the root of the repository getting inherited
+     props for PATH. */
+  SVN_ERR(svn_ra_get_repos_root2(session, &repos_root_url, scratch_pool));
+  SVN_ERR(svn_ra_get_session_url(session, &session_url, scratch_pool));
+  parent_url = session_url;
+
+  while (strcmp(repos_root_url, parent_url))
+    {
+      apr_hash_index_t *hi;
+      apr_hash_t *parent_props;
+      apr_hash_t *final_hash = apr_hash_make(result_pool);
+      svn_error_t *err;
+
+      svn_pool_clear(iterpool);
+      parent_url = svn_uri_dirname(parent_url, iterpool);
+      SVN_ERR(svn_ra_reparent(session, parent_url, iterpool));
+      err = session->vtable->get_dir(session, NULL, NULL,
+                                     &parent_props, "",
+                                     revision, SVN_DIRENT_ALL,
+                                     iterpool);
+
+      /* If the user doesn't have read access to a parent path then
+         skip, but allow them to inherit from further up. */
+      if (err)
+        {
+          if ((err->apr_err == SVN_ERR_RA_NOT_AUTHORIZED)
+              || (err->apr_err == SVN_ERR_RA_DAV_FORBIDDEN))
+            {
+              svn_error_clear(err);
+              continue;
+            }
+          else
+            {
+              return svn_error_trace(err);
+            }
+        }
+
+      for (hi = apr_hash_first(scratch_pool, parent_props);
+           hi;
+           hi = apr_hash_next(hi))
+        {
+          const char *name = svn__apr_hash_index_key(hi);
+          apr_ssize_t klen = svn__apr_hash_index_klen(hi);
+          svn_string_t *value = svn__apr_hash_index_val(hi);
+
+          if (svn_property_kind2(name) == svn_prop_regular_kind)
+            {
+              name = apr_pstrdup(result_pool, name);
+              value = svn_string_dup(value, result_pool);
+              apr_hash_set(final_hash, name, klen, value);
+            }
+        }
+
+      if (apr_hash_count(final_hash))
+        {
+          svn_prop_inherited_item_t *new_iprop =
+            apr_palloc(result_pool, sizeof(*new_iprop));
+          new_iprop->path_or_url = apr_pstrdup(result_pool, parent_url);
+          new_iprop->prop_hash = final_hash;
+          svn_sort__array_insert(&new_iprop, *inherited_props, 0);
+        }
+    }
+
+  /* Reparent session back to original URL. */
+  SVN_ERR(svn_ra_reparent(session, session_url, scratch_pool));
+
+  svn_pool_destroy(iterpool);
+  return SVN_NO_ERROR;
+}

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra/deprecated.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra/deprecated.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra/deprecated.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra/deprecated.c Tue Oct 30 20:03:28 2012
@@ -33,6 +33,7 @@
 #include "svn_pools.h"
 
 #include "ra_loader.h"
+#include "deprecated.h"
 
 #include "svn_private_config.h"
 
@@ -209,8 +210,8 @@ svn_error_t *svn_ra_get_commit_editor2(s
                                        const svn_delta_editor_t **editor,
                                        void **edit_baton,
                                        const char *log_msg,
-                                       svn_commit_callback2_t callback,
-                                       void *callback_baton,
+                                       svn_commit_callback2_t commit_callback,
+                                       void *commit_baton,
                                        apr_hash_t *lock_tokens,
                                        svn_boolean_t keep_locks,
                                        apr_pool_t *pool)
@@ -221,7 +222,7 @@ svn_error_t *svn_ra_get_commit_editor2(s
                  APR_HASH_KEY_STRING,
                  svn_string_create(log_msg, pool));
   return svn_ra_get_commit_editor3(session, editor, edit_baton, revprop_table,
-                                   callback, callback_baton,
+                                   commit_callback, commit_baton,
                                    lock_tokens, keep_locks, pool);
 }
 
@@ -417,3 +418,40 @@ svn_error_t *svn_ra_do_status(svn_ra_ses
                                     SVN_DEPTH_INFINITY_OR_IMMEDIATES(recurse),
                                     status_editor, status_baton, pool);
 }
+
+svn_error_t *svn_ra_get_dir(svn_ra_session_t *session,
+                            const char *path,
+                            svn_revnum_t revision,
+                            apr_hash_t **dirents,
+                            svn_revnum_t *fetched_rev,
+                            apr_hash_t **props,
+                            apr_pool_t *pool)
+{
+  SVN_ERR_ASSERT(*path != '/');
+  return session->vtable->get_dir(session, dirents, fetched_rev, props,
+                                  path, revision, SVN_DIRENT_ALL, pool);
+}
+
+svn_error_t *
+svn_ra_local__deprecated_init(int abi_version,
+                              apr_pool_t *pool,
+                              apr_hash_t *hash)
+{
+  return svn_error_trace(svn_ra_local_init(abi_version, pool, hash));
+}
+
+svn_error_t *
+svn_ra_svn__deprecated_init(int abi_version,
+                            apr_pool_t *pool,
+                            apr_hash_t *hash)
+{
+  return svn_error_trace(svn_ra_svn_init(abi_version, pool, hash));
+}
+
+svn_error_t *
+svn_ra_serf__deprecated_init(int abi_version,
+                             apr_pool_t *pool,
+                             apr_hash_t *hash)
+{
+  return svn_error_trace(svn_ra_serf_init(abi_version, pool, hash));
+}

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra/editor.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra/editor.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra/editor.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra/editor.c Tue Oct 30 20:03:28 2012
@@ -42,6 +42,11 @@ struct fp_baton {
   void *cb_baton;
 };
 
+struct fb_baton {
+  svn_ra__provide_base_cb_t provide_base_cb;
+  void *cb_baton;
+};
+
 /* The shims currently want a callback that provides props for a given
    REPOS_RELPATH at a given BASE_REVISION. However, the RA Ev2 interface
    has a callback that provides properties for the REPOS_RELPATH from any
@@ -72,13 +77,49 @@ fetch_props(apr_hash_t **props,
                                                result_pool, scratch_pool));
 }
 
+/* See note above regarding BASE_REVISION.
+   This also pulls down the entire contents of the file stream from the
+   RA layer and stores them in a local file, returning the path.
+*/
+static svn_error_t *
+fetch_base(const char **filename,
+           void *baton,
+           const char *repos_relpath,
+           svn_revnum_t base_revision,
+           apr_pool_t *result_pool,
+           apr_pool_t *scratch_pool)
+{
+  struct fb_baton *fbb = baton;
+  svn_revnum_t unused_revision;
+  svn_stream_t *contents;
+  svn_stream_t *file_stream;
+  const char *tmp_filename;
+
+  /* Ignored: BASE_REVISION.  */
+
+  SVN_ERR(fbb->provide_base_cb(&contents, &unused_revision, fbb->cb_baton,
+                               repos_relpath, result_pool, scratch_pool));
+
+  SVN_ERR(svn_stream_open_unique(&file_stream, &tmp_filename, NULL,
+                                 svn_io_file_del_on_pool_cleanup,
+                                 scratch_pool, scratch_pool));
+  SVN_ERR(svn_stream_copy3(contents, file_stream, NULL, NULL, scratch_pool));
+
+  *filename = apr_pstrdup(result_pool, tmp_filename);
+
+ 
+
+  return SVN_NO_ERROR;
+}
+
+
 
 svn_error_t *
 svn_ra__use_commit_shim(svn_editor_t **editor,
                         svn_ra_session_t *session,
                         apr_hash_t *revprop_table,
-                        svn_commit_callback2_t callback,
-                        void *callback_baton,
+                        svn_commit_callback2_t commit_callback,
+                        void *commit_baton,
                         apr_hash_t *lock_tokens,
                         svn_boolean_t keep_locks,
                         svn_ra__provide_base_cb_t provide_base_cb,
@@ -108,7 +149,7 @@ svn_ra__use_commit_shim(svn_editor_t **e
   /* Fetch the RA provider's Ev1 commit editor.  */
   SVN_ERR(session->vtable->get_commit_editor(session, &deditor, &dedit_baton,
                                              revprop_table,
-                                             callback, callback_baton,
+                                             commit_callback, commit_baton,
                                              lock_tokens, keep_locks,
                                              result_pool));
 
@@ -173,3 +214,126 @@ svn_ra__use_commit_shim(svn_editor_t **e
 
   return SVN_NO_ERROR;
 }
+
+
+struct wrapped_replay_baton_t {
+  svn_ra__replay_revstart_ev2_callback_t revstart_func;
+  svn_ra__replay_revfinish_ev2_callback_t revfinish_func;
+  void *replay_baton;
+
+  svn_ra_session_t *session;
+
+  svn_ra__provide_base_cb_t provide_base_cb;
+  svn_ra__provide_props_cb_t provide_props_cb;
+  void *cb_baton;
+
+  /* This will be populated by the revstart wrapper. */
+  svn_editor_t *editor;
+};
+
+static svn_error_t *
+revstart_func_wrapper(svn_revnum_t revision,
+                      void *replay_baton,
+                      const svn_delta_editor_t **deditor,
+                      void **dedit_baton,
+                      apr_hash_t *rev_props,
+                      apr_pool_t *result_pool)
+{
+  struct wrapped_replay_baton_t *wrb = replay_baton;
+  const char *repos_root;
+  const char *session_url;
+  const char *base_relpath;
+  svn_boolean_t *found_abs_paths;
+  struct fp_baton *fpb;
+  struct svn_delta__extra_baton *exb;
+
+  /* Get the Ev2 editor from the original revstart func. */
+  SVN_ERR(wrb->revstart_func(revision, wrb->replay_baton, &wrb->editor,
+                             rev_props, result_pool));
+
+  /* Get or calculate the appropriate repos root and base relpath. */
+  SVN_ERR(svn_ra_get_repos_root2(wrb->session, &repos_root, result_pool));
+  SVN_ERR(svn_ra_get_session_url(wrb->session, &session_url, result_pool));
+  base_relpath = svn_uri_skip_ancestor(repos_root, session_url, result_pool);
+
+  /* We will assume that when the underlying Ev1 editor is finally driven
+     by the shim, that we will not need to prepend "/" to the paths. Place
+     this on the heap because it is examined much later. Set to FALSE.  */
+  found_abs_paths = apr_pcalloc(result_pool, sizeof(*found_abs_paths));
+
+  /* The PROVIDE_PROPS_CB callback does not match what the shims want.
+     Let's jigger things around a little bit here.  */
+  fpb = apr_palloc(result_pool, sizeof(*fpb));
+  fpb->provide_props_cb = wrb->provide_props_cb;
+  fpb->cb_baton = wrb->cb_baton;
+
+  /* Create the extra baton. */
+  exb = apr_pcalloc(result_pool, sizeof(*exb));
+
+  /* Create the Ev1 editor from the Ev2 editor provided by the RA layer.
+
+     Note: GET_COPYSRC_KIND_CB is compatible in type/semantics with the
+     shim's FETCH_KIND_FUNC parameter.  */
+  SVN_ERR(svn_delta__delta_from_editor(deditor, dedit_baton, wrb->editor,
+                                       NULL, NULL,
+                                       found_abs_paths,
+                                       repos_root, base_relpath,
+                                       fetch_props, wrb->cb_baton,
+                                       fetch_base, wrb->cb_baton,
+                                       exb, result_pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+revfinish_func_wrapper(svn_revnum_t revision,
+                       void *replay_baton,
+                       const svn_delta_editor_t *editor,
+                       void *edit_baton,
+                       apr_hash_t *rev_props,
+                       apr_pool_t *pool)
+{
+  struct wrapped_replay_baton_t *wrb = replay_baton;
+
+  SVN_ERR(wrb->revfinish_func(revision, replay_baton, wrb->editor, rev_props,
+                              pool));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_ra__use_replay_range_shim(svn_ra_session_t *session,
+                              svn_revnum_t start_revision,
+                              svn_revnum_t end_revision,
+                              svn_revnum_t low_water_mark,
+                              svn_boolean_t send_deltas,
+                              svn_ra__replay_revstart_ev2_callback_t revstart_func,
+                              svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+                              void *replay_baton,
+                              svn_ra__provide_base_cb_t provide_base_cb,
+                              svn_ra__provide_props_cb_t provide_props_cb,
+                              void *cb_baton,
+                              apr_pool_t *scratch_pool)
+{
+  /* The basic strategy here is to wrap the callback start and finish
+     functions to appropriately return an Ev1 editor which is itself wrapped
+     from the Ev2 one the provided callbacks will give us. */
+
+  struct wrapped_replay_baton_t *wrb = apr_pcalloc(scratch_pool, sizeof(*wrb));
+
+  wrb->revstart_func = revstart_func;
+  wrb->revfinish_func = revfinish_func;
+  wrb->replay_baton = replay_baton;
+  wrb->session = session;
+
+  wrb->provide_base_cb = provide_base_cb;
+  wrb->provide_props_cb = provide_props_cb;
+  wrb->cb_baton = cb_baton;
+
+  return svn_error_trace(svn_ra_replay_range(session, start_revision,
+                                             end_revision, low_water_mark,
+                                             send_deltas,
+                                             revstart_func_wrapper,
+                                             revfinish_func_wrapper,
+                                             wrb, scratch_pool));
+}

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.c Tue Oct 30 20:03:28 2012
@@ -43,8 +43,12 @@
 #include "svn_xml.h"
 #include "svn_path.h"
 #include "svn_dso.h"
+#include "svn_props.h"
+#include "svn_sorts.h"
+
 #include "svn_config.h"
 #include "ra_loader.h"
+#include "deprecated.h"
 
 #include "private/svn_ra_private.h"
 #include "svn_private_config.h"
@@ -75,7 +79,7 @@ static const struct ra_lib_defn {
     svn_schemes,
 #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
     svn_ra_svn__init,
-    svn_ra_svn_init
+    svn_ra_svn__deprecated_init
 #endif
   },
 
@@ -84,7 +88,7 @@ static const struct ra_lib_defn {
     local_schemes,
 #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_LOCAL
     svn_ra_local__init,
-    svn_ra_local_init
+    svn_ra_local__deprecated_init
 #endif
   },
 
@@ -93,7 +97,7 @@ static const struct ra_lib_defn {
     dav_schemes,
 #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SERF
     svn_ra_serf__init,
-    svn_ra_serf_init
+    svn_ra_serf__deprecated_init
 #endif
   },
 
@@ -466,6 +470,8 @@ svn_error_t *svn_ra_open4(svn_ra_session
 
   /* Create the session object. */
   session = apr_pcalloc(sesspool, sizeof(*session));
+  session->cancel_func = callbacks->cancel_func;
+  session->cancel_baton = callback_baton;
   session->vtable = vtable;
   session->pool = sesspool;
 
@@ -577,22 +583,6 @@ svn_error_t *svn_ra_get_path_relative_to
   return SVN_NO_ERROR;
 }
 
-svn_error_t *
-svn_ra__get_fspath_relative_to_root(svn_ra_session_t *ra_session,
-                                    const char **fspath,
-                                    const char *url,
-                                    apr_pool_t *pool)
-{
-  const char *relpath;
-
-  SVN_ERR(svn_ra_get_path_relative_to_root(ra_session, &relpath, url, pool));
-  if (*relpath)
-    *fspath = apr_pstrcat(pool, "/", relpath, (char *)NULL);
-  else
-    *fspath = "/";
-  return SVN_NO_ERROR;
-}
-
 svn_error_t *svn_ra_get_latest_revnum(svn_ra_session_t *session,
                                       svn_revnum_t *latest_revnum,
                                       apr_pool_t *pool)
@@ -719,19 +709,19 @@ svn_error_t *svn_ra_get_commit_editor3(s
                                        const svn_delta_editor_t **editor,
                                        void **edit_baton,
                                        apr_hash_t *revprop_table,
-                                       svn_commit_callback2_t callback,
-                                       void *callback_baton,
+                                       svn_commit_callback2_t commit_callback,
+                                       void *commit_baton,
                                        apr_hash_t *lock_tokens,
                                        svn_boolean_t keep_locks,
                                        apr_pool_t *pool)
 {
-  remap_commit_callback(&callback, &callback_baton,
-                        session, callback, callback_baton,
+  remap_commit_callback(&commit_callback, &commit_baton,
+                        session, commit_callback, commit_baton,
                         pool);
 
   return session->vtable->get_commit_editor(session, editor, edit_baton,
                                             revprop_table,
-                                            callback, callback_baton,
+                                            commit_callback, commit_baton,
                                             lock_tokens, keep_locks, pool);
 }
 
@@ -748,19 +738,6 @@ svn_error_t *svn_ra_get_file(svn_ra_sess
                                    fetched_rev, props, pool);
 }
 
-svn_error_t *svn_ra_get_dir(svn_ra_session_t *session,
-                            const char *path,
-                            svn_revnum_t revision,
-                            apr_hash_t **dirents,
-                            svn_revnum_t *fetched_rev,
-                            apr_hash_t **props,
-                            apr_pool_t *pool)
-{
-  SVN_ERR_ASSERT(*path != '/');
-  return session->vtable->get_dir(session, dirents, fetched_rev, props,
-                                  path, revision, SVN_DIRENT_ALL, pool);
-}
-
 svn_error_t *svn_ra_get_dir2(svn_ra_session_t *session,
                              apr_hash_t **dirents,
                              svn_revnum_t *fetched_rev,
@@ -1155,6 +1132,47 @@ svn_ra__replay_ev2(svn_ra_session_t *ses
   SVN__NOT_IMPLEMENTED();
 }
 
+static svn_error_t *
+replay_range_from_replays(svn_ra_session_t *session,
+                          svn_revnum_t start_revision,
+                          svn_revnum_t end_revision,
+                          svn_revnum_t low_water_mark,
+                          svn_boolean_t text_deltas,
+                          svn_ra_replay_revstart_callback_t revstart_func,
+                          svn_ra_replay_revfinish_callback_t revfinish_func,
+                          void *replay_baton,
+                          apr_pool_t *scratch_pool)
+{
+  apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  svn_revnum_t rev;
+
+  for (rev = start_revision ; rev <= end_revision ; rev++)
+    {
+      const svn_delta_editor_t *editor;
+      void *edit_baton;
+      apr_hash_t *rev_props;
+
+      svn_pool_clear(iterpool);
+
+      SVN_ERR(svn_ra_rev_proplist(session, rev, &rev_props, iterpool));
+
+      SVN_ERR(revstart_func(rev, replay_baton,
+                            &editor, &edit_baton,
+                            rev_props,
+                            iterpool));
+      SVN_ERR(svn_ra_replay(session, rev, low_water_mark,
+                            text_deltas, editor, edit_baton,
+                            iterpool));
+      SVN_ERR(revfinish_func(rev, replay_baton,
+                             editor, edit_baton,
+                             rev_props,
+                             iterpool));
+    }
+  svn_pool_destroy(iterpool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_ra_replay_range(svn_ra_session_t *session,
                     svn_revnum_t start_revision,
@@ -1172,40 +1190,17 @@ svn_ra_replay_range(svn_ra_session_t *se
                                   revstart_func, revfinish_func,
                                   replay_baton, pool);
 
-  if (err && (err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED))
-    {
-      apr_pool_t *subpool = svn_pool_create(pool);
-      svn_revnum_t rev;
-
-      svn_error_clear(err);
-      err = SVN_NO_ERROR;
-
-      for (rev = start_revision ; rev <= end_revision ; rev++)
-        {
-          const svn_delta_editor_t *editor;
-          void *edit_baton;
-          apr_hash_t *rev_props;
-
-          svn_pool_clear(subpool);
-
-          SVN_ERR(svn_ra_rev_proplist(session, rev, &rev_props, subpool));
-
-          SVN_ERR(revstart_func(rev, replay_baton,
-                                &editor, &edit_baton,
-                                rev_props,
-                                subpool));
-          SVN_ERR(svn_ra_replay(session, rev, low_water_mark,
-                                text_deltas, editor, edit_baton,
-                                subpool));
-          SVN_ERR(revfinish_func(rev, replay_baton,
-                                 editor, edit_baton,
-                                 rev_props,
-                                 subpool));
-        }
-      svn_pool_destroy(subpool);
-    }
+  if (!err || (err && (err->apr_err != SVN_ERR_RA_NOT_IMPLEMENTED)))
+    return svn_error_trace(err);
 
-  return err;
+  svn_error_clear(err);
+  return svn_error_trace(replay_range_from_replays(session, start_revision,
+                                                   end_revision,
+                                                   low_water_mark,
+                                                   text_deltas,
+                                                   revstart_func,
+                                                   revfinish_func,
+                                                   replay_baton, pool));
 }
 
 svn_error_t *
@@ -1217,9 +1212,38 @@ svn_ra__replay_range_ev2(svn_ra_session_
                          svn_ra__replay_revstart_ev2_callback_t revstart_func,
                          svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
                          void *replay_baton,
+                         svn_ra__provide_base_cb_t provide_base_cb,
+                         svn_ra__provide_props_cb_t provide_props_cb,
+                         svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
+                         void *cb_baton,
                          apr_pool_t *scratch_pool)
 {
-  SVN__NOT_IMPLEMENTED();
+  if (session->vtable->replay_range_ev2 == NULL)
+    {
+      /* The specific RA layer does not have an implementation. Use our
+         default shim over the normal replay editor.  */
+
+      /* This will call the Ev1 replay range handler with modified
+         callbacks. */
+      return svn_error_trace(svn_ra__use_replay_range_shim(
+                                session,
+                                start_revision,
+                                end_revision,
+                                low_water_mark,
+                                send_deltas,
+                                revstart_func,
+                                revfinish_func,
+                                replay_baton,
+                                provide_base_cb,
+                                provide_props_cb,
+                                cb_baton,
+                                scratch_pool));
+    }
+
+  return svn_error_trace(session->vtable->replay_range_ev2(
+                            session, start_revision, end_revision,
+                            low_water_mark, send_deltas, revstart_func,
+                            revfinish_func, replay_baton, scratch_pool));
 }
 
 svn_error_t *svn_ra_has_capability(svn_ra_session_t *session,
@@ -1269,21 +1293,51 @@ svn_ra_get_deleted_rev(svn_ra_session_t 
   return err;
 }
 
+svn_error_t *
+svn_ra_get_inherited_props(svn_ra_session_t *session,
+                           apr_array_header_t **iprops,
+                           const char *path,
+                           svn_revnum_t revision,
+                           apr_pool_t *result_pool,
+                           apr_pool_t *scratch_pool)
+{
+  svn_boolean_t iprop_capable;
+
+  /* Path must be relative. */
+  SVN_ERR_ASSERT(*path != '/');
+
+  SVN_ERR(svn_ra_has_capability(session, &iprop_capable,
+                                SVN_RA_CAPABILITY_INHERITED_PROPS,
+                                scratch_pool));
+
+  if (iprop_capable)
+    {
+      SVN_ERR(session->vtable->get_inherited_props(session, iprops, path,
+                                                   revision, result_pool,
+                                                   scratch_pool));
+    }
+  else
+    {
+      /* Fallback for legacy servers. */
+      SVN_ERR(svn_ra__get_inherited_props_walk(session, path, revision, iprops,
+                                               result_pool, scratch_pool));
+    }
+
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_ra__get_commit_ev2(svn_editor_t **editor,
                        svn_ra_session_t *session,
                        apr_hash_t *revprop_table,
-                       svn_commit_callback2_t callback,
-                       void *callback_baton,
+                       svn_commit_callback2_t commit_callback,
+                       void *commit_baton,
                        apr_hash_t *lock_tokens,
                        svn_boolean_t keep_locks,
                        svn_ra__provide_base_cb_t provide_base_cb,
                        svn_ra__provide_props_cb_t provide_props_cb,
                        svn_ra__get_copysrc_kind_cb_t get_copysrc_kind_cb,
                        void *cb_baton,
-                       svn_cancel_func_t cancel_func,
-                       void *cancel_baton,
                        apr_pool_t *result_pool,
                        apr_pool_t *scratch_pool)
 {
@@ -1293,22 +1347,22 @@ svn_ra__get_commit_ev2(svn_editor_t **ed
          default shim over the normal commit editor.  */
 
       /* Remap for RA layers exposing Ev1.  */
-      remap_commit_callback(&callback, &callback_baton,
-                            session, callback, callback_baton,
+      remap_commit_callback(&commit_callback, &commit_baton,
+                            session, commit_callback, commit_baton,
                             result_pool);
 
       return svn_error_trace(svn_ra__use_commit_shim(
                                editor,
                                session,
                                revprop_table,
-                               callback, callback_baton,
+                               commit_callback, commit_baton,
                                lock_tokens,
                                keep_locks,
                                provide_base_cb,
                                provide_props_cb,
                                get_copysrc_kind_cb,
                                cb_baton,
-                               cancel_func, cancel_baton,
+                               session->cancel_func, session->cancel_baton,
                                result_pool, scratch_pool));
     }
 
@@ -1319,17 +1373,16 @@ svn_ra__get_commit_ev2(svn_editor_t **ed
                            editor,
                            session,
                            revprop_table,
-                           callback, callback_baton,
+                           commit_callback, commit_baton,
                            lock_tokens,
                            keep_locks,
                            provide_base_cb,
                            provide_props_cb,
                            get_copysrc_kind_cb,
                            cb_baton,
-                           cancel_func, cancel_baton,
+                           session->cancel_func, session->cancel_baton,
                            result_pool, scratch_pool));
 }
-
 
 
 svn_error_t *
@@ -1470,16 +1523,6 @@ svn_ra_get_ra_library(svn_ra_plugin_t **
    implementation for svn_ra_foo_init which returns a "not implemented"
    error. */
 
-#ifndef SVN_LIBSVN_CLIENT_LINKS_RA_NEON
-svn_error_t *
-svn_ra_dav_init(int abi_version,
-                apr_pool_t *pool,
-                apr_hash_t *hash)
-{
-  return svn_error_create(SVN_ERR_RA_NOT_IMPLEMENTED, NULL, NULL);
-}
-#endif /* ! SVN_LIBSVN_CLIENT_LINKS_RA_NEON */
-
 #ifndef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
 svn_error_t *
 svn_ra_svn_init(int abi_version,

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.h?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra/ra_loader.h Tue Oct 30 20:03:28 2012
@@ -299,7 +299,13 @@ typedef struct svn_ra__vtable_t {
   /* See svn_ra__register_editor_shim_callbacks() */
   svn_error_t *(*register_editor_shim_callbacks)(svn_ra_session_t *session,
                                     svn_delta_shim_callbacks_t *callbacks);
-
+  /* See svn_ra_get_inherited_props(). */
+  svn_error_t *(*get_inherited_props)(svn_ra_session_t *session,
+                                      apr_array_header_t **iprops,
+                                      const char *path,
+                                      svn_revnum_t revision,
+                                      apr_pool_t *result_pool,
+                                      apr_pool_t *scratch_pool);
   /* See svn_ra__get_commit_ev2()  */
   svn_error_t *(*get_commit_ev2)(
     svn_editor_t **editor,
@@ -318,12 +324,28 @@ typedef struct svn_ra__vtable_t {
     apr_pool_t *result_pool,
     apr_pool_t *scratch_pool);
 
+  /* See svn_ra__replay_range_ev2() */
+  svn_error_t *(*replay_range_ev2)(
+    svn_ra_session_t *session,
+    svn_revnum_t start_revision,
+    svn_revnum_t end_revision,
+    svn_revnum_t low_water_mark,
+    svn_boolean_t send_deltas,
+    svn_ra__replay_revstart_ev2_callback_t revstart_func,
+    svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+    void *replay_baton,
+    apr_pool_t *scratch_pool);
+
 } svn_ra__vtable_t;
 
 /* The RA session object. */
 struct svn_ra_session_t {
   const svn_ra__vtable_t *vtable;
 
+  /* Cancellation handlers consumers may want to use. */
+  svn_cancel_func_t cancel_func;
+  void *cancel_baton;
+
   /* Pool used to manage this session. */
   apr_pool_t *pool;
 
@@ -473,6 +495,21 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
                                  apr_pool_t *pool);
 
 
+/**
+ * Fallback logic for svn_ra_get_fileX and svn_ra_get_dirX when those APIs
+ * need to find PATH's inherited properties on a legacy server that
+ * doesn't have the SVN_RA_CAPABILITY_INHERITED_PROPS capability.
+ *
+ * All arguments are as per the two aforementioned APIs.
+ */
+svn_error_t *
+svn_ra__get_inherited_props_walk(svn_ra_session_t *session,
+                                 const char *path,
+                                 svn_revnum_t revision,
+                                 apr_array_header_t **inherited_props,
+                                 apr_pool_t *result_pool,
+                                 apr_pool_t *scratch_pool);
+
 /* Utility function to provide a shim between a returned Ev2 and an RA
    provider's Ev1-based commit editor.
 
@@ -494,6 +531,24 @@ svn_ra__use_commit_shim(svn_editor_t **e
                         apr_pool_t *result_pool,
                         apr_pool_t *scratch_pool);
 
+/* Utility function to provide a shim between a returned Ev2 and an RA
+   provider's Ev1-based commit editor.
+
+   See svn_ra__replay_range_ev2() for parameter semantics.  */
+svn_error_t *
+svn_ra__use_replay_range_shim(svn_ra_session_t *session,
+                              svn_revnum_t start_revision,
+                              svn_revnum_t end_revision,
+                              svn_revnum_t low_water_mark,
+                              svn_boolean_t send_deltas,
+                              svn_ra__replay_revstart_ev2_callback_t revstart_func,
+                              svn_ra__replay_revfinish_ev2_callback_t revfinish_func,
+                              void *replay_baton,
+                              svn_ra__provide_base_cb_t provide_base_cb,
+                              svn_ra__provide_props_cb_t provide_props_cb,
+                              void *cb_baton,
+                              apr_pool_t *scratch_pool);
+
 
 #ifdef __cplusplus
 }

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_local/ra_plugin.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_local/ra_plugin.c Tue Oct 30 20:03:28 2012
@@ -337,7 +337,7 @@ make_reporter(svn_ra_session_t *session,
                                               pool));
 
   /* Build a reporter baton. */
-  SVN_ERR(svn_repos_begin_report2(&rbaton,
+  SVN_ERR(svn_repos_begin_report3(&rbaton,
                                   revision,
                                   sess->repos,
                                   sess->fs_path->data,
@@ -351,6 +351,8 @@ make_reporter(svn_ra_session_t *session,
                                   edit_baton,
                                   NULL,
                                   NULL,
+                                  1024 * 1024,  /* process-local transfers
+                                                   should be fast */
                                   pool));
 
   /* Wrap the report baton given us by the repos layer with our own
@@ -752,6 +754,8 @@ svn_ra_local__get_commit_editor(svn_ra_s
   revprop_table = apr_hash_copy(pool, revprop_table);
   apr_hash_set(revprop_table, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
                svn_string_create(sess->username, pool));
+  apr_hash_set(revprop_table, SVN_PROP_TXN_CLIENT_COMPAT_VERSION,
+               APR_HASH_KEY_STRING, svn_string_create(SVN_VER_NUMBER, pool));
 
   /* Get the repos commit-editor */
   return svn_repos_get_commit_editor5
@@ -1038,41 +1042,70 @@ svn_ra_local__stat(svn_ra_session_t *ses
 
 static svn_error_t *
 get_node_props(apr_hash_t **props,
+               apr_array_header_t **inherited_props,
                svn_ra_local__session_baton_t *sess,
                svn_fs_root_t *root,
                const char *path,
-               apr_pool_t *pool)
+               apr_pool_t *result_pool,
+               apr_pool_t *scratch_pool)
 {
   svn_revnum_t cmt_rev;
   const char *cmt_date, *cmt_author;
 
   /* Create a hash with props attached to the fs node. */
-  SVN_ERR(svn_fs_node_proplist(props, root, path, pool));
+  if (props)
+    {
+      SVN_ERR(svn_fs_node_proplist(props, root, path, result_pool));
+    }
+
+  /* Turn FS-path keys into URLs. */
+  if (inherited_props)
+    {
+      int i;
+
+      SVN_ERR(svn_repos_fs_get_inherited_props(inherited_props, root, path,
+                                               NULL, NULL,
+                                               result_pool, scratch_pool));
+
+      for (i = 0; i < (*inherited_props)->nelts; i++)
+        {
+          svn_prop_inherited_item_t *i_props =
+            APR_ARRAY_IDX(*inherited_props, i, svn_prop_inherited_item_t *);
+          i_props->path_or_url = svn_path_url_add_component2(
+            sess->repos_url, i_props->path_or_url, result_pool);
+        }
+    }
 
   /* Now add some non-tweakable metadata to the hash as well... */
 
-  /* The so-called 'entryprops' with info about CR & friends. */
-  SVN_ERR(svn_repos_get_committed_info(&cmt_rev, &cmt_date,
-                                       &cmt_author, root, path, pool));
-
-  apr_hash_set(*props,
-               SVN_PROP_ENTRY_COMMITTED_REV,
-               APR_HASH_KEY_STRING,
-               svn_string_createf(pool, "%ld", cmt_rev));
-  apr_hash_set(*props,
-               SVN_PROP_ENTRY_COMMITTED_DATE,
-               APR_HASH_KEY_STRING,
-               cmt_date ? svn_string_create(cmt_date, pool) : NULL);
-  apr_hash_set(*props,
-               SVN_PROP_ENTRY_LAST_AUTHOR,
-               APR_HASH_KEY_STRING,
-               cmt_author ? svn_string_create(cmt_author, pool) : NULL);
-  apr_hash_set(*props,
-               SVN_PROP_ENTRY_UUID,
-               APR_HASH_KEY_STRING,
-               svn_string_create(sess->uuid, pool));
+  if (props)
+    {
+      /* The so-called 'entryprops' with info about CR & friends. */
+      SVN_ERR(svn_repos_get_committed_info(&cmt_rev, &cmt_date,
+                                           &cmt_author, root, path,
+                                           scratch_pool));
+
+      apr_hash_set(*props,
+                   SVN_PROP_ENTRY_COMMITTED_REV,
+                   APR_HASH_KEY_STRING,
+                   svn_string_createf(result_pool, "%ld", cmt_rev));
+      apr_hash_set(*props,
+                   SVN_PROP_ENTRY_COMMITTED_DATE,
+                   APR_HASH_KEY_STRING,
+                   cmt_date ? svn_string_create(cmt_date,
+                                                result_pool) : NULL);
+      apr_hash_set(*props,
+                   SVN_PROP_ENTRY_LAST_AUTHOR,
+                   APR_HASH_KEY_STRING,
+                   cmt_author ? svn_string_create(cmt_author,
+                                                  result_pool) : NULL);
+      apr_hash_set(*props,
+                   SVN_PROP_ENTRY_UUID,
+                   APR_HASH_KEY_STRING,
+                   svn_string_create(sess->uuid, result_pool));
 
-  /* We have no 'wcprops' in ra_local, but might someday. */
+      /* We have no 'wcprops' in ra_local, but might someday. */
+    }
 
   return SVN_NO_ERROR;
 }
@@ -1144,7 +1177,7 @@ svn_ra_local__get_file(svn_ra_session_t 
 
   /* Handle props if requested. */
   if (props)
-    SVN_ERR(get_node_props(props, sess, root, abs_path, pool));
+    SVN_ERR(get_node_props(props, NULL, sess, root, abs_path, pool, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1255,7 +1288,7 @@ svn_ra_local__get_dir(svn_ra_session_t *
 
   /* Handle props if requested. */
   if (props)
-    SVN_ERR(get_node_props(props, sess, root, abs_path, pool));
+    SVN_ERR(get_node_props(props, NULL, sess, root, abs_path, pool, pool));
 
   return SVN_NO_ERROR;
 }
@@ -1489,7 +1522,8 @@ svn_ra_local__has_capability(svn_ra_sess
       || strcmp(capability, SVN_RA_CAPABILITY_LOG_REVPROPS) == 0
       || strcmp(capability, SVN_RA_CAPABILITY_PARTIAL_REPLAY) == 0
       || strcmp(capability, SVN_RA_CAPABILITY_COMMIT_REVPROPS) == 0
-      || strcmp(capability, SVN_RA_CAPABILITY_ATOMIC_REVPROPS) == 0)
+      || strcmp(capability, SVN_RA_CAPABILITY_ATOMIC_REVPROPS) == 0
+      || strcmp(capability, SVN_RA_CAPABILITY_INHERITED_PROPS) == 0)
     {
       *has = TRUE;
     }
@@ -1533,6 +1567,44 @@ svn_ra_local__get_deleted_rev(svn_ra_ses
 }
 
 static svn_error_t *
+svn_ra_local__get_inherited_props(svn_ra_session_t *session,
+                                  apr_array_header_t **iprops,
+                                  const char *path,
+                                  svn_revnum_t revision,
+                                  apr_pool_t *result_pool,
+                                  apr_pool_t *scratch_pool)
+{
+  svn_fs_root_t *root;
+  svn_revnum_t youngest_rev;
+  svn_ra_local__session_baton_t *sess = session->priv;
+  const char *abs_path = svn_fspath__join(sess->fs_path->data, path,
+                                          scratch_pool);
+  svn_node_kind_t node_kind;
+
+  /* Open the revision's root. */
+  if (! SVN_IS_VALID_REVNUM(revision))
+    {
+      SVN_ERR(svn_fs_youngest_rev(&youngest_rev, sess->fs, scratch_pool));
+      SVN_ERR(svn_fs_revision_root(&root, sess->fs, youngest_rev,
+                                   scratch_pool));
+    }
+  else
+    {
+      SVN_ERR(svn_fs_revision_root(&root, sess->fs, revision, scratch_pool));
+    }
+
+  SVN_ERR(svn_fs_check_path(&node_kind, root, abs_path, scratch_pool));
+  if (node_kind == svn_node_none)
+    {
+      return svn_error_createf(SVN_ERR_FS_NOT_FOUND, NULL,
+                               _("'%s' path not found"), abs_path);
+    }
+
+  return svn_error_trace(get_node_props(NULL, iprops, sess, root, abs_path,
+                                        result_pool, scratch_pool));
+}
+
+static svn_error_t *
 svn_ra_local__register_editor_shim_callbacks(svn_ra_session_t *session,
                                     svn_delta_shim_callbacks_t *callbacks)
 {
@@ -1645,6 +1717,7 @@ static const svn_ra__vtable_t ra_local_v
   svn_ra_local__replay_range,
   svn_ra_local__get_deleted_rev,
   svn_ra_local__register_editor_shim_callbacks,
+  svn_ra_local__get_inherited_props,
   svn_ra_local__get_commit_ev2
 };
 

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_serf/commit.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_serf/commit.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_serf/commit.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_serf/commit.c Tue Oct 30 20:03:28 2012
@@ -1983,7 +1983,8 @@ apply_textdelta(void *file_baton,
   ctx->stream = svn_stream_create(ctx, pool);
   svn_stream_set_write(ctx->stream, svndiff_stream_write);
 
-  svn_txdelta_to_svndiff2(handler, handler_baton, ctx->stream, 0, pool);
+  svn_txdelta_to_svndiff3(handler, handler_baton, ctx->stream, 0,
+                          SVN_DELTA_COMPRESSION_LEVEL_DEFAULT, pool);
 
   if (base_checksum)
     ctx->base_checksum = apr_pstrdup(ctx->pool, base_checksum);
@@ -2113,7 +2114,7 @@ close_file(void *file_baton,
         {
           handler->body_delegate = create_put_body;
           handler->body_delegate_baton = ctx;
-          handler->body_type = "application/vnd.svn-svndiff";
+          handler->body_type = SVN_SVNDIFF_MIME_TYPE;
         }
 
       handler->header_delegate = setup_put_headers;
@@ -2269,6 +2270,7 @@ svn_ra_serf__get_commit_editor(svn_ra_se
   apr_hash_index_t *hi;
   const char *repos_root;
   const char *base_relpath;
+  svn_boolean_t supports_ephemeral_props;
 
   ctx = apr_pcalloc(pool, sizeof(*ctx));
 
@@ -2289,6 +2291,23 @@ svn_ra_serf__get_commit_editor(svn_ra_se
                    svn_string_dup(val, pool));
     }
 
+  /* If the server supports ephemeral properties, add some carrying
+     interesting version information. */
+  SVN_ERR(svn_ra_serf__has_capability(ra_session, &supports_ephemeral_props,
+                                      SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
+                                      pool));
+  if (supports_ephemeral_props)
+    {
+      apr_hash_set(ctx->revprop_table,
+                   apr_pstrdup(pool, SVN_PROP_TXN_CLIENT_COMPAT_VERSION),
+                   APR_HASH_KEY_STRING,
+                   svn_string_create(SVN_VER_NUMBER, pool));
+      apr_hash_set(ctx->revprop_table,
+                   apr_pstrdup(pool, SVN_PROP_TXN_USER_AGENT),
+                   APR_HASH_KEY_STRING,
+                   svn_string_create(session->useragent, pool));
+    }
+
   ctx->callback = callback;
   ctx->callback_baton = callback_baton;
 

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_serf/options.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_serf/options.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_serf/options.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_serf/options.c Tue Oct 30 20:03:28 2012
@@ -199,6 +199,18 @@ capabilities_headers_iterator_callback(v
                        SVN_RA_CAPABILITY_PARTIAL_REPLAY, APR_HASH_KEY_STRING,
                        capability_yes);
         }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_INHERITED_PROPS, vals))
+        {
+          apr_hash_set(session->capabilities,
+                       SVN_RA_CAPABILITY_INHERITED_PROPS,
+                       APR_HASH_KEY_STRING, capability_yes);
+        }
+      if (svn_cstring_match_list(SVN_DAV_NS_DAV_SVN_EPHEMERAL_TXNPROPS, vals))
+        {
+          apr_hash_set(session->capabilities,
+                       SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS, APR_HASH_KEY_STRING,
+                       capability_yes);
+        }
     }
 
   /* SVN-specific headers -- if present, server supports HTTP protocol v2 */
@@ -317,6 +329,10 @@ options_response_handler(serf_request_t 
                    APR_HASH_KEY_STRING, capability_no);
       apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_ATOMIC_REVPROPS,
                    APR_HASH_KEY_STRING, capability_no);
+      apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_INHERITED_PROPS,
+                   APR_HASH_KEY_STRING, capability_no);
+      apr_hash_set(session->capabilities, SVN_RA_CAPABILITY_EPHEMERAL_TXNPROPS,
+                   APR_HASH_KEY_STRING, capability_no);
 
       /* Then see which ones we can discover. */
       serf_bucket_headers_do(hdrs, capabilities_headers_iterator_callback,
@@ -325,7 +341,7 @@ options_response_handler(serf_request_t 
       opt_ctx->headers_processed = TRUE;
     }
 
-  /* Execute the 'real' response handler to XML-parse the repsonse body. */
+  /* Execute the 'real' response handler to XML-parse the response body. */
   return opt_ctx->inner_handler(request, response, opt_ctx->inner_baton, pool);
 }
 

Modified: subversion/branches/master-passphrase/subversion/libsvn_ra_serf/property.c
URL: http://svn.apache.org/viewvc/subversion/branches/master-passphrase/subversion/libsvn_ra_serf/property.c?rev=1403849&r1=1403848&r2=1403849&view=diff
==============================================================================
--- subversion/branches/master-passphrase/subversion/libsvn_ra_serf/property.c (original)
+++ subversion/branches/master-passphrase/subversion/libsvn_ra_serf/property.c Tue Oct 30 20:03:28 2012
@@ -322,16 +322,11 @@ propfind_closed(svn_ra_serf__xml_estate_
   else
     {
       apr_hash_t *gathered;
-      const char *path;
 
       SVN_ERR_ASSERT(leaving_state == PROPSTAT);
 
       gathered = svn_ra_serf__xml_gather_since(xes, PROPSTAT);
 
-      path = apr_hash_get(gathered, "path", APR_HASH_KEY_STRING);
-      if (path == NULL)
-        path = ctx->path;
-
       /* If we've squirreled away a note that says we want to ignore
          these properties, we'll do so.  Otherwise, we need to copy
          them from the temporary hash into the ctx->ret_props hash. */



Mime
View raw message