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

svn commit: r1595112 - in /subversion/trunk/subversion/libsvn_fs_x: ./ fs.c fs.h fs_x.c hotcopy.c recovery.c transaction.c transaction.h util.c util.h

Author: stefan2
Date: Fri May 16 06:03:32 2014
New Revision: 1595112

URL: http://svn.apache.org/r1595112
Log:
Sync'ing FSX with FSFS:
Merge r1588815,1589243,1589250,1589252,1589284,1589368,1589373,
1589376, 1591919 and 1593015 from /subversion/libsvn_fs_fs into
subversion/libsvn_fs_x.  Conflicts were due to the locking code
being moved to transaction.* in FSX.

This ports the locking improvements.

Modified:
    subversion/trunk/subversion/libsvn_fs_x/   (props changed)
    subversion/trunk/subversion/libsvn_fs_x/fs.c
    subversion/trunk/subversion/libsvn_fs_x/fs.h
    subversion/trunk/subversion/libsvn_fs_x/fs_x.c
    subversion/trunk/subversion/libsvn_fs_x/hotcopy.c
    subversion/trunk/subversion/libsvn_fs_x/recovery.c
    subversion/trunk/subversion/libsvn_fs_x/transaction.c
    subversion/trunk/subversion/libsvn_fs_x/transaction.h
    subversion/trunk/subversion/libsvn_fs_x/util.c
    subversion/trunk/subversion/libsvn_fs_x/util.h

Propchange: subversion/trunk/subversion/libsvn_fs_x/
------------------------------------------------------------------------------
  Merged /subversion/trunk/subversion/libsvn_fs_fs:r1588815,1589243,1589250,1589252,1589368,1589373,1589376,1591919,1593015

Modified: subversion/trunk/subversion/libsvn_fs_x/fs.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/fs.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/fs.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/fs.c Fri May 16 06:03:32 2014
@@ -97,11 +97,15 @@ x_serialized_init(svn_fs_t *fs, apr_pool
          intra-process synchronization when grabbing the repository write
          lock. */
       SVN_ERR(svn_mutex__init(&ffsd->fs_write_lock,
-                              SVN_FS_X__USE_LOCK_MUTEX, TRUE, common_pool));
+                              TRUE, TRUE, common_pool));
+
+      /* ... the pack lock ... */
+      SVN_ERR(svn_mutex__init(&ffsd->fs_pack_lock,
+                              TRUE, TRUE, common_pool));
 
       /* ... not to mention locking the txn-current file. */
       SVN_ERR(svn_mutex__init(&ffsd->txn_current_lock,
-                              SVN_FS_X__USE_LOCK_MUTEX, TRUE, common_pool));
+                              TRUE, TRUE, common_pool));
 
       /* We also need a mutex for synchronizing access to the active
          transaction list and free transaction pointer.  This one is

Modified: subversion/trunk/subversion/libsvn_fs_x/fs.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/fs.h?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/fs.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/fs.h Fri May 16 06:03:32 2014
@@ -55,6 +55,7 @@ extern "C" {
 #define PATH_UUID             "uuid"             /* Contains UUID */
 #define PATH_CURRENT          "current"          /* Youngest revision */
 #define PATH_LOCK_FILE        "write-lock"       /* Revision lock file */
+#define PATH_PACK_LOCK_FILE   "pack-lock"        /* Pack lock file */
 #define PATH_REVS_DIR         "revs"             /* Directory of revisions */
 #define PATH_REVPROPS_DIR     "revprops"         /* Directory of revprops */
 #define PATH_TXNS_DIR         "transactions"     /* Directory of transactions */
@@ -147,17 +148,6 @@ typedef struct fs_x_shared_txn_data_t
   apr_pool_t *pool;
 } fs_x_shared_txn_data_t;
 
-/* On most operating systems apr implements file locks per process, not
-   per file.  On Windows apr implements the locking as per file handle
-   locks, so we don't have to add our own mutex for just in-process
-   synchronization. */
-/* Compare ../libsvn_subr/named_atomic.c:USE_THREAD_MUTEX */
-#if APR_HAS_THREADS && !defined(WIN32)
-#define SVN_FS_X__USE_LOCK_MUTEX 1
-#else
-#define SVN_FS_X__USE_LOCK_MUTEX 0
-#endif
-
 /* Private FSX-specific data shared between all svn_fs_t objects that
    relate to a particular filesystem, as identified by filesystem UUID.
    Objects of this type are allocated in the common pool. */
@@ -173,6 +163,12 @@ typedef struct fs_x_shared_data_t
      Access to this object is synchronised under TXN_LIST_LOCK. */
   fs_x_shared_txn_data_t *free_txn;
 
+  /* The following lock must be taken out in reverse order of their
+     declaration here.  Any subset may be acquired and held at any given
+     time but their relative acquisition order must not change.
+
+     (lock 'txn-current' before 'pack' before 'write' before 'txn-list') */
+
   /* A lock for intra-process synchronization when accessing the TXNS list. */
   svn_mutex__t *txn_list_lock;
 
@@ -180,6 +176,10 @@ typedef struct fs_x_shared_data_t
      repository write lock. */
   svn_mutex__t *fs_write_lock;
 
+  /* A lock for intra-process synchronization when grabbing the
+     repository pack operation lock. */
+  svn_mutex__t *fs_pack_lock;
+
   /* A lock for intra-process synchronization when locking the
      txn-current file. */
   svn_mutex__t *txn_current_lock;

Modified: subversion/trunk/subversion/libsvn_fs_x/fs_x.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/fs_x.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/fs_x.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/fs_x.c Fri May 16 06:03:32 2014
@@ -525,7 +525,7 @@ svn_fs_x__upgrade(svn_fs_t *fs,
   baton.cancel_func = cancel_func;
   baton.cancel_baton = cancel_baton;
   
-  return svn_fs_x__with_write_lock(fs, upgrade_body, (void *)&baton, pool);
+  return svn_fs_x__with_all_locks(fs, upgrade_body, (void *)&baton, pool);
 }
 
 

Modified: subversion/trunk/subversion/libsvn_fs_x/hotcopy.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/hotcopy.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/hotcopy.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/hotcopy.c Fri May 16 06:03:32 2014
@@ -910,7 +910,8 @@ hotcopy_locking_src_body(void *baton, ap
   struct hotcopy_body_baton *hbb = baton;
   fs_x_data_t *src_ffd = hbb->src_fs->fsap_data;
 
-  return hotcopy_body(baton, pool);
+  return svn_error_trace(svn_fs_x__with_pack_lock(hbb->src_fs, hotcopy_body,
+                                                  baton, pool));
 }
 
 /* Create an empty filesystem at DST_FS at DST_PATH with the same

Modified: subversion/trunk/subversion/libsvn_fs_x/recovery.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/recovery.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/recovery.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/recovery.c Fri May 16 06:03:32 2014
@@ -234,5 +234,5 @@ svn_fs_x__recover(svn_fs_t *fs,
   b.fs = fs;
   b.cancel_func = cancel_func;
   b.cancel_baton = cancel_baton;
-  return svn_fs_x__with_write_lock(fs, recover_body, &b, pool);
+  return svn_fs_x__with_all_locks(fs, recover_body, &b, pool);
 }

Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.c Fri May 16 06:03:32 2014
@@ -212,31 +212,77 @@ reset_lock_flag(void *baton_void)
   return APR_SUCCESS;
 }
 
-/* Obtain a write lock on the file LOCK_FILENAME (protecting with
-   LOCK_MUTEX if APR is threaded) in a subpool of POOL, call BODY with
-   BATON and that subpool, destroy the subpool (releasing the write
-   lock) and return what BODY returned.  If IS_GLOBAL_LOCK is set,
-   set the HAS_WRITE_LOCK flag while we keep the write lock. */
-static svn_error_t *
-with_some_lock_file(svn_fs_t *fs,
-                    svn_error_t *(*body)(void *baton,
-                                         apr_pool_t *pool),
-                    void *baton,
-                    const char *lock_filename,
-                    svn_boolean_t is_global_lock,
-                    apr_pool_t *pool)
+/* Structure defining a file system lock to be acquired and the function
+   to be executed while the lock is held.
+
+   Instances of this structure may be nested to allow for multiple locks to
+   be taken out before executing the user-provided body.  In that case, BODY
+   and BATON of the outer instances will be with_lock and a with_lock_baton_t
+   instance (transparently, no special treatment is required.).  It is
+   illegal to attempt to acquire the same lock twice within the same lock
+   chain or via nesting calls using separate lock chains.
+
+   All instances along the chain share the same LOCK_POOL such that only one
+   pool needs to be created and cleared for all locks.  We also allocate as
+   much data from that lock pool as possible to minimize memory usage in
+   caller pools. */
+typedef struct with_lock_baton_t
 {
-  apr_pool_t *subpool = svn_pool_create(pool);
-  svn_error_t *err = get_lock_on_filesystem(lock_filename, subpool);
+  /* The filesystem we operate on.  Same for all instances along the chain. */
+  svn_fs_t *fs;
+
+  /* Mutex to complement the lock file in an APR threaded process.
+     No-op object for non-threaded processes but never NULL. */
+  svn_mutex__t *mutex;
+
+  /* Path to the file to lock. */
+  const char *lock_path;
+
+  /* If true, set FS->HAS_WRITE_LOCK after we acquired the lock. */
+  svn_boolean_t is_global_lock;
+
+  /* Function body to execute after we acquired the lock.
+     This may be user-provided or a nested call to with_lock(). */
+  svn_error_t *(*body)(void *baton,
+                       apr_pool_t *pool);
+
+  /* Baton to pass to BODY; possibly NULL.
+     This may be user-provided or a nested lock baton instance. */
+  void *baton;
+
+  /* Pool for all allocations along the lock chain and BODY.  Will hold the
+     file locks and gets destroyed after the outermost BODY returned,
+     releasing all file locks.
+     Same for all instances along the chain. */
+  apr_pool_t *lock_pool;
+
+  /* TRUE, iff BODY is the user-provided body. */
+  svn_boolean_t is_inner_most_lock;
+
+  /* TRUE, iff this is not a nested lock.
+     Then responsible for destroying LOCK_POOL. */
+  svn_boolean_t is_outer_most_lock;
+} with_lock_baton_t;
+
+/* Obtain a write lock on the file BATON->LOCK_PATH and call BATON->BODY
+   with BATON->BATON.  If this is the outermost lock call, release all file
+   locks after the body returned.  If BATON->IS_GLOBAL_LOCK is set, set the
+   HAS_WRITE_LOCK flag while we keep the write lock. */
+static svn_error_t *
+with_some_lock_file(with_lock_baton_t *baton)
+{
+  apr_pool_t *pool = baton->lock_pool;
+  svn_error_t *err = get_lock_on_filesystem(baton->lock_path, pool);
 
   if (!err)
     {
+      svn_fs_t *fs = baton->fs;
       fs_x_data_t *ffd = fs->fsap_data;
 
-      if (is_global_lock)
+      if (baton->is_global_lock)
         {
           /* set the "got the lock" flag and register reset function */
-          apr_pool_cleanup_register(subpool,
+          apr_pool_cleanup_register(pool,
                                     ffd,
                                     reset_lock_flag,
                                     apr_pool_cleanup_null);
@@ -245,16 +291,151 @@ with_some_lock_file(svn_fs_t *fs,
 
       /* nobody else will modify the repo state
          => read HEAD & pack info once */
-      SVN_ERR(svn_fs_x__update_min_unpacked_rev(fs, pool));
-      SVN_ERR(svn_fs_x__youngest_rev(&ffd->youngest_rev_cache, fs, pool));
-      err = body(baton, subpool);
+      if (baton->is_inner_most_lock)
+        {
+          err = svn_fs_x__update_min_unpacked_rev(fs, pool);
+          if (!err)
+            err = svn_fs_x__youngest_rev(&ffd->youngest_rev_cache, fs, pool);
+        }
+
+      if (!err)
+        err = baton->body(baton->baton, pool);
     }
 
-  svn_pool_destroy(subpool);
+  if (baton->is_outer_most_lock)
+    svn_pool_destroy(pool);
 
   return svn_error_trace(err);
 }
 
+/* Wraps with_some_lock_file, protecting it with BATON->MUTEX.
+
+   POOL is unused here and only provided for signature compatibility with
+   WITH_LOCK_BATON_T.BODY. */
+static svn_error_t *
+with_lock(void *baton,
+          apr_pool_t *pool)
+{
+  with_lock_baton_t *lock_baton = baton;
+  SVN_MUTEX__WITH_LOCK(lock_baton->mutex, with_some_lock_file(lock_baton));
+
+  return SVN_NO_ERROR;
+}
+
+/* Enum identifying a filesystem lock. */
+typedef enum lock_id_t
+{
+  write_lock,
+  txn_lock,
+  pack_lock
+} lock_id_t;
+
+/* Initialize BATON->MUTEX, BATON->LOCK_PATH and BATON->IS_GLOBAL_LOCK
+   according to the LOCK_ID.  All other members of BATON must already be
+   valid. */
+static void
+init_lock_baton(with_lock_baton_t *baton,
+                lock_id_t lock_id)
+{
+  fs_x_data_t *ffd = baton->fs->fsap_data;
+  fs_x_shared_data_t *ffsd = ffd->shared;
+
+  switch (lock_id)
+    {
+    case write_lock:
+      baton->mutex = ffsd->fs_write_lock;
+      baton->lock_path = svn_fs_x__path_lock(baton->fs, baton->lock_pool);
+      baton->is_global_lock = TRUE;
+      break;
+
+    case txn_lock:
+      baton->mutex = ffsd->txn_current_lock;
+      baton->lock_path = svn_fs_x__path_txn_current_lock(baton->fs,
+                                                         baton->lock_pool);
+      baton->is_global_lock = FALSE;
+      break;
+
+    case pack_lock:
+      baton->mutex = ffsd->fs_pack_lock;
+      baton->lock_path = svn_fs_x__path_pack_lock(baton->fs,
+                                                  baton->lock_pool);
+      baton->is_global_lock = FALSE;
+      break;
+    }
+}
+
+/* Return the  baton for the innermost lock of a (potential) lock chain.
+   The baton shall take out LOCK_ID from FS and execute BODY with BATON
+   while the lock is being held.  Allocate the result in a sub-pool of POOL.
+ */
+static with_lock_baton_t *
+create_lock_baton(svn_fs_t *fs,
+                  lock_id_t lock_id,
+                  svn_error_t *(*body)(void *baton,
+                                       apr_pool_t *pool),
+                  void *baton,
+                  apr_pool_t *pool)
+{
+  /* Allocate everything along the lock chain into a single sub-pool.
+     This minimizes memory usage and cleanup overhead. */
+  apr_pool_t *lock_pool = svn_pool_create(pool);
+  with_lock_baton_t *result = apr_pcalloc(lock_pool, sizeof(*result));
+
+  /* Store parameters. */
+  result->fs = fs;
+  result->body = body;
+  result->baton = baton;
+
+  /* File locks etc. will use this pool as well for easy cleanup. */
+  result->lock_pool = lock_pool;
+
+  /* Right now, we are the first, (only, ) and last struct in the chain. */
+  result->is_inner_most_lock = TRUE;
+  result->is_outer_most_lock = TRUE;
+
+  /* Select mutex and lock file path depending on LOCK_ID.
+     Also, initialize dependent members (IS_GLOBAL_LOCK only, ATM). */
+  init_lock_baton(result, lock_id);
+
+  return result;
+}
+
+/* Return a baton that wraps NESTED and requests LOCK_ID as additional lock.
+ *
+ * That means, when you create a lock chain, start with the last / innermost
+ * lock to take out and add the first / outermost lock last.
+ */
+static with_lock_baton_t *
+chain_lock_baton(lock_id_t lock_id,
+                 with_lock_baton_t *nested)
+{
+  /* Use the same pool for batons along the lock chain. */
+  apr_pool_t *lock_pool = nested->lock_pool;
+  with_lock_baton_t *result = apr_pcalloc(lock_pool, sizeof(*result));
+
+  /* All locks along the chain operate on the same FS. */
+  result->fs = nested->fs;
+
+  /* Execution of this baton means acquiring the nested lock and its
+     execution. */
+  result->body = with_lock;
+  result->baton = nested;
+
+  /* Shared among all locks along the chain. */
+  result->lock_pool = lock_pool;
+
+  /* We are the new outermost lock but surely not the innermost lock. */
+  result->is_inner_most_lock = FALSE;
+  result->is_outer_most_lock = TRUE;
+  nested->is_outer_most_lock = FALSE;
+
+  /* Select mutex and lock file path depending on LOCK_ID.
+     Also, initialize dependent members (IS_GLOBAL_LOCK only, ATM). */
+  init_lock_baton(result, lock_id);
+
+  return result;
+}
+
 svn_error_t *
 svn_fs_x__with_write_lock(svn_fs_t *fs,
                           svn_error_t *(*body)(void *baton,
@@ -262,39 +443,57 @@ svn_fs_x__with_write_lock(svn_fs_t *fs,
                           void *baton,
                           apr_pool_t *pool)
 {
-  fs_x_data_t *ffd = fs->fsap_data;
-  fs_x_shared_data_t *ffsd = ffd->shared;
+  return svn_error_trace(
+           with_lock(create_lock_baton(fs, write_lock, body, baton, pool),
+                     pool));
+}
 
-  SVN_MUTEX__WITH_LOCK(ffsd->fs_write_lock,
-                       with_some_lock_file(fs, body, baton,
-                                           svn_fs_x__path_lock(fs, pool),
-                                           TRUE,
-                                           pool));
+svn_error_t *
+svn_fs_x__with_pack_lock(svn_fs_t *fs,
+                         svn_error_t *(*body)(void *baton,
+                                              apr_pool_t *pool),
+                         void *baton,
+                         apr_pool_t *pool)
+{
+  return svn_error_trace(
+           with_lock(create_lock_baton(fs, pack_lock, body, baton, pool),
+                     pool));
+}
 
-  return SVN_NO_ERROR;
+svn_error_t *
+svn_fs_x__with_txn_current_lock(svn_fs_t *fs,
+                                svn_error_t *(*body)(void *baton,
+                                                     apr_pool_t *pool),
+                                void *baton,
+                                apr_pool_t *pool)
+{
+  return svn_error_trace(
+           with_lock(create_lock_baton(fs, txn_lock, body, baton, pool),
+                     pool));
 }
 
-/* Run BODY (with BATON and POOL) while the txn-current file
-   of FS is locked. */
-static svn_error_t *
-with_txn_current_lock(svn_fs_t *fs,
-                      svn_error_t *(*body)(void *baton,
-                                           apr_pool_t *pool),
-                      void *baton,
-                      apr_pool_t *pool)
+svn_error_t *
+svn_fs_x__with_all_locks(svn_fs_t *fs,
+                         svn_error_t *(*body)(void *baton,
+                                              apr_pool_t *pool),
+                         void *baton,
+                         apr_pool_t *pool)
 {
   fs_x_data_t *ffd = fs->fsap_data;
-  fs_x_shared_data_t *ffsd = ffd->shared;
 
-  SVN_MUTEX__WITH_LOCK(ffsd->txn_current_lock,
-                       with_some_lock_file(fs, body, baton,
-                                svn_fs_x__path_txn_current_lock(fs, pool),
-                                FALSE,
-                                pool));
+  /* Be sure to use the correct lock ordering as documented in
+     fs_fs_shared_data_t.  The lock chain is being created in 
+     innermost (last to acquire) -> outermost (first to acquire) order. */
+  with_lock_baton_t *lock_baton
+    = create_lock_baton(fs, write_lock, body, baton, pool);
 
-  return SVN_NO_ERROR;
+  lock_baton = chain_lock_baton(pack_lock, lock_baton);
+  lock_baton = chain_lock_baton(txn_lock, lock_baton);
+
+  return svn_error_trace(with_lock(lock_baton, pool));
 }
 
+
 /* A structure used by unlock_proto_rev() and unlock_proto_rev_body(),
    which see. */
 struct unlock_proto_rev_baton
@@ -1015,10 +1214,10 @@ create_txn_dir(const char **id_p,
      number the transaction is based off into the transaction id. */
   cb.pool = pool;
   cb.fs = fs;
-  SVN_ERR(with_txn_current_lock(fs,
-                                get_and_increment_txn_key_body,
-                                &cb,
-                                pool));
+  SVN_ERR(svn_fs_x__with_txn_current_lock(fs,
+                                          get_and_increment_txn_key_body,
+                                          &cb,
+                                          pool));
   *txn_id = cb.txn_number;
 
   *id_p = svn_fs_x__txn_name(*txn_id, pool);

Modified: subversion/trunk/subversion/libsvn_fs_x/transaction.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/transaction.h?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/transaction.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/transaction.h Fri May 16 06:03:32 2014
@@ -40,6 +40,38 @@ svn_fs_x__with_write_lock(svn_fs_t *fs,
                           void *baton,
                           apr_pool_t *pool);
 
+/* Obtain a pack operation lock on the filesystem FS in a subpool of POOL,
+   call BODY with BATON and that subpool, destroy the subpool (releasing the
+   write lock) and return what BODY returned. */
+svn_error_t *
+svn_fs_x__with_pack_lock(svn_fs_t *fs,
+                         svn_error_t *(*body)(void *baton,
+                                              apr_pool_t *pool),
+                         void *baton,
+                         apr_pool_t *pool);
+
+/* Run BODY (with BATON and POOL) while the txn-current file
+   of FS is locked. */
+svn_error_t *
+svn_fs_x__with_txn_current_lock(svn_fs_t *fs,
+                                svn_error_t *(*body)(void *baton,
+                                                     apr_pool_t *pool),
+                                void *baton,
+                                apr_pool_t *pool);
+
+/* Obtain all locks on the filesystem FS in a subpool of POOL, call BODY
+   with BATON and that subpool, destroy the subpool (releasing the locks)
+   and return what BODY returned.
+
+   This combines svn_fs_fs__with_write_lock, svn_fs_fs__with_pack_lock,
+   and svn_fs_fs__with_txn_current_lock, ensuring correct lock ordering. */
+svn_error_t *
+svn_fs_x__with_all_locks(svn_fs_t *fs,
+                         svn_error_t *(*body)(void *baton,
+                                              apr_pool_t *pool),
+                         void *baton,
+                         apr_pool_t *pool);
+
 /* Store NODEREV as the node-revision for the node whose id is ID in
    FS, after setting its is_fresh_txn_root to FRESH_TXN_ROOT.  Do any
    necessary temporary allocation in POOL. */

Modified: subversion/trunk/subversion/libsvn_fs_x/util.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/util.c?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/util.c (original)
+++ subversion/trunk/subversion/libsvn_fs_x/util.c Fri May 16 06:03:32 2014
@@ -125,6 +125,13 @@ svn_fs_x__path_lock(svn_fs_t *fs, apr_po
 }
 
 const char *
+svn_fs_x__path_pack_lock(svn_fs_t *fs,
+                         apr_pool_t *pool)
+{
+  return svn_dirent_join(fs->path, PATH_PACK_LOCK_FILE, pool);
+}
+
+const char *
 svn_fs_x__path_revprop_generation(svn_fs_t *fs, apr_pool_t *pool)
 {
   return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool);

Modified: subversion/trunk/subversion/libsvn_fs_x/util.h
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_fs_x/util.h?rev=1595112&r1=1595111&r2=1595112&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_fs_x/util.h (original)
+++ subversion/trunk/subversion/libsvn_fs_x/util.h Fri May 16 06:03:32 2014
@@ -107,6 +107,13 @@ const char *
 svn_fs_x__path_lock(svn_fs_t *fs,
                     apr_pool_t *pool);
 
+/* Return the full path of the pack operation lock file in FS.
+ * The result will be allocated in POOL.
+ */
+const char *
+svn_fs_x__path_pack_lock(svn_fs_t *fs,
+                         apr_pool_t *pool);
+
 const char *
 svn_fs_x__path_revprop_generation(svn_fs_t *fs,
                                   apr_pool_t *pool);