def test_timestamp_ts_then_nots(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table with the key consistency checking turned on. That checking will verify # any individual key is always or never used with a timestamp. And if it is used with a # timestamp that the timestamps are in increasing order for that key. uri = 'table:ts' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format) + ',write_timestamp_usage=ordered') c = self.session.open_cursor(uri) key = ds.key(5) self.session.begin_transaction() c[key] = ds.value(11) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(20)) self.session.begin_transaction() c[key] = ds.value(12) msg ='/configured to always use timestamps once they are first used/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg)
def test_alter(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) if self.init_always: start = 'always' switch = 'never' else: start = 'never' switch = 'always' # Open the object, configuring the initial timestamp usage. # Check it. # Switch the object to the opposite usage. # Check it. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + ',' + 'write_timestamp_usage={}'.format(start) + ',assert=(write_timestamp=on)') self.check(ds, uri, self.init_always) self.session.alter(uri, 'write_timestamp_usage={}'.format(switch)) self.check(ds, uri, not self.init_always)
def test_wtu_never(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring write_timestamp usage. uri = 'table:ts' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format) + ',write_timestamp_usage=never') c = self.session.open_cursor(uri) self.session.begin_transaction() c[ds.key(7)] = ds.value(8) # Commit with a timestamp. if self.with_ts: # Check both an explicit timestamp set and a set at commit. commit_ts = 'commit_timestamp=' + self.timestamp_str(10) if not self.commit_ts: self.session.timestamp_transaction(commit_ts) commit_ts = '' msg = '/set when disallowed/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(commit_ts), msg) # Commit without a timestamp. else: self.session.commit_transaction()
def test_log_ts(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring write_timestamp usage. uri = 'table:ts' config = ',write_timestamp_usage=' config += 'always' if self.always else 'never' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format) + config) c = self.session.open_cursor(uri) # Commit with a timestamp. self.session.begin_transaction() c[ds.key(1)] = ds.value(1) self.session.breakpoint() self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(10)) # Commit without a timestamp. self.session.begin_transaction() c[ds.key(2)] = ds.value(2) self.session.commit_transaction()
def test_commit_larger_than_active_timestamp(self): if not wiredtiger.diagnostic_build(): self.skipTest('requires a diagnostic build') uri = 'table:test_txn26' self.session.create(uri, 'key_format=S,value_format=S') cursor = self.session.open_cursor(uri) self.conn.set_timestamp( 'oldest_timestamp=' + timestamp_str(1) + ',stable_timestamp=' + timestamp_str(1)) value = 'a' # Start a session with timestamp 10 session2 = self.conn.open_session(self.session_config) session2.begin_transaction('read_timestamp=' + timestamp_str(10)) # Try to commit at timestamp 10 self.session.begin_transaction() cursor[str(0)] = value with self.expectedStderrPattern("must be greater than the latest active read timestamp"): try: self.session.commit_transaction('commit_timestamp=' + timestamp_str(10)) except wiredtiger.WiredTigerError as e: gotException = True self.pr('got expected exception: ' + str(e)) self.assertTrue(str(e).find('nvalid argument') >= 0) self.assertTrue(gotException, msg = 'expected exception')
def test_timestamp_ts_order(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table with the key consistency checking turned on. That checking will verify # any individual key is always or never used with a timestamp. And if it is used with a # timestamp that the timestamps are in increasing order for that key. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + ',write_timestamp_usage=ordered') c = self.session.open_cursor(uri) key1 = ds.key(6) key2 = ds.key(7) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(30)) c[key1] = ds.value(14) c[key2] = ds.value(15) self.session.commit_transaction() self.assertEquals(c[key1], ds.value(14)) self.assertEquals(c[key2], ds.value(15)) self.session.begin_transaction() c[key1] = ds.value(16) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(31)) c[key2] = ds.value(17) self.session.commit_transaction() self.assertEquals(c[key1], ds.value(16)) self.assertEquals(c[key2], ds.value(17)) self.session.begin_transaction() c[key1] = ds.value(18) c[key2] = ds.value(19) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(32)) self.session.commit_transaction() self.assertEquals(c[key1], ds.value(18)) self.assertEquals(c[key2], ds.value(19)) self.session.begin_transaction() c[key1] = ds.value(20) c[key2] = ds.value(21) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(33)) self.assertEquals(c[key1], ds.value(20)) self.assertEquals(c[key2], ds.value(21))
def test_timestamp_inconsistent_update(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table with the key consistency checking turned on. That checking will verify # any individual key is always or never used with a timestamp. And if it is used with a # timestamp that the timestamps are in increasing order for that key. uri = 'table:ts' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format) + ',write_timestamp_usage=ordered') c = self.session.open_cursor(uri) key = ds.key(1) # Insert an item at timestamp 2. self.session.begin_transaction() c[key] = ds.value(1) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(2)) # Upate the data item at timestamp 1, which should fail. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(1)) c[key] = ds.value(2) msg = '/updates a value with an older timestamp/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg) # Make sure we can successfully add a different key at timestamp 1. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(1)) c[ds.key(2)] = ds.value(3) self.session.commit_transaction() # Insert key1 at timestamp 10 and key2 at 15. Then update both keys in one transaction at # timestamp 13, and we should get a complaint about usage. key1 = ds.key(3) key2 = ds.key(4) self.session.begin_transaction() c[key1] = ds.value(3) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(10)) self.session.begin_transaction() c[key2] = ds.value(4) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(15)) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(13)) c[key1] = ds.value(5) c[key2] = ds.value(6) msg = '/updates a value with an older timestamp/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg)
def test_read_timestamp(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring read timestamp usage. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + ',assert=(read_timestamp=' + self.read_ts + ')') c = self.session.open_cursor(uri) key = ds.key(10) value = ds.value(10) # Insert a data item at a timestamp (although it doesn't really matter). self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(10)) c[key] = value self.session.timestamp_transaction() self.session.commit_transaction() # Try reading without a timestamp. self.session.begin_transaction() c.set_key(key) if self.read_ts != 'always': self.assertEquals(c.search(), 0) self.assertEqual(c.get_value(), value) else: msg = '/read timestamps required and none set/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: c.search(), msg) self.session.rollback_transaction() # Try reading with a timestamp. self.session.begin_transaction() self.session.timestamp_transaction('read_timestamp=20') c.set_key(key) if self.read_ts != 'never': self.assertEquals(c.search(), 0) self.assertEqual(c.get_value(), value) else: msg = '/read timestamps disallowed/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: c.search(), msg) self.session.rollback_transaction()
def test_in_memory_ts(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring write_timestamp usage. uri = 'table:ts' config = ',' + self.obj_config config += ',write_timestamp_usage=' config += 'ordered' if self.always else 'never' self.session.breakpoint() self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + config) c = self.session.open_cursor(uri) # Commit with a timestamp. self.session.begin_transaction() c[ds.key(1)] = ds.value(1) if self.always == True or self.obj_ignore == True: self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(1)) else: msg = '/unexpected timestamp usage/' self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.commit_transaction( 'commit_timestamp=' + self.timestamp_str(1)), msg) # Commit without a timestamp (but first with a timestamp if in ordered mode so we get # a failure). if self.always: self.session.begin_transaction() c[ds.key(2)] = ds.value(2) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(2)) self.session.begin_transaction() c[ds.key(2)] = ds.value(2) if self.always == False or self.obj_ignore == True: self.session.commit_transaction() else: msg = '/no timestamp provided/' self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg)
def test_bulk_load_row_order_nocheck(self): uri = self.type + self.name self.session.create(uri, 'key_format=S,value_format=S') cursor = self.session.open_cursor(uri, None, "bulk,skip_sort_check") cursor[key_populate(cursor, 10)] = value_populate(cursor, 10) cursor[key_populate(cursor, 1)] = value_populate(cursor, 1) if not wiredtiger.diagnostic_build(): self.skipTest('requires a diagnostic build') # Close explicitly, there's going to be a fallure. msg = '/are incorrectly sorted/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.conn.close(), msg)
def test_alter(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring "never" timestamp usage. # Check it. # Switch the object to "ordered" usage. # Check it. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + ',write_timestamp_usage=never') c = self.session.open_cursor(uri) self.session.begin_transaction() c[ds.key(10)] = ds.value(10) msg = '/set when disallowed by table configuration/' self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.commit_transaction('commit_timestamp=' + self. timestamp_str(10)), msg) c.close() self.session.alter(uri, 'write_timestamp_usage=ordered') c = self.session.open_cursor(uri) self.session.begin_transaction() c[ds.key(10)] = ds.value(10) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(11)) self.session.begin_transaction() c[ds.key(10)] = ds.value(10) msg = '/always use timestamps/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg)
def test_always_never(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring write_timestamp usage. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + ',write_timestamp_usage=' + self.write_timestamp + ',' + ',assert=(write_timestamp=' + self.assert_ts + ')') c = self.session.open_cursor(uri) self.session.begin_transaction() c[ds.key(7)] = ds.value(8) # Commit with a timestamp. if self.with_ts: # Check both an explicit timestamp set and a set at commit. commit_ts = 'commit_timestamp=' + self.timestamp_str(10) if not self.commit_ts: self.session.timestamp_transaction(commit_ts) commit_ts = '' if self.assert_ts == 'off' or self.write_timestamp == 'always': self.session.commit_transaction(commit_ts) else: with self.expectedStderrPattern('set when disallowed'): self.session.commit_transaction(commit_ts) # Commit without a timestamp. else: if self.assert_ts == 'off' or self.write_timestamp == 'never': self.session.commit_transaction() else: with self.expectedStderrPattern('timestamp required by table'): self.session.commit_transaction()
def test_in_memory_ts(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Open the object, configuring write_timestamp usage. uri = 'table:ts' config = ',' + self.obj_config config += ',write_timestamp_usage=' config += 'always' if self.always else 'never' config += ',assert=(write_timestamp=on)' self.session.breakpoint() self.session.create( uri, 'key_format={},value_format={}'.format( self.key_format, self.value_format) + config) c = self.session.open_cursor(uri) # Commit with a timestamp. self.session.begin_transaction() c[ds.key(1)] = ds.value(1) if self.always == True or self.obj_ignore == True: self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(1)) else: with self.expectedStderrPattern('unexpected timestamp usage'): self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(1)) # Commit without a timestamp. self.session.begin_transaction() c[ds.key(2)] = ds.value(2) if self.always == False or self.obj_ignore == True: self.session.commit_transaction() else: with self.expectedStderrPattern('unexpected timestamp usage'): self.session.commit_transaction()
def prepare_resolve(self, resolve): ds = self.dataset(self, "table:rts30", 10, key_format=self.keyfmt, value_format=self.valfmt) ds.populate() # Pin oldest and stable timestamps to 1. self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(1) + ',stable_timestamp=' + self.timestamp_str(1)) # Write some data and prepare it. cursor = self.session.open_cursor(ds.uri) self.session.begin_transaction() # Modify a row. cursor[ds.key(5)] = ds.value(20) # Prepare at timestamp 10. self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(10)) # Roll back to stable should fail because there's an active transaction. msg = '/rollback_to_stable.*active/' if wiredtiger.diagnostic_build(): with self.expectedStdoutPattern('transaction state dump'): self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.conn.rollback_to_stable(), msg) else: self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.conn.rollback_to_stable(), msg) # Set commit, durable timestamps to 20. self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(20) + ',durable_timestamp=' + self.timestamp_str(20)) # Commit or abort the prepared transaction. resolve()
def test_bulk_load_row_order_nocheck(self): # Row-store offers an optional fast-past that skips the relatively # expensive key-order checks, used when the input is known to be # correct. Column-store comparisons are cheap, so it doesn't have # that fast-path support. if self.keyfmt != 'S': return uri = self.type + self.name self.session.create( uri, 'key_format=' + self.keyfmt + ',value_format=' + self.valfmt) cursor = self.session.open_cursor(uri, None, "bulk,skip_sort_check") cursor[simple_key(cursor, 10)] = simple_value(cursor, 10) cursor[simple_key(cursor, 1)] = simple_value(cursor, 1) if not wiredtiger.diagnostic_build(): self.skipTest('requires a diagnostic build') # Close explicitly, there's going to be a failure. msg = '/are incorrectly sorted/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.conn.close(), msg)
def test_bulk_load_row_order_nocheck(self): # Row-store offers an optional fast-past that skips the relatively # expensive key-order checks, used when the input is known to be # correct. Column-store comparisons are cheap, so it doesn't have # that fast-path support. if self.keyfmt != 'S': return uri = self.type + self.name self.session.create(uri, 'key_format=' + self.keyfmt + ',value_format=' + self.valfmt) cursor = self.session.open_cursor(uri, None, "bulk,skip_sort_check") cursor[simple_key(cursor, 10)] = simple_value(cursor, 10) cursor[simple_key(cursor, 1)] = simple_value(cursor, 1) if not wiredtiger.diagnostic_build(): self.skipTest('requires a diagnostic build') # Close explicitly, there's going to be a fallure. msg = '/are incorrectly sorted/' self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.conn.close(), msg)
def test_timestamp_alter(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) cfg_on = 'write_timestamp_usage=ordered' cfg_off = 'write_timestamp_usage=none' # Create the table without the key consistency checking turned on. # Create a few items breaking the rules. # Then alter the setting and verify the inconsistent usage is detected. uri = 'file:assert06' self.session.create( uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format)) c = self.session.open_cursor(uri) # Insert a data item at timestamp 2. key = ds.key(1) self.session.begin_transaction() c[key] = ds.value(1) self.apply_timestamps(2, True) self.session.commit_transaction() # Modify the data item at timestamp 1, illegally moving the timestamp backward. self.session.begin_transaction() c[key] = ds.value(2) self.apply_timestamps(1, True) self.session.commit_transaction() # Insert a non-timestamped item. # Then illegally modify with a timestamp. # Then illegally modify without a timestamp. key = ds.key(2) self.session.begin_transaction() c[key] = ds.value(3) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(4) self.apply_timestamps(2, True) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(5) self.session.commit_transaction() # Now alter the setting and make sure we detect incorrect usage. # We must move the oldest timestamp forward in order to alter, otherwise alter closing the # file will fail with EBUSY. self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(2)) c.close() self.session.alter(uri, cfg_on) c = self.session.open_cursor(uri) # Update at timestamp 5, then detect not using a timestamp. key = ds.key(3) self.session.begin_transaction() c[key] = ds.value(6) self.apply_timestamps(5, True) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(6) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), self.msg_usage) # Detect using a timestamp on a non-timestamp key. We must first use a non-timestamped # operation on the key in order to violate the key consistency condition in the following # transaction. key = ds.key(4) self.session.begin_transaction() c[key] = ds.value(7) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(8) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(3)) # Test to make sure that key consistency can be turned off after turning it on. self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(4)) c.close() self.session.alter(uri, cfg_off) c = self.session.open_cursor(uri) # Detection is off we can successfully change the same key with and without a timestamp. key = ds.key(5) self.session.begin_transaction() c[key] = ds.value(9) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(1) self.apply_timestamps(6, True) self.session.commit_transaction()
def test_timestamp_usage(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table with the key consistency checking turned on. That checking will verify # any individual key is always or never used with a timestamp. And if it is used with a # timestamp that the timestamps are in increasing order for that key. uri = 'file:assert06' self.session.create( uri, 'key_format={},value_format={},'.format( self.key_format, self.value_format) + 'write_timestamp_usage=ordered,assert=(write_timestamp=on)') c = self.session.open_cursor(uri) # Insert a data item at timestamp 2. self.session.begin_transaction() c[ds.key(1)] = ds.value(1) self.apply_timestamps(2, True) self.session.commit_transaction() # Make sure we can successfully add a different key at timestamp 1. self.session.begin_transaction() c[ds.key(2)] = ds.value(2) self.apply_timestamps(1, True) self.session.commit_transaction() # Insert key_ts3 at timestamp 10 and key_ts4 at 15, then modify both keys in one transaction # at timestamp 13, which should result in an error message. c = self.session.open_cursor(uri) self.session.begin_transaction() c[ds.key(3)] = ds.value(3) self.apply_timestamps(10, True) self.session.commit_transaction() self.session.begin_transaction() c[ds.key(4)] = ds.value(4) self.apply_timestamps(15, True) self.session.commit_transaction() self.session.begin_transaction() c[ds.key(3)] = ds.value(5) c[ds.key(4)] = ds.value(6) self.apply_timestamps(13, False) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), '/unexpected timestamp usage/') self.assertEquals(c[ds.key(3)], ds.value(3)) self.assertEquals(c[ds.key(4)], ds.value(4)) # Modify a key previously used with timestamps without one. We should get the inconsistent # usage message. key = ds.key(5) self.session.begin_transaction() c[key] = ds.value(7) self.apply_timestamps(14, True) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(8) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), self.msg_usage) # Set the timestamp in the beginning, middle or end of the transaction. key = ds.key(6) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(16)) c[key] = ds.value(9) self.session.commit_transaction() self.assertEquals(c[key], ds.value(9)) key = ds.key(7) self.session.begin_transaction() c[key] = ds.value(10) c[key] = ds.value(11) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(17)) c[key] = ds.value(12) c[key] = ds.value(13) self.session.commit_transaction() self.assertEquals(c[key], ds.value(13)) key = ds.key(8) self.session.begin_transaction() c[key] = ds.value(14) self.apply_timestamps(18, True) self.session.commit_transaction() self.assertEquals(c[key], ds.value(14)) # Confirm it is okay to set the durable timestamp on the commit call. key = ds.key(9) self.session.begin_transaction() c[key] = ds.value(15) c[key] = ds.value(16) self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(22)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(22)) self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(22)) self.session.commit_transaction() # Confirm that rolling back after preparing doesn't fire an assertion. key = ds.key(10) self.session.begin_transaction() c[key] = ds.value(17) self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(30)) self.session.rollback_transaction()
def test_timestamp_api(self): format = 'key_format={},value_format={}'.format( self.key_format, self.value_format) self.session.create(self.uri, format) c = self.session.open_cursor(self.uri) self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(20)) self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(30)) # It is illegal to set the prepare timestamp older than the stable # timestamp. self.session.begin_transaction() self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + self.timestamp_str(10)), "/not newer than the stable timestamp/") self.session.rollback_transaction() # Check setting a prepared transaction timestamps earlier than the # stable timestamp is valid with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(20)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(25)) self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(35)) self.session.commit_transaction() # Check setting a prepared transaction timestamps earlier than the # *oldest* timestamp is also accepted with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(10)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(15)) self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(35)) self.session.commit_transaction() ''' Commented out for now: the system panics if we fail after preparing a transaction. # Check setting a prepared transaction timestamps earlier than the # stable timestamp is invalid even with roundup_timestamps, if the # durable timestamp is less than the stable timestamp. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(20)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(25)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.timestamp_transaction( 'durable_timestamp=' + self.timestamp_str(25)), "/is less than the stable timestamp/") self.session.rollback_transaction() ''' # Check the cases with an active reader. # Start a new reader to have an active read timestamp. s_reader = self.conn.open_session() s_reader.begin_transaction('read_timestamp=' + self.timestamp_str(40)) # It is illegal to set the prepare timestamp as earlier than an active # read timestamp even with roundup_timestamps settings. This is only # checked in diagnostic builds. if wiredtiger.diagnostic_build(): self.session.begin_transaction( 'roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + self.timestamp_str(10)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # It is illegal to set the prepare timestamp the same as an active read # timestamp even with roundup_timestamps settings. self.session.begin_transaction( 'roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + self.timestamp_str(40)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() ''' Commented out for now: the system panics if we fail after preparing a transaction. # It is illegal to set a commit timestamp less than the prepare # timestamp of a transaction. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(45)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction( 'commit_timestamp=' + self.timestamp_str(30)), "/less than the prepare timestamp/") ''' ''' Commented out for now: the system panics if we fail after preparing a transaction. # It is legal to set a commit timestamp older than prepare timestamp of # a transaction with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + self.timestamp_str(45)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(30)) #self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(30)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.timestamp_transaction( 'durable_timestamp=' + self.timestamp_str(30)), "/is less than the commit timestamp/") self.session.rollback_transaction() ''' s_reader.commit_transaction()
def test_ordered(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet(self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table without the key consistency checking turned on. # Create a few items breaking the rules. Then alter the setting and # verify the inconsistent usage is detected. uri = 'table:ts' self.session.create( uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format)) c = self.session.open_cursor(uri) key = ds.key(10) # Insert a data item at timestamp 2. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(2)) c[key] = ds.value(10) self.session.commit_transaction() # Update the data item at timestamp 1. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(1)) c[key] = ds.value(11) self.session.commit_transaction() key = ds.key(12) # Insert a non-timestamped item, then update with a timestamp and then without a timestamp. self.session.begin_transaction() c[key] = ds.value(12) self.session.commit_transaction() self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(2)) c[key] = ds.value(13) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(14) self.session.commit_transaction() # Now alter the setting and make sure we detect incorrect usage. We must move the oldest # timestamp forward in order to alter, otherwise alter will fail with EBUSY. c.close() self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10)) config = 'assert=(write_timestamp=on)' self.session.alter(uri, 'write_timestamp_usage=ordered,' + config) c = self.session.open_cursor(uri) key = ds.key(15) # Detect decreasing timestamp. self.session.begin_transaction() c[key] = ds.value(15) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(15)) msg = 'with an older timestamp' self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(14)) c[key] = ds.value(16) with self.expectedStderrPattern(msg): self.session.commit_transaction() # Detect not using a timestamp. msg = 'use timestamps once they are first used' self.session.begin_transaction() c[key] = ds.value(17) with self.expectedStderrPattern(msg): self.session.commit_transaction() # Now alter the setting again and detection is off. c.close() self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(20)) self.session.alter(uri, 'assert=(write_timestamp=off)') c = self.session.open_cursor(uri) key = ds.key(18) # Detection is off we can successfully change the same key with then without a timestamp. self.session.begin_transaction() c[key] = ds.value(18) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(21)) self.session.begin_transaction() c[key] = ds.value(19) self.session.commit_transaction() c.close()
def test_timestamp_api(self): self.session.create(self.uri, 'key_format=i,value_format=i') c = self.session.open_cursor(self.uri) # It is illegal to set the prepare timestamp older than the oldest # timestamp. self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(20)) self.conn.set_timestamp('stable_timestamp=' + timestamp_str(30)) self.session.begin_transaction() self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(10)), "/older than the oldest timestamp/") self.session.rollback_transaction() # Check setting a prepared transaction timestamps earlier than the # oldest timestamp is valid with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(10)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(15)) self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(35)) self.session.commit_transaction() # Check setting a prepared transaction timestamps earlier than the # oldest timestamp is invalid, if durable timestamp is less than the # stable timestamp. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(10)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(15)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.timestamp_transaction( 'durable_timestamp=' + timestamp_str(25)), "/is less than the stable timestamp/") self.session.rollback_transaction() # Check the cases with an active reader. # Start a new reader to have an active read timestamp. s_reader = self.conn.open_session() s_reader.begin_transaction('read_timestamp=' + timestamp_str(40)) # It is illegal to set the prepare timestamp as earlier than an active # read timestamp even with roundup_timestamps settings. This is only # checked in diagnostic builds. if wiredtiger.diagnostic_build(): self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(10)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # It is illegal to set the prepare timestamp the same as an active read # timestamp even with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(40)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # It is illegal to set a commit timestamp less than the prepare # timestamp of a transaction. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(45)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction( 'commit_timestamp=' + timestamp_str(30)), "/less than the prepare timestamp/") # It is legal to set a commit timestamp older than prepare timestamp of # a transaction with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(45)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(30)) #self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(30)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.timestamp_transaction( 'durable_timestamp=' + timestamp_str(30)), "/is less than the commit timestamp/") self.session.rollback_transaction() s_reader.commit_transaction()
def test_timestamp_api(self): format = 'key_format={},value_format={}'.format( self.key_format, self.value_format) self.session.create(self.uri, format) c = self.session.open_cursor(self.uri) # It is illegal to set a prepare timestamp older than the stable timestamp. self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(2)) self.session.begin_transaction() self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + self.timestamp_str(1)), "/not newer than the stable timestamp/") self.session.rollback_transaction() # It is also illegal to set a prepare timestamp the same as the stable timestamp. self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(2)) self.session.begin_transaction() self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + self.timestamp_str(2)), "/not newer than the stable timestamp/") self.session.rollback_transaction() # Check setting the prepare timestamp immediately after the stable timestamp is valid. self.session.begin_transaction() self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(3)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(3)) self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(3)) self.session.commit_transaction() # In a single transaction it is illegal to set a commit timestamp # before invoking prepare for this transaction. # Note: Values are not important, setting commit timestamp before # prepare itself is illegal. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(3)) self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + self.timestamp_str(2)), "/should not have been set before/") self.session.rollback_transaction() # This is also true even if the prepare timestamp was set first. self.session.begin_transaction() self.session.timestamp_transaction('prepare_timestamp=' + self.timestamp_str(3)) self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. timestamp_transaction('commit_timestamp=' + self.timestamp_str(3)), "/commit timestamp must not be set/") self.session.rollback_transaction() # It is illegal to set a prepare timestamp same as or earlier than an # active read timestamp. # Start a new reader to have an active read timestamp. if wiredtiger.diagnostic_build(): s_reader = self.conn.open_session() s_reader.begin_transaction('read_timestamp=' + self.timestamp_str(4)) self.session.begin_transaction() self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + self.timestamp_str(4)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # Check setting the prepare timestamp as later than active read # timestamp is valid. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(5)) # Resolve the reader transaction started earlier. s_reader.rollback_transaction() self.session.rollback_transaction() ''' Commented out for now: the system panics if we fail after preparing a transaction. # It is illegal to set a commit timestamp older than prepare timestamp of a transaction. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(5)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction( 'commit_timestamp=' + self.timestamp_str(4)), "/less than the prepare timestamp/") ''' # It is legal to set a commit timestamp as same as prepare # timestamp. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(5)) self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(5)) self.session.timestamp_transaction('durable_timestamp=' + self.timestamp_str(5)) self.session.commit_transaction()
def test_timestamp_range(self): if not wiredtiger.timestamp_build() or not wiredtiger.diagnostic_build( ): self.skipTest('requires a timestamp and diagnostic build') base = 'timestamp10' uri = 'file:' + base # Create a data item at a timestamp self.session.create(uri, 'key_format=S,value_format=S') # Insert a data item at timestamp 2 c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(2)) c['key'] = 'value2' self.session.commit_transaction() c.close() # Modify the data item at timestamp 1 # # The docs say: # The commits to a particular data item must be performed in timestamp # order. Again, this is only checked in diagnostic builds and if # applications violate this rule, data consistency can be violated. # c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(1)) c['key'] = 'value1' msg = 'on new update is older than' with self.expectedStdoutPattern(msg): self.session.commit_transaction() c.close() # Make sure we can successfully add a different key at timestamp 1. c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(1)) c['key1'] = 'value1' self.session.commit_transaction() c.close() # # Insert key2 at timestamp 10 and key3 at 15. # Then modify both keys in one transaction at timestamp 14. # Modifying the one from 15 should report a warning message, but # the update will be applied. # c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(10)) c['key2'] = 'value10' self.session.commit_transaction() self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(15)) c['key3'] = 'value15' self.session.commit_transaction() c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(14)) c['key2'] = 'value14' c['key3'] = 'value14' with self.expectedStdoutPattern(msg): self.session.commit_transaction() c.close() c = self.session.open_cursor(uri) self.assertEquals(c['key2'], 'value14') self.assertEquals(c['key3'], 'value14') c.close() # # Separately, we should be able to update key2 at timestamp 16. # c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(16)) c['key2'] = 'value16' self.session.commit_transaction() # Updating key3 inserted at timestamp 13 will report a warning. c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(13)) c['key3'] = 'value13' with self.expectedStdoutPattern(msg): self.session.commit_transaction() c.close() # Test that updating again with an invalid timestamp reports a warning. c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(12)) c['key3'] = 'value12' with self.expectedStdoutPattern(msg): self.session.commit_transaction() c.close() c = self.session.open_cursor(uri) self.assertEquals(c['key3'], 'value12') c.close() # Now try a later timestamp. c = self.session.open_cursor(uri) self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(17)) c['key3'] = 'value17' self.session.commit_transaction() c.close()
def test_timestamp_api(self): self.session.create(self.uri, 'key_format=i,value_format=i') c = self.session.open_cursor(self.uri) # It is illegal to set the prepare timestamp older than the oldest # timestamp. self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(20)) self.conn.set_timestamp('stable_timestamp=' + timestamp_str(30)) self.session.begin_transaction() self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + timestamp_str(10)), "/older than the oldest timestamp/") self.session.rollback_transaction() # Check setting a prepared transaction timestamps earlier than the # oldest timestamp is valid with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(10)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(15)) self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(35)) self.session.commit_transaction() # Check setting a prepared transaction timestamps earlier than the # oldest timestamp is invalid, if durable timestamp is less than the # stable timestamp. self.session.begin_transaction('roundup_timestamps=(prepared=true)') self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(10)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(15)) self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. timestamp_transaction('durable_timestamp=' + timestamp_str(25)), "/is less than the stable timestamp/") self.session.rollback_transaction() # Check the cases with an active reader. # Start a new reader to have an active read timestamp. s_reader = self.conn.open_session() s_reader.begin_transaction('read_timestamp=' + timestamp_str(40)) # It is illegal to set the prepare timestamp as earlier than an active # read timestamp even with roundup_timestamps settings. This is only # checked in diagnostic builds. if wiredtiger.diagnostic_build(): self.session.begin_transaction( 'roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + timestamp_str(10)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # It is illegal to set the prepare timestamp the same as an active read # timestamp even with roundup_timestamps settings. self.session.begin_transaction( 'roundup_timestamps=(prepared=true)') self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. prepare_transaction('prepare_timestamp=' + timestamp_str(40)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # It is illegal to set a commit timestamp less than the prepare # timestamp of a transaction. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(45)) self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. commit_transaction('commit_timestamp=' + timestamp_str(30)), "/less than the prepare timestamp/") # It is legal to set a commit timestamp older than prepare timestamp of # a transaction with roundup_timestamps settings. self.session.begin_transaction('roundup_timestamps=(prepared=true)') c[1] = 1 self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(45)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(30)) #self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(30)) self.assertRaisesWithMessage( wiredtiger.WiredTigerError, lambda: self.session. timestamp_transaction('durable_timestamp=' + timestamp_str(30)), "/is less than the commit timestamp/") self.session.rollback_transaction() s_reader.commit_transaction()
def test_timestamp_api(self): self.session.create(self.uri, 'key_format=i,value_format=i') c = self.session.open_cursor(self.uri) # It is illegal to set a prepare timestamp older than oldest timestamp. self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(2)) self.session.begin_transaction() self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(1)), "/older than the oldest timestamp/") self.session.commit_transaction('commit_timestamp=' + timestamp_str(3)) # Check setting the prepare timestamp same as oldest timestamp is valid. self.session.begin_transaction() self.session.prepare_transaction('prepare_timestamp=' + timestamp_str(2)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(3)) self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(3)) self.session.commit_transaction() # In a single transaction it is illegal to set a commit timestamp # before invoking prepare for this transaction. # Note: Values are not important, setting commit timestamp before # prepare itself is illegal. self.session.begin_transaction() self.session.timestamp_transaction( 'commit_timestamp=' + timestamp_str(3)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(2)), "/should not have been set before/") self.session.commit_transaction('commit_timestamp=' + timestamp_str(3)) # It is illegal to set a prepare timestamp same as or earlier than an # active read timestamp. # Start a new reader to have an active read timestamp. if wiredtiger.diagnostic_build(): s_reader = self.conn.open_session() s_reader.begin_transaction('read_timestamp=' + timestamp_str(4)) self.session.begin_transaction() self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(4)), "/must be greater than the latest active read timestamp/") self.session.rollback_transaction() # Check setting the prepare timestamp as later than active read # timestamp is valid. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(5)) # Resolve the reader transaction started earlier. s_reader.rollback_transaction() self.session.rollback_transaction() # It is illegal to set a commit timestamp older than prepare # timestamp of a transaction. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(5)) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction( 'commit_timestamp=' + timestamp_str(4)), "/less than the prepare timestamp/") # It is legal to set a commit timestamp as same as prepare # timestamp. self.session.begin_transaction() c[1] = 1 self.session.prepare_transaction( 'prepare_timestamp=' + timestamp_str(5)) self.session.timestamp_transaction('commit_timestamp=' + timestamp_str(5)) self.session.timestamp_transaction('durable_timestamp=' + timestamp_str(5)) self.session.commit_transaction()
def test_alter_inconsistent_update(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) # Create the table without the key consistency checking turned on. # Create a few items breaking the rules. Then alter the setting and # verify the inconsistent usage is detected. uri = 'table:ts' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format)) c = self.session.open_cursor(uri) key = ds.key(10) # Insert a data item at timestamp 2. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(2)) c[key] = ds.value(10) self.session.commit_transaction() # Update the data item at timestamp 1. self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(1)) c[key] = ds.value(11) self.session.commit_transaction() key = ds.key(12) # Insert a non-timestamped item, then update with a timestamp and then without a timestamp. self.session.begin_transaction() c[key] = ds.value(12) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(13) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(2)) self.session.begin_transaction() c[key] = ds.value(14) self.session.commit_transaction() # Now alter the setting and make sure we detect incorrect usage. We must move the oldest # timestamp forward in order to alter, otherwise alter will fail with EBUSY. c.close() self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10)) self.session.alter(uri, 'write_timestamp_usage=ordered') c = self.session.open_cursor(uri) key = ds.key(15) # Detect decreasing timestamp. self.session.begin_transaction() c[key] = ds.value(15) self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(15)) msg = '/with an older timestamp/' self.session.begin_transaction() self.session.timestamp_transaction('commit_timestamp=' + self.timestamp_str(14)) c[key] = ds.value(16) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg) # Detect not using a timestamp. msg = '/use timestamps once they are first used/' self.session.begin_transaction() c[key] = ds.value(17) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), msg)
def test_timestamp_alter(self): if wiredtiger.diagnostic_build(): self.skipTest('requires a non-diagnostic build') # Create an object that's never written, it's just used to generate valid k/v pairs. ds = SimpleDataSet( self, 'file:notused', 10, key_format=self.key_format, value_format=self.value_format) cfg_on = 'write_timestamp_usage=ordered' cfg_off = 'write_timestamp_usage=none' # Create a few items with and without timestamps. # Then alter the setting and verify the inconsistent usage is detected. uri = 'file:assert06' self.session.create(uri, 'key_format={},value_format={}'.format(self.key_format, self.value_format)) c = self.session.open_cursor(uri) # Insert a data item at timestamp 2. key = ds.key(1) self.session.begin_transaction() c[key] = ds.value(1) self.apply_timestamps(2, True) self.session.commit_transaction() # Modify the data item without a timestamp. self.session.begin_transaction('no_timestamp=true') c[key] = ds.value(2) self.session.commit_transaction() # Insert an item without a timestamp. # Then modify with a timestamp. # Then modify without a timestamp. key = ds.key(2) self.session.begin_transaction('no_timestamp=true') c[key] = ds.value(3) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(4) self.apply_timestamps(2, True) self.session.commit_transaction() self.session.begin_transaction('no_timestamp=true') c[key] = ds.value(5) self.session.commit_transaction() # Now alter the setting and make sure we detect incorrect usage. # We must move the oldest timestamp forward in order to alter, otherwise alter closing the # file will fail with EBUSY. self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(2)) c.close() self.session.alter(uri, cfg_on) c = self.session.open_cursor(uri) # Update at timestamp 5, then detect not using a timestamp. key = ds.key(3) self.session.begin_transaction() c[key] = ds.value(6) self.apply_timestamps(5, True) self.session.commit_transaction() self.session.begin_transaction() c[key] = ds.value(6) self.assertRaisesWithMessage(wiredtiger.WiredTigerError, lambda: self.session.commit_transaction(), self.msg_usage)