summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Cahill <michael.cahill@wiredtiger.com>2012-06-20 14:01:27 +1000
committerMichael Cahill <michael.cahill@wiredtiger.com>2012-06-20 15:32:48 +1000
commit8896c8d450ff08052d22928dee7c6faad535cf48 (patch)
tree30ddb9e94390a4fe69c762d1a71eadf8d9b6abc4
parent3c4adbdbb247106841132bf903eccf8fef43f563 (diff)
downloadmongo-8896c8d450ff08052d22928dee7c6faad535cf48.tar.gz
Fix a case where checkpoints could self-deadlock trying to reenter the connection spinlock.
-rw-r--r--dist/api_data.py12
-rw-r--r--src/conn/conn_btree.c31
-rw-r--r--src/include/api.h1
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