diff options
author | Michael Cahill <michael.cahill@wiredtiger.com> | 2012-06-20 14:01:27 +1000 |
---|---|---|
committer | Michael Cahill <michael.cahill@wiredtiger.com> | 2012-06-20 15:32:48 +1000 |
commit | 8896c8d450ff08052d22928dee7c6faad535cf48 (patch) | |
tree | 30ddb9e94390a4fe69c762d1a71eadf8d9b6abc4 | |
parent | 3c4adbdbb247106841132bf903eccf8fef43f563 (diff) | |
download | mongo-8896c8d450ff08052d22928dee7c6faad535cf48.tar.gz |
Fix a case where checkpoints could self-deadlock trying to reenter the connection spinlock.
-rw-r--r-- | dist/api_data.py | 12 | ||||
-rw-r--r-- | src/conn/conn_btree.c | 31 | ||||
-rw-r--r-- | src/include/api.h | 1 |
3 files changed, 33 insertions, 11 deletions
diff --git a/dist/api_data.py b/dist/api_data.py index 30195b7c890..12c790dec5c 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -425,6 +425,14 @@ flags = { ################################################### # Structure flag declarations ################################################### - 'conn' : [ 'CONN_NOSYNC', 'CONN_TRANSACTIONAL', 'SERVER_RUN' ], - 'session' : [ 'SESSION_INTERNAL', 'SESSION_SALVAGE_QUIET_ERR' ], + 'conn' : [ + 'CONN_NOSYNC', + 'CONN_TRANSACTIONAL', + 'SERVER_RUN' + ], + 'session' : [ + 'SESSION_HAS_CONNLOCK', + 'SESSION_INTERNAL', + 'SESSION_SALVAGE_QUIET_ERR' + ], } diff --git a/src/conn/conn_btree.c b/src/conn/conn_btree.c index b68448be4f6..0dc8c804166 100644 --- a/src/conn/conn_btree.c +++ b/src/conn/conn_btree.c @@ -84,9 +84,15 @@ __conn_btree_get(WT_SESSION_IMPL *session, conn = S2C(session); + /* + * If we aren't holding the connection spinlock at a higher level, + * acquire it now. + */ + if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK)) + __wt_spin_lock(session, &conn->spinlock); + /* Increment the reference count if we already have the btree open. */ matched = 0; - __wt_spin_lock(session, &conn->spinlock); TAILQ_FOREACH(btree, &conn->btqh, q) { if (strcmp(name, btree->name) == 0 && ((snapshot == NULL && btree->snapshot == NULL) || @@ -99,7 +105,8 @@ __conn_btree_get(WT_SESSION_IMPL *session, } } if (matched) { - __wt_spin_unlock(session, &conn->spinlock); + if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK)) + __wt_spin_unlock(session, &conn->spinlock); __wt_conn_btree_open_lock(session, flags); return (0); } @@ -124,7 +131,9 @@ __conn_btree_get(WT_SESSION_IMPL *session, TAILQ_INSERT_TAIL(&conn->btqh, btree, q); ++conn->btqcnt; } - __wt_spin_unlock(session, &conn->spinlock); + + if (!F_ISSET(session, WT_SESSION_HAS_CONNLOCK)) + __wt_spin_unlock(session, &conn->spinlock); if (ret == 0) session->btree = btree; @@ -299,6 +308,7 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session, saved_btree = session->btree; __wt_spin_lock(session, &conn->spinlock); + F_SET(session, WT_SESSION_HAS_CONNLOCK); TAILQ_FOREACH(btree, &conn->btqh, q) if (F_ISSET(btree, WT_BTREE_OPEN) && btree->snapshot == NULL && @@ -313,7 +323,8 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session, WT_ERR(func(session, cfg)); } -err: __wt_spin_unlock(session, &conn->spinlock); +err: F_CLR(session, WT_SESSION_HAS_CONNLOCK); + __wt_spin_unlock(session, &conn->spinlock); session->btree = saved_btree; return (ret); } @@ -336,6 +347,8 @@ __wt_conn_btree_close(WT_SESSION_IMPL *session, int locked) if (F_ISSET(btree, WT_BTREE_OPEN)) WT_STAT_DECR(conn->stats, file_open); + WT_ASSERT(session, !F_ISSET(session, WT_SESSION_HAS_CONNLOCK)); + /* * Decrement the reference count. If we really are the last reference, * get an exclusive lock on the handle so that we can close it. @@ -383,7 +396,10 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name) conn = S2C(session); saved_btree = session->btree; + WT_ASSERT(session, !F_ISSET(session, WT_SESSION_HAS_CONNLOCK)); + __wt_spin_lock(session, &conn->spinlock); + F_SET(session, WT_SESSION_HAS_CONNLOCK); TAILQ_FOREACH(btree, &conn->btqh, q) { if (strcmp(btree->name, name) != 0) continue; @@ -409,8 +425,6 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name) * necessary. */ if (F_ISSET(btree, WT_BTREE_OPEN)) { - __wt_spin_unlock(session, &conn->spinlock); - ret = __wt_meta_track_sub_on(session); if (ret == 0) ret = __wt_conn_btree_sync_and_close(session); @@ -423,8 +437,6 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name) */ if (ret == 0) ret = __wt_meta_track_sub_off(session); - - __wt_spin_lock(session, &conn->spinlock); } if (!WT_META_TRACKING(session)) @@ -434,7 +446,8 @@ __wt_conn_btree_close_all(WT_SESSION_IMPL *session, const char *name) WT_ERR(ret); } -err: __wt_spin_unlock(session, &conn->spinlock); +err: F_CLR(session, WT_SESSION_HAS_CONNLOCK); + __wt_spin_unlock(session, &conn->spinlock); return (ret); } diff --git a/src/include/api.h b/src/include/api.h index 3e2483961ce..d111b1336c5 100644 --- a/src/include/api.h +++ b/src/include/api.h @@ -337,6 +337,7 @@ extern WT_PROCESS __wt_process; #define WT_PAGE_FREE_IGNORE_DISK 0x00000001 #define WT_REC_SINGLE 0x00000001 #define WT_SERVER_RUN 0x00000001 +#define WT_SESSION_HAS_CONNLOCK 0x00000004 #define WT_SESSION_INTERNAL 0x00000002 #define WT_SESSION_SALVAGE_QUIET_ERR 0x00000001 #define WT_VERB_block 0x00001000 |