44 */
55
66#include < gtest/gtest.h>
7-
87#include < atomic>
98#include < chrono>
10- #include < cstdio>
119#include < thread>
1210#include < vector>
11+ #include < cstdio>
1312
1413#include " catalog/catalog.hpp"
1514#include " common/config.hpp"
1615#include " storage/buffer_pool_manager.hpp"
17- #include " storage/heap_table.hpp"
1816#include " storage/storage_manager.hpp"
17+ #include " storage/heap_table.hpp"
1918#include " transaction/lock_manager.hpp"
2019#include " transaction/transaction.hpp"
2120#include " transaction/transaction_manager.hpp"
@@ -31,49 +30,51 @@ namespace {
3130 * @brief Fixture for transaction-related coverage tests to ensure proper resource management.
3231 */
3332class TransactionCoverageTests : public ::testing::Test {
34- protected:
33+ protected:
3534 void SetUp () override {
36- catalog = Catalog::create ();
37- disk_manager = std::make_unique<StorageManager>(" ./test_data" );
38- bpm = std::make_unique<BufferPoolManager>(config::Config::DEFAULT_BUFFER_POOL_SIZE,
39- *disk_manager);
40- lm = std::make_unique<LockManager>();
41- tm = std::make_unique<TransactionManager>(*lm, *catalog, *bpm, nullptr );
35+ catalog_ptr = Catalog::create ();
36+ disk_manager_ptr = std::make_unique<StorageManager>(" ./test_data" );
37+ bpm_ptr = std::make_unique<BufferPoolManager>(config::Config::DEFAULT_BUFFER_POOL_SIZE, *disk_manager_ptr);
38+ lm_ptr = std::make_unique<LockManager>();
39+ tm_ptr = std::make_unique<TransactionManager>(*lm_ptr, *catalog_ptr, *bpm_ptr, nullptr );
4240
4341 std::vector<ColumnInfo> cols = {{" id" , common::ValueType::TYPE_INT64, 0 },
4442 {" val" , common::ValueType::TYPE_TEXT, 1 }};
45- catalog ->create_table (" rollback_stress" , cols);
46-
43+ catalog_ptr ->create_table (" rollback_stress" , cols);
44+
4745 executor::Schema schema;
4846 schema.add_column (" id" , common::ValueType::TYPE_INT64);
4947 schema.add_column (" val" , common::ValueType::TYPE_TEXT);
50-
51- table = std::make_unique<HeapTable>(" rollback_stress" , *bpm , schema);
52- table ->create ();
53-
48+
49+ table_ptr = std::make_unique<HeapTable>(" rollback_stress" , *bpm_ptr , schema);
50+ table_ptr ->create ();
51+
5452 txn = nullptr ;
5553 }
5654
5755 void TearDown () override {
5856 if (txn != nullptr ) {
59- tm ->abort (txn);
57+ tm_ptr ->abort (txn);
6058 }
61- table .reset ();
62- tm .reset ();
63- lm .reset ();
64- bpm .reset ();
65- disk_manager .reset ();
66- catalog .reset ();
67-
59+ table_ptr .reset ();
60+ tm_ptr .reset ();
61+ lm_ptr .reset ();
62+ bpm_ptr .reset ();
63+ disk_manager_ptr .reset ();
64+ catalog_ptr .reset ();
65+
6866 static_cast <void >(std::remove (" ./test_data/rollback_stress.heap" ));
6967 }
7068
71- std::unique_ptr<Catalog> catalog;
72- std::unique_ptr<StorageManager> disk_manager;
73- std::unique_ptr<BufferPoolManager> bpm;
74- std::unique_ptr<LockManager> lm;
75- std::unique_ptr<TransactionManager> tm;
76- std::unique_ptr<HeapTable> table;
69+ // Pointers managed by the fixture
70+ std::unique_ptr<Catalog> catalog_ptr;
71+ std::unique_ptr<StorageManager> disk_manager_ptr;
72+ std::unique_ptr<BufferPoolManager> bpm_ptr;
73+ std::unique_ptr<LockManager> lm_ptr;
74+ std::unique_ptr<TransactionManager> tm_ptr;
75+ std::unique_ptr<HeapTable> table_ptr;
76+
77+ // Live transaction pointer for cleanup
7778 Transaction* txn;
7879};
7980
@@ -88,7 +89,7 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
8889 std::atomic<bool > stop{false };
8990
9091 Transaction writer_txn (100 );
91-
92+
9293 // Writers holds exclusive lock initially
9394 ASSERT_TRUE (lm.acquire_exclusive (&writer_txn, " RESOURCE" ));
9495
@@ -111,7 +112,7 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
111112
112113 // Release writer lock, readers should proceed
113114 lm.unlock (&writer_txn, " RESOURCE" );
114-
115+
115116 // Wait for all readers to get the lock
116117 for (int i = 0 ; i < 50 && shared_granted.load () < num_readers; ++i) {
117118 std::this_thread::sleep_for (std::chrono::milliseconds (50 ));
@@ -126,46 +127,44 @@ TEST(TransactionCoverageTestsStandalone, LockManagerConcurrency) {
126127
127128/* *
128129 * @brief Tests deep rollback functionality via the Undo Log.
130+ * Uses the TransactionCoverageTests fixture for automated cleanup.
129131 */
130132TEST_F (TransactionCoverageTests, DeepRollback) {
131- txn = tm->begin ();
133+ // Expose symbols to reuse existing test body logic
134+ TransactionManager& tm = *tm_ptr;
135+ HeapTable& table = *table_ptr;
132136
137+ txn = tm.begin ();
138+
133139 // 1. Insert some data
134- auto rid1 = table->insert (
135- executor::Tuple ({common::Value::make_int64 (1 ), common::Value::make_text (" A" )}),
136- txn->get_id ());
140+ auto rid1 = table.insert (executor::Tuple ({common::Value::make_int64 (1 ), common::Value::make_text (" A" )}), txn->get_id ());
137141 txn->add_undo_log (UndoLog::Type::INSERT, " rollback_stress" , rid1);
138-
139- auto rid2 = table->insert (
140- executor::Tuple ({common::Value::make_int64 (2 ), common::Value::make_text (" B" )}),
141- txn->get_id ());
142+
143+ auto rid2 = table.insert (executor::Tuple ({common::Value::make_int64 (2 ), common::Value::make_text (" B" )}), txn->get_id ());
142144 txn->add_undo_log (UndoLog::Type::INSERT, " rollback_stress" , rid2);
143145
144146 // 2. Update data
145- table->remove (rid1, txn->get_id ()); // Mark old version deleted
146- auto rid1_new = table->insert (
147- executor::Tuple ({common::Value::make_int64 (1 ), common::Value::make_text (" A_NEW" )}),
148- txn->get_id ());
147+ table.remove (rid1, txn->get_id ()); // Mark old version deleted
148+ auto rid1_new = table.insert (executor::Tuple ({common::Value::make_int64 (1 ), common::Value::make_text (" A_NEW" )}), txn->get_id ());
149149 txn->add_undo_log (UndoLog::Type::UPDATE, " rollback_stress" , rid1_new, rid1);
150150
151151 // 3. Delete data
152- table-> remove (rid2, txn->get_id ());
152+ table. remove (rid2, txn->get_id ());
153153 txn->add_undo_log (UndoLog::Type::DELETE, " rollback_stress" , rid2);
154154
155- EXPECT_EQ (table-> tuple_count (), 1U ); // rid1_new is active, rid1 and rid2 are logically deleted
155+ EXPECT_EQ (table. tuple_count (), 1U ); // rid1_new is active, rid1 and rid2 are logically deleted
156156
157157 // 4. Abort
158- tm-> abort (txn);
159- txn = nullptr ; // Marked as aborted and handled by TearDown if still set
158+ tm. abort (txn);
159+ txn = nullptr ; // Marked as aborted and handled by TearDown if still set
160160
161161 // 5. Verify restoration
162- EXPECT_EQ (table->tuple_count (),
163- 0U ); // Inserted rows should be physically removed or logically invisible
164-
162+ EXPECT_EQ (table.tuple_count (), 0U ); // Inserted rows should be physically removed or logically invisible
163+
165164 // The table should be empty because we aborted the inserts
166- auto iter = table-> scan ();
165+ auto iter = table. scan ();
167166 executor::Tuple t;
168167 EXPECT_FALSE (iter.next (t));
169168}
170169
171- } // namespace
170+ } // namespace
0 commit comments