From: Dmitry Lenev Date: September 23 2010 3:20pm Subject: bzr commit into mysql-5.5-runtime branch (Dmitry.Lenev:3142) Bug#56405 Bug#56715 List-Archive: http://lists.mysql.com/commits/118974 X-Bug: 56405,56715 Message-Id: <20100923152100.4B555E5905@mockturtle> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============1076233357==" --===============1076233357== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///home/dlenev/src/bzr/mysql-5.5-rt-56715/ based on revid:jon.hauglid@stripped 3142 Dmitry Lenev 2010-09-23 A better fix for bug #56405 "Deadlock in the MDL deadlock detector", which doesn't introduce bug #56715 "Concurrent transactions + FLUSH result in sporadical unwarranted deadlock errors". Deadlock could have occurred when workload containing mix of DML, DDL and FLUSH TABLES statements affecting same set of tables was executed in heavily concurrent environment. This deadlock occurred when several connections tried to perform deadlock detection in metadata locking subsystem. The first connection started traversing wait-for graph, encountered sub-graph representing wait for flush, acquired LOCK_open and dived into sub-graph inspection. When it has encountered sub-graph corresponding to wait for metadata lock and blocked while trying to acquire rd-lock on MDL_lock::m_rwlock protecting this subgraph, since some other thread had wr-lock on it. When this wr-lock was released it could have happened (if there was other pending wr-lock against this rwlock) that rd-lock from the first connection was left unsatisfied but at the same time new rd-lock request from the second connection sneaked in and was satisfied (for this to be possible second rd- request should come exactly after wr-lock is released but before pending wr-lock manages to grab rwlock, which is possible both on Linux and in our own rwlock implementation). If this second connection continued traversing wait-for graph and encountered sub-graph representing wait for flush it tried to acquire LOCK_open and thus deadlock was created. The previous patch tried to workaround this problem by not allowing deadlock detector to lock LOCK_open mutex if some other thread doing deadlock detection already owns it and current search depth is greater than 0. Instead deadlock was reported. As result it has introduced bug #56715. This patch solves this problem in a different way. It introduces a new rw_pr_lock_t implementation to be used by MDL subsystem instead of one based on Linux rwlocks or our own rwlock implementation. This new implementation never allows situation in which rwlock is rd-locked and there is a blocked pending rd-lock. Thus situation which has caused this bug becomes impossible with it. Due to fact that this implementation is optimized for wr-lock/unlock scenario which is most common in MDL subsystem it doesn't introduce noticiable performance regressions in sysbench tests. Moreover it significantly improves situation for POINT_SELECT test when many connections are used. No test case is provided as this bug is very hard to repeat in MTR environment but is repeatable with the help of RQG tests. This patch also doesn't include test for bug #56715 "Concurrent transactions + FLUSH result in sporadical unwarranted deadlock errors" as it takes too much time to be run as part of normal test-suite runs. QQ: Should we also remove support for preferring readers from my_rw_lock_t implementation? @ config.h.cmake We no longer need to check for presence of pthread_rwlockattr_setkind_np as we no longer use Linux-specific implementation of rw_pr_lock_t which uses this function. @ configure.cmake We no longer need to check for presence of pthread_rwlockattr_setkind_np as we no longer use Linux-specific implementation of rw_pr_lock_t which uses this function. @ configure.in We no longer need to check for presence of pthread_rwlockattr_setkind_np as we no longer use Linux-specific implementation of rw_pr_lock_t which uses this function. @ include/my_pthread.h Introduced new implementation of rw_pr_lock_t. Since it never allows situation in which rwlock is rd-locked and there is a blocked pending rd-lock it is not affected by bug #56405 "Deadlock in the MDL deadlock detector". This implementation is also optimized for wr-lock/unlock scenario which is most common in MDL subsystem. So it doesn't introduce noticiable performance regressions in sysbench tests (compared to old Linux-specific implementation). Moreover it significantly improves situation for POINT_SELECT test when many connections are used. @ mysys/thr_rwlock.c Introduced new implementation of rw_pr_lock_t. Since it never allows situation in which rwlock is rd-locked and there is a blocked pending rd-lock it is not affected by bug #56405 "Deadlock in the MDL deadlock detector". This implementation is also optimized for wr-lock/unlock scenario which is most common in MDL subsystem. So it doesn't introduce noticiable performance regressions in sysbench tests (compared to old Linux-specific implementation). Moreover it significantly improves situation for POINT_SELECT test when many connections are used. modified: config.h.cmake configure.cmake configure.in include/my_pthread.h mysys/thr_rwlock.c === modified file 'config.h.cmake' --- a/config.h.cmake 2010-07-29 09:42:55 +0000 +++ b/config.h.cmake 2010-09-23 15:20:40 +0000 @@ -220,7 +220,6 @@ #cmakedefine HAVE_PTHREAD_KEY_DELETE 1 #cmakedefine HAVE_PTHREAD_KILL 1 #cmakedefine HAVE_PTHREAD_RWLOCK_RDLOCK 1 -#cmakedefine HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP 1 #cmakedefine HAVE_PTHREAD_SETPRIO_NP 1 #cmakedefine HAVE_PTHREAD_SETSCHEDPARAM 1 #cmakedefine HAVE_PTHREAD_SIGMASK 1 === modified file 'configure.cmake' --- a/configure.cmake 2010-07-29 09:42:55 +0000 +++ b/configure.cmake 2010-09-23 15:20:40 +0000 @@ -346,7 +346,6 @@ CHECK_FUNCTION_EXISTS (pthread_condattr_ CHECK_FUNCTION_EXISTS (pthread_init HAVE_PTHREAD_INIT) CHECK_FUNCTION_EXISTS (pthread_key_delete HAVE_PTHREAD_KEY_DELETE) CHECK_FUNCTION_EXISTS (pthread_rwlock_rdlock HAVE_PTHREAD_RWLOCK_RDLOCK) -CHECK_FUNCTION_EXISTS (pthread_rwlockattr_setkind_np HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) CHECK_FUNCTION_EXISTS (pthread_sigmask HAVE_PTHREAD_SIGMASK) CHECK_FUNCTION_EXISTS (pthread_threadmask HAVE_PTHREAD_THREADMASK) CHECK_FUNCTION_EXISTS (pthread_yield_np HAVE_PTHREAD_YIELD_NP) === modified file 'configure.in' --- a/configure.in 2010-08-25 14:05:33 +0000 +++ b/configure.in 2010-09-23 15:20:40 +0000 @@ -2169,7 +2169,7 @@ AC_CHECK_FUNCS(alarm bfill bmove bsearch mkstemp mlockall perror poll pread pthread_attr_create mmap mmap64 getpagesize \ pthread_attr_getstacksize pthread_attr_setstacksize pthread_condattr_create \ pthread_getsequence_np pthread_key_delete pthread_rwlock_rdlock \ - pthread_rwlockattr_setkind_np pthread_sigmask \ + pthread_sigmask \ readlink realpath rename rint rwlock_init setupterm \ shmget shmat shmdt shmctl sigaction sigemptyset sigaddset \ sighold sigset sigthreadmask port_create sleep thr_yield \ === modified file 'include/my_pthread.h' --- a/include/my_pthread.h 2010-08-10 21:12:01 +0000 +++ b/include/my_pthread.h 2010-09-23 15:20:40 +0000 @@ -606,49 +606,72 @@ int my_pthread_fastmutex_lock(my_pthread #endif /* USE_MUTEX_INSTEAD_OF_RW_LOCKS */ -/* - Portable read-write locks which prefer readers. +/** + Portable implementation of special type of read-write locks. - Required by some algorithms in order to provide correctness. + These locks have two properties which are unusual for rwlocks: + 1) They "prefer readers" in the sense that they do not allow + situations in which rwlock is rd-locked and there is a + pending rd-lock which is blocked (e.g. due to pending + request for wr-lock). + This is a stronger guarantee than one which is provided for + PTHREAD_RWLOCK_PREFER_READER_NP rwlocks in Linux. + MDL subsystem deadlock detector relies on this property for + its correctness. + 2) They are optimized for uncontended wr-lock/unlock case. + This is scenario in which they are most oftenly used + within MDL subsystem. Optimizing for it gives significant + performance improvements in some of tests involving many + connections. */ -#if defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) -/* - On systems which have a way to specify that readers should - be preferred through attribute mechanism (e.g. Linux) we use - system implementation of read/write locks. -*/ -#define rw_pr_lock_t pthread_rwlock_t +typedef struct st_rw_pr_lock_t { + /** + Lock which protects the structure. + Also held for the duration of wr-lock. + */ + pthread_mutex_t lock; + /** + Condition variable which is used to wake-up + writers waiting for readers to go away. + */ + pthread_cond_t no_active_readers; + /** Number of active readers. */ + uint active_readers; + /** Number of writers waiting for readers to go away. */ + uint writers_waiting_readers; + /** Indicates whether there is an active writer. */ + my_bool active_writer; +#ifdef SAFE_MUTEX + /** Thread holding wr-lock (for debug purposes only). */ + pthread_t writer_thread; +#endif +} rw_pr_lock_t; + extern int rw_pr_init(rw_pr_lock_t *); -#define rw_pr_rdlock(A) pthread_rwlock_rdlock(A) -#define rw_pr_wrlock(A) pthread_rwlock_wrlock(A) -#define rw_pr_tryrdlock(A) pthread_rwlock_tryrdlock(A) -#define rw_pr_trywrlock(A) pthread_rwlock_trywrlock(A) -#define rw_pr_unlock(A) pthread_rwlock_unlock(A) -#define rw_pr_destroy(A) pthread_rwlock_destroy(A) +extern int rw_pr_rdlock(rw_pr_lock_t *); +extern int rw_pr_wrlock(rw_pr_lock_t *); +extern int rw_pr_tryrdlock(rw_pr_lock_t *); +extern int rw_pr_trywrlock(rw_pr_lock_t *); +extern int rw_pr_unlock(rw_pr_lock_t *); +extern int rw_pr_destroy(rw_pr_lock_t *); +#ifdef SAFE_MUTEX +#define rw_pr_lock_assert_write_owner(A) \ + DBUG_ASSERT((A)->active_writer && pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#define rw_pr_lock_assert_not_write_owner(A) \ + DBUG_ASSERT(! (A)->active_writer || ! pthread_equal(pthread_self(), \ + (A)->writer_thread)) +#else #define rw_pr_lock_assert_write_owner(A) #define rw_pr_lock_assert_not_write_owner(A) -#else -/* Otherwise we have to use our own implementation of read/write locks. */ -#define NEED_MY_RW_LOCK 1 -struct st_my_rw_lock_t; -#define rw_pr_lock_t my_rw_lock_t -extern int rw_pr_init(struct st_my_rw_lock_t *); -#define rw_pr_rdlock(A) my_rw_rdlock((A)) -#define rw_pr_wrlock(A) my_rw_wrlock((A)) -#define rw_pr_tryrdlock(A) my_rw_tryrdlock((A)) -#define rw_pr_trywrlock(A) my_rw_trywrlock((A)) -#define rw_pr_unlock(A) my_rw_unlock((A)) -#define rw_pr_destroy(A) my_rw_destroy((A)) -#define rw_pr_lock_assert_write_owner(A) my_rw_lock_assert_write_owner((A)) -#define rw_pr_lock_assert_not_write_owner(A) my_rw_lock_assert_not_write_owner((A)) -#endif /* defined(HAVE_PTHREAD_RWLOCK_RDLOCK) && defined(HAVE_PTHREAD_RWLOCKATTR_SETKIND_NP) */ +#endif /* SAFE_MUTEX */ #ifdef NEED_MY_RW_LOCK /* - On systems which don't support native read/write locks, or don't support - read/write locks which prefer readers we have to use own implementation. + On systems which don't support native read/write locks we have + to use own implementation. */ typedef struct st_my_rw_lock_t { pthread_mutex_t lock; /* lock for structure */ === modified file 'mysys/thr_rwlock.c' --- a/mysys/thr_rwlock.c 2010-08-12 13:50:23 +0000 +++ b/mysys/thr_rwlock.c 2010-09-23 15:20:40 +0000 @@ -192,30 +192,148 @@ int my_rw_unlock(my_rw_lock_t *rwp) return(0); } +#endif /* defined(NEED_MY_RW_LOCK) */ + -int rw_pr_init(struct st_my_rw_lock_t *rwlock) +int rw_pr_init(rw_pr_lock_t *rwlock) { - my_bool prefer_readers_attr= TRUE; - return my_rw_init(rwlock, &prefer_readers_attr); + pthread_mutex_init(&rwlock->lock, NULL); + pthread_cond_init(&rwlock->no_active_readers, NULL); + rwlock->active_readers= 0; + rwlock->writers_waiting_readers= 0; + rwlock->active_writer= FALSE; +#ifdef SAFE_MUTEX + rwlock->writer_thread= 0; +#endif + return 0; } -#else -/* - We are on system which has native read/write locks which support - preferring of readers. -*/ +int rw_pr_destroy(rw_pr_lock_t *rwlock) +{ + pthread_cond_destroy(&rwlock->no_active_readers); + pthread_mutex_destroy(&rwlock->lock); + return 0; +} -int rw_pr_init(rw_pr_lock_t *rwlock) + +int rw_pr_rdlock(rw_pr_lock_t *rwlock) { - pthread_rwlockattr_t rwlock_attr; + pthread_mutex_lock(&rwlock->lock); + /* + The fact that we were able to acquire 'lock' mutex means + that there are no active writers and we can acquire rd-lock. + Increment active readers counter to prevent requests for + wr-lock from succeeding and unlock mutex. + */ + rwlock->active_readers++; + pthread_mutex_unlock(&rwlock->lock); + return 0; +} + - pthread_rwlockattr_init(&rwlock_attr); - pthread_rwlockattr_setkind_np(&rwlock_attr, PTHREAD_RWLOCK_PREFER_READER_NP); - pthread_rwlock_init(rwlock, NULL); - pthread_rwlockattr_destroy(&rwlock_attr); +int rw_pr_tryrdlock(rw_pr_lock_t *rwlock) +{ + if (pthread_mutex_lock(&rwlock->lock)) + return EBUSY; + rwlock->active_readers++; + pthread_mutex_unlock(&rwlock->lock); return 0; } -#endif /* defined(NEED_MY_RW_LOCK) */ + +int rw_pr_wrlock(rw_pr_lock_t *rwlock) +{ + pthread_mutex_lock(&rwlock->lock); + + if (rwlock->active_readers != 0) + { + /* There are active readers. We have to wait until they are gone. */ + rwlock->writers_waiting_readers++; + + while (rwlock->active_readers != 0) + pthread_cond_wait(&rwlock->no_active_readers, &rwlock->lock); + + rwlock->writers_waiting_readers--; + } + + /* + We own 'lock' mutex so there is no active writers. + Also there are no active readers. + This means that we can grant wr-lock. + Not releasing 'lock' mutex until unlock will block + both requests for rd and wr-locks. + Set 'active_writer' flag to simplify unlock. + + Thanks to the fact wr-lock/unlock in the absence of + contention from readers is essentially mutex lock/unlock + with a few simple checks make this rwlock implementation + wr-lock optimized. + */ + rwlock->active_writer= TRUE; +#ifdef SAFE_MUTEX + rwlock->writer_thread= pthread_self(); +#endif + return 0; +} + + +int rw_pr_trywrlock(rw_pr_lock_t *rwlock) +{ + if (pthread_mutex_lock(&rwlock->lock)) + return EBUSY; + + if (rwlock->active_readers != 0) + { + pthread_mutex_unlock(&rwlock->lock); + return EBUSY; + } + + rwlock->active_writer= TRUE; +#ifdef SAFE_MUTEX + rwlock->writer_thread= pthread_self(); +#endif + return 0; +} + + +int rw_pr_unlock(rw_pr_lock_t *rwlock) +{ + if (rwlock->active_writer) + { + /* We are unlocking wr-lock. */ +#ifdef SAFE_MUTEX + rwlock->writer_thread= 0; +#endif + rwlock->active_writer= FALSE; + if (rwlock->writers_waiting_readers) + { + /* + Avoid expensive cond signal in case when + there is no contention or it is wr-only. + */ + pthread_cond_signal(&rwlock->no_active_readers); + } + pthread_mutex_unlock(&rwlock->lock); + } + else + { + /* We are unlocking rd-lock. */ + pthread_mutex_lock(&rwlock->lock); + rwlock->active_readers--; + if (rwlock->active_readers == 0 && + rwlock->writers_waiting_readers) + { + /* + If we are last reader and there are waiting + writers wake them up. + */ + pthread_cond_signal(&rwlock->no_active_readers); + } + pthread_mutex_unlock(&rwlock->lock); + } + return 0; +} + + #endif /* defined(THREAD) */ --===============1076233357== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/dmitry.lenev@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: dmitry.lenev@stripped # target_branch: file:///home/dlenev/src/bzr/mysql-5.5-rt-56715/ # testament_sha1: 6ca2dc0378615b2b497ba67fb691ec842e916775 # timestamp: 2010-09-23 19:21:00 +0400 # base_revision_id: jon.hauglid@stripped\ # mpy5ty4vmw0k5j19 # # Begin bundle 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 --===============1076233357==--