diff options
author | Alex Gorrod <alexg@wiredtiger.com> | 2016-03-18 14:18:38 +1100 |
---|---|---|
committer | Alex Gorrod <alexg@wiredtiger.com> | 2016-03-18 14:18:38 +1100 |
commit | 5b4e57c4b5d3651a6d8a7d5fbc63f32a345b6e17 (patch) | |
tree | c001c2f7dd0430655448e023199dbf02e4423c0f | |
parent | d5a67f2c0f84527a8db92ad17204be02f314366b (diff) | |
download | mongo-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.c | 22 | ||||
-rw-r--r-- | test/suite/test_drop.py | 15 |
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): |