Beispiel #1
0
    def test_rollback_to_stable(self):
        nrows = 1000

        # Create a table without logging.
        uri = "table:rollback_to_stable07"
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format="S",
                           config='log=(enabled=false)')
        ds.populate()

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
                                ',stable_timestamp=' + self.timestamp_str(10))

        value_a = "aaaaa" * 100
        value_b = "bbbbb" * 100
        value_c = "ccccc" * 100
        value_d = "ddddd" * 100

        # Perform several updates.
        self.large_updates(uri, value_d, ds, nrows, self.prepare, 20)
        self.large_updates(uri, value_c, ds, nrows, self.prepare, 30)
        self.large_updates(uri, value_b, ds, nrows, self.prepare, 40)
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 50)

        # Verify data is visible and correct.
        self.check(value_d, uri, nrows, 20)
        self.check(value_c, uri, nrows, 30)
        self.check(value_b, uri, nrows, 40)
        self.check(value_a, uri, nrows, 50)

        # Pin stable to timestamp 50 if prepare otherwise 40.
        if self.prepare:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(50))
        else:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(40))

        # Perform additional updates.
        self.large_updates(uri, value_b, ds, nrows, self.prepare, 60)
        self.large_updates(uri, value_c, ds, nrows, self.prepare, 70)
        self.large_updates(uri, value_d, ds, nrows, self.prepare, 80)

        # Checkpoint to ensure the data is flushed to disk.
        self.session.checkpoint()

        # Verify additional update data is visible and correct.
        self.check(value_b, uri, nrows, 60)
        self.check(value_c, uri, nrows, 70)
        self.check(value_d, uri, nrows, 80)

        # Simulate a server crash and restart.
        simulate_crash_restart(self, ".", "RESTART")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_b, uri, nrows, 40)
        self.check(value_b, uri, nrows, 80)
        self.check(value_c, uri, nrows, 30)
        self.check(value_d, uri, nrows, 20)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        calls = stat_cursor[stat.conn.txn_rts][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        keys_restored = stat_cursor[stat.conn.txn_rts_keys_restored][2]
        pages_visited = stat_cursor[stat.conn.txn_rts_pages_visited][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(calls, 0)
        self.assertEqual(keys_removed, 0)
        self.assertEqual(keys_restored, 0)
        self.assertGreaterEqual(upd_aborted, 0)
        self.assertGreater(pages_visited, 0)
        self.assertGreaterEqual(hs_removed, nrows * 4)

        # Simulate another server crash and restart.
        simulate_crash_restart(self, "RESTART", "RESTART2")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_b, uri, nrows, 40)
        self.check(value_b, uri, nrows, 80)
        self.check(value_c, uri, nrows, 30)
        self.check(value_d, uri, nrows, 20)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        calls = stat_cursor[stat.conn.txn_rts][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        keys_restored = stat_cursor[stat.conn.txn_rts_keys_restored][2]
        pages_visited = stat_cursor[stat.conn.txn_rts_pages_visited][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(calls, 0)
        self.assertEqual(keys_removed, 0)
        self.assertEqual(keys_restored, 0)
        self.assertGreaterEqual(pages_visited, 0)
        self.assertEqual(upd_aborted, 0)
        self.assertEqual(hs_removed, 0)
Beispiel #2
0
    def test_rollback_to_stable36(self):
        nrows = 1000

        # Create a table.
        uri = "table:rollback_to_stable36"
        ds = SimpleDataSet(
            self, uri, 0, key_format=self.key_format, value_format=self.value_format,
            config=self.extraconfig)
        ds.populate()

        if self.value_format == '8t':
            value_a = 97
        else:
            value_a = "aaaaa" * 100

        # 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 baseline data to table 1 at time 10.
        cursor1 = self.session.open_cursor(ds.uri)
        self.session.begin_transaction()
        for i in range(1, nrows + 1):
            cursor1[ds.key(i)] = value_a
            if i % 109 == 0:
                self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(10))
                self.session.begin_transaction()
        self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(10))
        cursor1.close()

        # Mark it stable.
        self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(10))

        # Reopen the connection so nothing is in memory and we can fast-truncate.
        self.reopen_conn()

        # Truncate most of the table.
        # Commit the truncate at time 20.
        self.session.begin_transaction()
        err = self.truncate(ds.uri, ds.key, 50, nrows - 50)
        self.assertEqual(err, 0)
        self.session.commit_transaction('commit_timestamp=' + self.timestamp_str(20))

        # Make sure we did at least one fast-delete. For columns, there's no fast-delete
        # support (yet) so assert we didn't.
        stat_cursor = self.session.open_cursor('statistics:', None, None)
        fastdelete_pages = stat_cursor[stat.conn.rec_page_delete_fast][2]
        if self.key_format == 'r' or self.trunc_with_remove:
            self.assertEqual(fastdelete_pages, 0)
        else:
            self.assertGreater(fastdelete_pages, 0)
        stat_cursor.close()

        # Checkpoint.
        self.session.checkpoint()

        # Roll back, either via crashing or by explicit RTS.
        if self.crash:
            simulate_crash_restart(self, ".", "RESTART")
        else:
            self.conn.rollback_to_stable()

        # Currently rolling back a fast-truncate works by instantiating the pages and
        # rolling back the instantiated updates, so we should see some page instantiations.
        # (But again, not for columns, yet.)
        stat_cursor = self.session.open_cursor('statistics:', None, None)
        read_deleted = stat_cursor[stat.conn.cache_read_deleted][2]
        if self.key_format == 'r' or self.trunc_with_remove:
            self.assertEqual(read_deleted, 0)
        else:
            self.assertGreater(read_deleted, 0)
        stat_cursor.close()

        # Validate the data; we should see all of it, since the truncations weren't stable.
        self.check(ds, value_a, nrows, 15)
        self.check(ds, value_a, nrows, 25)
Beispiel #3
0
    def test_rollback_to_stable(self):
        nrows = 1000

        # Create a table.
        self.pr("create/populate tables")
        uri_1 = "table:rollback_to_stable10_1"
        ds_1 = SimpleDataSet(self,
                             uri_1,
                             0,
                             key_format=self.key_format,
                             value_format=self.value_format)
        ds_1.populate()

        # Create another table.
        uri_2 = "table:rollback_to_stable10_2"
        ds_2 = SimpleDataSet(self,
                             uri_2,
                             0,
                             key_format=self.key_format,
                             value_format=self.value_format)
        ds_2.populate()

        if self.value_format == '8t':
            value_a = 97
            value_b = 98
            value_c = 99
            value_d = 100
            value_e = 101
            value_f = 102
        else:
            value_a = "aaaaa" * 100
            value_b = "bbbbb" * 100
            value_c = "ccccc" * 100
            value_d = "ddddd" * 100
            value_e = "eeeee" * 100
            value_f = "fffff" * 100

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
                                ',stable_timestamp=' + self.timestamp_str(10))

        # Perform several updates.
        self.pr("large updates")
        self.large_updates(uri_1, value_d, ds_1, nrows, self.prepare, 20)
        self.large_updates(uri_1, value_c, ds_1, nrows, self.prepare, 30)
        self.large_updates(uri_1, value_b, ds_1, nrows, self.prepare, 40)
        self.large_updates(uri_1, value_a, ds_1, nrows, self.prepare, 50)

        self.large_updates(uri_2, value_d, ds_2, nrows, self.prepare, 20)
        self.large_updates(uri_2, value_c, ds_2, nrows, self.prepare, 30)
        self.large_updates(uri_2, value_b, ds_2, nrows, self.prepare, 40)
        self.large_updates(uri_2, value_a, ds_2, nrows, self.prepare, 50)

        # Verify data is visible and correct.
        self.check(value_d, uri_1, nrows, None, 21 if self.prepare else 20)
        self.check(value_c, uri_1, nrows, None, 31 if self.prepare else 30)
        self.check(value_b, uri_1, nrows, None, 41 if self.prepare else 40)
        self.check(value_a, uri_1, nrows, None, 51 if self.prepare else 50)

        self.check(value_d, uri_2, nrows, None, 21 if self.prepare else 20)
        self.check(value_c, uri_2, nrows, None, 31 if self.prepare else 30)
        self.check(value_b, uri_2, nrows, None, 41 if self.prepare else 40)
        self.check(value_a, uri_2, nrows, None, 51 if self.prepare else 50)

        # Pin stable to timestamp 60 if prepare otherwise 50.
        if self.prepare:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(60))
        else:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(50))

        # Create a checkpoint thread
        done = threading.Event()
        ckpt = checkpoint_thread(self.conn, done)
        try:
            self.pr("start checkpoint")
            ckpt.start()
            # Sleep for sometime so that checkpoint starts.
            time.sleep(2)

            # Perform several updates in parallel with checkpoint.
            # Rollbacks may occur when checkpoint is running, so retry as needed.
            self.pr("updates")
            self.retry_rollback(
                'update ds1, e', None, lambda: self.large_updates(
                    uri_1, value_e, ds_1, nrows, self.prepare, 70))
            self.retry_rollback(
                'update ds2, e', None, lambda: self.large_updates(
                    uri_2, value_e, ds_2, nrows, self.prepare, 70))
            self.evict_cursor(uri_1, nrows, value_e)
            self.evict_cursor(uri_2, nrows, value_e)
            self.retry_rollback(
                'update ds1, f', None, lambda: self.large_updates(
                    uri_1, value_f, ds_1, nrows, self.prepare, 80))
            self.retry_rollback(
                'update ds2, f', None, lambda: self.large_updates(
                    uri_2, value_f, ds_2, nrows, self.prepare, 80))
            self.evict_cursor(uri_1, nrows, value_f)
            self.evict_cursor(uri_2, nrows, value_f)
        finally:
            done.set()
            ckpt.join()

        # Simulate a server crash and restart.
        self.pr("restart")
        simulate_crash_restart(self, ".", "RESTART")
        self.pr("restart complete")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_a, uri_1, nrows, None, 50)
        self.check(value_a, uri_1, nrows, None, 80)
        self.check(value_b, uri_1, nrows, None, 40)
        self.check(value_c, uri_1, nrows, None, 30)
        self.check(value_d, uri_1, nrows, None, 20)

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_c, uri_2, nrows, None, 30)
        self.check(value_a, uri_2, nrows, None, 50)
        self.check(value_a, uri_2, nrows, None, 80)
        self.check(value_b, uri_2, nrows, None, 40)
        self.check(value_d, uri_2, nrows, None, 20)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        calls = stat_cursor[stat.conn.txn_rts][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        hs_sweep = stat_cursor[stat.conn.txn_rts_sweep_hs_keys][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        keys_restored = stat_cursor[stat.conn.txn_rts_keys_restored][2]
        pages_visited = stat_cursor[stat.conn.txn_rts_pages_visited][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(calls, 0)
        self.assertEqual(keys_removed, 0)
        self.assertEqual(keys_restored, 0)
        self.assertGreaterEqual(upd_aborted, 0)
        self.assertGreater(pages_visited, 0)
        self.assertGreaterEqual(hs_removed, 0)
        self.assertGreater(hs_sweep, 0)
    def test_rollback_to_stable(self):
        nrows = 1000

        # Create a table without logging.
        uri = "table:rollback_to_stable23"
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format=self.value_format)
        ds.populate()

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
                                ',stable_timestamp=' + self.timestamp_str(10))

        value_a = "aaaaa" * 100

        value_modQ = mod_val(value_a, 'Q', 0)
        value_modR = mod_val(value_modQ, 'R', 1)
        value_modS = mod_val(value_modR, 'S', 2)
        value_modT = mod_val(value_modS, 'T', 3)

        # Perform a combination of modifies and updates.
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 20)
        self.large_modifies(uri, 'Q', ds, 0, 1, nrows, self.prepare, 30)
        self.large_modifies(uri, 'R', ds, 1, 1, nrows, self.prepare, 40)
        self.large_modifies(uri, 'S', ds, 2, 1, nrows, self.prepare, 50)
        self.large_modifies(uri, 'T', ds, 3, 1, nrows, self.prepare, 60)

        # Verify data is visible and correct.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_modQ, uri, nrows, None, 30)
        self.check(value_modR, uri, nrows, None, 40)
        self.check(value_modS, uri, nrows, None, 50)
        self.check(value_modT, uri, nrows, None, 60)

        # Pin stable to timestamp 60 if prepare otherwise 50.
        if self.prepare:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(60))
        else:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(50))

        # Checkpoint the database.
        self.session.checkpoint()

        # Simulate a server crash and restart.
        simulate_crash_restart(self, ".", "RESTART")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check_with_set_key(ds, value_a, uri, nrows, 20)
        self.check_with_set_key(ds, value_modQ, uri, nrows, 30)
        self.check_with_set_key(ds, value_modR, uri, nrows, 40)
        self.check_with_set_key(ds, value_modS, uri, nrows, 50)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        hs_restore_updates = stat_cursor[
            stat.conn.txn_rts_hs_restore_updates][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(hs_restore_updates, nrows)
        if self.prepare:
            self.assertGreaterEqual(upd_aborted, 0)
        else:
            self.assertEqual(upd_aborted, 0)
        self.assertGreaterEqual(hs_removed, nrows)
Beispiel #5
0
    def test_checkpoint_snapshot_with_txnid_and_timestamp(self):

        ds = SimpleDataSet(self,
                           self.uri,
                           0,
                           key_format="S",
                           value_format="S",
                           config='log=(enabled=false)')
        ds.populate()
        valuea = "aaaaa" * 100
        valueb = "bbbbb" * 100

        # Pin oldest and stable timestamps to 10.
        self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(10) +
                                ',stable_timestamp=' + timestamp_str(10))

        session1 = self.conn.open_session()
        session1.begin_transaction()

        self.large_updates(self.uri, valuea, ds, self.nrows, 20)
        self.check(valuea, self.uri, self.nrows, 20)

        session2 = self.conn.open_session()
        session2.begin_transaction()
        cursor2 = session2.open_cursor(self.uri)

        for i in range((self.nrows + 1), (self.nrows * 2) + 1):
            cursor2.set_key(ds.key(i))
            cursor2.set_value(valuea)
            self.assertEqual(cursor2.insert(), 0)
        session1.timestamp_transaction('commit_timestamp=' + timestamp_str(30))

        # Set stable timestamp to 40
        self.conn.set_timestamp('stable_timestamp=' + timestamp_str(40))

        # Create a checkpoint thread
        done = threading.Event()
        ckpt = checkpoint_thread(self.conn, done)
        try:
            ckpt.start()
            # Sleep for sometime so that checkpoint starts before committing last transaction.
            time.sleep(2)
            session2.commit_transaction()

        finally:
            done.set()
            ckpt.join()

        session1.rollback_transaction()
        #Simulate a crash by copying to a new directory(RESTART).
        simulate_crash_restart(self, ".", "RESTART")

        # Check the table contains the last checkpointed value.
        self.check(valuea, self.uri, self.nrows, 30)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        inconsistent_ckpt = stat_cursor[stat.conn.txn_rts_inconsistent_ckpt][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        stat_cursor.close()

        self.assertGreater(inconsistent_ckpt, 0)
        self.assertGreaterEqual(keys_removed, 0)

        simulate_crash_restart(self, "RESTART", "RESTART2")
        # Check the table contains the last checkpointed value.
        self.check(valuea, self.uri, self.nrows, 30)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        inconsistent_ckpt = stat_cursor[stat.conn.txn_rts_inconsistent_ckpt][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        stat_cursor.close()

        self.assertGreaterEqual(inconsistent_ckpt, 0)
        self.assertEqual(keys_removed, 0)
Beispiel #6
0
    def test_rollback_to_stable_no_history(self):
        nrows = 1000

        # Prepare transactions for column store table is not yet supported.
        if self.key_format == 'r':
            self.skipTest(
                'Prepare transactions for column store table is not yet supported'
            )

        # Create a table without logging.
        uri = "table:rollback_to_stable19"
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format="S",
                           config='log=(enabled=false)')
        ds.populate()

        # Pin oldest and stable timestamps to 10.
        self.conn.set_timestamp('oldest_timestamp=' + timestamp_str(10) +
                                ',stable_timestamp=' + timestamp_str(10))

        valuea = "aaaaa" * 100

        # Perform several updates and removes.
        s = self.conn.open_session()
        cursor = s.open_cursor(uri)
        s.begin_transaction()
        for i in range(1, nrows + 1):
            cursor[ds.key(i)] = valuea
            cursor.set_key(i)
            cursor.remove()
        cursor.close()
        s.prepare_transaction('prepare_timestamp=' + timestamp_str(20))

        # Configure debug behavior on a cursor to evict the page positioned on when the reset API is used.
        evict_cursor = self.session.open_cursor(uri, None,
                                                "debug=(release_evict)")

        # Search for the key so we position our cursor on the page that we want to evict.
        self.session.begin_transaction("ignore_prepare = true")
        evict_cursor.set_key(1)
        evict_cursor.search()
        evict_cursor.reset()
        evict_cursor.close()
        self.session.commit_transaction()

        # Pin stable timestamp to 20.
        self.conn.set_timestamp('stable_timestamp=' + timestamp_str(20))
        if not self.in_memory:
            self.session.checkpoint()

        if not self.in_memory:
            if self.crash:
                simulate_crash_restart(self, ".", "RESTART")
            else:
                # Close and reopen the connection
                self.reopen_conn()
        else:
            self.conn.rollback_to_stable()
            s.rollback_transaction()

        # Verify data is not visible.
        self.check(valuea, uri, 0, 20)
        self.check(valuea, uri, 0, 30)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        self.assertGreater(upd_aborted, 0)
        self.assertGreater(keys_removed, 0)
    def test_rollback_to_stable(self):
        nrows = 10

        # Create a table without logging.
        uri = "table:rollback_to_stable26"
        ds = SimpleDataSet(
            self, uri, 0, key_format=self.key_format, value_format=self.value_format,
            config='log=(enabled=false)')
        ds.populate()

        if self.value_format == '8t':
             value_a = 97
             value_b = 98
             value_c = 99
             value_d = 100
             value_e = 101
        else:
             value_a = "aaaaa" * 100
             value_b = "bbbbb" * 100
             value_c = "ccccc" * 100
             value_d = "ddddd" * 100
             value_e = "eeeee" * 100

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
            ',stable_timestamp=' + self.timestamp_str(10))

        self.large_updates(uri, value_a, ds, nrows, False, 20)
        self.large_updates(uri, value_b, ds, nrows, False, 30)

        if self.hs_remove:
            self.large_removes(uri, ds, nrows, False, 40)

        prepare_session = self.conn.open_session()
        prepare_session.begin_transaction()
        cursor = prepare_session.open_cursor(uri)
        for i in range (1, nrows + 1):
            cursor[i] = value_c
            if self.prepare_remove:
                cursor.set_key(i)
                self.assertEqual(cursor.remove(), 0)
        cursor.close()
        prepare_session.prepare_transaction('prepare_timestamp=' + self.timestamp_str(50))

        # Verify data is visible and correct.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_b, uri, nrows, None, 30)

        self.evict_cursor(uri, nrows)

        # Pin stable to timestamp 40.
        self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(40))

        # Create a checkpoint thread
        done = threading.Event()
        ckpt = checkpoint_thread(self.conn, done)
        try:
            ckpt.start()
            # Sleep for sometime so that checkpoint starts before committing last transaction.
            time.sleep(5)
            prepare_session.rollback_transaction()
        finally:
            done.set()
            ckpt.join()

        self.large_updates(uri, value_d, ds, nrows, False, 60)

        # Check that the correct data.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_b, uri, nrows, None, 30)
        self.check(value_d, uri, nrows, None, 60)

        # Simulate a server crash and restart.
        simulate_crash_restart(self, ".", "RESTART")

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        hs_restore_updates = stat_cursor[stat.conn.txn_rts_hs_restore_updates][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        stat_cursor.close()

        self.assertEqual(keys_removed, 0)
        self.assertEqual(hs_restore_updates, nrows)
        self.assertEqual(hs_removed, nrows)

        # Check that the correct data.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_b, uri, nrows, None, 30)

        self.large_updates(uri, value_e, ds, nrows, False, 60)

        self.evict_cursor(uri, nrows)

        # Check that the correct data.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_b, uri, nrows, None, 30)
        self.check(value_e, uri, nrows, None, 60)
Beispiel #8
0
    def test_checkpoint(self):
        uri = 'table:checkpoint14'
        nrows = 10000

        # Create a table.
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format=self.value_format,
                           config=self.extraconfig)
        ds.populate()

        if self.value_format == '8t':
            nrows *= 5
            value_a = 97
            value_b = 98
            value_c = 99
        else:
            value_a = "aaaaa" * 100
            value_b = "bbbbb" * 100
            value_c = "ccccc" * 100

        # Write some baseline data.
        self.large_updates(uri, ds, nrows, value_a)
        # Write this data out now so we aren't waiting for it while trying to
        # race with the later data.
        self.session.checkpoint()

        # Write some more data, and hold the transaction open.
        session2 = self.conn.open_session()
        cursor2 = session2.open_cursor(uri)
        session2.begin_transaction()
        for i in range(1, nrows + 1):
            cursor2[ds.key(i)] = value_b

        # Checkpoint in the background.
        done = threading.Event()
        if self.first_checkpoint is None:
            ckpt = checkpoint_thread(self.conn, done)
        else:
            ckpt = named_checkpoint_thread(self.conn, done,
                                           self.first_checkpoint)
        try:
            ckpt.start()

            # Wait for checkpoint to start before committing.
            ckpt_started = 0
            while not ckpt_started:
                stat_cursor = self.session.open_cursor('statistics:', None,
                                                       None)
                ckpt_started = stat_cursor[stat.conn.txn_checkpoint_running][2]
                stat_cursor.close()
                time.sleep(1)

            session2.commit_transaction()
        finally:
            done.set()
            ckpt.join()

        # Rinse and repeat.
        session2.begin_transaction()
        for i in range(1, nrows + 1):
            cursor2[ds.key(i)] = value_c

        # Checkpoint in the background.
        done = threading.Event()
        if self.second_checkpoint is None:
            ckpt = checkpoint_thread(self.conn, done)
        else:
            ckpt = named_checkpoint_thread(self.conn, done,
                                           self.second_checkpoint)
        try:
            ckpt.start()
            # Sleep a bit so that checkpoint starts before committing last transaction.
            time.sleep(2)
            session2.commit_transaction()
        finally:
            done.set()
            ckpt.join()

        # Other tests check for whether the visibility of a partially-written transaction
        # is handled correctly. Here we're interested in whether the visibility mechanism
        # is using the right snapshot for the checkpoint we're reading. So insist that we
        # not see the value_b transaction in the first checkpoint, or the value_c transaction
        # in the second checkpoint. If test machine lag causes either transaction to commit
        # before the checkpoint starts, we'll see value_b in the first checkpoint and/or
        # value_c in the second. But also, if we end up using the second checkpoint's snapshot
        # for the first checkpoint, we'll see value_b. So if this happens more than once in a
        # blue moon we should probably strengthen the test so we can more reliably distinguish
        # the cases, probably by doing a third transaction/checkpoint pair.
        #
        # If we end up using the first checkpoint's snapshot for reading the second checkpoint,
        # we'll most likely see no data at all; that would be a serious failure if it happened.

        # Read the checkpoints.
        self.check(ds, self.first_checkpoint, nrows, value_a)
        self.check(ds, self.second_checkpoint, nrows, value_b)

        # If we haven't died yet, pretend to crash, and run RTS to see if the
        # (second) checkpoint was inconsistent. Unfortunately we can't readily
        # check on both.
        simulate_crash_restart(self, ".", "RESTART")

        # Make sure we did get an inconsistent checkpoint.
        stat_cursor = self.session.open_cursor('statistics:', None, None)
        inconsistent_ckpt = stat_cursor[stat.conn.txn_rts_inconsistent_ckpt][2]
        stat_cursor.close()
        self.assertGreater(inconsistent_ckpt, 0)
Beispiel #9
0
    def test_rollback_to_stable(self):
        nrows = 100

        # Create a table without logging.
        self.pr("create/populate table")
        uri = "table:rollback_to_stable14"
        ds = SimpleDataSet(
            self, uri, 0, key_format=self.key_format, value_format=self.value_format,
            config='log=(enabled=false)')
        ds.populate()

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
            ',stable_timestamp=' + self.timestamp_str(10))

        value_a = "aaaaa" * 100

        value_modQ = mod_val(value_a, 'Q', 0)
        value_modR = mod_val(value_modQ, 'R', 1)
        value_modS = mod_val(value_modR, 'S', 2)
        value_modT = mod_val(value_modS, 'T', 3)
        value_modW = mod_val(value_modT, 'W', 4)
        value_modX = mod_val(value_modW, 'X', 5)
        value_modY = mod_val(value_modX, 'Y', 6)
        value_modZ = mod_val(value_modY, 'Z', 7)

        # Perform a combination of modifies and updates.
        self.pr("large updates and modifies")
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 20)
        self.large_modifies(uri, 'Q', ds, 0, 1, nrows, self.prepare, 30)
        self.large_modifies(uri, 'R', ds, 1, 1, nrows, self.prepare, 40)
        self.large_modifies(uri, 'S', ds, 2, 1, nrows, self.prepare, 50)
        self.large_modifies(uri, 'T', ds, 3, 1, nrows, self.prepare, 60)

        # Verify data is visible and correct.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_modQ, uri, nrows, None, 30)
        self.check(value_modR, uri, nrows, None, 40)
        self.check(value_modS, uri, nrows, None, 50)
        self.check(value_modT, uri, nrows, None, 60)

        # Pin stable to timestamp 60 if prepare otherwise 50.
        if self.prepare:
            self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(60))
        else:
            self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(50))

        # Create a checkpoint thread
        done = threading.Event()
        ckpt = checkpoint_thread(self.conn, done)
        try:
            self.pr("start checkpoint")
            ckpt.start()
            # Sleep for sometime so that checkpoint starts.
            time.sleep(2)

            # Perform several modifies in parallel with checkpoint.
            # Rollbacks may occur when checkpoint is running, so retry as needed.
            self.pr("modifies")
            self.retry_rollback('modify ds1, W', None,
                           lambda: self.large_modifies(uri, 'W', ds, 4, 1, nrows, self.prepare, 70))
            self.evict_cursor(uri, nrows, value_modW)
            self.retry_rollback('modify ds1, X', None,
                           lambda: self.large_modifies(uri, 'X', ds, 5, 1, nrows, self.prepare, 80))
            self.evict_cursor(uri, nrows, value_modX)
            self.retry_rollback('modify ds1, Y', None,
                           lambda: self.large_modifies(uri, 'Y', ds, 6, 1, nrows, self.prepare, 90))
            self.evict_cursor(uri, nrows, value_modY)
            self.retry_rollback('modify ds1, Z', None,
                           lambda: self.large_modifies(uri, 'Z', ds, 7, 1, nrows, self.prepare, 100))
            self.evict_cursor(uri, nrows, value_modZ)
        finally:
            done.set()
            ckpt.join()

        # Simulate a server crash and restart.
        self.pr("restart")
        simulate_crash_restart(self, ".", "RESTART")
        self.pr("restart complete")

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        calls = stat_cursor[stat.conn.txn_rts][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        hs_sweep = stat_cursor[stat.conn.txn_rts_sweep_hs_keys][2]
        hs_restore_updates = stat_cursor[stat.conn.txn_rts_hs_restore_updates][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        keys_restored = stat_cursor[stat.conn.txn_rts_keys_restored][2]
        pages_visited = stat_cursor[stat.conn.txn_rts_pages_visited][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(calls, 0)
        self.assertEqual(keys_removed, 0)
        self.assertEqual(hs_restore_updates, nrows)
        self.assertEqual(keys_restored, 0)
        if self.prepare:
            self.assertGreaterEqual(upd_aborted, 0)
        else:
            self.assertEqual(upd_aborted, 0)
        self.assertGreater(pages_visited, 0)
        self.assertGreaterEqual(hs_removed, nrows)
        self.assertGreaterEqual(hs_sweep, 0)

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_a, uri, nrows, None, 20)
        self.check(value_modQ, uri, nrows, None, 30)
        self.check(value_modR, uri, nrows, None, 40)
        self.check(value_modS, uri, nrows, None, 50)

        # The test may output the following message in eviction under cache pressure. Ignore that.
        self.ignoreStdoutPatternIfExists("oldest pinned transaction ID rolled back for eviction")
Beispiel #10
0
    def test_rollback_to_stable(self):
        nrows = 1

        # Create a table without logging.
        uri = "table:rollback_to_stable11"
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format=self.value_format)
        ds.populate()

        if self.value_format == '8t':
            value_a = 97
            value_b = 98
            value_c = 99
            value_d = 100
        else:
            value_a = "aaaaa" * 100
            value_b = "bbbbb" * 100
            value_c = "ccccc" * 100
            value_d = "ddddd" * 100

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
                                ',stable_timestamp=' + self.timestamp_str(10))

        # Perform several updates.
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 20)
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 20)
        self.large_updates(uri, value_a, ds, nrows, self.prepare, 20)
        self.large_updates(uri, value_b, ds, nrows, self.prepare, 20)

        # Verify data is visible and correct.
        self.check(value_b, uri, nrows, None, 20)

        # Pin stable to timestamp 28 if prepare otherwise 20.
        # large_updates() prepares at 1 before the timestamp passed (so 29)
        # and this is required to be strictly greater than (not >=) stable.
        if self.prepare:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(28))
        else:
            self.conn.set_timestamp('stable_timestamp=' +
                                    self.timestamp_str(20))

        # Checkpoint to ensure that all the updates are flushed to disk.
        self.session.checkpoint()

        # Simulate a server crash and restart.
        simulate_crash_restart(self, ".", "RESTART")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_b, uri, nrows, None, 20)

        # Perform several updates.
        self.large_updates(uri, value_c, ds, nrows, self.prepare, 30)
        self.large_updates(uri, value_c, ds, nrows, self.prepare, 30)
        self.large_updates(uri, value_c, ds, nrows, self.prepare, 30)
        self.large_updates(uri, value_d, ds, nrows, self.prepare, 30)

        # Verify data is visible and correct.
        self.check(value_d, uri, nrows, None, 30)

        # Checkpoint to ensure that all the updates are flushed to disk.
        self.session.checkpoint()

        # Simulate a server crash and restart.
        simulate_crash_restart(self, "RESTART", "RESTART2")

        # Check that the correct data is seen at and after the stable timestamp.
        self.check(value_b, uri, nrows, None, 20)
        self.check(value_b, uri, nrows, None, 40)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        calls = stat_cursor[stat.conn.txn_rts][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        hs_sweep = stat_cursor[stat.conn.txn_rts_sweep_hs_keys][2]
        keys_removed = stat_cursor[stat.conn.txn_rts_keys_removed][2]
        keys_restored = stat_cursor[stat.conn.txn_rts_keys_restored][2]
        pages_visited = stat_cursor[stat.conn.txn_rts_pages_visited][2]
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        stat_cursor.close()

        self.assertEqual(calls, 0)
        self.assertEqual(keys_removed, 0)
        self.assertEqual(keys_restored, 0)
        self.assertEqual(upd_aborted, 0)
        self.assertGreater(pages_visited, 0)
        self.assertEqual(hs_removed, 4)
        self.assertEqual(hs_sweep, 0)
Beispiel #11
0
    def test_rollback_to_stable(self):
        uri = 'table:test_rollback_to_stable29'
        nrows = 1000

        if self.value_format == '8t':
            value_a = 97
            value_b = 98
            value_c = 99
            value_d = 100
        else:
            value_a = 'a' * 100
            value_b = 'b' * 100
            value_c = 'c' * 100
            value_d = 'd' * 100

        # Create our table.
        ds = SimpleDataSet(self, uri, 0, key_format=self.key_format, value_format=self.value_format)
        ds.populate()

        # Pin oldest and stable to timestamp 1.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(1) +
            ',stable_timestamp=' + self.timestamp_str(1))

        self.large_updates(uri, value_a, ds, nrows, False, 10)

        # Pin oldest and stable to timestamp 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
            ',stable_timestamp=' + self.timestamp_str(10))

        old_reader_session = self.conn.open_session()
        old_reader_cursor = old_reader_session.open_cursor(uri)
        old_reader_session.begin_transaction('read_timestamp=' + self.timestamp_str(10))

        self.large_removes(uri, ds, nrows, False, 30)
        self.large_updates(uri, value_b, ds, nrows, False, 40)
        self.check(value_b, uri, nrows, None, 40)

        self.session.checkpoint()
        self.evict_cursor(uri, nrows, value_b)

        self.large_updates(uri, value_c, ds, nrows, False, 50)
        self.check(value_c, uri, nrows, None, 50)
        self.evict_cursor(uri, nrows, value_c)

        # Insert update without a timestamp.
        self.large_updates(uri, value_d, ds, nrows, False, 0)

        self.check(value_d, uri, nrows, None, 10)
        self.check(value_d, uri, nrows, None, 40)
        self.check(value_d, uri, nrows, None, 50)
        self.check(value_d, uri, nrows, None, 20)

        self.session.checkpoint()

        # Simulate a crash by copying to a new directory(RESTART).
        simulate_crash_restart(self, ".", "RESTART")

        self.check(value_d, uri, nrows, None, 10)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]
        stat_cursor.close()

        self.assertGreaterEqual(hs_removed, 0)
    def test_rollback_to_stable_with_history(self):
        nrows = 1000

        # Create a table without logging.
        uri = "table:rollback_to_stable19"
        ds = SimpleDataSet(self,
                           uri,
                           0,
                           key_format=self.key_format,
                           value_format="S",
                           config='log=(enabled=false)')
        ds.populate()

        # Pin oldest and stable timestamps to 10.
        self.conn.set_timestamp('oldest_timestamp=' + self.timestamp_str(10) +
                                ',stable_timestamp=' + self.timestamp_str(10))

        valuea = "aaaaa" * 100
        valueb = "bbbbb" * 100

        # Perform several updates.
        self.large_updates(uri, valuea, ds, nrows, 0, 20)

        # Perform several removes.
        self.large_removes(uri, ds, nrows, 0, 30)

        # Perform several updates and removes.
        s = self.conn.open_session()
        cursor = s.open_cursor(uri)
        s.begin_transaction()
        for i in range(1, nrows + 1):
            cursor[ds.key(i)] = valueb
            cursor.set_key(i)
            cursor.remove()
        cursor.close()
        s.prepare_transaction('prepare_timestamp=' + self.timestamp_str(40))

        # Configure debug behavior on a cursor to evict the page positioned on when the reset API is used.
        evict_cursor = self.session.open_cursor(uri, None,
                                                "debug=(release_evict)")

        # Search for the key so we position our cursor on the page that we want to evict.
        self.session.begin_transaction("ignore_prepare = true")
        evict_cursor.set_key(1)
        self.assertEquals(evict_cursor.search(), WT_NOTFOUND)
        evict_cursor.reset()
        evict_cursor.close()
        self.session.commit_transaction()

        # Search to make sure the data is not visible
        self.session.begin_transaction("ignore_prepare = true")
        cursor2 = self.session.open_cursor(uri)
        cursor2.set_key(1)
        self.assertEquals(cursor2.search(), WT_NOTFOUND)
        self.session.commit_transaction()
        cursor2.close()

        # Pin stable timestamp to 40.
        self.conn.set_timestamp('stable_timestamp=' + self.timestamp_str(40))
        if not self.in_memory:
            self.session.checkpoint()

        if not self.in_memory:
            if self.crash:
                simulate_crash_restart(self, ".", "RESTART")
            else:
                # Close and reopen the connection
                self.reopen_conn()
        else:
            self.conn.rollback_to_stable()
            s.rollback_transaction()

        # Verify data.
        self.check(valuea, uri, nrows, 20)
        self.check(valuea, uri, 0, 30)
        self.check(valuea, uri, 0, 40)

        stat_cursor = self.session.open_cursor('statistics:', None, None)
        upd_aborted = stat_cursor[stat.conn.txn_rts_upd_aborted][2]
        hs_removed = stat_cursor[stat.conn.txn_rts_hs_removed][2]

        # After restart (not crash) the stats for the aborted updates and history store removed will be 0,
        # as the updates aborted and history store removed will occur during shutdown, and on startup there
        # will be no updates to be removed.
        if not self.in_memory:
            if self.crash:
                self.assertGreater(hs_removed, 0)
            else:
                self.assertEqual(hs_removed, 0)
                self.assertEqual(upd_aborted, 0)
        else:
            self.assertGreater(upd_aborted, 0)