You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by ph...@apache.org on 2014/04/02 19:55:26 UTC

svn commit: r1584114 [1/2] - in /subversion/trunk/subversion: include/ libsvn_fs/ libsvn_fs_base/ libsvn_fs_fs/ libsvn_fs_x/ libsvn_ra_local/ libsvn_repos/ mod_dav_svn/ svnserve/ tests/libsvn_fs/ tests/libsvn_ra/

Author: philip
Date: Wed Apr  2 17:55:25 2014
New Revision: 1584114

URL: http://svn.apache.org/r1584114
Log:
Convert the new multi-path lock and unlock functions to a callback API,
rename from _lock2 and _unlock2 to _lock_many and _unlock_many.


* subversion/include/svn_fs.h
  (svn_fs_lock_result_t): Remove.
  (svn_fs_lock_callback_t):
  (svn_fs_lock2): Rename to...
  (svn_fs_lock_many): ...this, change to callback API.
  (svn_fs_unlock2): Rename to...
  (svn_fs_unlock_many): ...this, change to callback API.

* subversion/include/svn_repos.h
  (svn_repos_fs_lock2): Rename to...
  (svn_repos_fs_lock_many): ...this, change to callback API.
  (svn_repos_fs_unlock2): Rename to...
  (svn_repos_fs_unlock_many): ...this, change to callback API.

* subversion/libsvn_fs/fs-loader.h
  (struct fs_vtable_t): Change lock and unlock to callback API.

* subversion/libsvn_fs/fs-loader.c
  (struct lock_many_baton_t, lock_many_cb): New.
  (svn_fs_lock2): Rename to... 
  (svn_fs_lock_many): ...this, change to callback API.
  (struct lock_baton_t, lock_cb): New.
  (svn_fs_lock): Adapt to callback API.
  (svn_fs_unlock2): Rename to... 
  (svn_fs_unlock_many): ...this, change to callback API.
  (svn_fs_unlock): Adapt to callback API.

* subversion/libsvn_fs_fs/lock.h
* subversion/libsvn_fs_fs/lock.c
  (svn_fs_fs__lock, svn_fs_fs__unlock): Change to callback API.

* subversion/libsvn_fs_base/lock.h
* subversion/libsvn_fs_base/lock.c
  (svn_fs_base__lock, svn_fs_base__unlock): Change to callback API.

* subversion/libsvn_fs_x/lock.h
* subversion/libsvn_fs_x/lock.c
  (svn_fs_x__lock, svn_fs_x__unlock): Change to callback API.

* subversion/libsvn_ra_local/ra_plugin.c
  (deltify_etc): Adapt to callback API.
  (struct lock_baton_t, lock_cb): New.
  (svn_ra_local__lock, svn_ra_local__unlock): Adapt to callback API.

* subversion/libsvn_repos/fs-wrap.c
  (struct lock_many_baton_t, lock_many_cb): New.
  (svn_repos_fs_lock2): Rename to...
  (svn_repos_fs_lock_many): ...this, change to callback API.
  (struct lock_baton_t, lock_cb): New.
  (svn_repos_fs_lock): Adapt to callback API.
  (svn_repos_fs_unlock2): Rename to...
  (svn_repos_fs_unlock_many): ...this, change to callback API.
  (svn_repos_fs_unlock): Adapt to callback API.

* subversion/mod_dav_svn/version.c
  (unlock_many_cb): New.
  (release_locks): Adapt to callback API.

* subversion/svnserve/serve.c
  (write_lock): Make parameter const.
  (lock_cb): New.
  (unlock_paths): Adapt to callback API.
  (struct lock_result_t, struct lock_many_baton_t, lock_many_cb): New.
  (clear_lock_result_hash): New.
  (lock_many, unlock_many): Adapt to callback API.

* subversion/tests/libsvn_fs/locks-test.c
  (struct lock_result_t): New.
  (expect_lock, expect_error, expect_unlock, expect_unlock_error): Change
   to struct lock_result_t.
  (struct lock_many_baton_t, lock_many_cb): New.
  (lock_multiple_paths): Adapt to callback API.

* subversion/tests/libsvn_ra/ra-test.c
  (struct lock_result_t): New.
  (lock_cb, expect_lock, expect_error, expect_unlock, expect_unlock_error,
   lock_test): Change to struct lock_result_t.

Modified:
    subversion/trunk/subversion/include/svn_fs.h
    subversion/trunk/subversion/include/svn_repos.h
    subversion/trunk/subversion/libsvn_fs/fs-loader.c
    subversion/trunk/subversion/libsvn_fs/fs-loader.h
    subversion/trunk/subversion/libsvn_fs_base/lock.c
    subversion/trunk/subversion/libsvn_fs_base/lock.h
    subversion/trunk/subversion/libsvn_fs_fs/lock.c
    subversion/trunk/subversion/libsvn_fs_fs/lock.h
    subversion/trunk/subversion/libsvn_fs_x/lock.c
    subversion/trunk/subversion/libsvn_fs_x/lock.h
    subversion/trunk/subversion/libsvn_ra_local/ra_plugin.c
    subversion/trunk/subversion/libsvn_repos/fs-wrap.c
    subversion/trunk/subversion/mod_dav_svn/version.c
    subversion/trunk/subversion/svnserve/serve.c
    subversion/trunk/subversion/tests/libsvn_fs/locks-test.c
    subversion/trunk/subversion/tests/libsvn_ra/ra-test.c

Modified: subversion/trunk/subversion/include/svn_fs.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_fs.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_fs.h (original)
+++ subversion/trunk/subversion/include/svn_fs.h Wed Apr  2 17:55:25 2014
@@ -2512,7 +2512,7 @@ svn_fs_set_uuid(svn_fs_t *fs,
  * expiration error (depending on the API).
  */
 
-/** The @a targets hash passed to svn_fs_lock2() has <tt>const char
+/** The @a targets hash passed to svn_fs_lock_many() has <tt>const char
  * *</tt> keys and <tt>svn_fs_lock_target_t *</tt> values.
  *
  * @since New in 1.9.
@@ -2524,23 +2524,26 @@ typedef struct svn_fs_lock_target_t
 
 } svn_fs_lock_target_t;
 
-/** The @a results hash returned by svn_fs_lock2() and svn_fs_unlock2()
- * has <tt>const char *</tt> keys and <tt>svn_fs_lock_result_t *</tt>
- * values.
+/** The callback invoked by svn_fs_lock_many() and svn_fs_unlock_many().
  *
- * @since New in 1.9.
- */
-typedef struct svn_fs_lock_result_t
-{
-  svn_lock_t *lock;
-  svn_error_t *err;
-
-} svn_fs_lock_result_t;
+ * @a path and @a lock are allocated in the result_pool passed to
+ * svn_fs_lock_many/svn_fs_unlock_many and so will persist beyond the
+ * callback invocation. @a fs_err will be cleared after the callback
+ * returns, use svn_error_dup() to preserve the error.
+ *
+ * If the callback returns an error no further callbacks will be made
+ * and svn_fs_lock_many/svn_fs_unlock_many will return an error.
+ */
+typedef svn_error_t *(*svn_fs_lock_callback_t)(void *baton,
+                                               const char *path,
+                                               const svn_lock_t *lock,
+                                               svn_error_t *fs_err,
+                                               apr_pool_t *pool);
 
 /** Lock the paths in @a targets in @a fs, and set @a *results to the
  * locks or errors representing each new lock.
  *
- * @warning You may prefer to use svn_repos_fs_lock2() instead,
+ * @warning You may prefer to use svn_repos_fs_lock_many() instead,
  * which see.
  *
  * @a fs must have a username associated with it (see
@@ -2568,7 +2571,7 @@ typedef struct svn_fs_lock_result_t
  * last-changed-revision of the path (or if the path doesn't exist in
  * HEAD), yield an #SVN_ERR_FS_OUT_OF_DATE error for this path.
  *
- * If a path is already locked, then return #SVN_ERR_FS_PATH_ALREADY_LOCKED,
+ * If a path is already locked, then yield #SVN_ERR_FS_PATH_ALREADY_LOCKED,
  * unless @a steal_lock is TRUE, in which case "steal" the existing
  * lock, even if the FS access-context's username does not match the
  * current lock's owner: delete the existing lock on the path, and
@@ -2577,34 +2580,30 @@ typedef struct svn_fs_lock_result_t
  * If @a expiration_date is zero, then create a non-expiring lock.
  * Else, the lock will expire at @a expiration_date.
  *
- * The results are returned in @a *results hash where the keys are
- * <tt>const char *</tt> paths and the values are
- * <tt>svn_fs_lock_result_t *</tt>.  The error associated with each
- * path is returned as #svn_fs_lock_result_t->err. The lock associated
- * with each path is returned as #svn_fs_lock_result_t->lock; this
- * will be @c NULL if no lock was created. @a *results will always be
- * a valid hash and in all cases the caller must ensure that all
- * errors it contains are handled to avoid leaks.
+ * For each path in @a targets @a lock_callback will be invoked
+ * passing @a lock_baton and the lock and error that apply to path.
+ * @a lock_callback can be NULL in which case it is not called.
  *
- * Allocate @a *results in @a result_pool. Use @a scratch_pool for
- * temporary allocations.
+ * The lock and path passed to @a lock_callback will be allocated in
+ * @a result_pool.  Use @a scratch_pool for temporary allocations.
  *
  * @note At this time, only files can be locked.
  *
  * @since New in 1.9.
  */
 svn_error_t *
-svn_fs_lock2(apr_hash_t **results,
-             svn_fs_t *fs,
-             apr_hash_t *targets,
-             const char *comment,
-             svn_boolean_t is_dav_comment,
-             apr_time_t expiration_date,
-             svn_boolean_t steal_lock,
-             apr_pool_t *result_pool,
-             apr_pool_t *scratch_pool);
+svn_fs_lock_many(svn_fs_t *fs,
+                 apr_hash_t *targets,
+                 const char *comment,
+                 svn_boolean_t is_dav_comment,
+                 apr_time_t expiration_date,
+                 svn_boolean_t steal_lock,
+                 svn_fs_lock_callback_t lock_callback,
+                 void *lock_baton,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool);
 
-/** Similar to svn_fs_lock2() but locks only a single @a path and
+/** Similar to svn_fs_lock_many() but locks only a single @a path and
  * returns the lock in @a *lock, allocated in @a pool, or an error.
  *
  * @since New in 1.2.
@@ -2652,35 +2651,30 @@ svn_fs_generate_lock_token(const char **
  * however, don't return error; allow the lock to be "broken" in any
  * case.  In the latter case, the token shall be @c NULL.
  *
- * The results are returned in @a *results hash where the keys are
- * <tt>const char *</tt> paths and the values are
- * <tt>svn_fs_lock_result_t *</tt>.  The error associated with each
- * path is returned as #svn_fs_lock_result_t->err.  @a *results will
- * always be a valid hash and in all cases the caller must ensure that
- * all errors it contains are handled to avoid leaks.
+ * For each path in @a targets @a lock_callback will be invoked
+ * passing @a lock_baton and error that apply to path.  The @a lock
+ * passed to the callback will be NULL.  @a lock_callback can be NULL
+ * in which case it is not called.
  *
  * @note #svn_fs_lock_target_t is used to allow @c NULL tokens to be
  * passed (it is not possible to pass @c NULL as a hash value
  * directly), #svn_fs_lock_target_t->current_rev is ignored.
  *
- * @note #svn_fs_lock_result_t is used to allow @c SVN_NO_ERROR to
- * be returned (it is not possible to return @c SVN_NO_ERROR as a hash
- * value directly), #svn_fs_lock_result_t->lock is always NULL.
- *
- * Allocate @a *results in @a result_pool. Use @a scratch_pool for
- * temporary allocations.
+ * The path passed to lock_callback will be allocated in @a result_pool.
+ * Use @a scratch_pool for temporary allocations.
  *
  * @since New in 1.9.
  */
 svn_error_t *
-svn_fs_unlock2(apr_hash_t **results,
-               svn_fs_t *fs,
-               apr_hash_t *targets,
-               svn_boolean_t break_lock,
-               apr_pool_t *result_pool,
-               apr_pool_t *scratch_pool);
+svn_fs_unlock_many(svn_fs_t *fs,
+                   apr_hash_t *targets,
+                   svn_boolean_t break_lock,
+                   svn_fs_lock_callback_t lock_callback,
+                   void *lock_baton,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool);
 
-/** Similar to svn_fs_unlock2() but only unlocks a single path.
+/** Similar to svn_fs_unlock_many() but only unlocks a single path.
  *
  * @since New in 1.2.
  */

Modified: subversion/trunk/subversion/include/svn_repos.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_repos.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_repos.h (original)
+++ subversion/trunk/subversion/include/svn_repos.h Wed Apr  2 17:55:25 2014
@@ -2184,15 +2184,16 @@ svn_repos_fs_begin_txn_for_update(svn_fs
  * @{
  */
 
-/** Like svn_fs_lock2(), but invoke the @a repos's pre- and
+/** Like svn_fs_lock_many(), but invoke the @a repos's pre- and
  * post-lock hooks before and after the locking action.
  *
  * The pre-lock is run for every path in @a targets. Those targets for
- * which the pre-lock is successful are passed to svn_fs_lock2 and the
- * post-lock is run for those that are successfully locked.
+ * which the pre-lock is successful are passed to svn_fs_lock_many and
+ * the post-lock is run for those that are successfully locked.
  *
- * @a *results contains the result for each target of running the
- * pre-lock and svn_fs_lock2 if the pre-lock was successful.
+ * For each path in @a targets @a lock_callback will be invoked
+ * passing @a lock_baton and the lock and error that apply to path.
+ * @a lock_callback can be NULL in which case it is not called.
  *
  * If an error occurs when running the post-lock hook the error is
  * returned wrapped with #SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED.  If the
@@ -2204,23 +2205,24 @@ svn_repos_fs_begin_txn_for_update(svn_fs
  * lock, instead of the token supplied; see the pre-lock-hook
  * documentation for more.
  *
- * Allocate @a *results in @a result_pool. Use @a scratch_pool for
- * temporary allocations.
+ * The lock and path passed to @a lock_callback will be allocated in
+ * @a result_pool.  Use @a scratch_pool for temporary allocations.
  *
  * @since New in 1.9.
  */
 svn_error_t *
-svn_repos_fs_lock2(apr_hash_t **results,
-                   svn_repos_t *repos,
-                   apr_hash_t *targets,
-                   const char *comment,
-                   svn_boolean_t is_dav_comment,
-                   apr_time_t expiration_date,
-                   svn_boolean_t steal_lock,
-                   apr_pool_t *result_pool,
-                   apr_pool_t *scratch_pool);
+svn_repos_fs_lock_many(svn_repos_t *repos,
+                       apr_hash_t *targets,
+                       const char *comment,
+                       svn_boolean_t is_dav_comment,
+                       apr_time_t expiration_date,
+                       svn_boolean_t steal_lock,
+                       svn_fs_lock_callback_t lock_callback,
+                       void *lock_baton,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool);
 
-/** Similar to svn_repos_fs_lock2() but locks only a single path.
+/** Similar to svn_repos_fs_lock_many() but locks only a single path.
  *
  * @since New in 1.2.
  */
@@ -2237,37 +2239,40 @@ svn_repos_fs_lock(svn_lock_t **lock,
                   apr_pool_t *pool);
 
 
-/** Like svn_fs_unlock2(), but invoke the @a repos's pre- and
+/** Like svn_fs_unlock_many(), but invoke the @a repos's pre- and
  * post-unlock hooks before and after the unlocking action.
  *
  * The pre-unlock hook is run for every path in @a targets. Those
  * targets for which the pre-unlock is successful are passed to
- * svn_fs_unlock2 and the post-unlock is run for those that are
+ * svn_fs_unlock_many and the post-unlock is run for those that are
  * successfully unlocked.
  *
- * @a *results contains the result for each target of running the
- * pre-unlock and svn_fs_unlock2 if the pre-unlock was successful.
-
+ * For each path in @a targets @a lock_callback will be invoked
+ * passing @a lock_baton and error that apply to path.  The lock
+ * passed to the callback will be NULL.  @a lock_callback can be NULL
+ * in which case it is not called.
+ *
  * If an error occurs when running the post-unlock hook, return the
  * original error wrapped with #SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED.
  * If the caller sees this error, it knows that some unlocks
  * succeeded.  In all cases the caller must handle all errors in @a
  * *results to avoid leaks.
  *
- * Allocate @a *results in @a result_pool. Use @a scratch_pool for
- * temporary allocations.
+ * The path passed to @a lock_callback will be allocated in @a result_pool.
+ * Use @a scratch_pool for temporary allocations.
  *
  * @since New in 1.9.
  */
 svn_error_t *
-svn_repos_fs_unlock2(apr_hash_t **results,
-                     svn_repos_t *repos,
-                     apr_hash_t *targets,
-                     svn_boolean_t break_lock,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool);
+svn_repos_fs_unlock_many(svn_repos_t *repos,
+                         apr_hash_t *targets,
+                         svn_boolean_t break_lock,
+                         svn_fs_lock_callback_t lock_callback,
+                         void *lock_baton,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool);
 
-/** Similar to svn_repos_fs_unlock2() but only unlocks a single path.
+/** Similar to svn_repos_fs_unlock_many() but only unlocks a single path.
  *
  * @since New in 1.2.
  */

Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.c (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.c Wed Apr  2 17:55:25 2014
@@ -1582,22 +1582,46 @@ svn_fs_set_uuid(svn_fs_t *fs, const char
   return svn_error_trace(fs->vtable->set_uuid(fs, uuid, pool));
 }
 
+struct lock_many_baton_t {
+  svn_fs_lock_callback_t lock_callback;
+  void *lock_baton;
+  svn_error_t *cb_err;
+};
+
+/* Implements svn_fs_lock_callback_t.  Used by svn_fs_lock_many and
+   svn_fs_unlock_many to forward to the supplied callback and record
+   any error from the callback. */
+static svn_error_t *
+lock_many_cb(void *lock_baton,
+             const char *path,
+             const svn_lock_t *lock,
+             svn_error_t *fs_err,
+             apr_pool_t *pool)
+{
+  struct lock_many_baton_t *b = lock_baton;
+
+  if (!b->cb_err)
+    b->cb_err = b->lock_callback(b->lock_baton, path, lock, fs_err, pool);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
-svn_fs_lock2(apr_hash_t **results,
-             svn_fs_t *fs,
-             apr_hash_t *targets,
-             const char *comment,
-             svn_boolean_t is_dav_comment,
-             apr_time_t expiration_date,
-             svn_boolean_t steal_lock,
-             apr_pool_t *result_pool,
-             apr_pool_t *scratch_pool)
+svn_fs_lock_many(svn_fs_t *fs,
+                 apr_hash_t *targets,
+                 const char *comment,
+                 svn_boolean_t is_dav_comment,
+                 apr_time_t expiration_date,
+                 svn_boolean_t steal_lock,
+                 svn_fs_lock_callback_t lock_callback,
+                 void *lock_baton,
+                 apr_pool_t *result_pool,
+                 apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
-  apr_hash_t *ok_targets = apr_hash_make(scratch_pool), *ok_results;
-  svn_error_t *err;
-
-  *results = apr_hash_make(result_pool);
+  apr_hash_t *ok_targets = apr_hash_make(scratch_pool);
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
+  struct lock_many_baton_t baton;
 
   /* Enforce that the comment be xml-escapable. */
   if (comment)
@@ -1645,29 +1669,58 @@ svn_fs_lock2(apr_hash_t **results,
 
       if (err)
         {
-          svn_fs_lock_result_t *result
-            = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-
-          result->err = err;
-          result->lock = NULL;
-          svn_hash_sets(*results, svn__apr_hash_index_key(hi), result);
+          if (!cb_err)
+            cb_err = lock_callback(lock_baton, svn__apr_hash_index_key(hi),
+                                   NULL, err, scratch_pool);
+          svn_error_clear(err);
         }
       else
         svn_hash_sets(ok_targets, svn__apr_hash_index_key(hi), target);
     }
 
-  err = fs->vtable->lock(&ok_results, fs, ok_targets, comment,
-                         is_dav_comment, expiration_date,
-                         steal_lock, result_pool, scratch_pool);
-
-  for (hi = apr_hash_first(scratch_pool, ok_results);
-       hi; hi = apr_hash_next(hi))
-    svn_hash_sets(*results, svn__apr_hash_index_key(hi),
-                  svn__apr_hash_index_val(hi));
+  if (!apr_hash_count(ok_targets))
+    return svn_error_trace(cb_err);
+
+  baton.lock_callback = lock_callback;
+  baton.lock_baton = lock_baton;
+  baton.cb_err = cb_err;
+
+  err = fs->vtable->lock(fs, ok_targets, comment, is_dav_comment,
+                         expiration_date, steal_lock,
+                         lock_many_cb, &baton,
+                         result_pool, scratch_pool);
+
+  if (err && baton.cb_err)
+    svn_error_compose(err, baton.cb_err);
+  else if (!err)
+    err = baton.cb_err;
 
   return svn_error_trace(err);
 }
 
+struct lock_baton_t {
+  const svn_lock_t *lock;
+  svn_error_t *fs_err;
+};
+
+/* Implements svn_fs_lock_callback_t. Used by svn_fs_lock and
+   svn_fs_unlock to record the lock and error from svn_fs_lock_many
+   and svn_fs_unlock_many. */
+static svn_error_t *
+lock_cb(void *lock_baton,
+        const char *path,
+        const svn_lock_t *lock,
+        svn_error_t *fs_err,
+        apr_pool_t *pool)
+{
+  struct lock_baton_t *b = lock_baton;
+
+  b->lock = lock;
+  b->fs_err = svn_error_dup(fs_err);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
 svn_fs_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
             const char *token, const char *comment,
@@ -1675,32 +1728,28 @@ svn_fs_lock(svn_lock_t **lock, svn_fs_t 
             svn_revnum_t current_rev, svn_boolean_t steal_lock,
             apr_pool_t *pool)
 {
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   svn_fs_lock_target_t target; 
   svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   target.token = token;
   target.current_rev = current_rev;
   svn_hash_sets(targets, path, &target);
 
-  err = svn_fs_lock2(&results, fs, targets, comment, is_dav_comment,
-                     expiration_date, steal_lock, pool, pool);
-
-  if (apr_hash_count(results))
-    {
-      svn_fs_lock_result_t *result
-        = svn__apr_hash_index_val(apr_hash_first(pool, results));
-
-      if (result->lock)
-        *lock = result->lock;
-
-      if (err && result->err)
-        svn_error_compose(err, result->err);
-      else if (!err)
-        err = result->err;
-    }
+  err = svn_fs_lock_many(fs, targets, comment, is_dav_comment,
+                         expiration_date, steal_lock, lock_cb, &baton,
+                         pool, pool);
+
+  if (baton.lock)
+    *lock = (svn_lock_t*)baton.lock;
+
+  if (err && baton.fs_err)
+    svn_error_compose(err, baton.fs_err);
+  else if (!err)
+    err = baton.fs_err;
   
-  return err;
+  return svn_error_trace(err);
 }
 
 svn_error_t *
@@ -1710,14 +1759,16 @@ svn_fs_generate_lock_token(const char **
 }
 
 svn_error_t *
-svn_fs_unlock2(apr_hash_t **results,
-               svn_fs_t *fs,
-               apr_hash_t *targets,
-               svn_boolean_t break_lock,
-               apr_pool_t *result_pool,
-               apr_pool_t *scratch_pool)
+svn_fs_unlock_many(svn_fs_t *fs,
+                   apr_hash_t *targets,
+                   svn_boolean_t break_lock,
+                   svn_fs_lock_callback_t lock_callback,
+                   void *lock_baton,
+                   apr_pool_t *result_pool,
+                   apr_pool_t *scratch_pool)
 {
-  return svn_error_trace(fs->vtable->unlock(results, fs, targets, break_lock,
+  return svn_error_trace(fs->vtable->unlock(fs, targets, break_lock,
+                                            lock_callback, lock_baton,
                                             result_pool, scratch_pool));
 }
 
@@ -1725,27 +1776,23 @@ svn_error_t *
 svn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
               svn_boolean_t break_lock, apr_pool_t *pool)
 {
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   if (!token)
     token = "";
   svn_hash_sets(targets, path, token);
 
-  err = svn_fs_unlock2(&results, fs, targets, break_lock, pool, pool);
-
-  if (apr_hash_count(results))
-    {
-      svn_fs_lock_result_t *result
-        = svn__apr_hash_index_val(apr_hash_first(pool, results));
+  err = svn_fs_unlock_many(fs, targets, break_lock, lock_cb, &baton,
+                           pool, pool);
 
-      if (err && result->err)
-        svn_error_compose(err, result->err);
-      else if (!err)
-        err = result->err;
-    }
+  if (err && baton.fs_err)
+    svn_error_compose(err, baton.fs_err);
+  else if (!err)
+    err = baton.fs_err;
 
-  return err;
+  return svn_error_trace(err);
 }
 
 svn_error_t *

Modified: subversion/trunk/subversion/libsvn_fs/fs-loader.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs/fs-loader.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs/fs-loader.h (original)
+++ subversion/trunk/subversion/libsvn_fs/fs-loader.h Wed Apr  2 17:55:25 2014
@@ -218,17 +218,17 @@ typedef struct fs_vtable_t
   svn_error_t *(*list_transactions)(apr_array_header_t **names_p,
                                     svn_fs_t *fs, apr_pool_t *pool);
   svn_error_t *(*deltify)(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool);
-  svn_error_t *(*lock)(apr_hash_t **results,
-                       svn_fs_t *fs,
+  svn_error_t *(*lock)(svn_fs_t *fs,
                        apr_hash_t *targets,
                        const char *comment, svn_boolean_t is_dav_comment,
                        apr_time_t expiration_date, svn_boolean_t steal_lock,
+                       svn_fs_lock_callback_t lock_callback, void *lock_baton,
                        apr_pool_t *result_pool, apr_pool_t *scratch_pool);
   svn_error_t *(*generate_lock_token)(const char **token, svn_fs_t *fs,
                                       apr_pool_t *pool);
-  svn_error_t *(*unlock)(apr_hash_t ** results,
-                         svn_fs_t *fs, apr_hash_t *targets,
+  svn_error_t *(*unlock)(svn_fs_t *fs, apr_hash_t *targets,
                          svn_boolean_t break_lock,
+                         svn_fs_lock_callback_t lock_callback, void *lock_baton,
                          apr_pool_t *result_pool, apr_pool_t *scratch_pool);
   svn_error_t *(*get_lock)(svn_lock_t **lock, svn_fs_t *fs,
                            const char *path, apr_pool_t *pool);

Modified: subversion/trunk/subversion/libsvn_fs_base/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/lock.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_base/lock.c Wed Apr  2 17:55:25 2014
@@ -217,19 +217,19 @@ txn_body_lock(void *baton, trail_t *trai
 
 
 svn_error_t *
-svn_fs_base__lock(apr_hash_t **results,
-                  svn_fs_t *fs,
+svn_fs_base__lock(svn_fs_t *fs,
                   apr_hash_t *targets,
                   const char *comment,
                   svn_boolean_t is_dav_comment,
                   apr_time_t expiration_date,
                   svn_boolean_t steal_lock,
+                  svn_fs_lock_callback_t lock_callback,
+                  void *lock_baton,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
-
-  *results = apr_hash_make(result_pool);
+  svn_error_t *cb_err = SVN_NO_ERROR;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
@@ -239,8 +239,7 @@ svn_fs_base__lock(apr_hash_t **results,
       const char *path = svn__apr_hash_index_key(hi);
       const svn_fs_lock_target_t *target = svn__apr_hash_index_val(hi);
       svn_lock_t *lock;
-      svn_fs_lock_result_t *result = apr_palloc(result_pool,
-                                                sizeof(svn_fs_lock_result_t));
+      svn_error_t *err;
 
       args.lock_p = &lock;
       args.path = svn_fs__canonicalize_abspath(path, result_pool);
@@ -251,13 +250,14 @@ svn_fs_base__lock(apr_hash_t **results,
       args.expiration_date = expiration_date;
       args.current_rev = target->current_rev;
       
-      result->err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, FALSE,
-                                           scratch_pool);
-      result->lock = lock;
-      svn_hash_sets(*results, args.path, result);
+      err = svn_fs_base__retry_txn(fs, txn_body_lock, &args, FALSE,
+                                   scratch_pool);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, path, lock, err, scratch_pool);
+      svn_error_clear(err);
     }
 
-  return SVN_NO_ERROR;
+  return svn_error_trace(cb_err);
 }
 
 
@@ -325,16 +325,16 @@ txn_body_unlock(void *baton, trail_t *tr
 
 
 svn_error_t *
-svn_fs_base__unlock(apr_hash_t **results,
-                    svn_fs_t *fs,
+svn_fs_base__unlock(svn_fs_t *fs,
                     apr_hash_t *targets,
                     svn_boolean_t break_lock,
+                    svn_fs_lock_callback_t lock_callback,
+                    void *lock_baton,
                     apr_pool_t *result_pool,
                     apr_pool_t *scratch_pool)
 {
   apr_hash_index_t *hi;
-
-  *results = apr_hash_make(result_pool);
+  svn_error_t *cb_err = SVN_NO_ERROR;
 
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
@@ -343,16 +343,17 @@ svn_fs_base__unlock(apr_hash_t **results
       struct unlock_args args;
       const char *path = svn__apr_hash_index_key(hi);
       const char *token = svn__apr_hash_index_val(hi);
-      svn_fs_lock_result_t *result = apr_palloc(result_pool,
-                                                sizeof(svn_fs_lock_result_t));
+      svn_error_t *err;
 
       args.path = svn_fs__canonicalize_abspath(path, result_pool);
       args.token = token;
       args.break_lock = break_lock;
-      result->err = svn_fs_base__retry_txn(fs, txn_body_unlock, &args, TRUE,
-                                           scratch_pool);
-      result->lock = NULL;
-      svn_hash_sets(*results, args.path, result);
+
+      err = svn_fs_base__retry_txn(fs, txn_body_unlock, &args, TRUE,
+                                   scratch_pool);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, path, NULL, err, scratch_pool);
+      svn_error_clear(err);
     }
 
   return SVN_NO_ERROR;

Modified: subversion/trunk/subversion/libsvn_fs_base/lock.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_base/lock.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_base/lock.h (original)
+++ subversion/trunk/subversion/libsvn_fs_base/lock.h Wed Apr  2 17:55:25 2014
@@ -35,13 +35,14 @@ extern "C" {
 /* These functions implement part of the FS loader library's fs
    vtables.  See the public svn_fs.h for docstrings.*/
 
-svn_error_t *svn_fs_base__lock(apr_hash_t **results,
-                               svn_fs_t *fs,
+svn_error_t *svn_fs_base__lock(svn_fs_t *fs,
                                apr_hash_t *targets,
                                const char *comment,
                                svn_boolean_t is_dav_comment,
                                apr_time_t expiration_date,
                                svn_boolean_t steal_lock,
+                               svn_fs_lock_callback_t lock_callback,
+                               void *lock_baton,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 
@@ -49,10 +50,11 @@ svn_error_t *svn_fs_base__generate_lock_
                                               svn_fs_t *fs,
                                               apr_pool_t *pool);
 
-svn_error_t *svn_fs_base__unlock(apr_hash_t **results,
-                                 svn_fs_t *fs,
+svn_error_t *svn_fs_base__unlock(svn_fs_t *fs,
                                  apr_hash_t *targets,
                                  svn_boolean_t break_lock,
+                                 svn_fs_lock_callback_t lock_callback,
+                                 void *lock_baton,
                                  apr_pool_t *result_pool,
                                  apr_pool_t *scratch_pool);
 

Modified: subversion/trunk/subversion/libsvn_fs_fs/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/lock.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/lock.c Wed Apr  2 17:55:25 2014
@@ -1165,13 +1165,14 @@ unlock_single(svn_fs_t *fs,
 /*** Public API implementations ***/
 
 svn_error_t *
-svn_fs_fs__lock(apr_hash_t **results,
-                svn_fs_t *fs,
+svn_fs_fs__lock(svn_fs_t *fs,
                 apr_hash_t *targets,
                 const char *comment,
                 svn_boolean_t is_dav_comment,
                 apr_time_t expiration_date,
                 svn_boolean_t steal_lock,
+                svn_fs_lock_callback_t lock_callback,
+                void *lock_baton,
                 apr_pool_t *result_pool,
                 apr_pool_t *scratch_pool)
 {
@@ -1179,11 +1180,9 @@ svn_fs_fs__lock(apr_hash_t **results,
   apr_array_header_t *sorted_targets;
   apr_hash_t *cannonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
-  *results = apr_hash_make(result_pool);
-
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
   /* We need to have a username attached to the fs. */
@@ -1224,16 +1223,18 @@ svn_fs_fs__lock(apr_hash_t **results,
     {
       struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
                                                 struct lock_info_t);
-      svn_fs_lock_result_t *result
-        = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-
-      result->lock = info->lock;
-      result->err = info->fs_err;
-
-      svn_hash_sets(*results, info->path, result);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, info->path, info->lock,
+                               info->fs_err, scratch_pool);
+      svn_error_clear(info->fs_err);
     }
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
 }
 
 
@@ -1254,10 +1255,11 @@ svn_fs_fs__generate_lock_token(const cha
 }
 
 svn_error_t *
-svn_fs_fs__unlock(apr_hash_t **results,
-                  svn_fs_t *fs,
+svn_fs_fs__unlock(svn_fs_t *fs,
                   apr_hash_t *targets,
                   svn_boolean_t break_lock,
+                  svn_fs_lock_callback_t lock_callback,
+                  void *lock_baton,
                   apr_pool_t *result_pool,
                   apr_pool_t *scratch_pool)
 {
@@ -1265,11 +1267,9 @@ svn_fs_fs__unlock(apr_hash_t **results,
   apr_array_header_t *sorted_targets;
   apr_hash_t *cannonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
-  *results = apr_hash_make(result_pool);
-
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
   /* We need to have a username attached to the fs. */
@@ -1304,16 +1304,18 @@ svn_fs_fs__unlock(apr_hash_t **results,
     {
       struct unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i,
                                                   struct unlock_info_t);
-      svn_fs_lock_result_t *result
-        = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-
-      result->lock = NULL;
-      result->err = info->fs_err;
-
-      svn_hash_sets(*results, info->path, result);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
+                               scratch_pool);
+      svn_error_clear(info->fs_err);
     }
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
 }
 
 

Modified: subversion/trunk/subversion/libsvn_fs_fs/lock.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_fs/lock.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_fs/lock.h (original)
+++ subversion/trunk/subversion/libsvn_fs_fs/lock.h Wed Apr  2 17:55:25 2014
@@ -32,13 +32,14 @@ extern "C" {
 /* These functions implement some of the calls in the FS loader
    library's fs vtables. */
 
-svn_error_t *svn_fs_fs__lock(apr_hash_t **results,
-                             svn_fs_t *fs,
+svn_error_t *svn_fs_fs__lock(svn_fs_t *fs,
                              apr_hash_t *targets,
                              const char *comment,
                              svn_boolean_t is_dav_comment,
                              apr_time_t expiration_date,
                              svn_boolean_t steal_lock,
+                             svn_fs_lock_callback_t lock_callback,
+                             void *lock_baton,
                              apr_pool_t *result_pool,
                              apr_pool_t *scratch_pool);
 
@@ -46,10 +47,11 @@ svn_error_t *svn_fs_fs__generate_lock_to
                                             svn_fs_t *fs,
                                             apr_pool_t *pool);
 
-svn_error_t *svn_fs_fs__unlock(apr_hash_t **results,
-                               svn_fs_t *fs,
+svn_error_t *svn_fs_fs__unlock(svn_fs_t *fs,
                                apr_hash_t *targets,
                                svn_boolean_t break_lock,
+                               svn_fs_lock_callback_t lock_callback,
+                               void *lock_baton,
                                apr_pool_t *result_pool,
                                apr_pool_t *scratch_pool);
 

Modified: subversion/trunk/subversion/libsvn_fs_x/lock.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/lock.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/lock.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/lock.c Wed Apr  2 17:55:25 2014
@@ -1165,13 +1165,14 @@ unlock_single(svn_fs_t *fs,
 /*** Public API implementations ***/
 
 svn_error_t *
-svn_fs_x__lock(apr_hash_t **results,
-               svn_fs_t *fs,
+svn_fs_x__lock(svn_fs_t *fs,
                apr_hash_t *targets,
                const char *comment,
                svn_boolean_t is_dav_comment,
                apr_time_t expiration_date,
                svn_boolean_t steal_lock,
+               svn_fs_lock_callback_t lock_callback,
+               void *lock_baton,
                apr_pool_t *result_pool,
                apr_pool_t *scratch_pool)
 {
@@ -1179,11 +1180,9 @@ svn_fs_x__lock(apr_hash_t **results,
   apr_array_header_t *sorted_targets;
   apr_hash_t *cannonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
-  *results = apr_hash_make(result_pool);
-
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
   /* We need to have a username attached to the fs. */
@@ -1224,16 +1223,18 @@ svn_fs_x__lock(apr_hash_t **results,
     {
       struct lock_info_t *info = &APR_ARRAY_IDX(lb.infos, i,
                                                 struct lock_info_t);
-      svn_fs_lock_result_t *result
-        = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-
-      result->lock = info->lock;
-      result->err = info->fs_err;
-
-      svn_hash_sets(*results, info->path, result);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, info->path, info->lock,
+                               info->fs_err, scratch_pool);
+      svn_error_clear(info->fs_err);
     }
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
 }
 
 
@@ -1254,10 +1255,11 @@ svn_fs_x__generate_lock_token(const char
 }
 
 svn_error_t *
-svn_fs_x__unlock(apr_hash_t **results,
-                 svn_fs_t *fs,
+svn_fs_x__unlock(svn_fs_t *fs,
                  apr_hash_t *targets,
                  svn_boolean_t break_lock,
+                 svn_fs_lock_callback_t lock_callback,
+                 void *lock_baton,
                  apr_pool_t *result_pool,
                  apr_pool_t *scratch_pool)
 {
@@ -1265,11 +1267,9 @@ svn_fs_x__unlock(apr_hash_t **results,
   apr_array_header_t *sorted_targets;
   apr_hash_t *cannonical_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   int i;
 
-  *results = apr_hash_make(result_pool);
-
   SVN_ERR(svn_fs__check_fs(fs, TRUE));
 
   /* We need to have a username attached to the fs. */
@@ -1304,16 +1304,18 @@ svn_fs_x__unlock(apr_hash_t **results,
     {
       struct unlock_info_t *info = &APR_ARRAY_IDX(ub.infos, i,
                                                   struct unlock_info_t);
-      svn_fs_lock_result_t *result
-        = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-
-      result->lock = NULL;
-      result->err = info->fs_err;
-
-      svn_hash_sets(*results, info->path, result);
+      if (!cb_err && lock_callback)
+        cb_err = lock_callback(lock_baton, info->path, NULL, info->fs_err,
+                               scratch_pool);
+      svn_error_clear(info->fs_err);
     }
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
 }
 
 

Modified: subversion/trunk/subversion/libsvn_fs_x/lock.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/lock.h?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/lock.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/lock.h Wed Apr  2 17:55:25 2014
@@ -32,13 +32,14 @@ extern "C" {
 /* These functions implement some of the calls in the FS loader
    library's fs vtables. */
 
-svn_error_t *svn_fs_x__lock(apr_hash_t **results,
-                            svn_fs_t *fs,
+svn_error_t *svn_fs_x__lock(svn_fs_t *fs,
                             apr_hash_t *targets,
                             const char *comment,
                             svn_boolean_t is_dav_comment,
                             apr_time_t expiration_date,
                             svn_boolean_t steal_lock,
+                            svn_fs_lock_callback_t lock_callback,
+                            void *lock_baton,
                             apr_pool_t *result_pool,
                             apr_pool_t *scratch_pool);
 
@@ -46,10 +47,11 @@ svn_error_t *svn_fs_x__generate_lock_tok
                                            svn_fs_t *fs,
                                            apr_pool_t *pool);
 
-svn_error_t *svn_fs_x__unlock(apr_hash_t **results,
-                              svn_fs_t *fs,
+svn_error_t *svn_fs_x__unlock(svn_fs_t *fs,
                               apr_hash_t *targets,
                               svn_boolean_t break_lock,
+                              svn_fs_lock_callback_t lock_callback,
+                              void *lock_baton,
                               apr_pool_t *result_pool,
                               apr_pool_t *scratch_pool);
   

Modified: subversion/trunk/subversion/libsvn_ra_local/ra_plugin.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_ra_local/ra_plugin.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_ra_local/ra_plugin.c (original)
+++ subversion/trunk/subversion/libsvn_ra_local/ra_plugin.c Wed Apr  2 17:55:25 2014
@@ -411,7 +411,6 @@ deltify_etc(const svn_commit_info_t *com
     {
       apr_pool_t *subpool = svn_pool_create(scratch_pool);
       apr_hash_t *targets = apr_hash_make(subpool);
-      apr_hash_t *results;
       apr_hash_index_t *hi;
 
       for (hi = apr_hash_first(subpool, deb->lock_tokens); hi;
@@ -428,14 +427,9 @@ deltify_etc(const svn_commit_info_t *com
       /* 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_unlock2(&results, deb->repos, targets,
-                                           FALSE, subpool, subpool));
-
-      for (hi = apr_hash_first(subpool, results); hi; hi = apr_hash_next(hi))
-        {
-          svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-          svn_error_clear(result->err);
-        }
+      svn_error_clear(svn_repos_fs_unlock_many(deb->repos, targets, FALSE,
+                                               NULL, NULL,
+                                               subpool, subpool));
 
       svn_pool_destroy(subpool);
     }
@@ -1381,6 +1375,36 @@ svn_ra_local__get_location_segments(svn_
                                           NULL, NULL, pool);
 }
 
+struct lock_baton_t {
+  svn_ra_lock_callback_t lock_func;
+  void *lock_baton;
+  const char *fs_path;
+  svn_boolean_t is_lock;
+  svn_error_t *cb_err;
+};
+
+/* Implements svn_fs_lock_callback_t.  Used by svn_ra_local__lock and
+   svn_ra_local__unlock to forward to supplied callback and record any
+   callback error. */
+static svn_error_t *
+lock_cb(void *lock_baton,
+        const char *path,
+        const svn_lock_t *lock,
+        svn_error_t *fs_err,
+        apr_pool_t *pool)
+{
+  struct lock_baton_t *b = lock_baton;
+
+  if (b && !b->cb_err && b->lock_func)
+    {
+      path = svn_fspath__skip_ancestor(b->fs_path, path);
+      b->cb_err = b->lock_func(b->lock_baton, path, b->is_lock, lock, fs_err,
+                               pool);
+    }
+  
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 svn_ra_local__lock(svn_ra_session_t *session,
                    apr_hash_t *path_revs,
@@ -1391,10 +1415,10 @@ svn_ra_local__lock(svn_ra_session_t *ses
                    apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   apr_hash_index_t *hi;
-  svn_error_t *err, *err_cb = SVN_NO_ERROR;
+  svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   /* A username is absolutely required to lock a path. */
   SVN_ERR(get_username(session, pool));
@@ -1412,31 +1436,23 @@ svn_ra_local__lock(svn_ra_session_t *ses
       svn_hash_sets(targets, abs_path, target);
     }
 
-  err = svn_repos_fs_lock2(&results, sess->repos, targets, comment,
-                           FALSE /* not DAV comment */,
-                           0 /* no expiration */, force,
-                           pool, iterpool);
-
-  /* Make sure we handle all locking errors in results hash. */
-  for (hi = apr_hash_first(pool, results); hi; hi = apr_hash_next(hi))
-    {
-      const char *path = svn__apr_hash_index_key(hi);
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-
-      svn_pool_clear(iterpool);
-
-      path = svn_fspath__skip_ancestor(sess->fs_path->data, path);
-      if (!err_cb)
-        err_cb = lock_func(lock_baton, path, TRUE, result->lock, result->err,
-                           iterpool);
-      svn_error_clear(result->err);
-    }
+  baton.lock_func = lock_func;
+  baton.lock_baton = lock_baton;
+  baton.fs_path = sess->fs_path->data;
+  baton.is_lock = TRUE;
+  baton.cb_err = SVN_NO_ERROR;
+
+  err = svn_repos_fs_lock_many(sess->repos, targets, comment,
+                               FALSE /* not DAV comment */,
+                               0 /* no expiration */, force,
+                               lock_cb, &baton,
+                               pool, pool);
 
-  svn_pool_destroy(iterpool);
-  if (err && err_cb)
-    svn_error_compose(err, err_cb);
+  if (err && baton.cb_err)
+    svn_error_compose(err, baton.cb_err);
   else if (!err)
-    err = err_cb;
+    err = baton.cb_err;
+
   return svn_error_trace(err);
 }
 
@@ -1450,10 +1466,10 @@ svn_ra_local__unlock(svn_ra_session_t *s
                      apr_pool_t *pool)
 {
   svn_ra_local__session_baton_t *sess = session->priv;
-  apr_pool_t *iterpool = svn_pool_create(pool);
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   apr_hash_index_t *hi;
-  svn_error_t *err, *err_cb = SVN_NO_ERROR;
+  svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   /* A username is absolutely required to unlock a path. */
   SVN_ERR(get_username(session, pool));
@@ -1468,29 +1484,20 @@ svn_ra_local__unlock(svn_ra_session_t *s
       svn_hash_sets(targets, abs_path, token);
     }
 
-  err = svn_repos_fs_unlock2(&results, sess->repos, targets, force,
-                             pool, iterpool);
+  baton.lock_func = lock_func;
+  baton.lock_baton = lock_baton;
+  baton.fs_path = sess->fs_path->data;
+  baton.is_lock = FALSE;
+  baton.cb_err = SVN_NO_ERROR;
 
-  /* Make sure we handle all locking errors in results hash. */
-  for (hi = apr_hash_first(pool, results); hi; hi = apr_hash_next(hi))
-    {
-      const char *path = svn__apr_hash_index_key(hi);
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
+  err = svn_repos_fs_unlock_many(sess->repos, targets, force, lock_cb, &baton,
+                                 pool, pool);
 
-      svn_pool_clear(iterpool);
-
-      path = svn_fspath__skip_ancestor(sess->fs_path->data, path);
-      if (lock_func && !err_cb)
-        err_cb = lock_func(lock_baton, path, FALSE, NULL, result->err,
-                           iterpool);
-      svn_error_clear(result->err);
-    }
-
-  svn_pool_destroy(iterpool);
-  if (err && err_cb)
-    svn_error_compose(err, err_cb);
+  if (err && baton.cb_err)
+    svn_error_compose(err, baton.cb_err);
   else if (!err)
-    err = err_cb;
+    err = baton.cb_err;
+
   return svn_error_trace(err);
 }
 

Modified: subversion/trunk/subversion/libsvn_repos/fs-wrap.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_repos/fs-wrap.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_repos/fs-wrap.c (original)
+++ subversion/trunk/subversion/libsvn_repos/fs-wrap.c Wed Apr  2 17:55:25 2014
@@ -507,28 +507,60 @@ svn_repos_fs_revision_proplist(apr_hash_
   return SVN_NO_ERROR;
 }
 
+struct lock_many_baton_t {
+  svn_boolean_t need_lock;
+  apr_array_header_t *paths;
+  svn_fs_lock_callback_t lock_callback;
+  void *lock_baton;
+  svn_error_t *cb_err;
+  apr_pool_t *pool;
+};
+
+/* Implements svn_fs_lock_callback_t.  Used by svn_repos_fs_lock_many
+   and svn_repos_fs_unlock_many to record the paths for use by post-
+   hooks, forward to the supplied callback and record any callback
+   error. */
+static svn_error_t *
+lock_many_cb(void *lock_baton,
+             const char *path,
+             const svn_lock_t *lock,
+             svn_error_t *fs_err,
+             apr_pool_t *pool)
+{
+  struct lock_many_baton_t *b = lock_baton;
+
+  if (!b->cb_err && b->lock_callback)
+    b->cb_err = b->lock_callback(b->lock_baton, path, lock, fs_err, pool);
+
+  if ((b->need_lock && lock) || (!b->need_lock && !fs_err))
+    APR_ARRAY_PUSH(b->paths, const char *) = apr_pstrdup(b->pool, path);
+
+  return SVN_NO_ERROR;
+}
+
 svn_error_t *
-svn_repos_fs_lock2(apr_hash_t **results,
-                   svn_repos_t *repos,
-                   apr_hash_t *targets,
-                   const char *comment,
-                   svn_boolean_t is_dav_comment,
-                   apr_time_t expiration_date,
-                   svn_boolean_t steal_lock,
-                   apr_pool_t *result_pool,
-                   apr_pool_t *scratch_pool)
+svn_repos_fs_lock_many(svn_repos_t *repos,
+                       apr_hash_t *targets,
+                       const char *comment,
+                       svn_boolean_t is_dav_comment,
+                       apr_time_t expiration_date,
+                       svn_boolean_t steal_lock,
+                       svn_fs_lock_callback_t lock_callback,
+                       void *lock_baton,
+                       apr_pool_t *result_pool,
+                       apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   svn_fs_access_t *access_ctx = NULL;
   const char *username = NULL;
   apr_hash_t *hooks_env;
   apr_hash_t *pre_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  apr_array_header_t *paths;
-  apr_hash_t *pre_results;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  struct lock_many_baton_t baton;
 
-  *results = apr_hash_make(result_pool);
+  if (!apr_hash_count(targets))
+    return SVN_NO_ERROR;
 
   /* Parse the hooks-env file (if any). */
   SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
@@ -557,11 +589,10 @@ svn_repos_fs_lock2(apr_hash_t **results,
                                       username, comment, steal_lock, iterpool);
       if (err)
         {
-          svn_fs_lock_result_t *result
-            = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-          result->lock = NULL;
-          result->err = err;
-          svn_hash_sets(*results, path, result);
+          if (!cb_err && lock_callback)
+            cb_err = lock_callback(lock_baton, path, NULL, err, iterpool);
+          svn_error_clear(err);
+          
           continue;
         }
 
@@ -571,39 +602,62 @@ svn_repos_fs_lock2(apr_hash_t **results,
       svn_hash_sets(pre_targets, path, target);
     }
 
-  err = svn_fs_lock2(&pre_results, repos->fs, pre_targets, comment,
-                     is_dav_comment, expiration_date, steal_lock,
-                     result_pool, iterpool);
-
-  /* Combine results so the caller can handle all the errors. */
-  for (hi = apr_hash_first(iterpool, pre_results); hi; hi = apr_hash_next(hi))
-    svn_hash_sets(*results, svn__apr_hash_index_key(hi),
-                  svn__apr_hash_index_val(hi));
+  if (!apr_hash_count(pre_targets))
+    return svn_error_trace(cb_err);
 
-  /* If there are locks and an error should we return or run the post-lock? */
-  if (err)
-    return svn_error_trace(err);
+  baton.need_lock = TRUE;
+  baton.paths = apr_array_make(scratch_pool, apr_hash_count(pre_targets),
+                               sizeof(const char *));
+  baton.lock_callback = lock_callback;
+  baton.lock_baton = lock_baton;
+  baton.cb_err = cb_err;
+  baton.pool = scratch_pool;
+
+  err = svn_fs_lock_many(repos->fs, pre_targets, comment,
+                         is_dav_comment, expiration_date, steal_lock,
+                         lock_many_cb, &baton, result_pool, iterpool);
 
-  /* Extract paths that were successfully locked for the post-lock. */
-  paths = apr_array_make(iterpool, apr_hash_count(pre_results),
-                         sizeof(const char *));
-  for (hi = apr_hash_first(iterpool, pre_results); hi; hi = apr_hash_next(hi))
+  /* If there are locks and an error should we return or run the post-lock? */
+  if (!err && baton.paths->nelts)
     {
-      const char *path = svn__apr_hash_index_key(hi);
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-
-      if (result->lock)
-        APR_ARRAY_PUSH(paths, const char *) = path;
+      err = svn_repos__hooks_post_lock(repos, hooks_env, baton.paths, username,
+                                       iterpool);
+      if (err)
+        err = svn_error_create(SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED, err,
+                            _("Locking succeeded, but post-lock hook failed"));
     }
 
-  err = svn_repos__hooks_post_lock(repos, hooks_env, paths, username, iterpool);
-  if (err)
-    err = svn_error_create(SVN_ERR_REPOS_POST_LOCK_HOOK_FAILED, err,
-                           "Locking succeeded, but post-lock hook failed");
-
   svn_pool_destroy(iterpool);
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
+}
+
+struct lock_baton_t {
+  const svn_lock_t *lock;
+  svn_error_t *fs_err;
+};
+
+/* Implements svn_fs_lock_callback_t.  Used by svn_repos_fs_lock and
+   svn_repos_fs_unlock to record the lock and error from
+   svn_repos_fs_lock_many and svn_repos_fs_unlock_many. */
+static svn_error_t *
+lock_cb(void *lock_baton,
+        const char *path,
+        const svn_lock_t *lock,
+        svn_error_t *fs_err,
+        apr_pool_t *pool)
+{
+  struct lock_baton_t *b = lock_baton;
+
+  b->lock = lock;
+  b->fs_err = svn_error_dup(fs_err);
+
+  return SVN_NO_ERROR;
 }
 
 svn_error_t *
@@ -618,55 +672,51 @@ svn_repos_fs_lock(svn_lock_t **lock,
                   svn_boolean_t steal_lock,
                   apr_pool_t *pool)
 {
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   svn_fs_lock_target_t target; 
   svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   target.token = token;
   target.current_rev = current_rev;
   svn_hash_sets(targets, path, &target);
 
-  err = svn_repos_fs_lock2(&results, repos, targets, comment, is_dav_comment,
-                           expiration_date, steal_lock,
-                           pool, pool);
-
-  if (apr_hash_count(results))
-    {
-      const svn_fs_lock_result_t *result
-        = svn__apr_hash_index_val(apr_hash_first(pool, results));
-
-      if (result->lock)
-        *lock = result->lock;
-
-      if (err && result->err)
-        svn_error_compose(err, result->err);
-      else if (!err)
-        err = result->err;
-    }
+  err = svn_repos_fs_lock_many(repos, targets, comment, is_dav_comment,
+                               expiration_date, steal_lock, lock_cb, &baton,
+                               pool, pool);
+
+  if (baton.lock)
+    *lock = (svn_lock_t*)baton.lock;
+
+  if (err && baton.fs_err)
+    svn_error_compose(err, baton.fs_err);
+  else if (!err)
+    err = baton.fs_err;
 
-  return err;
+  return svn_error_trace(err);
 }
 
 
 svn_error_t *
-svn_repos_fs_unlock2(apr_hash_t **results,
-                     svn_repos_t *repos,
-                     apr_hash_t *targets,
-                     svn_boolean_t break_lock,
-                     apr_pool_t *result_pool,
-                     apr_pool_t *scratch_pool)
+svn_repos_fs_unlock_many(svn_repos_t *repos,
+                         apr_hash_t *targets,
+                         svn_boolean_t break_lock,
+                         svn_fs_lock_callback_t lock_callback,
+                         void *lock_baton,
+                         apr_pool_t *result_pool,
+                         apr_pool_t *scratch_pool)
 {
-  svn_error_t *err;
+  svn_error_t *err, *cb_err = SVN_NO_ERROR;
   svn_fs_access_t *access_ctx = NULL;
   const char *username = NULL;
   apr_hash_t *hooks_env;
   apr_hash_t *pre_targets = apr_hash_make(scratch_pool);
   apr_hash_index_t *hi;
-  apr_array_header_t *paths;
-  apr_hash_t *pre_results;
   apr_pool_t *iterpool = svn_pool_create(scratch_pool);
+  struct lock_many_baton_t baton;
 
-  *results = apr_hash_make(result_pool);
+  if (!apr_hash_count(targets))
+    return SVN_NO_ERROR;
 
   /* Parse the hooks-env file (if any). */
   SVN_ERR(svn_repos__parse_hooks_env(&hooks_env, repos->hooks_env_path,
@@ -682,7 +732,7 @@ svn_repos_fs_unlock2(apr_hash_t **result
        _("Cannot unlock, no authenticated username available"));
 
   /* Run pre-unlock hook.  This could throw error, preventing
-     svn_fs_unlock2() from happening for that path. */
+     svn_fs_unlock_many() from happening for that path. */
   for (hi = apr_hash_first(scratch_pool, targets); hi; hi = apr_hash_next(hi))
     {
       const char *path = svn__apr_hash_index_key(hi);
@@ -694,49 +744,47 @@ svn_repos_fs_unlock2(apr_hash_t **result
                                         break_lock, iterpool);
       if (err)
         {
-          svn_fs_lock_result_t *result
-            = apr_palloc(result_pool, sizeof(svn_fs_lock_result_t));
-          result->lock = NULL;
-          result->err = err;
-          svn_hash_sets(*results, path, result);
+          if (!cb_err && lock_callback)
+            cb_err = lock_callback(lock_baton, path, NULL, err, iterpool);
+          svn_error_clear(err);
+
           continue;
         }
 
       svn_hash_sets(pre_targets, path, token);
     }
 
-  err = svn_fs_unlock2(&pre_results, repos->fs, pre_targets, break_lock,
-                       result_pool, iterpool);
+  if (!apr_hash_count(pre_targets))
+    return svn_error_trace(cb_err);
 
-  /* Combine results for all paths. */
-  for (hi = apr_hash_first(iterpool, pre_results); hi; hi = apr_hash_next(hi))
-    svn_hash_sets(*results, svn__apr_hash_index_key(hi),
-                  svn__apr_hash_index_val(hi));
-
-  if (err)
-    return svn_error_trace(err);
-
-  /* Extract paths that were successfully unlocked for the post-unlock. */
-  paths = apr_array_make(iterpool, apr_hash_count(pre_results),
-                         sizeof(const char *));
-  for (hi = apr_hash_first(iterpool, pre_results); hi; hi = apr_hash_next(hi))
-    {
-      const char *path = svn__apr_hash_index_key(hi);
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
+  baton.need_lock = FALSE;
+  baton.paths = apr_array_make(scratch_pool, apr_hash_count(pre_targets),
+                               sizeof(const char *));
+  baton.lock_callback = lock_callback;
+  baton.lock_baton = lock_baton;
+  baton.cb_err = cb_err;
+  baton.pool = scratch_pool;
 
-      if (result->lock)
-        APR_ARRAY_PUSH(paths, const char *) = path;
-    }
-  
+  err = svn_fs_unlock_many(repos->fs, pre_targets, break_lock,
+                           lock_many_cb, &baton, result_pool, iterpool);
 
-  if ((err = svn_repos__hooks_post_unlock(repos, hooks_env, paths,
-                                          username, iterpool)))
-    err = svn_error_create(SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED, err,
+  if (!err && baton.paths->nelts)
+    {
+      err = svn_repos__hooks_post_unlock(repos, hooks_env, baton.paths,
+                                         username, iterpool);
+      if (err)
+        err = svn_error_create(SVN_ERR_REPOS_POST_UNLOCK_HOOK_FAILED, err,
                            _("Unlock succeeded, but post-unlock hook failed"));
+    }
 
   svn_pool_destroy(iterpool);
 
-  return err;
+  if (err && cb_err)
+    svn_error_compose(err, cb_err);
+  else if (!err)
+    err = cb_err;
+
+  return svn_error_trace(err);
 }
 
 svn_error_t *
@@ -746,28 +794,24 @@ svn_repos_fs_unlock(svn_repos_t *repos,
                     svn_boolean_t break_lock,
                     apr_pool_t *pool)
 {
-  apr_hash_t *targets = apr_hash_make(pool), *results;
+  apr_hash_t *targets = apr_hash_make(pool);
   svn_error_t *err;
+  struct lock_baton_t baton = {0};
 
   if (!token)
     token = "";
 
   svn_hash_sets(targets, path, token);
 
-  err = svn_repos_fs_unlock2(&results, repos, targets, break_lock, pool, pool);
+  err = svn_repos_fs_unlock_many(repos, targets, break_lock, lock_cb, &baton,
+                                 pool, pool);
 
-  if (apr_hash_count(results))
-    {
-      const svn_fs_lock_result_t *result
-        = svn__apr_hash_index_val(apr_hash_first(pool, results));
-
-      if (err && result->err)
-        svn_error_compose(err, result->err);
-      else if (!err)
-        err = result->err;
-    }
+  if (err && baton.fs_err)
+    svn_error_compose(err, baton.fs_err);
+  else if (!err)
+    err = baton.fs_err;
 
-  return err;
+  return svn_error_trace(err);
 }
 
 

Modified: subversion/trunk/subversion/mod_dav_svn/version.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/mod_dav_svn/version.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/mod_dav_svn/version.c (original)
+++ subversion/trunk/subversion/mod_dav_svn/version.c Wed Apr  2 17:55:25 2014
@@ -1354,6 +1354,23 @@ dav_svn__push_locks(dav_resource *resour
   return NULL;
 }
 
+/* Implements svn_fs_lock_callback_t. */
+static svn_error_t *
+unlock_many_cb(void *lock_baton,
+               const char *path,
+               const svn_lock_t *lock,
+               svn_error_t *fs_err,
+               apr_pool_t *pool)
+{
+  request_rec *r = lock_baton;
+
+  if (fs_err)
+    ap_log_rerror(APLOG_MARK, APLOG_ERR, fs_err->apr_err, r,
+                  "%s", fs_err->message);
+
+  return SVN_NO_ERROR;
+}
+
 
 /* Helper for merge().  Free every lock in LOCKS.  The locks
    live in REPOS.  Log any errors for REQUEST.  Use POOL for temporary
@@ -1367,7 +1384,6 @@ release_locks(apr_hash_t *locks,
   apr_hash_index_t *hi;
   apr_pool_t *subpool = svn_pool_create(pool);
   apr_hash_t *targets = apr_hash_make(subpool);
-  apr_hash_t *results;
   svn_error_t *err;
 
   for (hi = apr_hash_first(subpool, locks); hi; hi = apr_hash_next(hi))
@@ -1378,16 +1394,9 @@ release_locks(apr_hash_t *locks,
       svn_hash_sets(targets, path, token);
     }
 
-  err = svn_repos_fs_unlock2(&results, repos, targets, FALSE, subpool, subpool);
+  err = svn_repos_fs_unlock_many(repos, targets, FALSE, unlock_many_cb, r,
+                                 subpool, subpool);
 
-  for (hi = apr_hash_first(subpool, results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-      if (result->err)
-        ap_log_rerror(APLOG_MARK, APLOG_ERR, result->err->apr_err, r,
-                      "%s", result->err->message);
-      svn_error_clear(result->err);
-    }
   if (err) /* If we got an error, just log it and move along. */
     ap_log_rerror(APLOG_MARK, APLOG_ERR, err->apr_err, r,
                   "%s", err->message);

Modified: subversion/trunk/subversion/svnserve/serve.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/svnserve/serve.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/svnserve/serve.c (original)
+++ subversion/trunk/subversion/svnserve/serve.c Wed Apr  2 17:55:25 2014
@@ -1029,7 +1029,7 @@ static svn_error_t *write_prop_diffs(svn
 /* Write out a lock to the client. */
 static svn_error_t *write_lock(svn_ra_svn_conn_t *conn,
                                apr_pool_t *pool,
-                               svn_lock_t *lock)
+                               const svn_lock_t *lock)
 {
   const char *cdate, *edate;
 
@@ -1345,6 +1345,21 @@ static svn_error_t *add_lock_tokens(cons
   return SVN_NO_ERROR;
 }
 
+/* Implements svn_fs_lock_callback_t. */
+static svn_error_t *
+lock_cb(void *baton,
+        const char *path,
+        const svn_lock_t *lock,
+        svn_error_t *fs_err,
+        apr_pool_t *pool)
+{
+  server_baton_t *sb = baton;
+
+  log_error(fs_err, sb);
+
+  return SVN_NO_ERROR;
+}
+
 /* Unlock the paths with lock tokens in LOCK_TOKENS, ignoring any errors.
    LOCK_TOKENS contains svn_ra_svn_item_t elements, assumed to be lists. */
 static svn_error_t *unlock_paths(const apr_array_header_t *lock_tokens,
@@ -1354,8 +1369,6 @@ static svn_error_t *unlock_paths(const a
   int i;
   apr_pool_t *subpool = svn_pool_create(pool);
   apr_hash_t *targets = apr_hash_make(subpool);
-  apr_hash_t *results;
-  apr_hash_index_t *hi;
   svn_error_t *err;
 
   for (i = 0; i < lock_tokens->nelts; ++i)
@@ -1378,15 +1391,8 @@ static svn_error_t *unlock_paths(const a
 
   /* The lock may have become defunct after the commit, so ignore such
      errors. */
-  err = svn_repos_fs_unlock2(&results, sb->repository->repos, targets,
-                             FALSE, subpool, subpool);
-  for (hi = apr_hash_first(subpool, results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-
-      log_error(result->err, sb);
-      svn_error_clear(result->err);
-    }
+  err = svn_repos_fs_unlock_many(sb->repository->repos, targets, FALSE,
+                                 lock_cb, sb, subpool, subpool);
   log_error(err, sb);
   svn_error_clear(err);
 
@@ -2706,6 +2712,48 @@ static svn_error_t *lock(svn_ra_svn_conn
   return SVN_NO_ERROR;
 }
 
+struct lock_result_t {
+  const svn_lock_t *lock;
+  svn_error_t *err;
+};
+
+struct lock_many_baton_t {
+  apr_hash_t *results;
+  apr_pool_t *pool;
+};
+
+/* Implements svn_fs_lock_callback_t. */
+static svn_error_t *
+lock_many_cb(void *baton,
+             const char *path,
+             const svn_lock_t *fs_lock,
+             svn_error_t *fs_err,
+             apr_pool_t *pool)
+{
+  struct lock_many_baton_t *b = baton;
+  struct lock_result_t *result = apr_palloc(b->pool,
+                                            sizeof(struct lock_result_t));
+
+  result->lock = fs_lock;
+  result->err = svn_error_dup(fs_err);
+  svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result);
+
+  return SVN_NO_ERROR;
+}
+
+static void
+clear_lock_result_hash(apr_hash_t *results,
+                       apr_pool_t *scratch_pool)
+{
+  apr_hash_index_t *hi;
+
+  for (hi = apr_hash_first(scratch_pool, results); hi; hi = apr_hash_next(hi))
+    {
+      struct lock_result_t *result = svn__apr_hash_index_val(hi);
+      svn_error_clear(result->err);
+    }
+}
+
 static svn_error_t *lock_many(svn_ra_svn_conn_t *conn, apr_pool_t *pool,
                               apr_array_header_t *params, void *baton)
 {
@@ -2718,8 +2766,8 @@ static svn_error_t *lock_many(svn_ra_svn
   svn_error_t *err, *write_err = SVN_NO_ERROR;
   apr_hash_t *targets = apr_hash_make(pool);
   apr_hash_t *authz_results = apr_hash_make(pool);
-  apr_hash_t *results;
   apr_hash_index_t *hi;
+  struct lock_many_baton_t lmb;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "(?c)bl", &comment, &steal_lock,
                                   &path_revs));
@@ -2774,8 +2822,8 @@ static svn_error_t *lock_many(svn_ra_svn
 
       if (! lookup_access(subpool, b, svn_authz_write, full_path, TRUE))
         {
-          svn_fs_lock_result_t *result
-            = apr_palloc(pool, sizeof(svn_fs_lock_result_t));
+          struct lock_result_t *result
+            = apr_palloc(pool, sizeof(struct lock_result_t));
 
           result->lock = NULL;
           result->err = error_create_and_log(SVN_ERR_RA_NOT_AUTHORIZED,
@@ -2785,10 +2833,14 @@ static svn_error_t *lock_many(svn_ra_svn
         }
     }
 
-  err = svn_repos_fs_lock2(&results, b->repository->repos, targets,
-                           comment, FALSE,
-                           0, /* No expiration time. */
-                           steal_lock, pool, subpool);
+  lmb.results = apr_hash_make(pool);
+  lmb.pool = pool;
+
+  err = svn_repos_fs_lock_many(b->repository->repos, targets,
+                               comment, FALSE,
+                               0, /* No expiration time. */
+                               steal_lock, lock_many_cb, &lmb,
+                               pool, subpool);
 
   /* The client expects results in the same order as paths were supplied. */
   for (i = 0; i < path_revs->nelts; ++i)
@@ -2797,7 +2849,7 @@ static svn_error_t *lock_many(svn_ra_svn
       svn_revnum_t current_rev;
       svn_ra_svn_item_t *item = &APR_ARRAY_IDX(path_revs, i,
                                                svn_ra_svn_item_t);
-      svn_fs_lock_result_t *result;
+      struct lock_result_t *result;
 
       svn_pool_clear(subpool);
 
@@ -2810,7 +2862,7 @@ static svn_error_t *lock_many(svn_ra_svn
                                    svn_relpath_canonicalize(path, subpool),
                                    subpool);
 
-      result = svn_hash_gets(results, full_path);
+      result = svn_hash_gets(lmb.results, full_path);
       if (!result)
         result = svn_hash_gets(authz_results, full_path);
       if (!result)
@@ -2833,16 +2885,8 @@ static svn_error_t *lock_many(svn_ra_svn
         break;
     }
 
-  for (hi = apr_hash_first(subpool, authz_results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-      svn_error_clear(result->err);
-    }
-  for (hi = apr_hash_first(subpool, results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-      svn_error_clear(result->err);
-    }
+  clear_lock_result_hash(authz_results, subpool);
+  clear_lock_result_hash(lmb.results, subpool);
 
   svn_pool_destroy(subpool);
 
@@ -2895,8 +2939,8 @@ static svn_error_t *unlock_many(svn_ra_s
   svn_error_t *err = SVN_NO_ERROR, *write_err;
   apr_hash_t *targets = apr_hash_make(pool);
   apr_hash_t *authz_results = apr_hash_make(pool);
-  apr_hash_t *results;
   apr_hash_index_t *hi;
+  struct lock_many_baton_t lmb;
 
   SVN_ERR(svn_ra_svn__parse_tuple(params, pool, "bl", &break_lock,
                                   &unlock_tokens));
@@ -2944,8 +2988,8 @@ static svn_error_t *unlock_many(svn_ra_s
       if (! lookup_access(subpool, b, svn_authz_write, full_path,
                           ! break_lock))
         {
-          svn_fs_lock_result_t *result
-            = apr_palloc(pool, sizeof(svn_fs_lock_result_t));
+          struct lock_result_t *result
+            = apr_palloc(pool, sizeof(struct lock_result_t));
 
           result->lock = NULL;
           result->err = error_create_and_log(SVN_ERR_RA_NOT_AUTHORIZED,
@@ -2955,8 +2999,12 @@ static svn_error_t *unlock_many(svn_ra_s
         }
     }
 
-  err = svn_repos_fs_unlock2(&results, b->repository->repos, targets,
-                             break_lock, pool, subpool);
+  lmb.results = apr_hash_make(pool);
+  lmb.pool = pool;
+
+  err = svn_repos_fs_unlock_many(b->repository->repos, targets,
+                                 break_lock, lock_many_cb, &lmb,
+                                 pool, subpool);
 
   /* Return results in the same order as the paths were supplied. */
   for (i = 0; i < unlock_tokens->nelts; ++i)
@@ -2964,7 +3012,7 @@ static svn_error_t *unlock_many(svn_ra_s
       const char *path, *token, *full_path;
       svn_ra_svn_item_t *item = &APR_ARRAY_IDX(unlock_tokens, i,
                                                svn_ra_svn_item_t);
-      svn_fs_lock_result_t *result;
+      struct lock_result_t *result;
 
       svn_pool_clear(subpool);
 
@@ -2977,7 +3025,7 @@ static svn_error_t *unlock_many(svn_ra_s
                                    svn_relpath_canonicalize(path, subpool),
                                    pool);
 
-      result = svn_hash_gets(results, full_path);
+      result = svn_hash_gets(lmb.results, full_path);
       if (!result)
         result = svn_hash_gets(authz_results, full_path);
       if (!result)
@@ -2993,16 +3041,8 @@ static svn_error_t *unlock_many(svn_ra_s
         break;
     }
 
-  for (hi = apr_hash_first(subpool, authz_results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-      svn_error_clear(result->err);
-    }
-  for (hi = apr_hash_first(subpool, results); hi; hi = apr_hash_next(hi))
-    {
-      svn_fs_lock_result_t *result = svn__apr_hash_index_val(hi);
-      svn_error_clear(result->err);
-    }
+  clear_lock_result_hash(authz_results, subpool);
+  clear_lock_result_hash(lmb.results, subpool);
 
   svn_pool_destroy(subpool);
 

Modified: subversion/trunk/subversion/tests/libsvn_fs/locks-test.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_fs/locks-test.c?rev=1584114&r1=1584113&r2=1584114&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_fs/locks-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_fs/locks-test.c Wed Apr  2 17:55:25 2014
@@ -787,6 +787,10 @@ lock_out_of_date(const svn_test_opts_t *
   return SVN_NO_ERROR;
 }
 
+struct lock_result_t {
+  const svn_lock_t *lock;
+  svn_error_t *fs_err;
+};
 
 static svn_error_t *
 expect_lock(const char *path,
@@ -795,9 +799,9 @@ expect_lock(const char *path,
             apr_pool_t *scratch_pool)
 {
   svn_lock_t *lock;
-  svn_fs_lock_result_t *result = svn_hash_gets(results, path);
+  struct lock_result_t *result = svn_hash_gets(results, path);
 
-  SVN_TEST_ASSERT(result && result->lock && !result->err);
+  SVN_TEST_ASSERT(result && result->lock && !result->fs_err);
   SVN_ERR(svn_fs_get_lock(&lock, fs, path, scratch_pool));
   SVN_TEST_ASSERT(lock);
   return SVN_NO_ERROR;
@@ -810,10 +814,10 @@ expect_error(const char *path,
              apr_pool_t *scratch_pool)
 {
   svn_lock_t *lock;
-  svn_fs_lock_result_t *result = svn_hash_gets(results, path);
+  struct lock_result_t *result = svn_hash_gets(results, path);
 
-  SVN_TEST_ASSERT(result && !result->lock && result->err);
-  svn_error_clear(result->err);
+  SVN_TEST_ASSERT(result && !result->lock && result->fs_err);
+  svn_error_clear(result->fs_err);
   SVN_ERR(svn_fs_get_lock(&lock, fs, path, scratch_pool));
   SVN_TEST_ASSERT(!lock);
   return SVN_NO_ERROR;
@@ -826,9 +830,9 @@ expect_unlock(const char *path,
               apr_pool_t *scratch_pool)
 {
   svn_lock_t *lock;
-  svn_fs_lock_result_t *result = svn_hash_gets(results, path);
+  struct lock_result_t *result = svn_hash_gets(results, path);
 
-  SVN_TEST_ASSERT(result && !result->err);
+  SVN_TEST_ASSERT(result && !result->fs_err);
   SVN_ERR(svn_fs_get_lock(&lock, fs, path, scratch_pool));
   SVN_TEST_ASSERT(!lock);
   return SVN_NO_ERROR;
@@ -841,15 +845,39 @@ expect_unlock_error(const char *path,
                     apr_pool_t *scratch_pool)
 {
   svn_lock_t *lock;
-  svn_fs_lock_result_t *result = svn_hash_gets(results, path);
+  struct lock_result_t *result = svn_hash_gets(results, path);
 
-  SVN_TEST_ASSERT(result && result->err);
-  svn_error_clear(result->err);
+  SVN_TEST_ASSERT(result && result->fs_err);
+  svn_error_clear(result->fs_err);
   SVN_ERR(svn_fs_get_lock(&lock, fs, path, scratch_pool));
   SVN_TEST_ASSERT(lock);
   return SVN_NO_ERROR;
 }
 
+struct lock_many_baton_t {
+  apr_hash_t *results;
+  apr_pool_t *pool;
+};
+
+/* Implements svn_fs_lock_callback_t. */
+static svn_error_t *
+lock_many_cb(void *lock_baton,
+             const char *path,
+             const svn_lock_t *lock,
+             svn_error_t *fs_err,
+             apr_pool_t *pool)
+{
+  struct lock_many_baton_t *b = lock_baton;
+  struct lock_result_t *result = apr_palloc(b->pool,
+                                            sizeof(struct lock_result_t));
+
+  result->lock = lock;
+  result->fs_err = svn_error_dup(fs_err);
+  svn_hash_sets(b->results, apr_pstrdup(b->pool, path), result);
+
+  return SVN_NO_ERROR;
+}
+
 static svn_error_t *
 lock_multiple_paths(const svn_test_opts_t *opts,
                     apr_pool_t *pool)
@@ -861,8 +889,8 @@ lock_multiple_paths(const svn_test_opts_
   svn_revnum_t newrev;
   svn_fs_access_t *access;
   svn_fs_lock_target_t target;
-  apr_hash_t *lock_paths, *unlock_paths, *results;
-  svn_fs_lock_result_t *result;
+  struct lock_many_baton_t baton;
+  apr_hash_t *lock_paths, *unlock_paths;
   apr_hash_index_t *hi;
 
   SVN_ERR(create_greek_fs(&fs, &newrev, "test-lock-multiple-paths",
@@ -878,10 +906,13 @@ lock_multiple_paths(const svn_test_opts_
   SVN_ERR(svn_fs_copy(root, "/A/mu", txn_root, "/A/BBB/mu", pool));
   SVN_ERR(svn_fs_commit_txn(&conflict, &newrev, txn, pool));
 
+  baton.results = apr_hash_make(pool);
+  baton.pool = pool;
   lock_paths = apr_hash_make(pool);
   unlock_paths = apr_hash_make(pool);
   target.token = NULL;
   target.current_rev = newrev;
+
   svn_hash_sets(lock_paths, "/A/B/E/alpha", &target);
   svn_hash_sets(lock_paths, "/A/B/E/beta", &target);
   svn_hash_sets(lock_paths, "/A/B/E/zulu", &target);
@@ -893,81 +924,91 @@ lock_multiple_paths(const svn_test_opts_
   svn_hash_sets(lock_paths, "/X/zulu", &target);
 
   /* Lock some paths. */
-  SVN_ERR(svn_fs_lock2(&results, fs, lock_paths, "comment", 0, 0, 0,
-                       pool, pool));
-
-  SVN_ERR(expect_lock("/A/B/E/alpha", results, fs, pool));
-  SVN_ERR(expect_lock("/A/B/E/beta", results, fs, pool));
-  SVN_ERR(expect_error("/A/B/E/zulu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/BB/mu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/BBB/mu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/D/G/pi", results, fs, pool));
-  SVN_ERR(expect_lock("/A/D/G/rho", results, fs, pool));
-  SVN_ERR(expect_lock("/A/mu", results, fs, pool));
-  SVN_ERR(expect_error("/X/zulu", results, fs, pool));
+  apr_hash_clear(baton.results);
+  SVN_ERR(svn_fs_lock_many(fs, lock_paths, "comment", 0, 0, 0,
+                           lock_many_cb, &baton,
+                           pool, pool));
+
+  SVN_ERR(expect_lock("/A/B/E/alpha", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/B/E/beta", baton.results, fs, pool));
+  SVN_ERR(expect_error("/A/B/E/zulu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/BB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/BBB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/D/G/pi", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/D/G/rho", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/mu", baton.results, fs, pool));
+  SVN_ERR(expect_error("/X/zulu", baton.results, fs, pool));
 
   /* Unlock without force and wrong tokens. */
   for (hi = apr_hash_first(pool, lock_paths); hi; hi = apr_hash_next(hi))
     svn_hash_sets(unlock_paths, svn__apr_hash_index_key(hi), "wrong-token");
-  SVN_ERR(svn_fs_unlock2(&results, fs, unlock_paths, FALSE, pool, pool));
-
-  SVN_ERR(expect_unlock_error("/A/B/E/alpha", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/B/E/beta", results, fs, pool));
-  SVN_ERR(expect_error("/A/B/E/zulu", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/BB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/BBB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/D/G/pi", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/D/G/rho", results, fs, pool));
-  SVN_ERR(expect_unlock_error("/A/mu", results, fs, pool));
-  SVN_ERR(expect_error("/X/zulu", results, fs, pool));
+  apr_hash_clear(baton.results);
+  SVN_ERR(svn_fs_unlock_many(fs, unlock_paths, FALSE, lock_many_cb, &baton,
+                             pool, pool));
+
+  SVN_ERR(expect_unlock_error("/A/B/E/alpha", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/B/E/beta", baton.results, fs, pool));
+  SVN_ERR(expect_error("/A/B/E/zulu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/BB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/BBB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/D/G/pi", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/D/G/rho", baton.results, fs, pool));
+  SVN_ERR(expect_unlock_error("/A/mu", baton.results, fs, pool));
+  SVN_ERR(expect_error("/X/zulu", baton.results, fs, pool));
 
   /* Force unlock. */
   for (hi = apr_hash_first(pool, lock_paths); hi; hi = apr_hash_next(hi))
     svn_hash_sets(unlock_paths, svn__apr_hash_index_key(hi), "");
-  SVN_ERR(svn_fs_unlock2(&results, fs, unlock_paths, TRUE, pool, pool));
-
-  SVN_ERR(expect_unlock("/A/B/E/alpha", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/B/E/beta", results, fs, pool));
-  SVN_ERR(expect_error("/A/B/E/zulu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/BB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/BBB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/D/G/pi", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/D/G/rho", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/mu", results, fs, pool));
-  SVN_ERR(expect_error("/X/zulu", results, fs, pool));
+  apr_hash_clear(baton.results);
+  SVN_ERR(svn_fs_unlock_many(fs, unlock_paths, TRUE, lock_many_cb, &baton,
+                             pool, pool));
+
+  SVN_ERR(expect_unlock("/A/B/E/alpha", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/B/E/beta", baton.results, fs, pool));
+  SVN_ERR(expect_error("/A/B/E/zulu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/BB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/BBB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/D/G/pi", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/D/G/rho", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/mu", baton.results, fs, pool));
+  SVN_ERR(expect_error("/X/zulu", baton.results, fs, pool));
 
   /* Lock again. */
-  SVN_ERR(svn_fs_lock2(&results, fs, lock_paths, "comment", 0, 0, 0,
-                       pool, pool));
-
-  SVN_ERR(expect_lock("/A/B/E/alpha", results, fs, pool));
-  SVN_ERR(expect_lock("/A/B/E/beta", results, fs, pool));
-  SVN_ERR(expect_error("/A/B/E/zulu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/BB/mu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/BBB/mu", results, fs, pool));
-  SVN_ERR(expect_lock("/A/D/G/pi", results, fs, pool));
-  SVN_ERR(expect_lock("/A/D/G/rho", results, fs, pool));
-  SVN_ERR(expect_lock("/A/mu", results, fs, pool));
-  SVN_ERR(expect_error("/X/zulu", results, fs, pool));
+  apr_hash_clear(baton.results);
+  SVN_ERR(svn_fs_lock_many(fs, lock_paths, "comment", 0, 0, 0,
+                           lock_many_cb, &baton,
+                           pool, pool));
+
+  SVN_ERR(expect_lock("/A/B/E/alpha", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/B/E/beta", baton.results, fs, pool));
+  SVN_ERR(expect_error("/A/B/E/zulu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/BB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/BBB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/D/G/pi", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/D/G/rho", baton.results, fs, pool));
+  SVN_ERR(expect_lock("/A/mu", baton.results, fs, pool));
+  SVN_ERR(expect_error("/X/zulu", baton.results, fs, pool));
 
   /* Unlock without force. */
-  for (hi = apr_hash_first(pool, results); hi; hi = apr_hash_next(hi))
+  for (hi = apr_hash_first(pool, baton.results); hi; hi = apr_hash_next(hi))
     {
-      result = svn__apr_hash_index_val(hi);
+      struct lock_result_t *result = svn__apr_hash_index_val(hi);
       svn_hash_sets(unlock_paths, svn__apr_hash_index_key(hi),
                     result->lock ? result->lock->token : "non-existent-token");
     }
-  SVN_ERR(svn_fs_unlock2(&results, fs, unlock_paths, FALSE, pool, pool));
-
-  SVN_ERR(expect_unlock("/A/B/E/alpha", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/B/E/beta", results, fs, pool));
-  SVN_ERR(expect_error("/A/B/E/zulu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/BB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/BBB/mu", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/D/G/pi", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/D/G/rho", results, fs, pool));
-  SVN_ERR(expect_unlock("/A/mu", results, fs, pool));
-  SVN_ERR(expect_error("/X/zulu", results, fs, pool));
+  apr_hash_clear(baton.results);
+  SVN_ERR(svn_fs_unlock_many(fs, unlock_paths, FALSE, lock_many_cb, &baton,
+                             pool, pool));
+
+  SVN_ERR(expect_unlock("/A/B/E/alpha", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/B/E/beta", baton.results, fs, pool));
+  SVN_ERR(expect_error("/A/B/E/zulu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/BB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/BBB/mu", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/D/G/pi", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/D/G/rho", baton.results, fs, pool));
+  SVN_ERR(expect_unlock("/A/mu", baton.results, fs, pool));
+  SVN_ERR(expect_error("/X/zulu", baton.results, fs, pool));
 
   return SVN_NO_ERROR;
 }



Re: svn commit: r1584114 [1/2] - in /subversion/trunk/subversion: include/ libsvn_fs/ libsvn_fs_base/ libsvn_fs_fs/ libsvn_fs_x/ libsvn_ra_local/ libsvn_repos/ mod_dav_svn/ svnserve/ tests/libsvn_fs/ tests/libsvn_ra/

Posted by Julian Foad <ju...@btopenworld.com>.
Philip Martin wrote:

> URL: http://svn.apache.org/r1584114
> Log:
> Convert the new multi-path lock and unlock functions to a callback API,
> rename from _lock2 and _unlock2 to _lock_many and _unlock_many.

> Modified: subversion/trunk/subversion/include/svn_fs.h
> ==============================================================================

> /** Lock the paths in @a targets in @a fs, and set @a *results to the

The old 'results' parameter no longer exists.

Same in _unlock_many() and in the two similar svn_repos.h functions.

- Julian