You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by bl...@apache.org on 2011/01/27 02:22:28 UTC
svn commit: r1063946 - /subversion/trunk/subversion/libsvn_subr/io.c
Author: blair
Date: Thu Jan 27 01:22:28 2011
New Revision: 1063946
URL: http://svn.apache.org/viewvc?rev=1063946&view=rev
Log:
Fix a deadlock that can occur when two or more multithreaded
Subversion servers on the same system serve two or more fsfs
repositories. See the comment in svn_io_file_lock2() and/or this
thread:
http://mail-archives.apache.org/mod_mbox/subversion-dev/201101.mbox/%3C4D3FC68F.7020709@orcaware.com%3E
* subversion/libsvn_subr/io.c
(WIN32_RETRY_LOOP):
Move the body of this macro into and use...
(RETRY_LOOP):
...this new macro which abstracts out the test on when to retry.
(EDEADLK_RETRY_LOOP):
New macro that retries if getting a lock returned EDEADLK. This
is only defined if EDEADLK is defined in a multithread capable
system, as deadlocks won't occur in single-threaded processes.
(svn_io_file_lock2):
Use EDEADLK_RETRY_LOOP on apr_file_lock().
Modified:
subversion/trunk/subversion/libsvn_subr/io.c
Modified: subversion/trunk/subversion/libsvn_subr/io.c
URL: http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/io.c?rev=1063946&r1=1063945&r2=1063946&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/io.c (original)
+++ subversion/trunk/subversion/libsvn_subr/io.c Thu Jan 27 01:22:28 2011
@@ -85,19 +85,14 @@
#define RETRY_INITIAL_SLEEP 1000
#define RETRY_MAX_SLEEP 128000
-#ifndef WIN32_RETRY_LOOP
-#if defined(WIN32) && !defined(SVN_NO_WIN32_RETRY_LOOP)
-#define WIN32_RETRY_LOOP(err, expr) \
+#define RETRY_LOOP(err, expr, test) \
do \
{ \
apr_status_t os_err = APR_TO_OS_ERROR(err); \
int sleep_count = RETRY_INITIAL_SLEEP; \
int retries; \
for (retries = 0; \
- retries < RETRY_MAX_ATTEMPTS && \
- (os_err == ERROR_ACCESS_DENIED \
- || os_err == ERROR_SHARING_VIOLATION \
- || os_err == ERROR_DIR_NOT_EMPTY); \
+ retries < RETRY_MAX_ATTEMPTS && (test); \
++retries, os_err = APR_TO_OS_ERROR(err)) \
{ \
apr_sleep(sleep_count); \
@@ -107,6 +102,20 @@
} \
} \
while (0)
+
+#if defined(EDEADLK) && APR_HAS_THREADS
+#define EDEADLK_RETRY_LOOP(err, expr) \
+ RETRY_LOOP(err, expr, (os_err == EDEADLK))
+#else
+#define EDEADLK_RETRY_LOOP(err, expr) ((void)0)
+#endif
+
+#ifndef WIN32_RETRY_LOOP
+#if defined(WIN32) && !defined(SVN_NO_WIN32_RETRY_LOOP)
+#define WIN32_RETRY_LOOP(err, expr) \
+ RETRY_LOOP(err, expr, (os_err == ERROR_ACCESS_DENIED \
+ || os_err == ERROR_SHARING_VIOLATION \
+ || os_err == ERROR_DIR_NOT_EMPTY))
#else
#define WIN32_RETRY_LOOP(err, expr) ((void)0)
#endif
@@ -1695,6 +1704,22 @@ svn_io_file_lock2(const char *lock_file,
/* Get lock on the filehandle. */
apr_err = apr_file_lock(lockfile_handle, locktype);
+
+ /* In deployments with two or more multithreaded servers running on
+ the same system serving two or more fsfs repositories it is
+ possible for a deadlock to occur when getting a write lock on
+ db/txn-current-lock:
+
+ Process 1 Process 2
+ --------- ---------
+ thread 1: get lock in repos A
+ thread 1: get lock in repos B
+ thread 2: block getting lock in repos A
+ thread 2: try to get lock in B *** deadlock ***
+
+ Retry for a while for the deadlock to clear. */
+ EDEADLK_RETRY_LOOP(apr_err, apr_file_lock(lockfile_handle, locktype));
+
if (apr_err)
{
switch (locktype & APR_FLOCK_TYPEMASK)