summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Gorrod <alexg@wiredtiger.com>2016-03-18 14:18:38 +1100
committerAlex Gorrod <alexg@wiredtiger.com>2016-03-18 14:18:38 +1100
commit5b4e57c4b5d3651a6d8a7d5fbc63f32a345b6e17 (patch)
treec001c2f7dd0430655448e023199dbf02e4423c0f
parentd5a67f2c0f84527a8db92ad17204be02f314366b (diff)
downloadmongo-5b4e57c4b5d3651a6d8a7d5fbc63f32a345b6e17.tar.gz
WT-2498 Fix a bug in LSM where table drop could hang.
If there are open cursors.
-rw-r--r--src/lsm/lsm_tree.c22
-rw-r--r--test/suite/test_drop.py15
2 files changed, 21 insertions, 16 deletions
diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c
index e79d52c18e9..bd9d0671bde 100644
--- a/src/lsm/lsm_tree.c
+++ b/src/lsm/lsm_tree.c
@@ -85,7 +85,7 @@ __lsm_tree_discard(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, bool final)
* Close an LSM tree structure.
*/
static int
-__lsm_tree_close(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
+__lsm_tree_close(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, bool wait)
{
WT_DECL_RET;
int i;
@@ -94,10 +94,13 @@ __lsm_tree_close(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
F_CLR(lsm_tree, WT_LSM_TREE_ACTIVE);
/*
- * Wait for all LSM operations and work units that were in flight to
- * finish.
+ * Wait for all LSM operations to drain. If WiredTiger is shutting
+ * down also wait for the tree reference count to go to zero, otherwise
+ * we know a user is holding a reference to the tree, so exclusive
+ * access is not available.
*/
- for (i = 0; lsm_tree->refcnt > 1 || lsm_tree->queue_ref > 0; ++i) {
+ for (i = 0;
+ lsm_tree->refcnt > 1 && (wait || lsm_tree->queue_ref > 0); ++i) {
/*
* Remove any work units from the manager queues. Do this step
* repeatedly in case a work unit was in the process of being
@@ -145,7 +148,7 @@ __wt_lsm_tree_close_all(WT_SESSION_IMPL *session)
* is unconditional.
*/
(void)__wt_atomic_add32(&lsm_tree->refcnt, 1);
- WT_TRET(__lsm_tree_close(session, lsm_tree));
+ WT_TRET(__lsm_tree_close(session, lsm_tree, true));
WT_TRET(__lsm_tree_discard(session, lsm_tree, true));
}
@@ -380,9 +383,12 @@ __lsm_tree_find(WT_SESSION_IMPL *session,
* open cursors - otherwise we can generate
* spurious busy returns.
*/
- if (__lsm_tree_close(session, lsm_tree) != 0 ||
- !__wt_atomic_cas32(
- &lsm_tree->refcnt, 0, 1)) {
+ (void)__wt_atomic_add32(&lsm_tree->refcnt, 1);
+ if (__lsm_tree_close(
+ session, lsm_tree, false) != 0 ||
+ lsm_tree->refcnt != 1) {
+ (void)__wt_atomic_sub32(
+ &lsm_tree->refcnt, 1);
F_SET(lsm_tree, WT_LSM_TREE_ACTIVE);
lsm_tree->excl_session = NULL;
return (EBUSY);
diff --git a/test/suite/test_drop.py b/test/suite/test_drop.py
index 5663b85d661..52ea7251ab5 100644
--- a/test/suite/test_drop.py
+++ b/test/suite/test_drop.py
@@ -41,12 +41,11 @@ class test_drop(wttest.WiredTigerTestCase):
scenarios = check_scenarios([
('file', dict(uri='file:')),
('table', dict(uri='table:')),
- #Not yet: drop failing with an open cursor needs handle locking
- #('table-lsm', dict(uri='table:', extra_config=',type=lsm')),
+ ('table-lsm', dict(uri='table:', extra_config=',type=lsm')),
])
# Populate an object, remove it and confirm it no longer exists.
- def drop(self, populate, with_cursor, close_session, drop_index):
+ def drop(self, populate, with_cursor, reopen, drop_index):
uri = self.uri + self.name
populate(self, uri, 'key_format=S' + self.extra_config, 10)
@@ -57,7 +56,7 @@ class test_drop(wttest.WiredTigerTestCase):
lambda: self.session.drop(uri, None))
cursor.close()
- if close_session:
+ if reopen:
self.reopen_conn()
if drop_index:
@@ -73,17 +72,17 @@ class test_drop(wttest.WiredTigerTestCase):
# Try all combinations except dropping the index, the simple
# case has no indices.
for with_cursor in [False, True]:
- for close_session in [False, True]:
- self.drop(simple_populate, with_cursor, close_session, False)
+ for reopen in [False, True]:
+ self.drop(simple_populate, with_cursor, reopen, False)
# A complex, multi-file table object.
# Try all test combinations.
if self.uri == "table:":
for with_cursor in [False, True]:
- for close_session in [False, True]:
+ for reopen in [False, True]:
for drop_index in [False, True]:
self.drop(complex_populate, with_cursor,
- close_session, drop_index)
+ reopen, drop_index)
# Test drop of a non-existent object: force succeeds, without force fails.
def test_drop_dne(self):