diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/suite')
16 files changed, 254 insertions, 120 deletions
diff --git a/src/third_party/wiredtiger/test/suite/hook_tiered.py b/src/third_party/wiredtiger/test/suite/hook_tiered.py index 1d64644e549..9fcd6cfa303 100755 --- a/src/third_party/wiredtiger/test/suite/hook_tiered.py +++ b/src/third_party/wiredtiger/test/suite/hook_tiered.py @@ -55,7 +55,7 @@ # from __future__ import print_function -import os, sys, unittest, wthooks, wttimestamp +import os, sys, unittest, wthooks from wttest import WiredTigerTestCase # These are the hook functions that are run when particular APIs are called. @@ -163,13 +163,6 @@ def connection_close_replace(orig_connection_close, connection_self, config): ret = orig_connection_close(connection_self, config) return ret -# Called to replace Connection.open_session -def connection_open_session_replace(orig_connection_open_session, connection_self, config): - ret_session = orig_connection_open_session(connection_self, config) - ret_session._connection = connection_self - ret_session._has_transaction = False - return ret_session - # Called to replace Session.checkpoint. # We add a call to flush_tier after the checkpoint to make sure we are exercising tiered # functionality. @@ -184,24 +177,6 @@ def session_checkpoint_replace(orig_session_checkpoint, session_self, config): ' Calling flush_tier() after checkpoint') return session_self.flush_tier(None) -# Called to replace Session.begin_transaction -def session_begin_transaction_replace(orig_session_begin_transaction, session_self, config): - ret = orig_session_begin_transaction(session_self, config) - session_self._has_transaction = True - return ret - -# Called to replace Session.commit_transaction -def session_commit_transaction_replace(orig_session_commit_transaction, session_self, config): - ret = orig_session_commit_transaction(session_self, config) - session_self._has_transaction = False - return ret - -# Called to replace Session.rollback_transaction -def session_rollback_transaction_replace(orig_session_rollback_transaction, session_self, config): - ret = orig_session_rollback_transaction(session_self, config) - session_self._has_transaction = False - return ret - # Called to replace Session.compact def session_compact_replace(orig_session_compact, session_self, uri, config): # Compact isn't implemented for tiered tables. Only call it if this can't be the uri @@ -242,9 +217,7 @@ def session_open_cursor_replace(orig_session_open_cursor, session_self, uri, dup if uri != None and uri.startswith("backup:"): testcase = WiredTigerTestCase.currentTestCase() testcase.skipTest("backup on tiered tables not yet implemented") - ret_cursor = orig_session_open_cursor(session_self, uri, dupcursor, config) - ret_cursor._session = session_self - return ret_cursor + return orig_session_open_cursor(session_self, uri, dupcursor, config) # Called to replace Session.rename def session_rename_replace(orig_session_rename, session_self, uri, newuri, config): @@ -289,14 +262,6 @@ class TieredHookCreator(wthooks.WiredTigerHookCreator): # Override some platform APIs self.platform_api = TieredPlatformAPI() - # This hook plays with timestamps, indirectly by modifying the behavior of the *DataSet classes. - # Here we declare our use of timestamp code, so that tests that have their own notion of - # timestamps can be skipped when running with this hook. - def uses(self, use_list): - if "timestamp" in use_list: - return True - return False - # Is this test one we should skip? def skip_test(self, test): # Skip any test that contains one of these strings as a substring @@ -333,7 +298,6 @@ class TieredHookCreator(wthooks.WiredTigerHookCreator): # This group fail within Python for various, sometimes unknown, reasons. "test_bug018.test_bug018", "test_checkpoint.test_checkpoint", - "test_checkpoint_target.test_checkpoint_target", "test_checkpoint_snapshot02.test_checkpoint_snapshot_with_txnid_and_timestamp", "test_compat05.test_compat05", "test_config05.test_too_many_sessions", @@ -401,22 +365,6 @@ class TieredHookCreator(wthooks.WiredTigerHookCreator): self.Connection['close'] = (wthooks.HOOK_REPLACE, lambda s, config=None: connection_close_replace(orig_connection_close, s, config)) - orig_connection_open_session = self.Connection['open_session'] - self.Connection['open_session'] = (wthooks.HOOK_REPLACE, lambda s, config=None: - connection_open_session_replace(orig_connection_open_session, s, config)) - - orig_session_begin_transaction = self.Session['begin_transaction'] - self.Session['begin_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: - session_begin_transaction_replace(orig_session_begin_transaction, s, config)) - - orig_session_commit_transaction = self.Session['commit_transaction'] - self.Session['commit_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: - session_commit_transaction_replace(orig_session_commit_transaction, s, config)) - - orig_session_rollback_transaction = self.Session['rollback_transaction'] - self.Session['rollback_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: - session_rollback_transaction_replace(orig_session_rollback_transaction, s, config)) - orig_session_compact = self.Session['compact'] self.Session['compact'] = (wthooks.HOOK_REPLACE, lambda s, uri, config=None: session_compact_replace(orig_session_compact, s, uri, config)) @@ -445,12 +393,6 @@ class TieredHookCreator(wthooks.WiredTigerHookCreator): # Override some platform APIs for this hook. class TieredPlatformAPI(wthooks.WiredTigerHookPlatformAPI): - def setUp(self): - self._timestamp = wttimestamp.WiredTigerTimeStamp() - - def tearDown(self): - pass - def tableExists(self, name): for i in range(1, 9): tablename = name + "-000000000{}.wtobj".format(i) @@ -464,10 +406,6 @@ class TieredPlatformAPI(wthooks.WiredTigerHookPlatformAPI): else: return wthooks.DefaultPlatformAPI.initialFileName(uri) - # By default, there is no timestamping by the data set classes. - def getTimestamp(self): - return self._timestamp - # Every hook file must have a top level initialize function, # returning a list of WiredTigerHook objects. diff --git a/src/third_party/wiredtiger/test/suite/hook_timestamp.py b/src/third_party/wiredtiger/test/suite/hook_timestamp.py new file mode 100644 index 00000000000..7322b2fc19e --- /dev/null +++ b/src/third_party/wiredtiger/test/suite/hook_timestamp.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# +# Public Domain 2014-present 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. +# +# [TEST_TAGS] +# ignored_file +# [END_TAGS] + +# hook_timestamp.py +# +# Insert the use of timestamps into data sets. +# +# These hooks have three functions. The primary one is setting up the platform API to return +# a "timestamper". The dataset package uses this platform API, and so will run with timestamps +# when this hook is enabled. The timestamper provides a timestamping cursor that "knows" to wrap +# timestamped transactions around certain operations, like insert. +# +# Secondly, we set hooks on the transaction APIs so we know when a transaction has been started or +# finished by the test application. If the application already a transaction in progress, +# the timestamping cursor should not try to open a transaction, but can place a timestamp on the +# current transaction. +# +# To run, for example, the cursor tests with these hooks enabled: +# ../test/suite/run.py --hooks timestamp cursor +# +from __future__ import print_function + +import os, sys, unittest, wthooks, wttimestamp +from wttest import WiredTigerTestCase + +# These are the hook functions that are run when particular APIs are called. + +# Called to replace Session.begin_transaction +def session_begin_transaction_replace(orig_session_begin_transaction, session_self, config): + ret = orig_session_begin_transaction(session_self, config) + session_self._has_transaction = True + return ret + +# Called to replace Session.commit_transaction +def session_commit_transaction_replace(orig_session_commit_transaction, session_self, config): + ret = orig_session_commit_transaction(session_self, config) + session_self._has_transaction = False + return ret + +# Called to replace Session.rollback_transaction +def session_rollback_transaction_replace(orig_session_rollback_transaction, session_self, config): + ret = orig_session_rollback_transaction(session_self, config) + session_self._has_transaction = False + return ret + +def make_dataset_names(): + import wtdataset + names = ['wtdataset'] + #g = globals(sys.modules['wtdataset']) + g = sys.modules['wtdataset'].__dict__ + for name in g: + if name.endswith('DataSet'): + names.append(name) + return names + +# Every hook file must have one or more classes descended from WiredTigerHook +# This is where the hook functions are 'hooked' to API methods. +class TimestampHookCreator(wthooks.WiredTigerHookCreator): + def __init__(self, arg=0): + # Caller can specify an optional command-line argument. We're not using it + # now, but this is where it would show up. + + # Override some platform APIs + self.platform_api = TimestampPlatformAPI() + + # This hook plays with timestamps, indirectly by modifying the behavior of the *DataSet classes. + # Here we declare our use of timestamp code, so that tests that have their own notion of + # timestamps can be skipped when running with this hook. + def uses(self, use_list): + if "timestamp" in use_list: + return True + return False + + dataset_names = make_dataset_names() + + # We skip tests that don't use datasets + def skip_test(self, test, known_skip): + import importlib + testname = str(test) + #print('CHECK: {}'.format(testname)) + modname = testname.split('.')[0] + if modname in known_skip: + return known_skip[modname] + g = sys.modules[modname].__dict__ + uses_dataset = False + for dsname in self.dataset_names: + if dsname in g: + uses_dataset = True + break + #print('CHECK: {}: {}'.format(test,uses_dataset)) + skip = not uses_dataset + known_skip[modname] = skip + return skip + + # Remove tests that won't work on timestamp cursors + def filter_tests(self, tests): + new_tests = unittest.TestSuite() + known_skip = dict() + new_tests.addTests([t for t in tests if not self.skip_test(t, known_skip)]) + return new_tests + + def get_platform_api(self): + return self.platform_api + + def setup_hooks(self): + orig_session_begin_transaction = self.Session['begin_transaction'] + self.Session['begin_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: + session_begin_transaction_replace(orig_session_begin_transaction, s, config)) + + orig_session_commit_transaction = self.Session['commit_transaction'] + self.Session['commit_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: + session_commit_transaction_replace(orig_session_commit_transaction, s, config)) + + orig_session_rollback_transaction = self.Session['rollback_transaction'] + self.Session['rollback_transaction'] = (wthooks.HOOK_REPLACE, lambda s, config=None: + session_rollback_transaction_replace(orig_session_rollback_transaction, s, config)) + +# Override some platform APIs for this hook. +class TimestampPlatformAPI(wthooks.WiredTigerHookPlatformAPI): + def setUp(self): + self._timestamp = wttimestamp.WiredTigerTimeStamp() + + def tearDown(self): + pass + + # Return a timestamping implementation, it will be used by the data set classes. + def getTimestamp(self): + return self._timestamp + + +# Every hook file must have a top level initialize function, +# returning a list of WiredTigerHook objects. +def initialize(arg): + return [TimestampHookCreator(arg)] diff --git a/src/third_party/wiredtiger/test/suite/suite_subprocess.py b/src/third_party/wiredtiger/test/suite/suite_subprocess.py index 2aab7e4f186..507c647757f 100755 --- a/src/third_party/wiredtiger/test/suite/suite_subprocess.py +++ b/src/third_party/wiredtiger/test/suite/suite_subprocess.py @@ -30,6 +30,7 @@ from __future__ import print_function import os, re, subprocess, sys from run import wt_builddir from wttest import WiredTigerTestCase +import wttest # suite_subprocess.py # Run a subprocess within the test suite @@ -224,15 +225,18 @@ class suite_subprocess: return [ returncode, new_home_dir ] # Run the wt utility. + + # FIXME-WT-9808: + # The tiered hook silently interjects tiered configuration and extensions, + # these are not yet dealt with when running the external 'wt' process. + @wttest.skip_for_hook("tiered", "runWt cannot add needed extensions") def runWt(self, args, infilename=None, outfilename=None, errfilename=None, closeconn=True, reopensession=True, failure=False): - # FIXME-WT-9808: - # The tiered hook silently interjects tiered configuration and extensions, - # these are not yet dealt with when running the external 'wt' process. - if 'tiered' in self.hook_names: - self.skipTest("runWt is not yet supported with tiering") + # FIXME-WT-9809: + if 'timestamp' in self.hook_names and args[0] == 'load': + self.skipTest("the load utility cannot be run when timestamps are already set") # Close the connection to guarantee everything is flushed, and that # we can open it from another process. diff --git a/src/third_party/wiredtiger/test/suite/test_checkpoint01.py b/src/third_party/wiredtiger/test/suite/test_checkpoint01.py index e8c08cbd48e..6f3940f47cb 100755 --- a/src/third_party/wiredtiger/test/suite/test_checkpoint01.py +++ b/src/third_party/wiredtiger/test/suite/test_checkpoint01.py @@ -209,15 +209,18 @@ class test_checkpoint_target(wttest.WiredTigerTestCase): ]) def update(self, uri, ds, value): - cursor = self.session.open_cursor(uri, None, "overwrite") + cursor = ds.open_cursor(uri, None, "overwrite") cursor[ds.key(10)] = value cursor.close() def check(self, uri, ds, value): - cursor = self.session.open_cursor(uri, None, "checkpoint=checkpoint-1") + cursor = ds.open_cursor(uri, None, "checkpoint=checkpoint-1") self.assertEquals(cursor[ds.key(10)], value) cursor.close() + # FIXME-WT-9902 + @wttest.skip_for_hook("tiered", "strange interaction with tiered and named checkpoints using target") + @wttest.skip_for_hook("timestamp", "strange interaction with timestamps and named checkpoints using target") def test_checkpoint_target(self): # Create 3 objects, change one record to an easily recognizable string. uri = self.uri + '1' diff --git a/src/third_party/wiredtiger/test/suite/test_compact01.py b/src/third_party/wiredtiger/test/suite/test_compact01.py index 9790816805c..4193a9e2dea 100755 --- a/src/third_party/wiredtiger/test/suite/test_compact01.py +++ b/src/third_party/wiredtiger/test/suite/test_compact01.py @@ -73,6 +73,7 @@ class test_compact(wttest.WiredTigerTestCase, suite_subprocess): return statDict # Test compaction. + @wttest.skip_for_hook("timestamp", "removing timestamped items will not free space") def test_compact(self): # Populate an object uri = self.type + self.name @@ -88,11 +89,11 @@ class test_compact(wttest.WiredTigerTestCase, suite_subprocess): stat_cursor.close() # Remove most of the object. - c1 = self.session.open_cursor(uri, None) + c1 = ds.open_cursor(uri, None) c1.set_key(ds.key(5)) - c2 = self.session.open_cursor(uri, None) + c2 = ds.open_cursor(uri, None) c2.set_key(ds.key(self.nentries - 5)) - self.session.truncate(None, c1, c2, None) + ds.truncate(None, c1, c2, None) c1.close() c2.close() diff --git a/src/third_party/wiredtiger/test/suite/test_cursor06.py b/src/third_party/wiredtiger/test/suite/test_cursor06.py index 88364288f83..03eafeed145 100755 --- a/src/third_party/wiredtiger/test/suite/test_cursor06.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor06.py @@ -62,7 +62,7 @@ class test_cursor06(wttest.WiredTigerTestCase): cursor.set_key(self.ds.key(10)) cursor.set_value(self.ds.value(10)) - @wttest.skip_for_hook("tiered", "crashes on final connection close") # FIXME-WT-9809 + @wttest.skip_for_hook("timestamp", "crashes on final connection close") # FIXME-WT-9809 def test_reconfigure_overwrite(self): uri = self.type + self.name for open_config in (None, "overwrite=0", "overwrite=1"): diff --git a/src/third_party/wiredtiger/test/suite/test_cursor12.py b/src/third_party/wiredtiger/test/suite/test_cursor12.py index 614bf5c713c..fb6187137e6 100755 --- a/src/third_party/wiredtiger/test/suite/test_cursor12.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor12.py @@ -339,7 +339,7 @@ class test_cursor12(wttest.WiredTigerTestCase): self.modify_confirm(ds, False) # Check that we can perform a large number of modifications to a record. - @wttest.skip_for_hook("tiered", "crashes on commit_transaction or connection close") # FIXME-WT-9809 + @wttest.skip_for_hook("timestamp", "crashes on commit_transaction or connection close") # FIXME-WT-9809 def test_modify_many(self): ds = SimpleDataSet(self, self.uri, 20, key_format=self.keyfmt, value_format=self.valuefmt) diff --git a/src/third_party/wiredtiger/test/suite/test_cursor17.py b/src/third_party/wiredtiger/test/suite/test_cursor17.py index 84cfc4d7c27..dbdddab1f6b 100755 --- a/src/third_party/wiredtiger/test/suite/test_cursor17.py +++ b/src/third_party/wiredtiger/test/suite/test_cursor17.py @@ -60,7 +60,7 @@ class test_cursor17(wttest.WiredTigerTestCase): self.ds = self.dataset(self, self.type + self.tablename, rownum, key_format=self.keyformat) self.ds.populate() - @wttest.skip_for_hook("tiered", "fails assertion 99") # FIXME-WT-9809 + @wttest.skip_for_hook("timestamp", "fails assertion 99") # FIXME-WT-9809 def test_globally_deleted_key(self): self.populate(100) diff --git a/src/third_party/wiredtiger/test/suite/test_flcs01.py b/src/third_party/wiredtiger/test/suite/test_flcs01.py index fae21b7e02c..44b2bbf551c 100755 --- a/src/third_party/wiredtiger/test/suite/test_flcs01.py +++ b/src/third_party/wiredtiger/test/suite/test_flcs01.py @@ -105,7 +105,7 @@ class test_flcs01(wttest.WiredTigerTestCase): self.check_prev(cursor, k, 0) self.session.rollback_transaction() - @wttest.skip_for_hook("tiered", "crashes in evict function, during cursor reset") # FIXME-WT-9809 + @wttest.skip_for_hook("timestamp", "crashes in evict function, during cursor reset") # FIXME-WT-9809 def test_flcs(self): uri = "table:test_flcs01" nrows = 44 diff --git a/src/third_party/wiredtiger/test/suite/test_flcs05.py b/src/third_party/wiredtiger/test/suite/test_flcs05.py index cff43208d7d..8bb60bab6f4 100755 --- a/src/third_party/wiredtiger/test/suite/test_flcs05.py +++ b/src/third_party/wiredtiger/test/suite/test_flcs05.py @@ -56,7 +56,7 @@ class test_flcs05(wttest.WiredTigerTestCase): self.session.rollback_transaction() evict_cursor.close() - @wttest.skip_for_hook("tiered", "fails at begin_transaction") # FIXME-WT-9809 + @wttest.skip_for_hook("timestamp", "fails at begin_transaction") # FIXME-WT-9809 def test_flcs(self): uri = "table:test_flcs05" nrows = 44 diff --git a/src/third_party/wiredtiger/test/suite/test_inmem01.py b/src/third_party/wiredtiger/test/suite/test_inmem01.py index 14263a1648e..4764f526030 100644 --- a/src/third_party/wiredtiger/test/suite/test_inmem01.py +++ b/src/third_party/wiredtiger/test/suite/test_inmem01.py @@ -63,7 +63,7 @@ class test_inmem01(wttest.WiredTigerTestCase): # Figure out the last key we successfully inserted, and check all # previous inserts are still there. - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) cursor.prev() last_key = int(cursor.get_key()) ds = SimpleDataSet(self, self.uri, last_key, key_format=self.keyfmt, @@ -81,13 +81,15 @@ class test_inmem01(wttest.WiredTigerTestCase): # Now that the database contains as much data as will fit into # the configured cache, verify removes succeed. - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) for i in range(1, 100): cursor.set_key(ds.key(i)) self.assertEqual(cursor.remove(), 0) # Run queries after adding, removing and re-inserting data. # Try out keeping a cursor open while adding new data. + + @wttest.skip_for_hook("timestamp", "removing timestamped items will not free space") def test_insert_over_delete_replace(self): msg = '/WT_CACHE_FULL.*/' ds = SimpleDataSet(self, self.uri, 10000000, key_format=self.keyfmt, @@ -95,7 +97,7 @@ class test_inmem01(wttest.WiredTigerTestCase): self.assertRaisesHavingMessage(wiredtiger.WiredTigerError, ds.populate, msg) - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) cursor.prev() last_key = int(cursor.get_key()) @@ -141,7 +143,7 @@ class test_inmem01(wttest.WiredTigerTestCase): # Now that the database contains as much data as will fit into # the configured cache, verify removes succeed. - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) for i in range(1, last_key // 4, 1): cursor.set_key(ds.key(i)) self.assertEqual(cursor.remove(), 0) @@ -176,7 +178,7 @@ class test_inmem01(wttest.WiredTigerTestCase): ds = SimpleDataSet(self, self.uri, 0, key_format=self.keyfmt, value_format=self.valuefmt, config=self.table_config) ds.populate() - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) run = 0 start, last_key = -1000, 0 diff --git a/src/third_party/wiredtiger/test/suite/test_stat01.py b/src/third_party/wiredtiger/test/suite/test_stat01.py index 6a4ad5423ad..5431a6f892d 100755 --- a/src/third_party/wiredtiger/test/suite/test_stat01.py +++ b/src/third_party/wiredtiger/test/suite/test_stat01.py @@ -142,6 +142,7 @@ class test_stat01(wttest.WiredTigerTestCase): cursor.close() # Test simple per-checkpoint statistics. + @wttest.skip_for_hook("timestamp", "__txn_visiable_all_id assertion hit") # FIXME-WT-9809 def test_checkpoint_stats(self): ds = SimpleDataSet(self, self.uri, self.nentries, config=self.config, key_format=self.keyfmt) diff --git a/src/third_party/wiredtiger/test/suite/test_stat05.py b/src/third_party/wiredtiger/test/suite/test_stat05.py index 6de398c0524..a93b309e585 100644 --- a/src/third_party/wiredtiger/test/suite/test_stat05.py +++ b/src/third_party/wiredtiger/test/suite/test_stat05.py @@ -92,7 +92,7 @@ class test_stat_cursor_config(wttest.WiredTigerTestCase): self, self.uri, 100, key_format=key_format, value_format=value_format, config=self.cfg) ds.populate() self.openAndWalkStatCursor() - cursor = self.session.open_cursor(self.uri, None) + cursor = ds.open_cursor(self.uri, None) for i in range(100, 40000 + 1): if i % 100 == 0: self.openAndWalkStatCursor() diff --git a/src/third_party/wiredtiger/test/suite/wtdataset.py b/src/third_party/wiredtiger/test/suite/wtdataset.py index afda18043b6..c6c399625ec 100755 --- a/src/third_party/wiredtiger/test/suite/wtdataset.py +++ b/src/third_party/wiredtiger/test/suite/wtdataset.py @@ -58,7 +58,7 @@ class BaseDataSet(object): if session == None: session = self.testcase.session c = session.open_cursor(uri, None, config) - return wttimestamp.TimestampedCursor(c, self.timestamp, self.testcase) + return wttimestamp.TimestampedCursor(session, c, self.timestamp, self.testcase) def truncate(self, uri, c1, c2, config, session=None): if session == None: diff --git a/src/third_party/wiredtiger/test/suite/wthooks.py b/src/third_party/wiredtiger/test/suite/wthooks.py index 2ee0e26c499..5f52a1def1f 100755 --- a/src/third_party/wiredtiger/test/suite/wthooks.py +++ b/src/third_party/wiredtiger/test/suite/wthooks.py @@ -143,7 +143,7 @@ def hooked_function(self, orig_func, hook_info_name, *args): class WiredTigerHookManager(object): def __init__(self, hooknames = []): self.hooks = [] - self.platform_api = None + self.platform_apis = [] names_seen = [] for name in hooknames: # The hooks are indicated as "somename=arg" or simply "somename". @@ -172,16 +172,8 @@ class WiredTigerHookManager(object): for hook in self.hooks: hook.setup_hooks() api = hook.get_platform_api() # can return None - if api: - # We currently don't allow multiple platforms to create their own API, - # but this could be relaxed. Imagine that hooks implement subsets of the - # API. We could create an ordered list, and try each platform_api in turn. - if self.platform_api: - raise Exception('Running multiple hooks, each with their own platform API, ' + - 'is not implemented') - self.platform_api = api - if self.platform_api == None: - self.platform_api = DefaultPlatformAPI() + self.platform_apis.append(api) + self.platform_apis.append(DefaultPlatformAPI()) def add_hook(self, clazz, method_name, hook_type, hook_func): if not hasattr(clazz, method_name): @@ -244,7 +236,7 @@ class WiredTigerHookManager(object): return self.hook_names def get_platform_api(self): - return self.platform_api + return MultiPlatformAPI(self.platform_apis) # Returns a list of hook names that use something on the list def hooks_using(self, use_list): @@ -297,39 +289,28 @@ class WiredTigerHookCreator(ABC): def uses(self, use_list): return False -class WiredTigerHookPlatformAPI(ABC): - @abstractmethod +class WiredTigerHookPlatformAPI(object): def setUp(self): """Called at the beginning of a test case""" pass - @abstractmethod def tearDown(self): """Called at the termination of a test case""" pass - @abstractmethod def tableExists(self, name): """Return boolean if local files exist for the table with the given base name""" - pass + raise NotImplementedError('tableExists method not implemented') - @abstractmethod def initialFileName(self, uri): """The first local backing file name created for this URI.""" - pass + raise NotImplementedError('initialFileName method not implemented') - @abstractmethod def getTimestamp(self): """The timestamp generator for this test case.""" - pass + raise NotImplementedError('getTimestamp method not implemented') class DefaultPlatformAPI(WiredTigerHookPlatformAPI): - def setUp(self): - pass - - def tearDown(self): - pass - def tableExists(self, name): tablename = name + ".wt" return os.path.exists(tablename) @@ -345,3 +326,44 @@ class DefaultPlatformAPI(WiredTigerHookPlatformAPI): # By default, there is no automatic timestamping by test infrastructure classes. def getTimestamp(self): return None + +class MultiPlatformAPI(WiredTigerHookPlatformAPI): + def __init__(self, platform_apis): + self.apis = platform_apis + + def setUp(self): + """Called at the beginning of a test case""" + for api in self.apis: + api.setUp() + + def tearDown(self): + """Called at the termination of a test case""" + for api in self.apis: + api.tearDown() + + def tableExists(self, name): + """Return boolean if local files exist for the table with the given base name""" + for api in self.apis: + try: + return api.tableExists(name) + except NotImplementedError: + pass + raise Exception('tableExists: no implementation') # should never happen + + def initialFileName(self, uri): + """The first local backing file name created for this URI.""" + for api in self.apis: + try: + return api.initialFileName(uri) + except NotImplementedError: + pass + raise Exception('initialFileName: no implementation') # should never happen + + def getTimestamp(self): + """The timestamp generator for this test case.""" + for api in self.apis: + try: + return api.getTimestamp() + except NotImplementedError: + pass + raise Exception('getTimestamp: no implementation') # should never happen diff --git a/src/third_party/wiredtiger/test/suite/wttimestamp.py b/src/third_party/wiredtiger/test/suite/wttimestamp.py index 26fff886d65..03edd2e7c7c 100755 --- a/src/third_party/wiredtiger/test/suite/wttimestamp.py +++ b/src/third_party/wiredtiger/test/suite/wttimestamp.py @@ -49,7 +49,8 @@ class WiredTigerTimeStamp(object): @contextmanager def session_timestamped_transaction(session, timestamper): need_commit = False - if timestamper != None and not getattr(session, "_has_transaction", False): + if timestamper != None and \ + not (hasattr(session, "_has_transaction") and session._has_transaction): session.begin_transaction() need_commit = True yield @@ -66,10 +67,13 @@ def session_timestamped_transaction(session, timestamper): # are passed to the implementation object (via __getattr__), # except for the ones that we explicitly override here. class TimestampedCursor(wiredtiger.Cursor): - def __init__(self, cursor, timeStamper, testcase): + def __init__(self, session, cursor, timeStamper, testcase): self._cursor = cursor self._timeStamper = timeStamper self._testcase = testcase + self._session = session + if not hasattr(session, "_has_transaction"): + session._has_transaction = False def __getattr__(self, name): return getattr(self._cursor, name) @@ -77,11 +81,7 @@ class TimestampedCursor(wiredtiger.Cursor): # A more convenient way to "wrap" an operation in a transaction @contextmanager def timestamped_transaction(self): - # Prefer the _session object if available, it returns a Python - # Session object that is 1-1 mapped to the WT_SESSION in the C API. - session = getattr(self._cursor, "_session", self._cursor.session) - timestamper = self._timeStamper - with session_timestamped_transaction(session, timestamper): + with session_timestamped_transaction(self._session, self._timeStamper): yield # Overrides Cursor.insert |