You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by br...@apache.org on 2012/08/16 12:18:03 UTC

svn commit: r1373783 [16/50] - in /subversion/branches/compressed-pristines: ./ build/ build/ac-macros/ build/generator/ build/generator/templates/ build/win32/ contrib/client-side/emacs/ contrib/client-side/svn-push/ contrib/client-side/svnmerge/ cont...

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/fs_fs.h
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/fs_fs.h?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/fs_fs.h (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/fs_fs.h Thu Aug 16 10:17:48 2012
@@ -131,8 +131,9 @@ svn_error_t *svn_fs_fs__rep_contents_dir
                                          apr_pool_t *pool);
 
 /* Set *DIRENT to the entry identified by NAME in the directory given
-   by NODEREV in filesystem FS.  The returned object is allocated in
-   RESULT_POOL; SCRATCH_POOL used for temporary allocations. */
+   by NODEREV in filesystem FS.  If no such entry exits, *DIRENT will
+   be NULL. The returned object is allocated in RESULT_POOL; SCRATCH_POOL
+   used for temporary allocations. */
 svn_error_t *
 svn_fs_fs__rep_contents_dir_entry(svn_fs_dirent_t **dirent,
                                   svn_fs_t *fs,
@@ -355,12 +356,6 @@ svn_error_t *svn_fs_fs__create(svn_fs_t 
                                const char *path,
                                apr_pool_t *pool);
 
-/* Store the uuid of the repository FS in *UUID.  Allocate space in
-   POOL. */
-svn_error_t *svn_fs_fs__get_uuid(svn_fs_t *fs,
-                                 const char **uuid,
-                                 apr_pool_t *pool);
-
 /* Set the uuid of repository FS to UUID, if UUID is not NULL;
    otherwise, set the uuid of FS to a newly generated UUID.  Perform
    temporary allocations in POOL. */

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/key-gen.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/key-gen.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/key-gen.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/key-gen.c Thu Aug 16 10:17:48 2012
@@ -60,7 +60,7 @@ svn_fs_fs__add_keys(const char *key1, co
       carry = val / 36;
       val = val % 36;
 
-      buf[i3++] = (val <= 9) ? (val + '0') : (val - 10 + 'a');
+      buf[i3++] = (char)((val <= 9) ? (val + '0') : (val - 10 + 'a'));
 
       if (i1>=0)
         i1--;
@@ -115,7 +115,7 @@ svn_fs_fs__next_key(const char *this, ap
               if (c == '9')
                 next[i] = 'a';
               else
-                next[i] = c + 1;
+                next[i] = ++c;
             }
         }
       else

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/lock.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/lock.c Thu Aug 16 10:17:48 2012
@@ -477,23 +477,31 @@ delete_lock(svn_fs_t *fs,
 
 /* Set *LOCK_P to the lock for PATH in FS.  HAVE_WRITE_LOCK should be
    TRUE if the caller (or one of its callers) has taken out the
-   repository-wide write lock, FALSE otherwise.  Use POOL for
-   allocations. */
+   repository-wide write lock, FALSE otherwise.  If MUST_EXIST is
+   not set, the function will simply return NULL in *LOCK_P instead
+   of creating an SVN_FS__ERR_NO_SUCH_LOCK error in case the lock
+   was not found (much faster).  Use POOL for allocations. */
 static svn_error_t *
 get_lock(svn_lock_t **lock_p,
          svn_fs_t *fs,
          const char *path,
          svn_boolean_t have_write_lock,
+         svn_boolean_t must_exist,
          apr_pool_t *pool)
 {
-  svn_lock_t *lock;
+  svn_lock_t *lock = NULL;
   const char *digest_path;
+  svn_node_kind_t kind;
 
   SVN_ERR(digest_path_from_path(&digest_path, fs->path, path, pool));
+  SVN_ERR(svn_io_check_path(digest_path, &kind, pool));
+
+  *lock_p = NULL;
+  if (kind != svn_node_none)
+    SVN_ERR(read_digest_file(NULL, &lock, fs->path, digest_path, pool));
 
-  SVN_ERR(read_digest_file(NULL, &lock, fs->path, digest_path, pool));
   if (! lock)
-    return SVN_FS__ERR_NO_SUCH_LOCK(fs, path, pool);
+    return must_exist ? SVN_FS__ERR_NO_SUCH_LOCK(fs, path) : SVN_NO_ERROR;
 
   /* Don't return an expired lock. */
   if (lock->expiration_date && (apr_time_now() > lock->expiration_date))
@@ -502,8 +510,7 @@ get_lock(svn_lock_t **lock_p,
          Read operations shouldn't change the filesystem. */
       if (have_write_lock)
         SVN_ERR(delete_lock(fs, lock, pool));
-      *lock_p = NULL;
-      return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token, pool);
+      return SVN_FS__ERR_LOCK_EXPIRED(fs, lock->token);
     }
 
   *lock_p = lock;
@@ -525,7 +532,7 @@ get_lock_helper(svn_fs_t *fs,
   svn_lock_t *lock;
   svn_error_t *err;
 
-  err = get_lock(&lock, fs, path, have_write_lock, pool);
+  err = get_lock(&lock, fs, path, have_write_lock, FALSE, pool);
 
   /* We've deliberately decided that this function doesn't tell the
      caller *why* the lock is unavailable.  */
@@ -648,7 +655,11 @@ walk_locks(svn_fs_t *fs,
            svn_boolean_t have_write_lock,
            apr_pool_t *pool)
 {
-  struct walk_locks_baton wlb = { get_locks_func, get_locks_baton, fs };
+  struct walk_locks_baton wlb;
+
+  wlb.get_locks_func = get_locks_func;
+  wlb.get_locks_baton = get_locks_baton;
+  wlb.fs = fs;
   SVN_ERR(walk_digest_files(fs->path, digest_path, locks_walker, &wlb,
                             have_write_lock, pool));
   return SVN_NO_ERROR;
@@ -766,7 +777,7 @@ lock_body(void *baton, apr_pool_t *pool)
   SVN_ERR(lb->fs->vtable->revision_root(&root, lb->fs, youngest, pool));
   SVN_ERR(svn_fs_fs__check_path(&kind, root, lb->path, pool));
   if (kind == svn_node_dir)
-    return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path, pool);
+    return SVN_FS__ERR_NOT_FILE(lb->fs, lb->path);
 
   /* While our locking implementation easily supports the locking of
      nonexistent paths, we deliberately choose not to allow such madness. */
@@ -786,7 +797,7 @@ lock_body(void *baton, apr_pool_t *pool)
 
   /* We need to have a username attached to the fs. */
   if (!lb->fs->access_ctx || !lb->fs->access_ctx->username)
-    return SVN_FS__ERR_NO_USER(lb->fs, pool);
+    return SVN_FS__ERR_NO_USER(lb->fs);
 
   /* Is the caller attempting to lock an out-of-date working file? */
   if (SVN_IS_VALID_REVNUM(lb->current_rev))
@@ -832,7 +843,7 @@ lock_body(void *baton, apr_pool_t *pool)
       if (! lb->steal_lock)
         {
           /* Sorry, the path is already locked. */
-          return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock, pool);
+          return SVN_FS__ERR_PATH_ALREADY_LOCKED(lb->fs, existing_lock);
         }
       else
         {
@@ -881,23 +892,23 @@ unlock_body(void *baton, apr_pool_t *poo
   svn_lock_t *lock;
 
   /* This could return SVN_ERR_FS_BAD_LOCK_TOKEN or SVN_ERR_FS_LOCK_EXPIRED. */
-  SVN_ERR(get_lock(&lock, ub->fs, ub->path, TRUE, pool));
+  SVN_ERR(get_lock(&lock, ub->fs, ub->path, TRUE, TRUE, pool));
 
   /* Unless breaking the lock, we do some checks. */
   if (! ub->break_lock)
     {
       /* Sanity check:  the incoming token should match lock->token. */
       if (strcmp(ub->token, lock->token) != 0)
-        return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path, pool);
+        return SVN_FS__ERR_NO_SUCH_LOCK(ub->fs, lock->path);
 
       /* There better be a username attached to the fs. */
       if (! (ub->fs->access_ctx && ub->fs->access_ctx->username))
-        return SVN_FS__ERR_NO_USER(ub->fs, pool);
+        return SVN_FS__ERR_NO_USER(ub->fs);
 
       /* And that username better be the same as the lock's owner. */
       if (strcmp(ub->fs->access_ctx->username, lock->owner) != 0)
         return SVN_FS__ERR_LOCK_OWNER_MISMATCH(
-           ub->fs, ub->fs->access_ctx->username, lock->owner, pool);
+           ub->fs, ub->fs->access_ctx->username, lock->owner);
     }
 
   /* Remove lock and lock token files. */

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache-db.sql
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache-db.sql?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache-db.sql (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache-db.sql Thu Aug 16 10:17:48 2012
@@ -41,25 +41,19 @@ SELECT revision, offset, size, expanded_
 FROM rep_cache
 WHERE hash = ?1
 
-
 -- STMT_SET_REP
 INSERT OR FAIL INTO rep_cache (hash, revision, offset, size, expanded_size)
 VALUES (?1, ?2, ?3, ?4, ?5)
 
-
 -- STMT_GET_REPS_FOR_RANGE
 SELECT hash, revision, offset, size, expanded_size
 FROM rep_cache
 WHERE revision >= ?1 AND revision <= ?2
 
-
 -- STMT_GET_MAX_REV
 SELECT MAX(revision)
 FROM rep_cache
 
-
 -- STMT_DEL_REPS_YOUNGER_THAN_REV
 DELETE FROM rep_cache
 WHERE revision > ?1
-
-

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/rep-cache.c Thu Aug 16 10:17:48 2012
@@ -158,11 +158,11 @@ svn_fs_fs__walk_rep_reference(svn_fs_t *
                                         STMT_GET_MAX_REV));
       SVN_ERR(svn_sqlite__step(&have_row, stmt2));
       max = svn_sqlite__column_revnum(stmt2, 0);
-      SVN_ERR(svn_fs_fs__revision_exists(max, fs, iterpool));
+      if (SVN_IS_VALID_REVNUM(max))  /* The rep-cache could be empty. */
+        SVN_ERR(svn_fs_fs__revision_exists(max, fs, iterpool));
       SVN_ERR(svn_sqlite__reset(stmt2));
     }
 
-  /* Get the statement. (There are no arguments to bind.) */
   SVN_ERR(svn_sqlite__get_statement(&stmt, ffd->rep_cache_db,
                                     STMT_GET_REPS_FOR_RANGE));
   SVN_ERR(svn_sqlite__bindf(stmt, "rr",

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/structure
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/structure?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/structure (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/structure Thu Aug 16 10:17:48 2012
@@ -40,6 +40,9 @@ repository) is:
   revprops/           Subdirectory containing rev-props
     <shard>/          Shard directory, if sharding is in use (see below)
       <revnum>        File containing rev-props for <revnum>
+    <shard>.pack/     Pack directory, if the repo has been packed (see below)
+      <rev>.<count>   Pack file, if the repository has been packed (see below)
+      manifest        Pack manifest file, if a pack file exists (see below)
     revprops.db       SQLite database of the packed revision properties
   transactions/       Subdirectory containing transactions
     <txnid>.txn/      Directory containing transaction <txnid>
@@ -134,6 +137,7 @@ The formats are:
   Format 3, understood by Subversion 1.5+
   Format 4, understood by Subversion 1.6+
   Format 5, understood by Subversion 1.7-dev, never released
+  Format 6, understood by Subversion 1.8
 
 The differences between the formats are:
 
@@ -173,6 +177,12 @@ Revision changed paths list:
   Format 1-3: Does not contain the node's kind.
   Format 4+:  Contains the node's kind.
 
+Shard packing:
+  Format 4:   Applied to revision data only.
+  Format 5:   Revprops would be packed independently of revision data.
+  Format 6+:  Applied equally to revision data and revprop data
+    (i.e. same min packed revision)
+
 # Incomplete list.  See SVN_FS_FS__MIN_*_FORMAT
 
 
@@ -232,6 +242,79 @@ See r1143829 of this file:
 http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/structure?view=markup&pathrev=1143829
 
 
+Packing revision properties (format 6+)
+---------------------------
+
+Similarly to the revision data, packing will concatenate multiple
+revprops into a single file.  Since they are mutable data, we put an
+upper limit to the size of these files:  We will concatenate the data
+up to the limit and then use a new file for the following revisions.
+
+The limit can be set and changed at will in the configuration file. 
+It is 64kB by default.  Because a pack file must contain at least one
+complete property list, files containing just one revision may exceed
+that limit.
+
+Furthermore, pack files can be compressed which saves about 75% of
+disk space.  A configuration file flag enables the compression; it is
+off by default and may be switched on and off at will.  The pack size
+limit is always applied to the uncompressed data.  For this reason,
+the default is 256kB while compression has been enabled.
+
+Files are named after their start revision as "<rev>.<counter>" where
+counter will be increased whenever we rewrite a pack file due to a
+revprop change.  The manifest file contains the list of pack file
+names, one line for each revision.
+
+Many tools track repository global data in revision properties at 
+revision 0.  To minimize I/O overhead for those applications,  we
+will never pack that revision, i.e. its data is always being kept
+in revprops/0/0.
+
+Pack file format
+
+  Top level: <length><packed container>
+
+  We always apply data compression to the pack file - using the
+  SVN_DELTA_COMPRESSION_LEVEL_NONE level if compression is disabled.
+  <length> is being encoded using the variable-length svndiff integer
+  format.
+
+  container := header '\n' (revprops)+
+  header    := start_rev '\n' rev_count '\n' (size '\n')+
+
+  All numbers in the header are given as ASCII decimals.  rev_count
+  is the number of revisions packed into this container.  There must
+  be exactly as many "size" and serialized "revprops".  The "size"
+  values in the list are the length in bytes of the serialized
+  revprops of the respective revision.
+
+Writing to packed revprops
+
+  The old pack file is being read and the new revprops serialized.
+  If they fit into the same pack file, a temp file with the new
+  content gets written and moved into place just like an non-packed
+  revprop file would. No name change or manifest update required.
+
+  If they don't fit into the same pack file,  i.e. exceed the pack
+  size limit,  the pack will be split into 2 or 3 new packs just
+  before and / or after the modified revision.
+
+  In the current implementation, they will never be merged again.
+  To minimize fragmentation, the initial packing process will only
+  use about 90% of the limit, i.e. leave some room for growth.
+
+  When a pack file gets split, its counter is being increased
+  creating a new file and leaving the old content in place and
+  available for concurrent readers.  Only after the new manifest
+  file got moved into place, will the old pack files be deleted. 
+
+  Write access to revprops is being serialized by the global
+  filesystem write lock.  We only need to build a few retries into
+  the reader code to gracefully handle manifest changes and pack
+  file deletions.
+
+
 Node-revision IDs
 -----------------
 

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/temp_serializer.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/temp_serializer.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/temp_serializer.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/temp_serializer.c Thu Aug 16 10:17:48 2012
@@ -30,6 +30,7 @@
 
 #include "private/svn_fs_util.h"
 #include "private/svn_temp_serializer.h"
+#include "private/svn_subr_private.h"
 
 #include "temp_serializer.h"
 
@@ -47,16 +48,16 @@ encode_number(apr_int64_t number, char *
   if (number < 0)
   {
     number = -number;
-    *key_buffer = (number & 63) + ' ' + 65;
+    *key_buffer = (char)((number & 63) + ' ' + 65);
   }
   else
-    *key_buffer = (number & 63) + ' ' + 1;
+    *key_buffer = (char)((number & 63) + ' ' + 1);
   number /= 64;
 
   /* write 7 bits / byte until no significant bits are left */
   while (number)
   {
-    *++key_buffer = (number & 127) + ' ' + 1;
+    *++key_buffer = (char)((number & 127) + ' ' + 1);
     number /= 128;
   }
 
@@ -359,7 +360,7 @@ serialize_dir(apr_hash_t *entries, apr_p
 static apr_hash_t *
 deserialize_dir(void *buffer, hash_data_t *hash_data, apr_pool_t *pool)
 {
-  apr_hash_t *result = apr_hash_make(pool);
+  apr_hash_t *result = svn_hash__make(pool);
   apr_size_t i;
   apr_size_t count;
   svn_fs_dirent_t *entry;
@@ -594,7 +595,7 @@ serialize_cstring_array(svn_temp_seriali
 {
   apr_size_t i;
   const char **entries = *strings;
-  
+
   /* serialize COUNT entries pointers (the array) */
   svn_temp_serializer__push(context,
                             (const void * const *)strings,
@@ -615,7 +616,7 @@ serialize_svn_string_array(svn_temp_seri
 {
   apr_size_t i;
   const svn_string_t **entries = *strings;
-  
+
   /* serialize COUNT entries pointers (the array) */
   svn_temp_serializer__push(context,
                             (const void * const *)strings,
@@ -645,14 +646,14 @@ svn_fs_fs__serialize_properties(void **d
   properties.count = apr_hash_count(hash);
   properties.keys = apr_palloc(pool, sizeof(const char*) * (properties.count + 1));
   properties.values = apr_palloc(pool, sizeof(const char*) * properties.count);
-  
+
   /* populate it with the hash entries */
   for (hi = apr_hash_first(pool, hash), i=0; hi; hi = apr_hash_next(hi), ++i)
     {
       properties.keys[i] = svn__apr_hash_index_key(hi);
       properties.values[i] = svn__apr_hash_index_val(hi);
     }
-  
+
   /* serialize it */
   context = svn_temp_serializer__init(&properties,
                                       sizeof(properties),
@@ -678,26 +679,26 @@ svn_fs_fs__deserialize_properties(void *
                                   apr_size_t data_len,
                                   apr_pool_t *pool)
 {
-  apr_hash_t *hash = apr_hash_make(pool);
+  apr_hash_t *hash = svn_hash__make(pool);
   properties_data_t *properties = (properties_data_t *)data;
   size_t i;
 
   /* de-serialize our auxilliary data structure */
   svn_temp_deserializer__resolve(properties, (void**)&properties->keys);
   svn_temp_deserializer__resolve(properties, (void**)&properties->values);
-  
+
   /* de-serialize each entry and put it into the hash */
   for (i = 0; i < properties->count; ++i)
     {
       apr_size_t len = properties->keys[i+1] - properties->keys[i] - 1;
-      svn_temp_deserializer__resolve(properties->keys, 
+      svn_temp_deserializer__resolve((void*)properties->keys,
                                      (void**)&properties->keys[i]);
-      
-      deserialize_svn_string(properties->values, 
+
+      deserialize_svn_string((void*)properties->values,
                              (svn_string_t **)&properties->values[i]);
-      
-      apr_hash_set(hash, 
-                   properties->keys[i], len, 
+
+      apr_hash_set(hash,
+                   properties->keys[i], len,
                    properties->values[i]);
     }
 
@@ -931,7 +932,7 @@ svn_fs_fs__extract_dir_entry(void **out,
           svn_temp_deserializer__ptr(entries, (const void *const *)&entries[pos]);
 
       /* Entries have been serialized one-by-one, each time including all
-       * nestes structures and strings. Therefore, they occupy a single
+       * nested structures and strings. Therefore, they occupy a single
        * block of memory whose end-offset is either the beginning of the
        * next entry or the end of the buffer
        */

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/tree.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/tree.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/tree.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_fs/tree.c Thu Aug 16 10:17:48 2012
@@ -155,7 +155,7 @@ locate_cache(svn_cache__t **cache,
     {
       fs_fs_data_t *ffd = root->fs->fsap_data;
       if (cache) *cache = ffd->rev_node_cache;
-      if (key && path) *key 
+      if (key && path) *key
         = svn_fs_fs__combine_number_and_string(root->rev, path, pool);
     }
 }
@@ -359,7 +359,7 @@ mutable_root_node(dag_node_t **node_p,
     return svn_fs_fs__dag_clone_root(node_p, root->fs, root->txn, pool);
   else
     /* If it's not a transaction root, we can't change its contents.  */
-    return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path, pool);
+    return SVN_FS__ERR_NOT_MUTABLE(root->fs, root->rev, error_path);
 }
 
 
@@ -696,7 +696,7 @@ open_path(parent_path_t **parent_path_p,
 
       /* The path isn't finished yet; we'd better be in a directory.  */
       if (svn_fs_fs__dag_node_kind(child) != svn_node_dir)
-        SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far, iterpool),
+        SVN_ERR_W(SVN_FS__ERR_NOT_DIRECTORY(fs, path_so_far),
                   apr_psprintf(iterpool, _("Failure opening '%s'"), path));
 
       rest = next;
@@ -1837,7 +1837,7 @@ fs_make_dir(svn_fs_root_t *root,
   /* If there's already a sub-directory by that name, complain.  This
      also catches the case of trying to make a subdirectory named `/'.  */
   if (parent_path->node)
-    return SVN_FS__ALREADY_EXISTS(root, path, pool);
+    return SVN_FS__ALREADY_EXISTS(root, path);
 
   /* Create the subdirectory.  */
   SVN_ERR(make_path_mutable(root, parent_path->parent, path, pool));
@@ -1925,17 +1925,7 @@ fs_same_p(svn_boolean_t *same_p,
           svn_fs_t *fs2,
           apr_pool_t *pool)
 {
-  const char *uuid1;
-  const char *uuid2;
-
-  /* Random thought: if fetching UUIDs to compare filesystems is too
-     expensive, one solution would be to cache the UUID in each fs
-     object (copying the UUID into fs->pool, of course). */
-
-  SVN_ERR(fs1->vtable->get_uuid(fs1, &uuid1, pool));
-  SVN_ERR(fs2->vtable->get_uuid(fs2, &uuid2, pool));
-
-  *same_p = ! strcmp(uuid1, uuid2);
+  *same_p = ! strcmp(fs1->uuid, fs2->uuid);
   return SVN_NO_ERROR;
 }
 
@@ -2182,7 +2172,7 @@ fs_make_file(svn_fs_root_t *root,
   /* If there's already a file by that name, complain.
      This also catches the case of trying to make a file named `/'.  */
   if (parent_path->node)
-    return SVN_FS__ALREADY_EXISTS(root, path, pool);
+    return SVN_FS__ALREADY_EXISTS(root, path);
 
   /* Check (non-recursively) to see if path is locked;  if so, check
      that we can use it. */
@@ -2468,17 +2458,8 @@ fs_apply_textdelta(svn_txdelta_window_ha
   tb->root = root;
   tb->path = path;
   tb->pool = pool;
-
-  if (base_checksum)
-    tb->base_checksum = svn_checksum_dup(base_checksum, pool);
-  else
-    tb->base_checksum = NULL;
-
-  if (result_checksum)
-    tb->result_checksum = svn_checksum_dup(result_checksum, pool);
-  else
-    tb->result_checksum = NULL;
-
+  tb->base_checksum = svn_checksum_dup(base_checksum, pool);
+  tb->result_checksum = svn_checksum_dup(result_checksum, pool);
 
   SVN_ERR(apply_textdelta(tb, pool));
 
@@ -2610,11 +2591,7 @@ fs_apply_text(svn_stream_t **contents_p,
   tb->root = root;
   tb->path = path;
   tb->pool = pool;
-
-  if (result_checksum)
-    tb->result_checksum = svn_checksum_dup(result_checksum, pool);
-  else
-    tb->result_checksum = NULL;
+  tb->result_checksum = svn_checksum_dup(result_checksum, pool);
 
   SVN_ERR(apply_text(tb, pool));
 
@@ -3749,7 +3726,8 @@ make_txn_root(svn_fs_root_t **root_p,
                                       svn_fs_fs__dag_deserialize,
                                       APR_HASH_KEY_STRING,
                                       32, 20, FALSE,
-                                      apr_pstrcat(pool, txn, ":TXN", (char *)NULL),
+                                      apr_pstrcat(pool, txn, ":TXN",
+                                                  (char *)NULL),
                                       root->pool));
 
   /* Initialize transaction-local caches in FS.
@@ -3816,8 +3794,9 @@ verify_node(dag_node_t *node,
         return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
                                  "Predecessor count mismatch: "
                                  "%s has %d, but %s has %d",
-                                 stringify_node(node, iterpool), pred_count, 
-                                 stringify_node(pred, iterpool), pred_pred_count);
+                                 stringify_node(node, iterpool), pred_count,
+                                 stringify_node(pred, iterpool),
+                                 pred_pred_count);
     }
 
   /* Kind-dependent verifications. */
@@ -3922,8 +3901,9 @@ svn_fs_fs__verify_root(svn_fs_root_t *ro
         if (pred_rev+1 != root->rev)
           /* Issue #4129. */
           return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL,
-                                   "r%ld's root node's predecessor is r%ld",
-                                   root->rev, pred_rev);
+                                   "r%ld's root node's predecessor is r%ld"
+                                   " but should be r%ld",
+                                   root->rev, pred_rev, root->rev - 1);
       }
   }
 

Modified: subversion/branches/compressed-pristines/subversion/libsvn_fs_util/fs-util.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_fs_util/fs-util.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_fs_util/fs-util.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_fs_util/fs-util.c Thu Aug 16 10:17:48 2012
@@ -163,7 +163,7 @@ svn_fs__append_to_merged_froms(svn_merge
   for (hi = apr_hash_first(pool, input); hi; hi = apr_hash_next(hi))
     {
       const char *path = svn__apr_hash_index_key(hi);
-      apr_array_header_t *rangelist = svn__apr_hash_index_val(hi);
+      svn_rangelist_t *rangelist = svn__apr_hash_index_val(hi);
 
       apr_hash_set(*output, svn_fspath__join(path, rel_path, pool),
                    APR_HASH_KEY_STRING, svn_rangelist_dup(rangelist, pool));

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra/compat.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra/compat.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra/compat.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra/compat.c Thu Aug 16 10:17:48 2012
@@ -757,8 +757,9 @@ svn_ra__file_revs_from_log(svn_ra_sessio
       /* Compute and send delta if client asked for it. */
       if (delta_handler)
         {
-          /* Get the content delta. */
-          svn_txdelta(&delta_stream, last_stream, stream, lastpool);
+          /* Get the content delta. Don't calculate checksums as we don't
+           * use them. */
+          svn_txdelta2(&delta_stream, last_stream, stream, FALSE, lastpool);
 
           /* And send. */
           SVN_ERR(svn_txdelta_send_txstream(delta_stream, delta_handler,

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra/debug_reporter.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra/debug_reporter.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra/debug_reporter.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra/debug_reporter.c Thu Aug 16 10:17:48 2012
@@ -95,7 +95,7 @@ finish_report(void *report_baton,
               apr_pool_t *pool)
 {
   struct report_baton *rb = report_baton;
-  SVN_ERR(svn_stream_printf(rb->out, pool, "finish_report()\n"));
+  SVN_ERR(svn_stream_puts(rb->out, "finish_report()\n"));
   SVN_ERR(rb->wrapped_reporter->finish_report(rb->wrapped_report_baton, pool));
   return SVN_NO_ERROR;
 }
@@ -105,7 +105,7 @@ abort_report(void *report_baton,
              apr_pool_t *pool)
 {
   struct report_baton *rb = report_baton;
-  SVN_ERR(svn_stream_printf(rb->out, pool, "abort_report()\n"));
+  SVN_ERR(svn_stream_puts(rb->out, "abort_report()\n"));
   SVN_ERR(rb->wrapped_reporter->abort_report(rb->wrapped_report_baton, pool));
   return SVN_NO_ERROR;
 }

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.c Thu Aug 16 10:17:48 2012
@@ -50,20 +50,6 @@
 #include "svn_private_config.h"
 
 
-/* ### This file maps URL schemes to particular RA libraries.
-   ### Currently, the only pair of RA libraries which support the same
-   ### protocols are neon and serf.  svn_ra_open3 makes the assumption
-   ### that this is the case; that their 'schemes' fields are both
-   ### dav_schemes; and that "neon" is listed first.
-
-   ### Users can choose which dav library to use with the http-library
-   ### preference in .subversion/servers; however, it is ignored by
-   ### any code which uses the pre-1.2 API svn_ra_get_ra_library
-   ### instead of svn_ra_open. */
-
-#if defined(SVN_HAVE_NEON) && defined(SVN_HAVE_SERF)
-#define CHOOSABLE_DAV_MODULE
-#endif
 
 
 /* These are the URI schemes that the respective libraries *may* support.
@@ -85,15 +71,6 @@ static const struct ra_lib_defn {
   svn_ra_init_func_t compat_initfunc;
 } ra_libraries[] = {
   {
-    "neon",
-    dav_schemes,
-#ifdef SVN_LIBSVN_CLIENT_LINKS_RA_NEON
-    svn_ra_neon__init,
-    svn_ra_dav_init
-#endif
-  },
-
-  {
     "svn",
     svn_schemes,
 #ifdef SVN_LIBSVN_CLIENT_LINKS_RA_SVN
@@ -413,8 +390,7 @@ svn_error_t *svn_ra_open4(svn_ra_session
                                             SVN_CONFIG_OPTION_HTTP_LIBRARY,
                                             DEFAULT_HTTP_LIBRARY);
 
-          if (strcmp(http_library, "neon") != 0 &&
-              strcmp(http_library, "serf") != 0)
+          if (strcmp(http_library, "serf") != 0)
             return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
                                      _("Invalid config: unknown HTTP library "
                                        "'%s'"),
@@ -706,6 +682,39 @@ commit_callback_wrapper(const svn_commit
   return ccwb->original_callback(ci, ccwb->original_baton, pool);
 }
 
+
+/* Some RA layers do not correctly fill in REPOS_ROOT in commit_info, or
+   they are third-party layers conforming to an older commit_info structure.
+   Interpose a utility function to ensure the field is valid.  */
+static void
+remap_commit_callback(svn_commit_callback2_t *callback,
+                      void **callback_baton,
+                      svn_ra_session_t *session,
+                      svn_commit_callback2_t original_callback,
+                      void *original_baton,
+                      apr_pool_t *result_pool)
+{
+  if (original_callback == NULL)
+    {
+      *callback = NULL;
+      *callback_baton = NULL;
+    }
+  else
+    {
+      /* Allocate this in RESULT_POOL, since the callback will be called
+         long after this function has returned. */
+      struct ccw_baton *ccwb = apr_palloc(result_pool, sizeof(*ccwb));
+
+      ccwb->session = session;
+      ccwb->original_callback = original_callback;
+      ccwb->original_baton = original_baton;
+
+      *callback = commit_callback_wrapper;
+      *callback_baton = ccwb;
+    }
+}
+
+
 svn_error_t *svn_ra_get_commit_editor3(svn_ra_session_t *session,
                                        const svn_delta_editor_t **editor,
                                        void **edit_baton,
@@ -716,20 +725,13 @@ svn_error_t *svn_ra_get_commit_editor3(s
                                        svn_boolean_t keep_locks,
                                        apr_pool_t *pool)
 {
-  /* Allocate this in a pool, since the callback will be called long after
-     this function as returned. */
-  struct ccw_baton *ccwb = apr_palloc(pool, sizeof(*ccwb));
-
-  ccwb->original_callback = callback;
-  ccwb->original_baton = callback_baton;
-  ccwb->session = session;
+  remap_commit_callback(&callback, &callback_baton,
+                        session, callback, callback_baton,
+                        pool);
 
   return session->vtable->get_commit_editor(session, editor, edit_baton,
                                             revprop_table,
-                                            callback
-                                                ? commit_callback_wrapper
-                                                : NULL,
-                                            callback ? ccwb : NULL,
+                                            callback, callback_baton,
                                             lock_tokens, keep_locks, pool);
 }
 
@@ -876,6 +878,8 @@ svn_error_t *svn_ra_do_diff3(svn_ra_sess
                              void *diff_baton,
                              apr_pool_t *pool)
 {
+  SVN_ERR_ASSERT(svn_path_is_empty(diff_target)
+                 || svn_path_is_single_path_component(diff_target));
   return session->vtable->do_diff(session,
                                   reporter, report_baton,
                                   revision, diff_target,
@@ -1141,6 +1145,17 @@ svn_error_t *svn_ra_replay(svn_ra_sessio
 }
 
 svn_error_t *
+svn_ra__replay_ev2(svn_ra_session_t *session,
+                   svn_revnum_t revision,
+                   svn_revnum_t low_water_mark,
+                   svn_boolean_t send_deltas,
+                   svn_editor_t *editor,
+                   apr_pool_t *scratch_pool)
+{
+  SVN__NOT_IMPLEMENTED();
+}
+
+svn_error_t *
 svn_ra_replay_range(svn_ra_session_t *session,
                     svn_revnum_t start_revision,
                     svn_revnum_t end_revision,
@@ -1193,6 +1208,20 @@ svn_ra_replay_range(svn_ra_session_t *se
   return err;
 }
 
+svn_error_t *
+svn_ra__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__NOT_IMPLEMENTED();
+}
+
 svn_error_t *svn_ra_has_capability(svn_ra_session_t *session,
                                    svn_boolean_t *has,
                                    const char *capability,
@@ -1228,8 +1257,7 @@ svn_ra_get_deleted_rev(svn_ra_session_t 
                                          end_revision,
                                          revision_deleted,
                                          pool);
-  if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE     /* serf */
-              || err->apr_err == SVN_ERR_RA_NOT_IMPLEMENTED)) /* neon */
+  if (err && (err->apr_err == SVN_ERR_UNSUPPORTED_FEATURE))
     {
       svn_error_clear(err);
 
@@ -1241,6 +1269,67 @@ svn_ra_get_deleted_rev(svn_ra_session_t 
   return err;
 }
 
+
+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,
+                       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)
+{
+  if (session->vtable->get_commit_ev2 == NULL)
+    {
+      /* The specific RA layer does not have an implementation. Use our
+         default shim over the normal commit editor.  */
+
+      /* Remap for RA layers exposing Ev1.  */
+      remap_commit_callback(&callback, &callback_baton,
+                            session, callback, callback_baton,
+                            result_pool);
+
+      return svn_error_trace(svn_ra__use_commit_shim(
+                               editor,
+                               session,
+                               revprop_table,
+                               callback, callback_baton,
+                               lock_tokens,
+                               keep_locks,
+                               provide_base_cb,
+                               provide_props_cb,
+                               get_copysrc_kind_cb,
+                               cb_baton,
+                               cancel_func, cancel_baton,
+                               result_pool, scratch_pool));
+    }
+
+  /* Note: no need to remap the callback for Ev2. RA layers providing this
+     vtable entry should completely fill in commit_info.  */
+
+  return svn_error_trace(session->vtable->get_commit_ev2(
+                           editor,
+                           session,
+                           revprop_table,
+                           callback, callback_baton,
+                           lock_tokens,
+                           keep_locks,
+                           provide_base_cb,
+                           provide_props_cb,
+                           get_copysrc_kind_cb,
+                           cb_baton,
+                           cancel_func, cancel_baton,
+                           result_pool, scratch_pool));
+}
+
 
 
 svn_error_t *

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.h
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.h?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.h (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra/ra_loader.h Thu Aug 16 10:17:48 2012
@@ -32,6 +32,8 @@
 
 #include "svn_ra.h"
 
+#include "private/svn_ra_private.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -56,7 +58,7 @@ typedef struct svn_ra__vtable_t {
      time this is called.  SESSION->priv may be set by this function. */
   svn_error_t *(*open_session)(svn_ra_session_t *session,
                                const char **corrected_url,
-                               const char *repos_URL,
+                               const char *session_URL,
                                const svn_ra_callbacks2_t *callbacks,
                                void *callback_baton,
                                apr_hash_t *config,
@@ -293,9 +295,29 @@ typedef struct svn_ra__vtable_t {
                                   svn_revnum_t end_revision,
                                   svn_revnum_t *revision_deleted,
                                   apr_pool_t *pool);
+
+  /* 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_commit_ev2()  */
+  svn_error_t *(*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,
+    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);
+
 } svn_ra__vtable_t;
 
 /* The RA session object. */
@@ -331,9 +353,6 @@ svn_error_t *svn_ra_local__init(const sv
 svn_error_t *svn_ra_svn__init(const svn_version_t *loader_version,
                               const svn_ra__vtable_t **vtable,
                               apr_pool_t *pool);
-svn_error_t *svn_ra_neon__init(const svn_version_t *loader_version,
-                              const svn_ra__vtable_t **vtable,
-                              apr_pool_t *pool);
 svn_error_t *svn_ra_serf__init(const svn_version_t *loader_version,
                                const svn_ra__vtable_t **vtable,
                                apr_pool_t *pool);
@@ -453,6 +472,29 @@ svn_ra__get_deleted_rev_from_log(svn_ra_
                                  svn_revnum_t *revision_deleted,
                                  apr_pool_t *pool);
 
+
+/* Utility function to provide a shim between a returned Ev2 and an RA
+   provider's Ev1-based commit editor.
+
+   See svn_ra__get_commit_ev2() for parameter semantics.  */
+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,
+                        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);
+
+
 #ifdef __cplusplus
 }
 #endif

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_local/ra_plugin.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_local/ra_plugin.c Thu Aug 16 10:17:48 2012
@@ -76,8 +76,6 @@ get_username(svn_ra_session_t *session,
              apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  svn_auth_iterstate_t *iterstate;
-  svn_fs_access_t *access_ctx;
 
   /* If we've already found the username don't ask for it again. */
   if (! sess->username)
@@ -88,6 +86,8 @@ get_username(svn_ra_session_t *session,
         {
           void *creds;
           svn_auth_cred_username_t *username_creds;
+          svn_auth_iterstate_t *iterstate;
+
           SVN_ERR(svn_auth_first_credentials(&creds, &iterstate,
                                              SVN_AUTH_CRED_USERNAME,
                                              sess->uuid, /* realmstring */
@@ -118,6 +118,8 @@ get_username(svn_ra_session_t *session,
   */
   if (*sess->username)
     {
+      svn_fs_access_t *access_ctx;
+
       SVN_ERR(svn_fs_create_access(&access_ctx, sess->username,
                                    session->pool));
       SVN_ERR(svn_fs_set_access(sess->fs, access_ctx));
@@ -367,11 +369,12 @@ struct deltify_etc_baton
 {
   svn_fs_t *fs;                     /* the fs to deltify in */
   svn_repos_t *repos;               /* repos for unlocking */
-  const char *fs_path;              /* fs-path part of split session URL */
+  const char *fspath_base;          /* fs-path part of split session URL */
+
   apr_hash_t *lock_tokens;          /* tokens to unlock, if any */
-  apr_pool_t *pool;                 /* pool for scratch work */
-  svn_commit_callback2_t callback;  /* the original callback */
-  void *callback_baton;             /* the original callback's baton */
+
+  svn_commit_callback2_t commit_cb; /* the original callback */
+  void *commit_baton;               /* the original callback's baton */
 };
 
 /* This implements 'svn_commit_callback_t'.  Its invokes the original
@@ -380,60 +383,107 @@ struct deltify_etc_baton
    BATON is 'struct deltify_etc_baton *'. */
 static svn_error_t *
 deltify_etc(const svn_commit_info_t *commit_info,
-            void *baton, apr_pool_t *pool)
+            void *baton,
+            apr_pool_t *scratch_pool)
 {
-  struct deltify_etc_baton *db = baton;
+  struct deltify_etc_baton *deb = baton;
   svn_error_t *err1 = SVN_NO_ERROR;
   svn_error_t *err2;
-  apr_hash_index_t *hi;
-  apr_pool_t *iterpool;
 
   /* Invoke the original callback first, in case someone's waiting to
      know the revision number so they can go off and annotate an
      issue or something. */
-  if (db->callback)
-    err1 = db->callback(commit_info, db->callback_baton, pool);
+  if (deb->commit_cb)
+    err1 = deb->commit_cb(commit_info, deb->commit_baton, scratch_pool);
 
   /* Maybe unlock the paths. */
-  if (db->lock_tokens)
+  if (deb->lock_tokens)
     {
-      iterpool = svn_pool_create(db->pool);
-      for (hi = apr_hash_first(db->pool, db->lock_tokens); hi;
+      apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+      apr_hash_index_t *hi;
+
+      for (hi = apr_hash_first(scratch_pool, deb->lock_tokens); hi;
            hi = apr_hash_next(hi))
         {
-          const void *rel_path;
-          void *val;
-          const char *abs_path, *token;
+          const void *relpath = svn__apr_hash_index_key(hi);
+          const char *token = svn__apr_hash_index_val(hi);
+          const char *fspath;
 
           svn_pool_clear(iterpool);
-          apr_hash_this(hi, &rel_path, NULL, &val);
-          token = val;
-          abs_path = svn_fspath__join(db->fs_path, rel_path, iterpool);
+
+          fspath = svn_fspath__join(deb->fspath_base, relpath, iterpool);
+
           /* We may get errors here if the lock was broken or stolen
              after the commit succeeded.  This is fine and should be
              ignored. */
-          svn_error_clear(svn_repos_fs_unlock(db->repos, abs_path, token,
+          svn_error_clear(svn_repos_fs_unlock(deb->repos, fspath, token,
                                               FALSE, iterpool));
         }
+
       svn_pool_destroy(iterpool);
     }
 
   /* But, deltification shouldn't be stopped just because someone's
      random callback failed, so proceed unconditionally on to
      deltification. */
-  err2 = svn_fs_deltify_revision(db->fs, commit_info->revision, db->pool);
+  err2 = svn_fs_deltify_revision(deb->fs, commit_info->revision, scratch_pool);
+
+  return svn_error_compose_create(err1, err2);
+}
+
 
-  /* It's more interesting if the original callback failed, so let
-     that one dominate. */
-  if (err1)
+/* If LOCK_TOKENS is not NULL, then copy all tokens into the access context
+   of FS. The tokens' paths will be prepended with FSPATH_BASE.
+
+   ACCESS_POOL must match (or exceed) the lifetime of the access context
+   that was associated with FS. Typically, this is the session pool.
+
+   Temporary allocations are made in SCRATCH_POOL.  */
+static svn_error_t *
+apply_lock_tokens(svn_fs_t *fs,
+                  const char *fspath_base,
+                  apr_hash_t *lock_tokens,
+                  apr_pool_t *access_pool,
+                  apr_pool_t *scratch_pool)
+{
+  if (lock_tokens)
     {
-      svn_error_clear(err2);
-      return err1;
+      svn_fs_access_t *access_ctx;
+
+      SVN_ERR(svn_fs_get_access(&access_ctx, fs));
+
+      /* If there is no access context, the filesystem will scream if a
+         lock is needed.  */
+      if (access_ctx)
+        {
+          apr_hash_index_t *hi;
+
+          /* Note: we have no use for an iterpool here since the data
+             within the loop is copied into ACCESS_POOL.  */
+
+          for (hi = apr_hash_first(scratch_pool, lock_tokens); hi;
+               hi = apr_hash_next(hi))
+            {
+              const void *relpath = svn__apr_hash_index_key(hi);
+              const char *token = svn__apr_hash_index_val(hi);
+              const char *fspath;
+
+              /* The path needs to live as long as ACCESS_CTX.  */
+              fspath = svn_fspath__join(fspath_base, relpath, access_pool);
+
+              /* The token must live as long as ACCESS_CTX.  */
+              token = apr_pstrdup(access_pool, token);
+
+              SVN_ERR(svn_fs_access_add_lock_token2(access_ctx, fspath,
+                                                    token));
+            }
+        }
     }
 
-  return err2;
+  return SVN_NO_ERROR;
 }
 
+
 /*----------------------------------------------------------------*/
 
 /*** The RA vtable routines ***/
@@ -679,47 +729,24 @@ svn_ra_local__get_commit_editor(svn_ra_s
                                 apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  struct deltify_etc_baton *db = apr_palloc(pool, sizeof(*db));
-  apr_hash_index_t *hi;
-  svn_fs_access_t *fs_access;
+  struct deltify_etc_baton *deb = apr_palloc(pool, sizeof(*deb));
 
-  db->fs = sess->fs;
-  db->repos = sess->repos;
-  db->fs_path = sess->fs_path->data;
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
   if (! keep_locks)
-    db->lock_tokens = lock_tokens;
+    deb->lock_tokens = lock_tokens;
   else
-    db->lock_tokens = NULL;
-  db->pool = pool;
-  db->callback = callback;
-  db->callback_baton = callback_baton;
+    deb->lock_tokens = NULL;
+  deb->commit_cb = callback;
+  deb->commit_baton = callback_baton;
 
   SVN_ERR(get_username(session, pool));
 
   /* If there are lock tokens to add, do so. */
-  if (lock_tokens)
-    {
-      SVN_ERR(svn_fs_get_access(&fs_access, sess->fs));
-
-      /* If there is no access context, the filesystem will scream if a
-         lock is needed. */
-      if (fs_access)
-        {
-          for (hi = apr_hash_first(pool, lock_tokens); hi;
-               hi = apr_hash_next(hi))
-            {
-              void *val;
-              const char *abs_path, *token;
-              const void *key;
-
-              apr_hash_this(hi, &key, NULL, &val);
-              abs_path = svn_fspath__join(sess->fs_path->data, key, pool);
-              token = val;
-              SVN_ERR(svn_fs_access_add_lock_token2(fs_access,
-                                                    abs_path, token));
-            }
-        }
-    }
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, pool));
 
   /* Copy the revprops table so we can add the username. */
   revprop_table = apr_hash_copy(pool, revprop_table);
@@ -730,7 +757,7 @@ svn_ra_local__get_commit_editor(svn_ra_s
   return svn_repos_get_commit_editor5
          (editor, edit_baton, sess->repos, NULL,
           svn_path_uri_decode(sess->repos_url, pool), sess->fs_path->data,
-          revprop_table, deltify_etc, db, NULL, NULL, pool);
+          revprop_table, deltify_etc, deb, NULL, NULL, pool);
 }
 
 
@@ -1514,6 +1541,62 @@ svn_ra_local__register_editor_shim_callb
   return SVN_NO_ERROR;
 }
 
+
+static svn_error_t *
+svn_ra_local__get_commit_ev2(svn_editor_t **editor,
+                             svn_ra_session_t *session,
+                             apr_hash_t *revprops,
+                             svn_commit_callback2_t commit_cb,
+                             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)
+{
+  svn_ra_local__session_baton_t *sess = session->priv;
+  struct deltify_etc_baton *deb = apr_palloc(result_pool, sizeof(*deb));
+
+  /* NOTE: the RA callbacks are ignored. We pass everything directly to
+     the REPOS editor.  */
+
+  /* Prepare the baton for deltify_etc()  */
+  deb->fs = sess->fs;
+  deb->repos = sess->repos;
+  deb->fspath_base = sess->fs_path->data;
+  if (! keep_locks)
+    deb->lock_tokens = lock_tokens;
+  else
+    deb->lock_tokens = NULL;
+  deb->commit_cb = commit_cb;
+  deb->commit_baton = commit_baton;
+
+  /* Ensure there is a username (and an FS access context) associated with
+     the session and its FS handle.  */
+  SVN_ERR(get_username(session, scratch_pool));
+
+  /* If there are lock tokens to add, do so.  */
+  SVN_ERR(apply_lock_tokens(sess->fs, sess->fs_path->data, lock_tokens,
+                            session->pool, scratch_pool));
+
+  /* Copy the REVPROPS and insert the author/username.  */
+  revprops = apr_hash_copy(scratch_pool, revprops);
+  apr_hash_set(revprops, SVN_PROP_REVISION_AUTHOR, APR_HASH_KEY_STRING,
+               svn_string_create(sess->username, scratch_pool));
+
+  return svn_error_trace(svn_repos__get_commit_ev2(
+                           editor, sess->repos, NULL /* authz */,
+                           NULL /* authz_repos_name */, NULL /* authz_user */,
+                           revprops,
+                           deltify_etc, deb, cancel_func, cancel_baton,
+                           result_pool, scratch_pool));
+}
+
 /*----------------------------------------------------------------*/
 
 static const svn_version_t *
@@ -1561,7 +1644,8 @@ static const svn_ra__vtable_t ra_local_v
   svn_ra_local__has_capability,
   svn_ra_local__replay_range,
   svn_ra_local__get_deleted_rev,
-  svn_ra_local__register_editor_shim_callbacks
+  svn_ra_local__register_editor_shim_callbacks,
+  svn_ra_local__get_commit_ev2
 };
 
 

Modified: subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/blame.c
URL: http://svn.apache.org/viewvc/subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/blame.c?rev=1373783&r1=1373782&r2=1373783&view=diff
==============================================================================
--- subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/blame.c (original)
+++ subversion/branches/compressed-pristines/subversion/libsvn_ra_serf/blame.c Thu Aug 16 10:17:48 2012
@@ -22,9 +22,6 @@
  */
 
 #include <apr_uri.h>
-
-#include <expat.h>
-
 #include <serf.h>
 
 #include "svn_pools.h"
@@ -49,7 +46,7 @@
  * This enum represents the current state of our XML parsing for a REPORT.
  */
 typedef enum blame_state_e {
-  NONE = 0,
+  INITIAL = 0,
   FILE_REVS_REPORT,
   FILE_REV,
   REV_PROP,
@@ -59,40 +56,6 @@ typedef enum blame_state_e {
   TXDELTA
 } blame_state_e;
 
-typedef struct blame_info_t {
-  /* Current pool. */
-  apr_pool_t *pool;
-
-  /* our suspicious file */
-  const char *path;
-
-  /* the intended suspect */
-  svn_revnum_t rev;
-
-  /* Hashtable of revision properties */
-  apr_hash_t *rev_props;
-
-  /* Added and removed properties (svn_prop_t*'s) */
-  apr_array_header_t *prop_diffs;
-
-  /* txdelta */
-  svn_txdelta_window_handler_t txdelta;
-  void *txdelta_baton;
-
-  /* returned txdelta stream */
-  svn_stream_t *stream;
-
-  /* Is this property base64-encoded? */
-  svn_boolean_t prop_base64;
-
-  /* The currently collected value as we build it up */
-  const char *prop_name;
-  svn_stringbuf_t *prop_value;
-
-  /* Merged revision flag */
-  svn_boolean_t merged_revision;
-
-} blame_info_t;
 
 typedef struct blame_context_t {
   /* pool passed to get_file_revs */
@@ -104,272 +67,213 @@ typedef struct blame_context_t {
   svn_revnum_t end;
   svn_boolean_t include_merged_revisions;
 
-  /* are we done? */
-  svn_boolean_t done;
-
   /* blame handler and baton */
   svn_file_rev_handler_t file_rev;
   void *file_rev_baton;
+
+  /* As we parse each FILE_REV, we collect data in these variables:
+     property changes and new content.  STREAM is valid when we're
+     in the TXDELTA state, processing the incoming cdata.  */
+  apr_hash_t *rev_props;
+  apr_array_header_t *prop_diffs;
+  apr_pool_t *state_pool;  /* put property stuff in here  */
+
+  svn_stream_t *stream;
+
 } blame_context_t;
 
-
-static blame_info_t *
-push_state(svn_ra_serf__xml_parser_t *parser,
-           blame_context_t *blame_ctx,
-           blame_state_e state)
-{
-  svn_ra_serf__xml_push_state(parser, state);
 
-  if (state == FILE_REV)
-    {
-      blame_info_t *info;
+#define D_ "DAV:"
+#define S_ SVN_XML_NAMESPACE
+static const svn_ra_serf__xml_transition_t blame_ttable[] = {
+  { INITIAL, S_, "file-revs-report", FILE_REVS_REPORT,
+    FALSE, { NULL }, FALSE },
 
-      info = apr_pcalloc(parser->state->pool, sizeof(*info));
+  { FILE_REVS_REPORT, S_, "file-rev", FILE_REV,
+    FALSE, { "path", "rev", NULL }, TRUE },
 
-      info->pool = parser->state->pool;
+  { FILE_REV, S_, "rev-prop", REV_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
-      info->rev = SVN_INVALID_REVNUM;
+  { FILE_REV, S_, "set-prop", SET_PROP,
+    TRUE, { "name", "?encoding", NULL }, TRUE },
 
-      info->rev_props = apr_hash_make(info->pool);
-      info->prop_diffs = apr_array_make(info->pool, 0, sizeof(svn_prop_t));
+  { FILE_REV, S_, "remove-prop", REMOVE_PROP,
+    FALSE, { "name", NULL }, TRUE },
 
-      info->prop_value = svn_stringbuf_create_empty(info->pool);
+  { FILE_REV, S_, "merged-revision", MERGED_REVISION,
+    FALSE, { NULL }, TRUE },
 
-      parser->state->private = info;
-    }
+  { FILE_REV, S_, "txdelta", TXDELTA,
+    FALSE, { NULL }, TRUE },
 
-  return parser->state->private;
-}
+  { 0 }
+};
 
 
-static const svn_string_t *
-create_propval(blame_info_t *info)
+/* Conforms to svn_ra_serf__xml_opened_t  */
+static svn_error_t *
+blame_opened(svn_ra_serf__xml_estate_t *xes,
+             void *baton,
+             int entered_state,
+             const svn_ra_serf__dav_props_t *tag,
+             apr_pool_t *scratch_pool)
 {
-  if (info->prop_base64)
+  blame_context_t *blame_ctx = baton;
+
+  if (entered_state == FILE_REV)
     {
-      const svn_string_t *morph;
+      apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes);
 
-      morph = svn_stringbuf__morph_into_string(info->prop_value);
-#ifdef SVN_DEBUG
-      info->prop_value = NULL;  /* morph killed the stringbuf.  */
-#endif
-      return svn_base64_decode_string(morph, info->pool);
+      /* Child elements will store properties in these structures.  */
+      blame_ctx->rev_props = apr_hash_make(state_pool);
+      blame_ctx->prop_diffs = apr_array_make(state_pool,
+                                             5, sizeof(svn_prop_t));
+      blame_ctx->state_pool = state_pool;
+
+      /* Clear this, so we can detect the absence of a TXDELTA.  */
+      blame_ctx->stream = NULL;
+    }
+  else if (entered_state == TXDELTA)
+    {
+      apr_pool_t *state_pool = svn_ra_serf__xml_state_pool(xes);
+      apr_hash_t *gathered = svn_ra_serf__xml_gather_since(xes, FILE_REV);
+      const char *path;
+      const char *rev;
+      const char *merged_revision;
+      svn_txdelta_window_handler_t txdelta;
+      void *txdelta_baton;
+
+      path = apr_hash_get(gathered, "path", APR_HASH_KEY_STRING);
+      rev = apr_hash_get(gathered, "rev", APR_HASH_KEY_STRING);
+      merged_revision = apr_hash_get(gathered,
+                                     "merged-revision", APR_HASH_KEY_STRING);
+
+      SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton,
+                                  path, SVN_STR_TO_REV(rev),
+                                  blame_ctx->rev_props,
+                                  merged_revision != NULL,
+                                  &txdelta, &txdelta_baton,
+                                  blame_ctx->prop_diffs,
+                                  state_pool));
+
+      blame_ctx->stream = svn_base64_decode(svn_txdelta_parse_svndiff(
+                                              txdelta, txdelta_baton,
+                                              TRUE /* error_on_early_close */,
+                                              state_pool),
+                                            state_pool);
     }
 
-  return svn_string_create_from_buf(info->prop_value, info->pool);
+  return SVN_NO_ERROR;
 }
 
+
+/* Conforms to svn_ra_serf__xml_closed_t  */
 static svn_error_t *
-start_blame(svn_ra_serf__xml_parser_t *parser,
-            svn_ra_serf__dav_props_t name,
-            const char **attrs,
-            apr_pool_t *scratch_pool)
+blame_closed(svn_ra_serf__xml_estate_t *xes,
+             void *baton,
+             int leaving_state,
+             const svn_string_t *cdata,
+             apr_hash_t *attrs,
+             apr_pool_t *scratch_pool)
 {
-  blame_context_t *blame_ctx = parser->user_data;
-  blame_state_e state;
+  blame_context_t *blame_ctx = baton;
 
-  state = parser->state->current_state;
+  if (leaving_state == FILE_REV)
+    {
+      /* Note that we test STREAM, but any pointer is currently invalid.
+         It was closed when left the TXDELTA state.  */
+      if (blame_ctx->stream == NULL)
+        {
+          const char *path;
+          const char *rev;
+
+          path = apr_hash_get(attrs, "path", APR_HASH_KEY_STRING);
+          rev = apr_hash_get(attrs, "rev", APR_HASH_KEY_STRING);
 
-  if (state == NONE && strcmp(name.name, "file-revs-report") == 0)
+          /* Send a "no content" notification.  */
+          SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton,
+                                      path, SVN_STR_TO_REV(rev),
+                                      blame_ctx->rev_props,
+                                      FALSE /* result_of_merge */,
+                                      NULL, NULL, /* txdelta / baton */
+                                      blame_ctx->prop_diffs,
+                                      scratch_pool));
+        }
+    }
+  else if (leaving_state == MERGED_REVISION)
     {
-      push_state(parser, blame_ctx, FILE_REVS_REPORT);
+      svn_ra_serf__xml_note(xes, FILE_REV, "merged-revision", "*");
     }
-  else if (state == FILE_REVS_REPORT &&
-           strcmp(name.name, "file-rev") == 0)
+  else if (leaving_state == TXDELTA)
     {
-      blame_info_t *info;
-
-      info = push_state(parser, blame_ctx, FILE_REV);
-
-      info->path = apr_pstrdup(info->pool,
-                               svn_xml_get_attr_value("path", attrs));
-      info->rev = SVN_STR_TO_REV(svn_xml_get_attr_value("rev", attrs));
+      SVN_ERR(svn_stream_close(blame_ctx->stream));
     }
-  else if (state == FILE_REV)
+  else
     {
-      blame_info_t *info;
-      const char *enc;
+      const char *name;
+      const svn_string_t *value;
 
-      info = parser->state->private;
+      SVN_ERR_ASSERT(leaving_state == REV_PROP
+                     || leaving_state == SET_PROP
+                     || leaving_state == REMOVE_PROP);
 
-      if (strcmp(name.name, "rev-prop") == 0)
-        {
-          push_state(parser, blame_ctx, REV_PROP);
-        }
-      else if (strcmp(name.name, "set-prop") == 0)
-        {
-          push_state(parser, blame_ctx, SET_PROP);
-        }
-      if (strcmp(name.name, "remove-prop") == 0)
-        {
-          push_state(parser, blame_ctx, REMOVE_PROP);
-        }
-      else if (strcmp(name.name, "merged-revision") == 0)
+      name = apr_pstrdup(blame_ctx->state_pool,
+                         apr_hash_get(attrs, "name", APR_HASH_KEY_STRING));
+
+      if (leaving_state == REMOVE_PROP)
         {
-          push_state(parser, blame_ctx, MERGED_REVISION);
+          value = NULL;
         }
-      else if (strcmp(name.name, "txdelta") == 0)
+      else
         {
-          SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton,
-                                      info->path, info->rev,
-                                      info->rev_props, info->merged_revision,
-                                      &info->txdelta, &info->txdelta_baton,
-                                      info->prop_diffs, info->pool));
-
-          info->stream = svn_base64_decode
-              (svn_txdelta_parse_svndiff(info->txdelta, info->txdelta_baton,
-                                         TRUE, info->pool), info->pool);
-
-          push_state(parser, blame_ctx, TXDELTA);
-        }
+          const char *encoding = apr_hash_get(attrs,
+                                              "encoding", APR_HASH_KEY_STRING);
 
-      state = parser->state->current_state;
-
-      switch (state)
-        {
-        case REV_PROP:
-        case SET_PROP:
-        case REMOVE_PROP:
-          info->prop_name = apr_pstrdup(info->pool,
-                                        svn_xml_get_attr_value("name", attrs));
-          svn_stringbuf_setempty(info->prop_value);
-
-          enc = svn_xml_get_attr_value("encoding", attrs);
-          if (enc && strcmp(enc, "base64") == 0)
-            {
-              info->prop_base64 = TRUE;
-            }
+          if (encoding && strcmp(encoding, "base64") == 0)
+            value = svn_base64_decode_string(cdata, blame_ctx->state_pool);
           else
-            {
-              info->prop_base64 = FALSE;
-            }
-          break;
-        case MERGED_REVISION:
-            info->merged_revision = TRUE;
-          break;
-        default:
-          break;
+            value = svn_string_dup(cdata, blame_ctx->state_pool);
         }
-    }
-
-  return SVN_NO_ERROR;
-}
 
-static svn_error_t *
-end_blame(svn_ra_serf__xml_parser_t *parser,
-          svn_ra_serf__dav_props_t name,
-          apr_pool_t *scratch_pool)
-{
-  blame_context_t *blame_ctx = parser->user_data;
-  blame_state_e state;
-  blame_info_t *info;
-
-  state = parser->state->current_state;
-  info = parser->state->private;
-
-  if (state == NONE)
-    {
-      return SVN_NO_ERROR;
-    }
-
-  if (state == FILE_REVS_REPORT &&
-      strcmp(name.name, "file-revs-report") == 0)
-    {
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (state == FILE_REV &&
-           strcmp(name.name, "file-rev") == 0)
-    {
-      /* no file changes. */
-      if (!info->stream)
+      if (leaving_state == REV_PROP)
         {
-          SVN_ERR(blame_ctx->file_rev(blame_ctx->file_rev_baton,
-                                      info->path, info->rev,
-                                      info->rev_props, FALSE,
-                                      NULL, NULL,
-                                      info->prop_diffs, info->pool));
+          apr_hash_set(blame_ctx->rev_props, name, APR_HASH_KEY_STRING, value);
         }
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (state == REV_PROP &&
-           strcmp(name.name, "rev-prop") == 0)
-    {
-      apr_hash_set(info->rev_props,
-                   info->prop_name, APR_HASH_KEY_STRING,
-                   create_propval(info));
-
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if ((state == SET_PROP &&
-            strcmp(name.name, "set-prop") == 0) ||
-           (state == REMOVE_PROP &&
-            strcmp(name.name, "remove-prop") == 0))
-    {
-      svn_prop_t *prop = apr_array_push(info->prop_diffs);
-      prop->name = info->prop_name;
-      prop->value = create_propval(info);
-
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (state == MERGED_REVISION &&
-           strcmp(name.name, "merged-revision") == 0)
-    {
-      svn_ra_serf__xml_pop_state(parser);
-    }
-  else if (state == TXDELTA &&
-           strcmp(name.name, "txdelta") == 0)
-    {
-      SVN_ERR(svn_stream_close(info->stream));
+      else
+        {
+          svn_prop_t *prop = apr_array_push(blame_ctx->prop_diffs);
 
-      svn_ra_serf__xml_pop_state(parser);
+          prop->name = name;
+          prop->value = value;
+        }
     }
 
   return SVN_NO_ERROR;
 }
 
+
+/* Conforms to svn_ra_serf__xml_cdata_t  */
 static svn_error_t *
-cdata_blame(svn_ra_serf__xml_parser_t *parser,
+blame_cdata(svn_ra_serf__xml_estate_t *xes,
+            void *baton,
+            int current_state,
             const char *data,
             apr_size_t len,
             apr_pool_t *scratch_pool)
 {
-  blame_context_t *blame_ctx = parser->user_data;
-  blame_state_e state;
-  blame_info_t *info;
-
-  UNUSED_CTX(blame_ctx);
-
-  state = parser->state->current_state;
-  info = parser->state->private;
-
-  if (state == NONE)
-    {
-      return SVN_NO_ERROR;
-    }
+  blame_context_t *blame_ctx = baton;
 
-  switch (state)
+  if (current_state == TXDELTA)
     {
-      case REV_PROP:
-      case SET_PROP:
-        svn_stringbuf_appendbytes(info->prop_value, data, len);
-        break;
-      case TXDELTA:
-        if (info->stream)
-          {
-            apr_size_t ret_len;
-
-            ret_len = len;
-
-            SVN_ERR(svn_stream_write(info->stream, data, &ret_len));
-          }
-        break;
-      default:
-        break;
+      SVN_ERR(svn_stream_write(blame_ctx->stream, data, &len));
+      /* Ignore the returned LEN value.  */
     }
 
   return SVN_NO_ERROR;
 }
 
+
 /* Implements svn_ra_serf__request_body_delegate_t */
 static svn_error_t *
 create_file_revs_body(serf_bucket_t **body_bkt,
@@ -426,9 +330,8 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   blame_context_t *blame_ctx;
   svn_ra_serf__session_t *session = ra_session->priv;
   svn_ra_serf__handler_t *handler;
-  svn_ra_serf__xml_parser_t *parser_ctx;
-  const char *relative_url, *basecoll_url, *req_url;
-  int status_code;
+  svn_ra_serf__xml_context_t *xmlctx;
+  const char *req_url;
   svn_error_t *err;
 
   blame_ctx = apr_pcalloc(pool, sizeof(*blame_ctx));
@@ -439,14 +342,19 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   blame_ctx->start = start;
   blame_ctx->end = end;
   blame_ctx->include_merged_revisions = include_merged_revisions;
-  blame_ctx->done = FALSE;
-
-  SVN_ERR(svn_ra_serf__get_baseline_info(&basecoll_url, &relative_url, session,
-                                         NULL, session->session_url.path,
-                                         end, NULL, pool));
-  req_url = svn_path_url_add_component2(basecoll_url, relative_url, pool);
 
-  handler = apr_pcalloc(pool, sizeof(*handler));
+  SVN_ERR(svn_ra_serf__get_stable_url(&req_url, NULL /* latest_revnum */,
+                                      session, NULL /* conn */,
+                                      NULL /* url */, end,
+                                      pool, pool));
+
+  xmlctx = svn_ra_serf__xml_context_create(blame_ttable,
+                                           blame_opened,
+                                           blame_closed,
+                                           blame_cdata,
+                                           blame_ctx,
+                                           pool);
+  handler = svn_ra_serf__create_expat_handler(xmlctx, pool);
 
   handler->method = "REPORT";
   handler->path = req_url;
@@ -456,27 +364,12 @@ svn_ra_serf__get_file_revs(svn_ra_sessio
   handler->conn = session->conns[0];
   handler->session = session;
 
-  parser_ctx = apr_pcalloc(pool, sizeof(*parser_ctx));
-
-  parser_ctx->pool = pool;
-  parser_ctx->user_data = blame_ctx;
-  parser_ctx->start = start_blame;
-  parser_ctx->end = end_blame;
-  parser_ctx->cdata = cdata_blame;
-  parser_ctx->done = &blame_ctx->done;
-  parser_ctx->status_code = &status_code;
-
-  handler->response_handler = svn_ra_serf__handle_xml_parser;
-  handler->response_baton = parser_ctx;
-
-  svn_ra_serf__request_create(handler);
-
-  err = svn_ra_serf__context_run_wait(&blame_ctx->done, session, pool);
+  err = svn_ra_serf__context_run_one(handler, pool);
 
   err = svn_error_compose_create(
-            svn_ra_serf__error_on_status(status_code,
+            svn_ra_serf__error_on_status(handler->sline.code,
                                          handler->path,
-                                         parser_ctx->location),
+                                         handler->location),
             err);
 
   return svn_error_trace(err);