@@ -19,7 +19,9 @@ struct TestTwoPhaseCommitter
1919 TwoPhaseCommitterPtr committer;
2020
2121public:
22- TestTwoPhaseCommitter (Txn * txn) : committer(std::make_shared<TwoPhaseCommitter>(txn)) {}
22+ TestTwoPhaseCommitter (Txn * txn)
23+ : committer(std::make_shared<TwoPhaseCommitter>(txn))
24+ {}
2325
2426 void prewriteKeys (Backoffer & bo, const std::vector<std::string> & keys) { committer->prewriteKeys (bo, keys); }
2527
@@ -28,6 +30,12 @@ struct TestTwoPhaseCommitter
2830 std::vector<std::string> keys () { return committer->keys ; }
2931
3032 void setCommitTS (int64_t commit_ts) { committer->commit_ts = commit_ts; }
33+
34+ uint64_t startTS () { return committer->start_ts ; }
35+
36+ uint64_t txnSize () { return committer->txn_size ; }
37+
38+ int lockTTL () { return committer->lock_ttl ; }
3139};
3240
3341} // namespace kv
@@ -71,7 +79,6 @@ class TestWith2PCRealTiKV : public testing::Test
7179
7280TEST_F (TestWith2PCRealTiKV, testCommitRollback)
7381{
74-
7582 // Commit.
7683 {
7784 Txn txn (test_cluster.get ());
@@ -97,7 +104,7 @@ TEST_F(TestWith2PCRealTiKV, testCommitRollback)
97104 txn2.set (" c" , " c2" );
98105 txn2.commit ();
99106
100- txn1.commit ();
107+ ASSERT_THROW ( txn1.commit (), Exception );
101108
102109 Snapshot snap (test_cluster.get ());
103110 ASSERT_EQ (snap.Get (" a" ), " a" );
@@ -106,9 +113,104 @@ TEST_F(TestWith2PCRealTiKV, testCommitRollback)
106113 }
107114}
108115
109- TEST_F (TestWith2PCRealTiKV, commitAfterReadByOtherTxn)
116+ TEST_F (TestWith2PCRealTiKV, testEmptyTxnCommit)
117+ {
118+ Txn txn (test_cluster.get ());
119+ ASSERT_NO_THROW (txn.commit ());
120+ }
121+
122+ TEST_F (TestWith2PCRealTiKV, testCommitTsExpiredRetries)
123+ {
124+ const std::string prefix = " clientc_commit_ts_expired_" + std::to_string (test_cluster->pd_client ->getTS ()) + " _" ;
125+ const std::string key = prefix + " k" ;
126+
127+ {
128+ Txn txn (test_cluster.get ());
129+ txn.set (key, " v0" );
130+ txn.commit ();
131+ }
132+
133+ Txn txn (test_cluster.get ());
134+ txn.set (key, " v1" );
135+ TestTwoPhaseCommitter committer{&txn};
136+ Backoffer prewrite_bo (prewriteMaxBackoff);
137+ committer.prewriteKeys (prewrite_bo, committer.keys ());
138+
139+ // A reader after prewrite pushes the lock's min_commit_ts. Commit with a
140+ // stale commit_ts should be rejected by TiKV with CommitTsExpired, and the
141+ // client should retry the same primary commit with a fresh commit_ts.
142+ Txn reader (test_cluster.get ());
143+ auto result = reader.get (key);
144+ ASSERT_EQ (result.second , true );
145+ ASSERT_EQ (result.first , " v0" );
146+
147+ committer.setCommitTS (committer.startTS () + 1 );
148+ Backoffer commit_bo (commitMaxBackoff);
149+ ASSERT_NO_THROW (committer.commitKeys (commit_bo, committer.keys ()));
150+
151+ Snapshot snap (test_cluster.get ());
152+ ASSERT_EQ (snap.Get (key), " v1" );
153+ }
154+
155+ TEST_F (TestWith2PCRealTiKV, testFailedPrewriteCleansWrittenLocks)
156+ {
157+ const std::string prefix = " clientc_cleanup_" + std::to_string (test_cluster->pd_client ->getTS ()) + " _" ;
158+ const std::string key_a = prefix + " a" ;
159+ const std::string key_b = prefix + " b" ;
160+ const std::string key_c = prefix + " c" ;
161+
162+ {
163+ Txn txn (test_cluster.get ());
164+ txn.set (key_a, " a0" );
165+ txn.set (key_b, " b0" );
166+ txn.set (key_c, " c0" );
167+ txn.commit ();
168+ }
169+
170+ test_cluster->splitRegion (key_c);
171+
172+ Txn older_writer (test_cluster.get ());
173+ older_writer.set (key_a, " a1" );
174+ older_writer.set (key_b, " b1" );
175+ older_writer.set (key_c, " c1" );
176+
177+ {
178+ Txn newer_writer (test_cluster.get ());
179+ newer_writer.set (key_c, " c2" );
180+ newer_writer.commit ();
181+ }
182+
183+ ASSERT_THROW (older_writer.commit (), Exception);
184+
185+ Backoffer mvcc_bo (GetMaxBackoff);
186+ ASSERT_FALSE (Snapshot (test_cluster.get ()).mvccGet (mvcc_bo, key_a).has_lock ());
187+ ASSERT_FALSE (Snapshot (test_cluster.get ()).mvccGet (mvcc_bo, key_b).has_lock ());
188+
189+ {
190+ Txn next_writer (test_cluster.get ());
191+ next_writer.set (key_a, " a2" );
192+ next_writer.set (key_b, " b2" );
193+ ASSERT_NO_THROW (next_writer.commit ());
194+ }
195+
196+ Snapshot snap (test_cluster.get ());
197+ ASSERT_EQ (snap.Get (key_a), " a2" );
198+ ASSERT_EQ (snap.Get (key_b), " b2" );
199+ ASSERT_EQ (snap.Get (key_c), " c2" );
200+ }
201+
202+ TEST_F (TestWith2PCRealTiKV, testLargeTxnTTLUsesBytes)
110203{
204+ Txn txn (test_cluster.get ());
205+ txn.set (" clientc_large_ttl_key" , std::string (33 * 1024 * 1024 , ' x' ));
206+ TestTwoPhaseCommitter committer{&txn};
207+
208+ ASSERT_GT (committer.txnSize (), 32ULL * 1024 * 1024 );
209+ ASSERT_EQ (committer.lockTTL (), 20000 );
210+ }
111211
212+ TEST_F (TestWith2PCRealTiKV, commitAfterReadByOtherTxn)
213+ {
112214 // Commit.
113215 {
114216 Txn txn (test_cluster.get ());
@@ -337,4 +439,4 @@ TEST_F(TestWith2PCRealTiKV, testScanWithLargeTxn)
337439 }
338440}
339441
340- } // namespace
442+ } // namespace pingcap::tests
0 commit comments