diff --git a/src/concurrency/transaction_manager.cpp b/src/concurrency/transaction_manager.cpp index 3faa8cbb9..cdf3570e9 100644 --- a/src/concurrency/transaction_manager.cpp +++ b/src/concurrency/transaction_manager.cpp @@ -47,7 +47,7 @@ auto TransactionManager::Begin(IsolationLevel isolation_level) -> Transaction * auto *txn_ref = txn.get(); txn_map_.insert(std::make_pair(txn_id, std::move(txn))); - // TODO(fall2023): set the timestamps here. Watermark updated below. + // TODO(P4): set the timestamps here. Watermark updated below. running_txns_.AddTxn(txn_ref->read_ts_); return txn_ref; @@ -65,7 +65,7 @@ auto TransactionManager::VerifyTxn(Transaction *txn) -> bool { return true; } auto TransactionManager::Commit(Transaction *txn) -> bool { std::unique_lock commit_lck(commit_mutex_); - // TODO(fall2023): acquire commit ts! + // TODO(P4): acquire commit ts! if (txn->state_ != TransactionState::RUNNING) { throw Exception("txn not in running state"); @@ -79,11 +79,11 @@ auto TransactionManager::Commit(Transaction *txn) -> bool { } } - // TODO(fall2023): Implement the commit logic! + // TODO(P4): Implement the commit logic! std::unique_lock lck(txn_map_mutex_); - // TODO(fall2023): set commit timestamp + update last committed timestamp here. + // TODO(P4): set commit timestamp + update last committed timestamp here. txn->state_ = TransactionState::COMMITTED; running_txns_.UpdateCommitTs(txn->commit_ts_); @@ -101,7 +101,7 @@ void TransactionManager::Abort(Transaction *txn) { throw Exception("txn not in running / tainted state"); } - // TODO(fall2023): Implement the abort logic! + // TODO(P4): Implement the abort logic! std::unique_lock lck(txn_map_mutex_); txn->state_ = TransactionState::ABORTED; diff --git a/src/concurrency/watermark.cpp b/src/concurrency/watermark.cpp index c8476c519..52339788b 100644 --- a/src/concurrency/watermark.cpp +++ b/src/concurrency/watermark.cpp @@ -21,11 +21,11 @@ auto Watermark::AddTxn(timestamp_t read_ts) -> void { throw Exception("read ts < commit ts"); } - // TODO(fall2023): implement me! + // TODO(P4): implement me! } auto Watermark::RemoveTxn(timestamp_t read_ts) -> void { - // TODO(fall2023): implement me! + // TODO(P4): implement me! } } // namespace bustub diff --git a/test/txn/txn_abort_serializable_test.cpp b/test/txn/txn_abort_serializable_test.cpp index 7c9bb35aa..b4cd84134 100644 --- a/test/txn/txn_abort_serializable_test.cpp +++ b/test/txn/txn_abort_serializable_test.cpp @@ -19,7 +19,7 @@ namespace bustub { // NOLINTBEGIN(bugprone-unchecked-optional-access) -TEST(TxnBonusTest, DISABLED_SerializableTest) { // NOLINT +TEST(TxnSerializableTest, DISABLED_SerializableTest) { // NOLINT fmt::println(stderr, "--- SerializableTest2: Serializable ---"); { auto bustub = std::make_unique(); @@ -45,7 +45,7 @@ TEST(TxnBonusTest, DISABLED_SerializableTest) { // NOLINT } } -TEST(TxnBonusTest, DISABLED_ConcurrentSerializableTest) { // NOLINT +TEST(TxnSerializableTest, DISABLED_ConcurrentSerializableTest) { // NOLINT fmt::println(stderr, "--- SerializableTest2: Concurrent Serializable ---"); { for (int i = 0; i < 10; i++) { @@ -99,8 +99,89 @@ TEST(TxnBonusTest, DISABLED_ConcurrentSerializableTest) { // NOLINT } } -TEST(TxnBonusTest, DISABLED_AbortTest) { // NOLINT - fmt::println(stderr, "--- AbortTest1: Simple Abort ---"); +TEST(TxnAbortTest, DISABLED_SimpleAbortTest) { // NOLINT + fmt::println(stderr, "--- SimpleAbortTest: Setup without primary key ---"); + auto bustub = std::make_unique(); + Execute(*bustub, "CREATE TABLE maintable(a int, b int)"); + auto table_info = bustub->catalog_->GetTable("maintable"); + + fmt::println(stderr, "A: INSERT then ABORT - ensure nothing persists"); + { + auto txn1 = BeginTxn(*bustub, "txn1"); + WithTxn(txn1, ExecuteTxn(*bustub, _var, _txn, "INSERT INTO maintable VALUES (1,10), (1,11), (2,20)")); + WithTxn(txn1, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {1, 11}, {2, 20}})); + WithTxn(txn1, AbortTxn(*bustub, _var, _txn)); + } + { + auto txn_check = BeginTxn(*bustub, "txn_check_after_abort_insert"); + WithTxn(txn_check, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", IntResult{})); + WithTxn(txn_check, CommitTxn(*bustub, _var, _txn)); + } + + fmt::println(stderr, "B: Prepare committed baseline for UPDATE/DELETE abort tests"); + { + auto txn2 = BeginTxn(*bustub, "txn2"); + WithTxn(txn2, ExecuteTxn(*bustub, _var, _txn, "INSERT INTO maintable VALUES (1,10), (2,200), (3,300)")); + WithTxn(txn2, CommitTxn(*bustub, _var, _txn)); + } + { + auto txn_check = BeginTxn(*bustub, "txn_check_baseline"); + WithTxn(txn_check, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {2, 200}, {3, 300}})); + WithTxn(txn_check, CommitTxn(*bustub, _var, _txn)); + } + + fmt::println(stderr, "C: UPDATE then ABORT - values should revert"); + { + auto txn3 = BeginTxn(*bustub, "txn3"); + WithTxn(txn3, ExecuteTxn(*bustub, _var, _txn, "UPDATE maintable SET b = 0 WHERE a >= 2")); + WithTxn(txn3, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {2, 0}, {3, 0}})); + WithTxn(txn3, AbortTxn(*bustub, _var, _txn)); + } + { + auto txn_check = BeginTxn(*bustub, "txn_check_after_abort_update"); + WithTxn(txn_check, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {2, 200}, {3, 300}})); + WithTxn(txn_check, CommitTxn(*bustub, _var, _txn)); + } + + fmt::println(stderr, "D: DELETE then ABORT - rows should reappear"); + { + auto txn4 = BeginTxn(*bustub, "txn4"); + WithTxn(txn4, ExecuteTxn(*bustub, _var, _txn, "DELETE FROM maintable")); + WithTxn(txn4, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", IntResult{})); + WithTxn(txn4, AbortTxn(*bustub, _var, _txn)); + } + { + auto txn_check = BeginTxn(*bustub, "txn_check_after_abort_delete"); + WithTxn(txn_check, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {2, 200}, {3, 300}})); + WithTxn(txn_check, CommitTxn(*bustub, _var, _txn)); + } + + fmt::println(stderr, "E: Commit with duplicates (no primary key) and verify"); + { + auto txn5 = BeginTxn(*bustub, "txn5"); + WithTxn(txn5, ExecuteTxn(*bustub, _var, _txn, "INSERT INTO maintable VALUES (1,999), (1,1000)")); + WithTxn(txn5, ExecuteTxn(*bustub, _var, _txn, "UPDATE maintable SET b = b + 1 WHERE a = 3")); + WithTxn(txn5, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {1, 999}, {1, 1000}, {2, 200}, {3, 301}})); + WithTxn(txn5, CommitTxn(*bustub, _var, _txn)); + } + + fmt::println(stderr, "F: Final verification from fresh transaction"); + { + auto txn_final = BeginTxn(*bustub, "txn_final"); + WithTxn(txn_final, QueryShowResult(*bustub, _var, _txn, "SELECT a, b FROM maintable ORDER BY a, b", + IntResult{{1, 10}, {1, 999}, {1, 1000}, {2, 200}, {3, 301}})); + WithTxn(txn_final, CommitTxn(*bustub, _var, _txn)); + } +} + +TEST(TxnAbortTest, DISABLED_AbortIndexTest) { // NOLINT + fmt::println(stderr, "--- AbortIndexTest1: Simple Abort ---"); { auto bustub = std::make_unique(); EnsureIndexScan(*bustub); diff --git a/test/txn/txn_index_concurrent_test.cpp b/test/txn/txn_index_concurrent_test.cpp index 4b1a71f91..13d3042f6 100644 --- a/test/txn/txn_index_concurrent_test.cpp +++ b/test/txn/txn_index_concurrent_test.cpp @@ -205,7 +205,7 @@ TEST(TxnIndexTest, DISABLED_IndexConcurrentUpdateTest) { // NOLINT } } -TEST(TxnIndexTest, DISABLED_IndexConcurrentUpdateAbortTest) { // NOLINT +TEST(TxnAbortTest, DISABLED_IndexConcurrentUpdateAbortTest) { // NOLINT const auto generate_sql = [](int n) -> std::string { return fmt::format("UPDATE maintable SET b = b + {} WHERE a = {}", 1, n); };