@@ -64,17 +64,96 @@ TEST_F(SerializableTransactionTests, ReadOnlyTransactionTest) {
6464 auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance ();
6565 // Just scan the table
6666 {
67+ // same as 'ConcurrentReadOnlyTransactionTest'
68+ thread_pool.Initialize (0 , CONNECTION_THREAD_COUNT + 3 );
6769 concurrency::EpochManagerFactory::GetInstance ().Reset ();
70+ concurrency::EpochManagerFactory::GetInstance ().StartEpoch ();
71+ gc::GCManagerFactory::Configure ();
72+ gc::GCManagerFactory::GetInstance ().StartGC ();
73+
74+ // this consists of 2 txns. 1.catalog creation 2.test table creation
6875 storage::DataTable *table = TestingTransactionUtil::CreateTable ();
69-
70- TransactionScheduler scheduler (1 , table, &txn_manager, true );
76+
77+ // manually update snapshot epoch number, so later snapshot read must get a larger epoch than table creating txn
78+ // or it may read nothing
79+ // wait one epoch. so that global epoch is guaranteed to increase
80+ std::this_thread::sleep_for (std::chrono::milliseconds (EPOCH_LENGTH));
81+ concurrency::EpochManagerFactory::GetInstance ().GetExpiredEpochId ();
82+
83+ TransactionScheduler scheduler (1 , table, &txn_manager, {0 });
7184 scheduler.Txn (0 ).Scan (0 );
7285 scheduler.Txn (0 ).Commit ();
7386
7487 scheduler.Run ();
7588
76- // Snapshot read cannot read the recent insert
77- EXPECT_EQ (0 , scheduler.schedules [0 ].results .size ());
89+ // it should read all the 10 tuples
90+ EXPECT_EQ (10 , scheduler.schedules [0 ].results .size ());
91+
92+ gc::GCManagerFactory::GetInstance ().StopGC ();
93+ concurrency::EpochManagerFactory::GetInstance ().StopEpoch ();
94+ thread_pool.Shutdown ();
95+ // reset to default value, other test cases
96+ gc::GCManagerFactory::Configure (0 );
97+ }
98+ }
99+ }
100+
101+ // test r/w txn with a read-only txn runs concurrently
102+ TEST_F (SerializableTransactionTests, ConcurrentReadOnlyTransactionTest) {
103+ for (auto protocol_type : PROTOCOL_TYPES) {
104+ concurrency::TransactionManagerFactory::Configure (protocol_type, ISOLATION_LEVEL_TYPE);
105+ auto &txn_manager = concurrency::TransactionManagerFactory::GetInstance ();
106+ // Txn #0 | Txn #1
107+ // ----------------
108+ // BEGIN |
109+ // W(X) |
110+ // | BEGIN R/O
111+ // | R(X)
112+ // W(X) |
113+ // COMMIT |
114+ // | R(X)
115+ // | COMMIT
116+
117+ {
118+ // if gc manager is active, finishing a txn will make the txn be removed from epoch list as well.
119+ // epoch manager needs this behavior to find the largest expired txn id.
120+ // that id is used to determine whether snapshot epoch falls behind and needs update.
121+ // gc and epoch manager both depend on thread pool
122+ thread_pool.Initialize (0 , CONNECTION_THREAD_COUNT + 3 );
123+ concurrency::EpochManagerFactory::GetInstance ().Reset ();
124+ concurrency::EpochManagerFactory::GetInstance ().StartEpoch ();
125+ gc::GCManagerFactory::Configure ();
126+ gc::GCManagerFactory::GetInstance ().StartGC ();
127+
128+ // this contains 2 txns: 1.create catalog table 2.create test table
129+ storage::DataTable *table = TestingTransactionUtil::CreateTable ();
130+
131+ // force snapshot epoch to be updated. it should be larger than table creation txn's epoch
132+ std::this_thread::sleep_for (std::chrono::milliseconds (EPOCH_LENGTH));
133+ concurrency::EpochManagerFactory::GetInstance ().GetExpiredEpochId ();
134+
135+ TransactionScheduler scheduler (2 , table, &txn_manager, {1 });
136+ scheduler.Txn (0 ).Update (0 , 1 );
137+ scheduler.Txn (1 ).Read (0 );
138+ scheduler.Txn (0 ).Update (0 , 2 );
139+ scheduler.Txn (0 ).Commit ();
140+ scheduler.Txn (1 ).Read (0 );
141+ scheduler.Txn (1 ).Commit ();
142+
143+ scheduler.Run ();
144+
145+ EXPECT_EQ (ResultType::SUCCESS, scheduler.schedules [0 ].txn_result );
146+ EXPECT_EQ (ResultType::SUCCESS, scheduler.schedules [1 ].txn_result );
147+
148+ // read only txn should read the same snapshot that exists after table creation and before update txn commits
149+ EXPECT_EQ (0 , scheduler.schedules [1 ].results [0 ]);
150+ EXPECT_EQ (0 , scheduler.schedules [1 ].results [1 ]);
151+
152+ gc::GCManagerFactory::GetInstance ().StopGC ();
153+ concurrency::EpochManagerFactory::GetInstance ().StopEpoch ();
154+ thread_pool.Shutdown ();
155+ // reset it to default value for test cases
156+ gc::GCManagerFactory::Configure (0 );
78157 }
79158 }
80159}
0 commit comments