summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2015-04-23 05:42:08 +0000
committerMichael Cahill <michael.cahill@mongodb.com>2015-04-25 12:50:52 +1000
commit785fab985bcbd01fb351bfca5f5362f7eea69516 (patch)
treed33f2f34929edeea9376eb87ac53e850709d3303
parent842dc0c5821ce4d5e33f527710a7a695ad335895 (diff)
downloadmongo-785fab985bcbd01fb351bfca5f5362f7eea69516.tar.gz
Fix a deadlock related to LSM. There are cases where closing a file with
an existing checkpoint could self deadlock. Check in the meta tracking whether we've already visited a checkpoint handle. Refs WT-716
-rw-r--r--src/include/extern.h1
-rw-r--r--src/meta/meta_track.c29
-rw-r--r--src/session/session_dhandle.c10
3 files changed, 39 insertions, 1 deletions
diff --git a/src/include/extern.h b/src/include/extern.h
index a259294caff..082ffb07a45 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -426,6 +426,7 @@ extern int __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key);
extern int __wt_metadata_search( WT_SESSION_IMPL *session, const char *key, char **valuep);
extern void __wt_meta_track_discard(WT_SESSION_IMPL *session);
extern int __wt_meta_track_on(WT_SESSION_IMPL *session);
+extern int __wt_meta_track_find_handle( WT_SESSION_IMPL *session, const char *name, const char *checkpoint);
extern int __wt_meta_track_off(WT_SESSION_IMPL *session, int need_sync, int unroll);
extern int __wt_meta_track_sub_on(WT_SESSION_IMPL *session);
extern int __wt_meta_track_sub_off(WT_SESSION_IMPL *session);
diff --git a/src/meta/meta_track.c b/src/meta/meta_track.c
index 3bc6a1f9d60..62d4df47ff6 100644
--- a/src/meta/meta_track.c
+++ b/src/meta/meta_track.c
@@ -184,6 +184,35 @@ free: trk->op = WT_ST_EMPTY;
}
/*
+ * __wt_meta_track_find_handle --
+ * Check if we have already seen a handle.
+ */
+int
+__wt_meta_track_find_handle(
+ WT_SESSION_IMPL *session, const char *name, const char *checkpoint)
+{
+ WT_META_TRACK *trk, *trk_orig;
+
+ WT_ASSERT(session,
+ WT_META_TRACKING(session) && session->meta_track_nest > 0);
+
+ trk_orig = session->meta_track;
+ trk = session->meta_track_next;
+
+ while (--trk >= trk_orig) {
+ if (trk->op != WT_ST_LOCK)
+ continue;
+ if (strcmp(trk->dhandle->name, name) == 0 &&
+ ((trk->dhandle->checkpoint == NULL && checkpoint == NULL) ||
+ (trk->dhandle->checkpoint != NULL &&
+ strcmp(trk->dhandle->checkpoint, checkpoint) == 0)))
+ return (0);
+ }
+
+ return (WT_NOTFOUND);
+}
+
+/*
* __wt_meta_track_off --
* Turn off metadata operation tracking, unrolling on error.
*/
diff --git a/src/session/session_dhandle.c b/src/session/session_dhandle.c
index 0825f783ca3..a6c9fb867e7 100644
--- a/src/session/session_dhandle.c
+++ b/src/session/session_dhandle.c
@@ -438,9 +438,18 @@ __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *checkpoint)
WT_DATA_HANDLE *dhandle, *saved_dhandle;
WT_DECL_RET;
+ WT_ASSERT(session, WT_META_TRACKING(session));
saved_dhandle = session->dhandle;
/*
+ * If we already have the checkpoint locked, don't attempt to lock
+ * it again.
+ */
+ if ((ret = __wt_meta_track_find_handle(
+ session, saved_dhandle->name, checkpoint)) != WT_NOTFOUND)
+ return (ret);
+
+ /*
* Get the checkpoint handle exclusive, so no one else can access it
* while we are creating the new checkpoint.
*/
@@ -463,7 +472,6 @@ __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *checkpoint)
dhandle = session->dhandle;
F_SET(dhandle, WT_DHANDLE_DISCARD);
- WT_ASSERT(session, WT_META_TRACKING(session));
WT_ERR(__wt_meta_track_handle_lock(session, 0));
/* Restore the original btree in the session. */