From 4d78cd2953df668c46773321efb632bcb3be6b03 Mon Sep 17 00:00:00 2001 From: Alex Gorrod Date: Thu, 16 Apr 2015 04:11:36 +0000 Subject: Fix a bug in LSM where updates with overwrite could be skipped. References JIRA BF-829 The issue was that we were not looking in all chunks of an LSM tree before deciding whether to apply an update (insert or remove). --- src/lsm/lsm_cursor.c | 16 ++++++--- test/suite/test_bug013.py | 84 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) create mode 100644 test/suite/test_bug013.py diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c index a18269baa28..4508c54b6ff 100644 --- a/src/lsm/lsm_cursor.c +++ b/src/lsm/lsm_cursor.c @@ -394,10 +394,18 @@ __clsm_open_cursors( lsm_tree = clsm->lsm_tree; chunk = NULL; - if (update) { - if (txn->isolation == TXN_ISO_SNAPSHOT) - F_SET(clsm, WT_CLSM_OPEN_SNAPSHOT); - } else + /* + * Ensure that any snapshot update has cursors on the right set of + * chunks to guarantee visibility is correct. + */ + if (update && txn->isolation == TXN_ISO_SNAPSHOT) + F_SET(clsm, WT_CLSM_OPEN_SNAPSHOT); + + /* + * Query operations need a full set of cursors. Overwrite cursors + * do queries in service of updates. + */ + if (!update || !F_ISSET(c, WT_CURSTD_OVERWRITE)) F_SET(clsm, WT_CLSM_OPEN_READ); if (lsm_tree->nchunks == 0) diff --git a/test/suite/test_bug013.py b/test/suite/test_bug013.py new file mode 100644 index 00000000000..2993385dba1 --- /dev/null +++ b/test/suite/test_bug013.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python +# +# Public Domain 2014-2015 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +import wiredtiger, wttest + +# test_bug013.py +# Test data consistency in LSM with updates. Ensure that overwrite +# cursors see all entries in the tree (i.e: they open cursors on all +# chunks in the LSM tree). +# See JIRA BF-829 +class test_bug013(wttest.WiredTigerTestCase): + """ + Test LSM data consistency. + """ + uri = 'table:test_bug013' + + def check_entries(self, keys): + # Test by iterating. + cursor = self.session.open_cursor(self.uri, None, None) + i = 0 + for i1, i2, i3, v1 in cursor: + self.assertEqual( keys[i], [i1, i2, i3]) + i += 1 + cursor.close() + self.assertEqual(i, len(keys)) + + def test_lsm_consistency(self): + self.session.reconfigure("isolation=snapshot") + self.session.create(self.uri, 'key_format=iii,value_format=i,type=lsm') + cursor = self.session.open_cursor(self.uri, None, None) + cursor[(2, 6, 1)] = 0 + cursor.close() + # Ensure the first chunk is flushed to disk, so the tree will have + # at least two chunks. Wrapped in a try, since it sometimes gets + # an EBUSY return + try: + self.session.verify(self.uri, None) + except wiredtiger.WiredTigerError: + pass + + # Add a key + cursor = self.session.open_cursor(self.uri, None, 'overwrite=false') + cursor[(1, 5, 1)] = 0 + cursor.close() + + # Remove the key we just added. If the LSM code is broken, the + # search for the key we just inserted returns not found - so the + # key isn't actually removed. + cursor = self.session.open_cursor(self.uri, None, 'overwrite=false') + cursor.set_key((1, 5, 1)) + cursor.remove() + cursor.close() + + # Verify that the data is as we expect + self.check_entries([[2, 6, 1]]) + +if __name__ == '__main__': + wttest.run() + -- cgit v1.2.1