write_committed_transaction_ts_test.cc 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #include "rocksdb/comparator.h"
  6. #include "rocksdb/db.h"
  7. #include "rocksdb/options.h"
  8. #include "rocksdb/utilities/transaction_db.h"
  9. #include "test_util/testutil.h"
  10. #include "utilities/merge_operators.h"
  11. #include "utilities/transactions/transaction_test.h"
  12. namespace ROCKSDB_NAMESPACE {
  13. INSTANTIATE_TEST_CASE_P(
  14. DBAsBaseDBAndStackableDB, WriteCommittedTxnWithTsTest,
  15. ::testing::Combine(/*use_stackable_db=*/::testing::Bool(),
  16. /*two_write_queue=*/::testing::Bool(),
  17. /*enable_indexing=*/::testing::Bool(),
  18. /*use_per_key_point_lock_mgr=*/::testing::Bool(),
  19. /*deadlock_timeout_us=*/::testing::Values(0, 1000)));
  20. TEST_P(WriteCommittedTxnWithTsTest, SanityChecks) {
  21. ASSERT_OK(ReOpenNoDelete());
  22. ColumnFamilyOptions cf_opts;
  23. cf_opts.comparator = test::BytewiseComparatorWithU64TsWrapper();
  24. const std::string test_cf_name = "test_cf";
  25. ColumnFamilyHandle* cfh = nullptr;
  26. assert(db);
  27. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  28. delete cfh;
  29. cfh = nullptr;
  30. std::vector<ColumnFamilyDescriptor> cf_descs;
  31. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  32. cf_descs.emplace_back(test_cf_name, cf_opts);
  33. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  34. std::unique_ptr<Transaction> txn(
  35. NewTxn(WriteOptions(), TransactionOptions()));
  36. assert(txn);
  37. ASSERT_OK(txn->Put(handles_[1], "foo", "value"));
  38. ASSERT_TRUE(txn->Commit().IsInvalidArgument());
  39. auto* pessimistic_txn =
  40. static_cast_with_check<PessimisticTransaction>(txn.get());
  41. ASSERT_TRUE(
  42. pessimistic_txn->CommitBatch(/*batch=*/nullptr).IsInvalidArgument());
  43. {
  44. WriteBatchWithIndex* wbwi = txn->GetWriteBatch();
  45. assert(wbwi);
  46. WriteBatch* wb = wbwi->GetWriteBatch();
  47. assert(wb);
  48. // Write a key to the batch for nonexisting cf.
  49. ASSERT_OK(WriteBatchInternal::Put(wb, /*column_family_id=*/10, /*key=*/"",
  50. /*value=*/""));
  51. }
  52. ASSERT_OK(txn->SetCommitTimestamp(20));
  53. ASSERT_TRUE(txn->Commit().IsInvalidArgument());
  54. txn.reset();
  55. std::unique_ptr<Transaction> txn1(
  56. NewTxn(WriteOptions(), TransactionOptions()));
  57. assert(txn1);
  58. ASSERT_OK(txn1->SetName("txn1"));
  59. ASSERT_OK(txn1->Put(handles_[1], "foo", "value"));
  60. {
  61. WriteBatchWithIndex* wbwi = txn1->GetWriteBatch();
  62. assert(wbwi);
  63. WriteBatch* wb = wbwi->GetWriteBatch();
  64. assert(wb);
  65. // Write a key to the batch for non-existing cf.
  66. ASSERT_OK(WriteBatchInternal::Put(wb, /*column_family_id=*/10, /*key=*/"",
  67. /*value=*/""));
  68. }
  69. ASSERT_OK(txn1->Prepare());
  70. ASSERT_OK(txn1->SetCommitTimestamp(21));
  71. ASSERT_TRUE(txn1->Commit().IsInvalidArgument());
  72. txn1.reset();
  73. }
  74. void CheckKeyValueTsWithIterator(
  75. Iterator* iter,
  76. std::vector<std::tuple<std::string, std::string, std::string>> entries) {
  77. size_t num_entries = entries.size();
  78. // test forward iteration
  79. for (size_t i = 0; i < num_entries; i++) {
  80. auto [key, value, timestamp] = entries[i];
  81. if (i == 0) {
  82. iter->Seek(key);
  83. } else {
  84. iter->Next();
  85. }
  86. ASSERT_TRUE(iter->Valid());
  87. ASSERT_EQ(iter->key(), key);
  88. ASSERT_EQ(iter->value(), value);
  89. ASSERT_EQ(iter->timestamp(), timestamp);
  90. }
  91. // test backward iteration
  92. for (size_t i = 0; i < num_entries; i++) {
  93. auto [key, value, timestamp] = entries[num_entries - 1 - i];
  94. if (i == 0) {
  95. iter->SeekForPrev(key);
  96. } else {
  97. iter->Prev();
  98. }
  99. ASSERT_TRUE(iter->Valid());
  100. ASSERT_EQ(iter->key(), key);
  101. ASSERT_EQ(iter->value(), value);
  102. ASSERT_EQ(iter->timestamp(), timestamp);
  103. }
  104. }
  105. // This is an incorrect usage of this API, supporting this should be removed
  106. // after MyRocks remove this pattern in a refactor.
  107. TEST_P(WriteCommittedTxnWithTsTest, WritesBypassTransactionAPIs) {
  108. options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  109. ASSERT_OK(ReOpen());
  110. const std::string test_cf_name = "test_cf";
  111. ColumnFamilyOptions cf_options;
  112. ColumnFamilyHandle* cfh = nullptr;
  113. assert(db);
  114. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  115. delete cfh;
  116. cfh = nullptr;
  117. std::vector<ColumnFamilyDescriptor> cf_descs;
  118. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  119. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  120. options.avoid_flush_during_shutdown = true;
  121. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  122. // Write in each transaction a mixture of column families that enable
  123. // timestamp and disable timestamps.
  124. TransactionOptions txn_opts;
  125. txn_opts.write_batch_track_timestamp_size = true;
  126. std::unique_ptr<Transaction> txn0(NewTxn(WriteOptions(), txn_opts));
  127. assert(txn0);
  128. ASSERT_OK(txn0->Put(handles_[0], "key1", "key1_val"));
  129. // Timestamp size info for writes like this can only be correctly tracked if
  130. // TransactionOptions.write_batch_track_timestamp_size is true.
  131. ASSERT_OK(txn0->GetWriteBatch()->GetWriteBatch()->Put(handles_[1], "foo",
  132. "foo_val"));
  133. ASSERT_OK(txn0->SetName("txn0"));
  134. ASSERT_OK(txn0->SetCommitTimestamp(2));
  135. ASSERT_OK(txn0->Prepare());
  136. ASSERT_OK(txn0->Commit());
  137. txn0.reset();
  138. // For keys written from transactions that disable
  139. // `write_batch_track_timestamp_size`
  140. // The keys has incorrect behavior like:
  141. // *Cannot be found after commit: because transaction's UpdateTimestamp do not
  142. // have correct timestamp size when this write bypass transaction write APIs.
  143. // *Can be found again after DB restart recovers the write from WAL log:
  144. // because recovered transaction's UpdateTimestamp get correct timestamp size
  145. // info directly from VersionSet.
  146. // If there is a flush that persisted this transaction into sst files after
  147. // it's committed, the key will be forever corrupted.
  148. std::unique_ptr<Transaction> txn1(
  149. NewTxn(WriteOptions(), TransactionOptions()));
  150. assert(txn1);
  151. ASSERT_OK(txn1->Put(handles_[0], "key2", "key2_val"));
  152. // Writing a key with more than 8 bytes so that we can manifest the error as
  153. // a NotFound error instead of an issue during `WriteBatch::UpdateTimestamp`.
  154. ASSERT_OK(txn1->GetWriteBatch()->GetWriteBatch()->Put(
  155. handles_[1], "foobarbaz", "baz_val"));
  156. ASSERT_OK(txn1->SetName("txn1"));
  157. ASSERT_OK(txn1->SetCommitTimestamp(2));
  158. ASSERT_OK(txn1->Prepare());
  159. ASSERT_OK(txn1->Commit());
  160. txn1.reset();
  161. ASSERT_OK(db->Flush(FlushOptions(), handles_[1]));
  162. std::unique_ptr<Transaction> txn2(
  163. NewTxn(WriteOptions(), TransactionOptions()));
  164. assert(txn2);
  165. ASSERT_OK(txn2->Put(handles_[0], "key3", "key3_val"));
  166. ASSERT_OK(txn2->GetWriteBatch()->GetWriteBatch()->Put(
  167. handles_[1], "bazbazbaz", "bazbazbaz_val"));
  168. ASSERT_OK(txn2->SetCommitTimestamp(2));
  169. ASSERT_OK(txn2->SetName("txn2"));
  170. ASSERT_OK(txn2->Prepare());
  171. ASSERT_OK(txn2->Commit());
  172. txn2.reset();
  173. std::unique_ptr<Transaction> txn3(
  174. NewTxn(WriteOptions(), TransactionOptions()));
  175. assert(txn3);
  176. std::string value;
  177. ReadOptions ropts;
  178. std::string read_ts;
  179. Slice timestamp = EncodeU64Ts(2, &read_ts);
  180. ropts.timestamp = &timestamp;
  181. ASSERT_OK(txn3->Get(ropts, handles_[0], "key1", &value));
  182. ASSERT_EQ("key1_val", value);
  183. ASSERT_OK(txn3->Get(ropts, handles_[0], "key2", &value));
  184. ASSERT_EQ("key2_val", value);
  185. ASSERT_OK(txn3->Get(ropts, handles_[0], "key3", &value));
  186. ASSERT_EQ("key3_val", value);
  187. txn3.reset();
  188. std::unique_ptr<Transaction> txn4(
  189. NewTxn(WriteOptions(), TransactionOptions()));
  190. assert(txn4);
  191. ASSERT_OK(txn4->Get(ReadOptions(), handles_[1], "foo", &value));
  192. ASSERT_EQ("foo_val", value);
  193. // Incorrect behavior: committed keys cannot be found
  194. ASSERT_TRUE(
  195. txn4->Get(ReadOptions(), handles_[1], "foobarbaz", &value).IsNotFound());
  196. ASSERT_TRUE(
  197. txn4->Get(ReadOptions(), handles_[1], "bazbazbaz", &value).IsNotFound());
  198. txn4.reset();
  199. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  200. std::unique_ptr<Transaction> txn5(
  201. NewTxn(WriteOptions(), TransactionOptions()));
  202. assert(txn5);
  203. ASSERT_OK(txn5->Get(ReadOptions(), handles_[1], "foo", &value));
  204. ASSERT_EQ("foo_val", value);
  205. // Incorrect behavior:
  206. // *unflushed key can be found after reopen replays the entries from WAL
  207. // (this is not suggesting using flushing as a workaround but to show a
  208. // possible misleading behavior)
  209. // *flushed key is forever corrupted.
  210. ASSERT_TRUE(
  211. txn5->Get(ReadOptions(), handles_[1], "foobarbaz", &value).IsNotFound());
  212. ASSERT_OK(txn5->Get(ReadOptions(), handles_[1], "bazbazbaz", &value));
  213. ASSERT_EQ("bazbazbaz_val", value);
  214. txn5.reset();
  215. }
  216. TEST_P(WriteCommittedTxnWithTsTest, ReOpenWithTimestamp) {
  217. options.merge_operator = MergeOperators::CreateUInt64AddOperator();
  218. ASSERT_OK(ReOpenNoDelete());
  219. ColumnFamilyOptions cf_opts;
  220. cf_opts.comparator = test::BytewiseComparatorWithU64TsWrapper();
  221. const std::string test_cf_name = "test_cf";
  222. ColumnFamilyHandle* cfh = nullptr;
  223. assert(db);
  224. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  225. delete cfh;
  226. cfh = nullptr;
  227. std::vector<ColumnFamilyDescriptor> cf_descs;
  228. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  229. cf_descs.emplace_back(test_cf_name, cf_opts);
  230. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  231. std::unique_ptr<Transaction> txn0(
  232. NewTxn(WriteOptions(), TransactionOptions()));
  233. assert(txn0);
  234. ASSERT_OK(txn0->Put(handles_[1], "foo", "value"));
  235. ASSERT_OK(txn0->SetName("txn0"));
  236. ASSERT_OK(txn0->Prepare());
  237. ASSERT_TRUE(txn0->Commit().IsInvalidArgument());
  238. txn0.reset();
  239. std::unique_ptr<Transaction> txn1(
  240. NewTxn(WriteOptions(), TransactionOptions()));
  241. assert(txn1);
  242. std::string write_ts;
  243. uint64_t write_ts_int = 23;
  244. PutFixed64(&write_ts, write_ts_int);
  245. ReadOptions read_opts;
  246. std::string read_ts;
  247. PutFixed64(&read_ts, write_ts_int + 1);
  248. Slice read_ts_slice = read_ts;
  249. read_opts.timestamp = &read_ts_slice;
  250. ASSERT_OK(txn1->Put(handles_[1], "bar", "value0"));
  251. ASSERT_OK(txn1->Put(handles_[1], "foo", "value1"));
  252. // (key, value, ts) pairs to check.
  253. std::vector<std::tuple<std::string, std::string, std::string>>
  254. entries_to_check;
  255. entries_to_check.emplace_back("bar", "value0", "");
  256. entries_to_check.emplace_back("foo", "value1", "");
  257. {
  258. std::string buf;
  259. PutFixed64(&buf, 23);
  260. ASSERT_OK(txn1->Put("id", buf));
  261. ASSERT_OK(txn1->Merge("id", buf));
  262. }
  263. // Check (key, value, ts) with overwrites in txn before `SetCommitTimestamp`.
  264. if (std::get<2>(GetParam())) { // enable_indexing = true
  265. std::unique_ptr<Iterator> iter(txn1->GetIterator(read_opts, handles_[1]));
  266. CheckKeyValueTsWithIterator(iter.get(), entries_to_check);
  267. }
  268. ASSERT_OK(txn1->SetName("txn1"));
  269. ASSERT_OK(txn1->Prepare());
  270. ASSERT_OK(txn1->SetCommitTimestamp(write_ts_int));
  271. // Check (key, value, ts) with overwrites in txn after `SetCommitTimestamp`.
  272. if (std::get<2>(GetParam())) { // enable_indexing = true
  273. std::unique_ptr<Iterator> iter(txn1->GetIterator(read_opts, handles_[1]));
  274. CheckKeyValueTsWithIterator(iter.get(), entries_to_check);
  275. }
  276. ASSERT_OK(txn1->Commit());
  277. entries_to_check.clear();
  278. entries_to_check.emplace_back("bar", "value0", write_ts);
  279. entries_to_check.emplace_back("foo", "value1", write_ts);
  280. // Check (key, value, ts) pairs with overwrites in txn after `Commit`.
  281. {
  282. std::unique_ptr<Iterator> iter(txn1->GetIterator(read_opts, handles_[1]));
  283. CheckKeyValueTsWithIterator(iter.get(), entries_to_check);
  284. }
  285. txn1.reset();
  286. {
  287. std::string value;
  288. const Status s =
  289. GetFromDb(ReadOptions(), handles_[1], "foo", /*ts=*/23, &value);
  290. ASSERT_OK(s);
  291. ASSERT_EQ("value1", value);
  292. }
  293. {
  294. std::string value;
  295. const Status s = db->Get(ReadOptions(), handles_[0], "id", &value);
  296. ASSERT_OK(s);
  297. uint64_t ival = 0;
  298. Slice value_slc = value;
  299. bool result = GetFixed64(&value_slc, &ival);
  300. assert(result);
  301. ASSERT_EQ(46, ival);
  302. }
  303. // Check (key, value, ts) pairs without overwrites in txn.
  304. {
  305. std::unique_ptr<Transaction> txn2(
  306. NewTxn(WriteOptions(), TransactionOptions()));
  307. std::unique_ptr<Iterator> iter(txn2->GetIterator(read_opts, handles_[1]));
  308. CheckKeyValueTsWithIterator(iter.get(), entries_to_check);
  309. }
  310. }
  311. TEST_P(WriteCommittedTxnWithTsTest, RecoverFromWal) {
  312. ASSERT_OK(ReOpenNoDelete());
  313. ColumnFamilyOptions cf_opts;
  314. cf_opts.comparator = test::BytewiseComparatorWithU64TsWrapper();
  315. const std::string test_cf_name = "test_cf";
  316. ColumnFamilyHandle* cfh = nullptr;
  317. assert(db);
  318. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  319. delete cfh;
  320. cfh = nullptr;
  321. std::vector<ColumnFamilyDescriptor> cf_descs;
  322. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  323. cf_descs.emplace_back(test_cf_name, cf_opts);
  324. options.avoid_flush_during_shutdown = true;
  325. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  326. std::unique_ptr<Transaction> txn0(
  327. NewTxn(WriteOptions(), TransactionOptions()));
  328. assert(txn0);
  329. ASSERT_OK(txn0->Put(handles_[1], "foo", "foo_value"));
  330. ASSERT_OK(txn0->SetName("txn0"));
  331. ASSERT_OK(txn0->Prepare());
  332. WriteOptions write_opts;
  333. write_opts.sync = true;
  334. std::unique_ptr<Transaction> txn1(NewTxn(write_opts, TransactionOptions()));
  335. assert(txn1);
  336. ASSERT_OK(txn1->Put("bar", "bar_value_1"));
  337. ASSERT_OK(txn1->Put(handles_[1], "bar", "bar_value_1"));
  338. ASSERT_OK(txn1->SetName("txn1"));
  339. ASSERT_OK(txn1->Prepare());
  340. ASSERT_OK(txn1->SetCommitTimestamp(/*ts=*/23));
  341. ASSERT_OK(txn1->Commit());
  342. txn1.reset();
  343. std::unique_ptr<Transaction> txn2(NewTxn(write_opts, TransactionOptions()));
  344. assert(txn2);
  345. ASSERT_OK(txn2->Put("key1", "value_3"));
  346. ASSERT_OK(txn2->Put(handles_[1], "key1", "value_3"));
  347. ASSERT_OK(txn2->SetCommitTimestamp(/*ts=*/24));
  348. ASSERT_OK(txn2->Commit());
  349. txn2.reset();
  350. txn0.reset();
  351. std::unique_ptr<Transaction> txn3(
  352. NewTxn(WriteOptions(), TransactionOptions()));
  353. assert(txn3);
  354. ASSERT_OK(txn3->Put(handles_[1], "baz", "baz_value"));
  355. ASSERT_OK(txn3->SetName("txn3"));
  356. ASSERT_OK(txn3->Prepare());
  357. txn3.reset();
  358. std::unique_ptr<Transaction> txn4(
  359. NewTxn(WriteOptions(), TransactionOptions()));
  360. assert(txn4);
  361. ASSERT_OK(txn4->SetName("no_op_txn"));
  362. txn4.reset();
  363. std::unique_ptr<Transaction> rolled_back_txn(
  364. NewTxn(write_opts, TransactionOptions()));
  365. ASSERT_NE(nullptr, rolled_back_txn);
  366. ASSERT_OK(rolled_back_txn->Put("non_exist0", "donotcare"));
  367. ASSERT_OK(rolled_back_txn->Put(handles_[1], "non_exist1", "donotcare"));
  368. ASSERT_OK(rolled_back_txn->SetName("rolled_back_txn"));
  369. ASSERT_OK(rolled_back_txn->Rollback());
  370. rolled_back_txn.reset();
  371. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  372. {
  373. Transaction* recovered_txn0 = db->GetTransactionByName("txn0");
  374. ASSERT_OK(recovered_txn0->SetCommitTimestamp(23));
  375. ASSERT_OK(recovered_txn0->Commit());
  376. delete recovered_txn0;
  377. std::string value;
  378. Status s = GetFromDb(ReadOptions(), handles_[1], "foo", /*ts=*/23, &value);
  379. ASSERT_OK(s);
  380. ASSERT_EQ("foo_value", value);
  381. s = db->Get(ReadOptions(), handles_[0], "bar", &value);
  382. ASSERT_OK(s);
  383. ASSERT_EQ("bar_value_1", value);
  384. value.clear();
  385. s = GetFromDb(ReadOptions(), handles_[1], "bar", /*ts=*/23, &value);
  386. ASSERT_OK(s);
  387. ASSERT_EQ("bar_value_1", value);
  388. s = GetFromDb(ReadOptions(), handles_[1], "key1", /*ts=*/23, &value);
  389. ASSERT_TRUE(s.IsNotFound());
  390. s = db->Get(ReadOptions(), handles_[0], "key1", &value);
  391. ASSERT_OK(s);
  392. ASSERT_EQ("value_3", value);
  393. s = GetFromDb(ReadOptions(), handles_[1], "key1", /*ts=*/24, &value);
  394. ASSERT_OK(s);
  395. ASSERT_EQ("value_3", value);
  396. s = GetFromDb(ReadOptions(), handles_[1], "baz", /*ts=*/24, &value);
  397. ASSERT_TRUE(s.IsNotFound());
  398. Transaction* no_op_txn = db->GetTransactionByName("no_op_txn");
  399. ASSERT_EQ(nullptr, no_op_txn);
  400. s = db->Get(ReadOptions(), handles_[0], "non_exist0", &value);
  401. ASSERT_TRUE(s.IsNotFound());
  402. s = GetFromDb(ReadOptions(), handles_[1], "non_exist1", /*ts=*/24, &value);
  403. ASSERT_TRUE(s.IsNotFound());
  404. }
  405. }
  406. TEST_P(WriteCommittedTxnWithTsTest, EnabledUDTDisabledRecoverFromWal) {
  407. // This feature is not compatible with UDT in memtable only.
  408. options.allow_concurrent_memtable_write = false;
  409. ASSERT_OK(ReOpenNoDelete());
  410. ColumnFamilyOptions cf_opts;
  411. cf_opts.comparator = test::BytewiseComparatorWithU64TsWrapper();
  412. cf_opts.persist_user_defined_timestamps = false;
  413. const std::string test_cf_name = "test_cf";
  414. ColumnFamilyHandle* cfh = nullptr;
  415. assert(db);
  416. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  417. delete cfh;
  418. cfh = nullptr;
  419. std::vector<ColumnFamilyDescriptor> cf_descs;
  420. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  421. cf_descs.emplace_back(test_cf_name, cf_opts);
  422. options.avoid_flush_during_shutdown = true;
  423. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  424. std::unique_ptr<Transaction> no_op_txn(
  425. NewTxn(WriteOptions(), TransactionOptions()));
  426. ASSERT_NE(nullptr, no_op_txn);
  427. ASSERT_OK(no_op_txn->SetName("no_op_txn"));
  428. no_op_txn.reset();
  429. std::unique_ptr<Transaction> prepared_but_uncommitted_txn(
  430. NewTxn(WriteOptions(), TransactionOptions()));
  431. ASSERT_NE(nullptr, prepared_but_uncommitted_txn);
  432. ASSERT_OK(prepared_but_uncommitted_txn->Put("foo0", "foo_value_0"));
  433. ASSERT_OK(
  434. prepared_but_uncommitted_txn->Put(handles_[1], "foo1", "foo_value_1"));
  435. ASSERT_OK(
  436. prepared_but_uncommitted_txn->SetName("prepared_but_uncommitted_txn"));
  437. ASSERT_OK(prepared_but_uncommitted_txn->Prepare());
  438. prepared_but_uncommitted_txn.reset();
  439. WriteOptions write_opts;
  440. write_opts.sync = true;
  441. std::unique_ptr<Transaction> committed_txn(
  442. NewTxn(write_opts, TransactionOptions()));
  443. ASSERT_NE(nullptr, committed_txn);
  444. ASSERT_OK(committed_txn->Put("bar0", "bar_value_0"));
  445. ASSERT_OK(committed_txn->Put(handles_[1], "bar1", "bar_value_1"));
  446. ASSERT_OK(committed_txn->SetName("committed_txn"));
  447. ASSERT_OK(committed_txn->Prepare());
  448. ASSERT_OK(committed_txn->SetCommitTimestamp(/*ts=*/23));
  449. ASSERT_OK(committed_txn->Commit());
  450. committed_txn.reset();
  451. std::unique_ptr<Transaction> committed_without_prepare_txn(
  452. NewTxn(write_opts, TransactionOptions()));
  453. ASSERT_NE(nullptr, committed_without_prepare_txn);
  454. ASSERT_OK(committed_without_prepare_txn->Put("baz0", "baz_value_0"));
  455. ASSERT_OK(
  456. committed_without_prepare_txn->Put(handles_[1], "baz1", "baz_value_1"));
  457. ASSERT_OK(
  458. committed_without_prepare_txn->SetName("committed_without_prepare_txn"));
  459. ASSERT_OK(committed_without_prepare_txn->SetCommitTimestamp(/*ts=*/24));
  460. ASSERT_OK(committed_without_prepare_txn->Commit());
  461. committed_without_prepare_txn.reset();
  462. std::unique_ptr<Transaction> rolled_back_txn(
  463. NewTxn(write_opts, TransactionOptions()));
  464. assert(rolled_back_txn);
  465. ASSERT_OK(rolled_back_txn->Put("non_exist0", "donotcare"));
  466. ASSERT_OK(rolled_back_txn->Put(handles_[1], "non_exist1", "donotcare"));
  467. ASSERT_OK(rolled_back_txn->SetName("rolled_back_txn"));
  468. ASSERT_OK(rolled_back_txn->Rollback());
  469. rolled_back_txn.reset();
  470. // Reopen and disable UDT to replay WAL entries.
  471. cf_descs[1].options.comparator = BytewiseComparator();
  472. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  473. {
  474. Transaction* recovered_txn0 = db->GetTransactionByName("no_op_txn");
  475. ASSERT_EQ(nullptr, recovered_txn0);
  476. Transaction* recovered_txn1 =
  477. db->GetTransactionByName("prepared_but_uncommitted_txn");
  478. ASSERT_NE(nullptr, recovered_txn1);
  479. std::string value;
  480. ASSERT_OK(recovered_txn1->Commit());
  481. Status s = db->Get(ReadOptions(), handles_[0], "foo0", &value);
  482. ASSERT_OK(s);
  483. ASSERT_EQ("foo_value_0", value);
  484. s = db->Get(ReadOptions(), handles_[1], "foo1", &value);
  485. ASSERT_OK(s);
  486. ASSERT_EQ("foo_value_1", value);
  487. delete recovered_txn1;
  488. ASSERT_EQ(nullptr, db->GetTransactionByName("committed_txn"));
  489. s = db->Get(ReadOptions(), handles_[0], "bar0", &value);
  490. ASSERT_OK(s);
  491. ASSERT_EQ("bar_value_0", value);
  492. s = db->Get(ReadOptions(), handles_[1], "bar1", &value);
  493. ASSERT_OK(s);
  494. ASSERT_EQ("bar_value_1", value);
  495. ASSERT_EQ(nullptr,
  496. db->GetTransactionByName("committed_without_prepare_txn"));
  497. s = db->Get(ReadOptions(), handles_[0], "baz0", &value);
  498. ASSERT_OK(s);
  499. ASSERT_EQ("baz_value_0", value);
  500. s = db->Get(ReadOptions(), handles_[1], "baz1", &value);
  501. ASSERT_OK(s);
  502. ASSERT_EQ("baz_value_1", value);
  503. ASSERT_EQ(nullptr, db->GetTransactionByName("rolled_back_txn"));
  504. s = db->Get(ReadOptions(), handles_[0], "non_exist0", &value);
  505. ASSERT_TRUE(s.IsNotFound());
  506. s = db->Get(ReadOptions(), handles_[1], "non_exist1", &value);
  507. ASSERT_TRUE(s.IsNotFound());
  508. }
  509. }
  510. TEST_P(WriteCommittedTxnWithTsTest, UDTNewlyEnabledRecoverFromWal) {
  511. ASSERT_OK(ReOpenNoDelete());
  512. ColumnFamilyOptions cf_opts;
  513. const std::string test_cf_name = "test_cf";
  514. ColumnFamilyHandle* cfh = nullptr;
  515. assert(db);
  516. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  517. delete cfh;
  518. cfh = nullptr;
  519. std::vector<ColumnFamilyDescriptor> cf_descs;
  520. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  521. cf_descs.emplace_back(test_cf_name, cf_opts);
  522. options.avoid_flush_during_shutdown = true;
  523. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  524. std::unique_ptr<Transaction> no_op_txn(
  525. NewTxn(WriteOptions(), TransactionOptions()));
  526. ASSERT_NE(nullptr, no_op_txn);
  527. ASSERT_OK(no_op_txn->SetName("no_op_txn"));
  528. no_op_txn.reset();
  529. std::unique_ptr<Transaction> prepared_but_uncommitted_txn(
  530. NewTxn(WriteOptions(), TransactionOptions()));
  531. ASSERT_NE(nullptr, prepared_but_uncommitted_txn);
  532. ASSERT_OK(
  533. prepared_but_uncommitted_txn->Put(handles_[0], "foo0", "foo_value_0"));
  534. ASSERT_OK(
  535. prepared_but_uncommitted_txn->Put(handles_[1], "foo1", "foo_value_1"));
  536. ASSERT_OK(
  537. prepared_but_uncommitted_txn->SetName("prepared_but_uncommitted_txn"));
  538. ASSERT_OK(prepared_but_uncommitted_txn->Prepare());
  539. prepared_but_uncommitted_txn.reset();
  540. WriteOptions write_opts;
  541. write_opts.sync = true;
  542. std::unique_ptr<Transaction> committed_txn(
  543. NewTxn(write_opts, TransactionOptions()));
  544. ASSERT_NE(nullptr, committed_txn);
  545. ASSERT_OK(committed_txn->Put("bar0", "bar_value_0"));
  546. ASSERT_OK(committed_txn->Put(handles_[1], "bar1", "bar_value_1"));
  547. ASSERT_OK(committed_txn->SetName("committed_txn"));
  548. ASSERT_OK(committed_txn->Prepare());
  549. ASSERT_OK(committed_txn->Commit());
  550. committed_txn.reset();
  551. std::unique_ptr<Transaction> committed_without_prepare_txn(
  552. NewTxn(write_opts, TransactionOptions()));
  553. assert(committed_without_prepare_txn);
  554. ASSERT_OK(committed_without_prepare_txn->Put("baz0", "baz_value_0"));
  555. ASSERT_OK(
  556. committed_without_prepare_txn->Put(handles_[1], "baz1", "baz_value_1"));
  557. ASSERT_OK(
  558. committed_without_prepare_txn->SetName("committed_without_prepare_txn"));
  559. ASSERT_OK(committed_without_prepare_txn->Commit());
  560. committed_without_prepare_txn.reset();
  561. std::unique_ptr<Transaction> rolled_back_txn(
  562. NewTxn(write_opts, TransactionOptions()));
  563. ASSERT_NE(nullptr, rolled_back_txn);
  564. ASSERT_OK(rolled_back_txn->Put("non_exist0", "donotcare"));
  565. ASSERT_OK(rolled_back_txn->Put(handles_[1], "non_exist1", "donotcare"));
  566. ASSERT_OK(rolled_back_txn->SetName("rolled_back_txn"));
  567. ASSERT_OK(rolled_back_txn->Rollback());
  568. rolled_back_txn.reset();
  569. // Reopen and enable UDT to replay WAL entries.
  570. options.allow_concurrent_memtable_write = false;
  571. cf_descs[1].options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  572. cf_descs[1].options.persist_user_defined_timestamps = false;
  573. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  574. {
  575. Transaction* recovered_txn1 =
  576. db->GetTransactionByName("prepared_but_uncommitted_txn");
  577. ASSERT_NE(nullptr, recovered_txn1);
  578. std::string value;
  579. ASSERT_OK(recovered_txn1->SetCommitTimestamp(23));
  580. ASSERT_OK(recovered_txn1->Commit());
  581. Status s = db->Get(ReadOptions(), handles_[0], "foo0", &value);
  582. ASSERT_OK(s);
  583. ASSERT_EQ("foo_value_0", value);
  584. s = GetFromDb(ReadOptions(), handles_[1], "foo1", /*ts=*/23, &value);
  585. ASSERT_OK(s);
  586. ASSERT_EQ("foo_value_1", value);
  587. delete recovered_txn1;
  588. ASSERT_EQ(nullptr, db->GetTransactionByName("committed_txn"));
  589. s = db->Get(ReadOptions(), handles_[0], "bar0", &value);
  590. ASSERT_OK(s);
  591. ASSERT_EQ("bar_value_0", value);
  592. s = GetFromDb(ReadOptions(), handles_[1], "bar1", /*ts=*/23, &value);
  593. ASSERT_OK(s);
  594. ASSERT_EQ("bar_value_1", value);
  595. ASSERT_EQ(nullptr,
  596. db->GetTransactionByName("committed_without_prepare_txn"));
  597. s = db->Get(ReadOptions(), handles_[0], "baz0", &value);
  598. ASSERT_OK(s);
  599. ASSERT_EQ("baz_value_0", value);
  600. s = GetFromDb(ReadOptions(), handles_[1], "baz1", /*ts=*/23, &value);
  601. ASSERT_OK(s);
  602. ASSERT_EQ("baz_value_1", value);
  603. ASSERT_EQ(nullptr, db->GetTransactionByName("rolled_back_txn"));
  604. s = db->Get(ReadOptions(), handles_[0], "non_exist0", &value);
  605. ASSERT_TRUE(s.IsNotFound());
  606. s = GetFromDb(ReadOptions(), handles_[1], "non_exist1", /*ts=*/23, &value);
  607. ASSERT_TRUE(s.IsNotFound());
  608. }
  609. }
  610. TEST_P(WriteCommittedTxnWithTsTest, ChangeFromWriteCommittedAndDisableUDT) {
  611. // This feature is not compatible with UDT in memtable only.
  612. options.allow_concurrent_memtable_write = false;
  613. ASSERT_OK(ReOpenNoDelete());
  614. ColumnFamilyOptions cf_opts;
  615. cf_opts.comparator = test::BytewiseComparatorWithU64TsWrapper();
  616. cf_opts.persist_user_defined_timestamps = false;
  617. const std::string test_cf_name = "test_cf";
  618. ColumnFamilyHandle* cfh = nullptr;
  619. assert(db);
  620. ASSERT_OK(db->CreateColumnFamily(cf_opts, test_cf_name, &cfh));
  621. delete cfh;
  622. cfh = nullptr;
  623. std::vector<ColumnFamilyDescriptor> cf_descs;
  624. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  625. cf_descs.emplace_back(test_cf_name, cf_opts);
  626. options.avoid_flush_during_shutdown = true;
  627. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  628. std::unique_ptr<Transaction> prepared_but_uncommitted_txn(
  629. NewTxn(WriteOptions(), TransactionOptions()));
  630. assert(prepared_but_uncommitted_txn);
  631. ASSERT_OK(prepared_but_uncommitted_txn->Put("foo0", "foo_value_0"));
  632. ASSERT_OK(
  633. prepared_but_uncommitted_txn->Put(handles_[1], "foo1", "foo_value_1"));
  634. ASSERT_OK(
  635. prepared_but_uncommitted_txn->SetName("prepared_but_uncommitted_txn"));
  636. ASSERT_OK(prepared_but_uncommitted_txn->Prepare());
  637. prepared_but_uncommitted_txn.reset();
  638. WriteOptions write_opts;
  639. write_opts.sync = true;
  640. std::unique_ptr<Transaction> committed_txn(
  641. NewTxn(write_opts, TransactionOptions()));
  642. assert(committed_txn);
  643. ASSERT_OK(committed_txn->Put("bar0", "bar_value_0"));
  644. ASSERT_OK(committed_txn->Put(handles_[1], "bar1", "bar_value_1"));
  645. ASSERT_OK(committed_txn->SetName("committed_txn"));
  646. ASSERT_OK(committed_txn->Prepare());
  647. ASSERT_OK(committed_txn->SetCommitTimestamp(/*ts=*/23));
  648. ASSERT_OK(committed_txn->Commit());
  649. committed_txn.reset();
  650. std::unique_ptr<Transaction> committed_without_prepare_txn(
  651. NewTxn(write_opts, TransactionOptions()));
  652. assert(committed_without_prepare_txn);
  653. ASSERT_OK(committed_without_prepare_txn->Put("baz0", "baz_value_0"));
  654. ASSERT_OK(
  655. committed_without_prepare_txn->Put(handles_[1], "baz1", "baz_value_1"));
  656. ASSERT_OK(
  657. committed_without_prepare_txn->SetName("committed_without_prepare_txn"));
  658. ASSERT_OK(committed_without_prepare_txn->SetCommitTimestamp(/*ts=*/24));
  659. ASSERT_OK(committed_without_prepare_txn->Commit());
  660. committed_without_prepare_txn.reset();
  661. // Disable UDT and change write policy.
  662. cf_descs[1].options.comparator = BytewiseComparator();
  663. txn_db_options.write_policy = TxnDBWritePolicy::WRITE_PREPARED;
  664. ASSERT_NOK(ReOpenNoDelete(cf_descs, &handles_));
  665. txn_db_options.write_policy = TxnDBWritePolicy::WRITE_UNPREPARED;
  666. ASSERT_NOK(ReOpenNoDelete(cf_descs, &handles_));
  667. }
  668. TEST_P(WriteCommittedTxnWithTsTest, TransactionDbLevelApi) {
  669. ASSERT_OK(ReOpenNoDelete());
  670. ColumnFamilyOptions cf_options;
  671. cf_options.merge_operator = MergeOperators::CreateStringAppendOperator();
  672. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  673. const std::string test_cf_name = "test_cf";
  674. ColumnFamilyHandle* cfh = nullptr;
  675. assert(db);
  676. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  677. delete cfh;
  678. cfh = nullptr;
  679. std::vector<ColumnFamilyDescriptor> cf_descs;
  680. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  681. cf_descs.emplace_back(test_cf_name, cf_options);
  682. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  683. std::string key_str = "tes_key";
  684. std::string ts_str;
  685. std::string value_str = "test_value";
  686. PutFixed64(&ts_str, 100);
  687. Slice value = value_str;
  688. assert(db);
  689. ASSERT_TRUE(
  690. db->Put(WriteOptions(), handles_[1], "foo", "bar").IsNotSupported());
  691. ASSERT_TRUE(db->Delete(WriteOptions(), handles_[1], "foo").IsNotSupported());
  692. ASSERT_TRUE(
  693. db->SingleDelete(WriteOptions(), handles_[1], "foo").IsNotSupported());
  694. ASSERT_TRUE(
  695. db->Merge(WriteOptions(), handles_[1], "foo", "+1").IsNotSupported());
  696. WriteBatch wb1(/*reserved_bytes=*/0, /*max_bytes=*/0,
  697. /*protection_bytes_per_key=*/0, /*default_cf_ts_sz=*/0);
  698. ASSERT_OK(wb1.Put(handles_[1], key_str, ts_str, value));
  699. ASSERT_TRUE(db->Write(WriteOptions(), &wb1).IsNotSupported());
  700. ASSERT_TRUE(db->Write(WriteOptions(), TransactionDBWriteOptimizations(), &wb1)
  701. .IsNotSupported());
  702. auto* pessimistic_txn_db =
  703. static_cast_with_check<PessimisticTransactionDB>(db);
  704. assert(pessimistic_txn_db);
  705. ASSERT_TRUE(
  706. pessimistic_txn_db->WriteWithConcurrencyControl(WriteOptions(), &wb1)
  707. .IsNotSupported());
  708. ASSERT_OK(db->Put(WriteOptions(), "foo", "value"));
  709. ASSERT_OK(db->Put(WriteOptions(), "bar", "value"));
  710. ASSERT_OK(db->Delete(WriteOptions(), "bar"));
  711. ASSERT_OK(db->SingleDelete(WriteOptions(), "foo"));
  712. ASSERT_OK(db->Put(WriteOptions(), "key", "value"));
  713. ASSERT_OK(db->Merge(WriteOptions(), "key", "_more"));
  714. WriteBatch wb2(/*reserved_bytes=*/0, /*max_bytes=*/0,
  715. /*protection_bytes_per_key=*/0, /*default_cf_ts_sz=*/0);
  716. ASSERT_OK(wb2.Put(key_str, value));
  717. ASSERT_OK(db->Write(WriteOptions(), &wb2));
  718. ASSERT_OK(db->Write(WriteOptions(), TransactionDBWriteOptimizations(), &wb2));
  719. ASSERT_OK(
  720. pessimistic_txn_db->WriteWithConcurrencyControl(WriteOptions(), &wb2));
  721. std::unique_ptr<Transaction> txn(
  722. NewTxn(WriteOptions(), TransactionOptions()));
  723. assert(txn);
  724. WriteBatch wb3(/*reserved_bytes=*/0, /*max_bytes=*/0,
  725. /*protection_bytes_per_key=*/0, /*default_cf_ts_sz=*/0);
  726. ASSERT_OK(wb3.Put(handles_[1], "key", "value"));
  727. auto* pessimistic_txn =
  728. static_cast_with_check<PessimisticTransaction>(txn.get());
  729. assert(pessimistic_txn);
  730. ASSERT_TRUE(pessimistic_txn->CommitBatch(&wb3).IsNotSupported());
  731. txn.reset();
  732. }
  733. TEST_P(WriteCommittedTxnWithTsTest, Merge) {
  734. options.merge_operator = MergeOperators::CreateStringAppendOperator();
  735. ASSERT_OK(ReOpenNoDelete());
  736. ColumnFamilyOptions cf_options;
  737. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  738. cf_options.merge_operator = MergeOperators::CreateStringAppendOperator();
  739. const std::string test_cf_name = "test_cf";
  740. ColumnFamilyHandle* cfh = nullptr;
  741. assert(db);
  742. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  743. delete cfh;
  744. cfh = nullptr;
  745. std::vector<ColumnFamilyDescriptor> cf_descs;
  746. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  747. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  748. options.avoid_flush_during_shutdown = true;
  749. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  750. std::unique_ptr<Transaction> txn(
  751. NewTxn(WriteOptions(), TransactionOptions()));
  752. assert(txn);
  753. ASSERT_OK(txn->Put(handles_[1], "foo", "bar"));
  754. ASSERT_OK(txn->Merge(handles_[1], "foo", "1"));
  755. ASSERT_OK(txn->SetCommitTimestamp(24));
  756. ASSERT_OK(txn->Commit());
  757. txn.reset();
  758. {
  759. std::string value;
  760. const Status s =
  761. GetFromDb(ReadOptions(), handles_[1], "foo", /*ts=*/24, &value);
  762. ASSERT_OK(s);
  763. ASSERT_EQ("bar,1", value);
  764. }
  765. }
  766. TEST_P(WriteCommittedTxnWithTsTest, GetForUpdate) {
  767. ASSERT_OK(ReOpenNoDelete());
  768. ColumnFamilyOptions cf_options;
  769. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  770. const std::string test_cf_name = "test_cf";
  771. ColumnFamilyHandle* cfh = nullptr;
  772. assert(db);
  773. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  774. delete cfh;
  775. cfh = nullptr;
  776. std::vector<ColumnFamilyDescriptor> cf_descs;
  777. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  778. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  779. options.avoid_flush_during_shutdown = true;
  780. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  781. std::unique_ptr<Transaction> txn0(
  782. NewTxn(WriteOptions(), TransactionOptions()));
  783. // Not set read timestamp, use blind write
  784. std::unique_ptr<Transaction> txn1(
  785. NewTxn(WriteOptions(), TransactionOptions()));
  786. ASSERT_OK(txn1->Put(handles_[1], "key", "value1"));
  787. ASSERT_OK(txn1->Put(handles_[1], "foo", "value1"));
  788. ASSERT_OK(txn1->SetCommitTimestamp(24));
  789. ASSERT_OK(txn1->Commit());
  790. txn1.reset();
  791. // Set read timestamp, use it for validation in GetForUpdate, validation fail
  792. // with conflict: timestamp from db(24) > read timestamp(23)
  793. std::string value;
  794. ASSERT_OK(txn0->SetReadTimestampForValidation(23));
  795. ASSERT_TRUE(
  796. txn0->GetForUpdate(ReadOptions(), handles_[1], "key", &value).IsBusy());
  797. ASSERT_OK(txn0->Rollback());
  798. txn0.reset();
  799. // Set read timestamp, use it for validation in GetForUpdate, validation pass
  800. // with no conflict: timestamp from db(24) < read timestamp (25)
  801. std::unique_ptr<Transaction> txn2(
  802. NewTxn(WriteOptions(), TransactionOptions()));
  803. ASSERT_OK(txn2->SetReadTimestampForValidation(25));
  804. ASSERT_OK(txn2->GetForUpdate(ReadOptions(), handles_[1], "key", &value));
  805. // Use a different read timestamp in ReadOptions while doing validation is
  806. // invalid.
  807. ReadOptions read_options;
  808. std::string read_timestamp;
  809. Slice diff_read_ts = EncodeU64Ts(24, &read_timestamp);
  810. read_options.timestamp = &diff_read_ts;
  811. ASSERT_TRUE(txn2->GetForUpdate(read_options, handles_[1], "foo", &value)
  812. .IsInvalidArgument());
  813. ASSERT_OK(txn2->SetCommitTimestamp(26));
  814. ASSERT_OK(txn2->Commit());
  815. txn2.reset();
  816. // Set read timestamp, call GetForUpdate without validation, invalid
  817. std::unique_ptr<Transaction> txn3(
  818. NewTxn(WriteOptions(), TransactionOptions()));
  819. ASSERT_OK(txn3->SetReadTimestampForValidation(27));
  820. ASSERT_TRUE(txn3->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  821. /*exclusive=*/true, /*do_validate=*/false)
  822. .IsInvalidArgument());
  823. ASSERT_OK(txn3->Rollback());
  824. txn3.reset();
  825. // Not set read timestamp, call GetForUpdate with validation, invalid
  826. std::unique_ptr<Transaction> txn4(
  827. NewTxn(WriteOptions(), TransactionOptions()));
  828. // ReadOptions.timestamp is not set, invalid
  829. ASSERT_TRUE(txn4->GetForUpdate(ReadOptions(), handles_[1], "key", &value)
  830. .IsInvalidArgument());
  831. // ReadOptions.timestamp is set, also invalid.
  832. // `SetReadTimestampForValidation` must have been called with the same
  833. // timestamp as in ReadOptions.timestamp for validation.
  834. Slice read_ts = EncodeU64Ts(27, &read_timestamp);
  835. read_options.timestamp = &read_ts;
  836. ASSERT_TRUE(txn4->GetForUpdate(read_options, handles_[1], "key", &value)
  837. .IsInvalidArgument());
  838. ASSERT_OK(txn4->Rollback());
  839. txn4.reset();
  840. // Not set read timestamp, call GetForUpdate without validation, pass
  841. std::unique_ptr<Transaction> txn5(
  842. NewTxn(WriteOptions(), TransactionOptions()));
  843. // ReadOptions.timestamp is not set, pass
  844. ASSERT_OK(txn5->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  845. /*exclusive=*/true, /*do_validate=*/false));
  846. // ReadOptions.timestamp explicitly set to max timestamp, pass
  847. Slice max_ts = MaxU64Ts();
  848. read_options.timestamp = &max_ts;
  849. ASSERT_OK(txn5->GetForUpdate(read_options, handles_[1], "foo", &value,
  850. /*exclusive=*/true, /*do_validate=*/false));
  851. // NOTE: this commit timestamp is smaller than the db's timestamp (26), but
  852. // this commit can still go through, that breaks the user-defined timestamp
  853. // invariant: newer user-defined timestamp should have newer sequence number.
  854. // So be aware of skipping UDT based validation. Unless users have their own
  855. // ways to ensure the UDT invariant is met, DO NOT skip it. Ways to ensure
  856. // the UDT invariant include: manage a monotonically increasing timestamp,
  857. // commit transactions in a single thread etc.
  858. ASSERT_OK(txn5->SetCommitTimestamp(3));
  859. ASSERT_OK(txn5->Commit());
  860. txn5.reset();
  861. }
  862. TEST_P(WriteCommittedTxnWithTsTest, GetForUpdateUdtValidationNotEnabled) {
  863. ASSERT_OK(ReOpenNoDelete());
  864. ColumnFamilyOptions cf_options;
  865. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  866. const std::string test_cf_name = "test_cf";
  867. ColumnFamilyHandle* cfh = nullptr;
  868. assert(db);
  869. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  870. delete cfh;
  871. cfh = nullptr;
  872. std::vector<ColumnFamilyDescriptor> cf_descs;
  873. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  874. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  875. options.avoid_flush_during_shutdown = true;
  876. txn_db_options.enable_udt_validation = false;
  877. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  878. // blind write a key/value for latter read via `GetForUpdate`.
  879. std::unique_ptr<Transaction> txn0(
  880. NewTxn(WriteOptions(), TransactionOptions()));
  881. ASSERT_OK(txn0->Put(handles_[1], "key", "value0"));
  882. ASSERT_OK(txn0->SetCommitTimestamp(20));
  883. ASSERT_OK(txn0->Commit());
  884. // When timestamp validation is disabled across the whole DB
  885. // `SetReadTimestampForValidation` should not be called.
  886. std::unique_ptr<Transaction> txn1(
  887. NewTxn(WriteOptions(), TransactionOptions()));
  888. std::string value;
  889. ASSERT_OK(txn1->SetReadTimestampForValidation(21));
  890. ASSERT_TRUE(txn1->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  891. /* exclusive= */ true, /*do_validate=*/true)
  892. .IsInvalidArgument());
  893. txn1.reset();
  894. // do_validate and no snapshot, no conflict checking at all
  895. std::unique_ptr<Transaction> txn2(
  896. NewTxn(WriteOptions(), TransactionOptions()));
  897. ASSERT_OK(txn2->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  898. /* exclusive= */ true, /*do_validate=*/true));
  899. ASSERT_OK(txn2->Put(handles_[1], "key", "value1"));
  900. ASSERT_OK(txn2->SetCommitTimestamp(21));
  901. ASSERT_OK(txn2->Commit());
  902. txn2.reset();
  903. // do_validate and set snapshot, execute sequence number based conflict
  904. // checking and skip timestamp based conflict checking.
  905. std::unique_ptr<Transaction> txn3(
  906. NewTxn(WriteOptions(), TransactionOptions()));
  907. txn3->SetSnapshot();
  908. ASSERT_OK(txn3->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  909. /* exclusive= */ true, /*do_validate=*/true));
  910. ASSERT_OK(txn3->Put(handles_[1], "key", "value2"));
  911. ASSERT_OK(txn3->SetCommitTimestamp(22));
  912. ASSERT_OK(txn3->Commit());
  913. txn3.reset();
  914. // Always check `ReadOptions.timestamp` to be consistent with the default
  915. // `read_timestamp_` if it's explicitly set, even if whole DB disables
  916. // timestamp validation.
  917. std::unique_ptr<Transaction> txn4(
  918. NewTxn(WriteOptions(), TransactionOptions()));
  919. ReadOptions ropts;
  920. std::string read_timestamp;
  921. Slice read_ts = EncodeU64Ts(27, &read_timestamp);
  922. ropts.timestamp = &read_ts;
  923. ASSERT_TRUE(txn4->GetForUpdate(ropts, handles_[1], "key", &value,
  924. /* exclusive= */ true, /*do_validate=*/true)
  925. .IsInvalidArgument());
  926. txn4.reset();
  927. // Conflict of timestamps not caught when parallel transactions commit with
  928. // some out of order timestamps.
  929. std::unique_ptr<Transaction> txn5(
  930. db->BeginTransaction(WriteOptions(), TransactionOptions()));
  931. assert(txn5);
  932. std::unique_ptr<Transaction> txn6(
  933. db->BeginTransaction(WriteOptions(), TransactionOptions()));
  934. assert(txn6);
  935. ASSERT_OK(txn6->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  936. /* exclusive= */ true, /*do_validate=*/true));
  937. ASSERT_OK(txn6->Put(handles_[1], "key", "value4"));
  938. ASSERT_OK(txn6->SetName("txn6"));
  939. ASSERT_OK(txn6->Prepare());
  940. ASSERT_OK(txn6->SetCommitTimestamp(24));
  941. ASSERT_OK(txn6->Commit());
  942. txn6.reset();
  943. txn5->SetSnapshot();
  944. ASSERT_OK(txn5->GetForUpdate(ReadOptions(), handles_[1], "key", &value,
  945. /* exclusive= */ true, /*do_validate=*/true));
  946. ASSERT_OK(txn5->Put(handles_[1], "key", "value3"));
  947. ASSERT_OK(txn5->SetName("txn5"));
  948. // txn5 commits after txn6 but writes a smaller timestamp
  949. ASSERT_OK(txn5->SetCommitTimestamp(23));
  950. ASSERT_OK(txn5->Commit());
  951. txn5.reset();
  952. }
  953. TEST_P(WriteCommittedTxnWithTsTest, BlindWrite) {
  954. ASSERT_OK(ReOpenNoDelete());
  955. ColumnFamilyOptions cf_options;
  956. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  957. const std::string test_cf_name = "test_cf";
  958. ColumnFamilyHandle* cfh = nullptr;
  959. assert(db);
  960. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  961. delete cfh;
  962. cfh = nullptr;
  963. std::vector<ColumnFamilyDescriptor> cf_descs;
  964. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  965. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  966. options.avoid_flush_during_shutdown = true;
  967. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  968. std::unique_ptr<Transaction> txn0(
  969. NewTxn(WriteOptions(), TransactionOptions()));
  970. assert(txn0);
  971. std::unique_ptr<Transaction> txn1(
  972. NewTxn(WriteOptions(), TransactionOptions()));
  973. assert(txn1);
  974. {
  975. std::string value;
  976. ASSERT_OK(txn0->SetReadTimestampForValidation(100));
  977. // Lock "key".
  978. ASSERT_TRUE(txn0->GetForUpdate(ReadOptions(), handles_[1], "key", &value)
  979. .IsNotFound());
  980. }
  981. ASSERT_OK(txn0->Put(handles_[1], "key", "value0"));
  982. ASSERT_OK(txn0->SetCommitTimestamp(101));
  983. ASSERT_OK(txn0->Commit());
  984. ASSERT_OK(txn1->Put(handles_[1], "key", "value1"));
  985. // In reality, caller needs to ensure commit_ts of txn1 is greater than the
  986. // commit_ts of txn0, which is true for lock-based concurrency control.
  987. ASSERT_OK(txn1->SetCommitTimestamp(102));
  988. ASSERT_OK(txn1->Commit());
  989. txn0.reset();
  990. txn1.reset();
  991. }
  992. TEST_P(WriteCommittedTxnWithTsTest, RefineReadTimestamp) {
  993. ASSERT_OK(ReOpenNoDelete());
  994. ColumnFamilyOptions cf_options;
  995. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  996. const std::string test_cf_name = "test_cf";
  997. ColumnFamilyHandle* cfh = nullptr;
  998. assert(db);
  999. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  1000. delete cfh;
  1001. cfh = nullptr;
  1002. std::vector<ColumnFamilyDescriptor> cf_descs;
  1003. cf_descs.emplace_back(kDefaultColumnFamilyName, options);
  1004. cf_descs.emplace_back(test_cf_name, Options(DBOptions(), cf_options));
  1005. options.avoid_flush_during_shutdown = true;
  1006. ASSERT_OK(ReOpenNoDelete(cf_descs, &handles_));
  1007. std::unique_ptr<Transaction> txn0(
  1008. NewTxn(WriteOptions(), TransactionOptions()));
  1009. assert(txn0);
  1010. std::unique_ptr<Transaction> txn1(
  1011. NewTxn(WriteOptions(), TransactionOptions()));
  1012. assert(txn1);
  1013. {
  1014. ASSERT_OK(txn0->SetReadTimestampForValidation(100));
  1015. // Lock "key0", "key1", ..., "key4".
  1016. for (int i = 0; i < 5; ++i) {
  1017. std::string value;
  1018. ASSERT_TRUE(txn0->GetForUpdate(ReadOptions(), handles_[1],
  1019. "key" + std::to_string(i), &value)
  1020. .IsNotFound());
  1021. }
  1022. }
  1023. ASSERT_OK(txn1->Put(handles_[1], "key5", "value5_0"));
  1024. ASSERT_OK(txn1->SetName("txn1"));
  1025. ASSERT_OK(txn1->Prepare());
  1026. ASSERT_OK(txn1->SetCommitTimestamp(101));
  1027. ASSERT_OK(txn1->Commit());
  1028. txn1.reset();
  1029. {
  1030. std::string value;
  1031. ASSERT_TRUE(txn0->GetForUpdate(ReadOptions(), handles_[1], "key5", &value)
  1032. .IsBusy());
  1033. ASSERT_OK(txn0->SetReadTimestampForValidation(102));
  1034. ASSERT_OK(txn0->GetForUpdate(ReadOptions(), handles_[1], "key5", &value));
  1035. ASSERT_EQ("value5_0", value);
  1036. }
  1037. for (int i = 0; i < 6; ++i) {
  1038. ASSERT_OK(txn0->Put(handles_[1], "key" + std::to_string(i),
  1039. "value" + std::to_string(i)));
  1040. }
  1041. ASSERT_OK(txn0->SetName("txn0"));
  1042. ASSERT_OK(txn0->Prepare());
  1043. ASSERT_OK(txn0->SetCommitTimestamp(103));
  1044. ASSERT_OK(txn0->Commit());
  1045. txn0.reset();
  1046. }
  1047. TEST_P(WriteCommittedTxnWithTsTest, CheckKeysForConflicts) {
  1048. options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  1049. ASSERT_OK(ReOpen());
  1050. std::unique_ptr<Transaction> txn1(
  1051. db->BeginTransaction(WriteOptions(), TransactionOptions()));
  1052. assert(txn1);
  1053. std::unique_ptr<Transaction> txn2(
  1054. db->BeginTransaction(WriteOptions(), TransactionOptions()));
  1055. assert(txn2);
  1056. ASSERT_OK(txn2->Put("foo", "v0"));
  1057. ASSERT_OK(txn2->SetCommitTimestamp(10));
  1058. ASSERT_OK(txn2->Commit());
  1059. txn2.reset();
  1060. // txn1 takes a snapshot after txn2 commits. The writes of txn2 have
  1061. // a smaller seqno than txn1's snapshot, thus should not affect conflict
  1062. // checking.
  1063. txn1->SetSnapshot();
  1064. std::unique_ptr<Transaction> txn3(
  1065. db->BeginTransaction(WriteOptions(), TransactionOptions()));
  1066. assert(txn3);
  1067. ASSERT_OK(txn3->SetReadTimestampForValidation(20));
  1068. std::string dontcare;
  1069. ASSERT_OK(txn3->GetForUpdate(ReadOptions(), "foo", &dontcare));
  1070. ASSERT_OK(txn3->SingleDelete("foo"));
  1071. ASSERT_OK(txn3->SetName("txn3"));
  1072. ASSERT_OK(txn3->Prepare());
  1073. ASSERT_OK(txn3->SetCommitTimestamp(30));
  1074. // txn3 reads at ts=20 > txn2's commit timestamp, and commits at ts=30.
  1075. // txn3 can commit successfully, leaving a tombstone with ts=30.
  1076. ASSERT_OK(txn3->Commit());
  1077. txn3.reset();
  1078. bool called = false;
  1079. SyncPoint::GetInstance()->DisableProcessing();
  1080. SyncPoint::GetInstance()->ClearAllCallBacks();
  1081. SyncPoint::GetInstance()->SetCallBack(
  1082. "DBImpl::GetLatestSequenceForKey:mem", [&](void* arg) {
  1083. auto* const ts_ptr = static_cast<std::string*>(arg);
  1084. assert(ts_ptr);
  1085. Slice ts_slc = *ts_ptr;
  1086. uint64_t last_ts = 0;
  1087. ASSERT_TRUE(GetFixed64(&ts_slc, &last_ts));
  1088. ASSERT_EQ(30, last_ts);
  1089. called = true;
  1090. });
  1091. SyncPoint::GetInstance()->EnableProcessing();
  1092. // txn1's read timestamp is 25 < 30 (commit timestamp of txn3). Therefore,
  1093. // the tombstone written by txn3 causes the conflict checking to fail.
  1094. ASSERT_OK(txn1->SetReadTimestampForValidation(25));
  1095. ASSERT_TRUE(txn1->GetForUpdate(ReadOptions(), "foo", &dontcare).IsBusy());
  1096. ASSERT_TRUE(called);
  1097. Transaction* reused_txn =
  1098. db->BeginTransaction(WriteOptions(), TransactionOptions(), txn1.get());
  1099. ASSERT_EQ(reused_txn, txn1.get());
  1100. ASSERT_OK(reused_txn->Put("foo", "v1"));
  1101. ASSERT_OK(reused_txn->SetCommitTimestamp(40));
  1102. ASSERT_OK(reused_txn->Commit());
  1103. SyncPoint::GetInstance()->DisableProcessing();
  1104. SyncPoint::GetInstance()->ClearAllCallBacks();
  1105. }
  1106. TEST_P(WriteCommittedTxnWithTsTest, GetEntityForUpdate) {
  1107. ASSERT_OK(ReOpenNoDelete());
  1108. ColumnFamilyOptions cf_options;
  1109. cf_options.comparator = test::BytewiseComparatorWithU64TsWrapper();
  1110. const std::string test_cf_name = "test_cf";
  1111. ColumnFamilyHandle* cfh = nullptr;
  1112. ASSERT_OK(db->CreateColumnFamily(cf_options, test_cf_name, &cfh));
  1113. std::unique_ptr<ColumnFamilyHandle> cfh_guard(cfh);
  1114. constexpr char foo[] = "foo";
  1115. constexpr char bar[] = "bar";
  1116. constexpr char baz[] = "baz";
  1117. constexpr char quux[] = "quux";
  1118. {
  1119. std::unique_ptr<Transaction> txn0(
  1120. NewTxn(WriteOptions(), TransactionOptions()));
  1121. {
  1122. std::unique_ptr<Transaction> txn1(
  1123. NewTxn(WriteOptions(), TransactionOptions()));
  1124. ASSERT_OK(txn1->Put(cfh, foo, bar));
  1125. ASSERT_OK(txn1->Put(cfh, baz, quux));
  1126. ASSERT_OK(txn1->SetCommitTimestamp(24));
  1127. ASSERT_OK(txn1->Commit());
  1128. }
  1129. ASSERT_OK(txn0->SetReadTimestampForValidation(23));
  1130. // Validation fails: timestamp from db(24) > validation timestamp(23)
  1131. PinnableWideColumns columns;
  1132. ASSERT_TRUE(
  1133. txn0->GetEntityForUpdate(ReadOptions(), cfh, foo, &columns).IsBusy());
  1134. ASSERT_OK(txn0->Rollback());
  1135. }
  1136. {
  1137. std::unique_ptr<Transaction> txn2(
  1138. NewTxn(WriteOptions(), TransactionOptions()));
  1139. ASSERT_OK(txn2->SetReadTimestampForValidation(25));
  1140. // Validation successful: timestamp from db(24) < validation timestamp (25)
  1141. {
  1142. PinnableWideColumns columns;
  1143. ASSERT_OK(txn2->GetEntityForUpdate(ReadOptions(), cfh, foo, &columns));
  1144. }
  1145. // Using a different read timestamp in ReadOptions while doing validation is
  1146. // not allowed
  1147. {
  1148. ReadOptions read_options;
  1149. std::string read_timestamp;
  1150. Slice diff_read_ts = EncodeU64Ts(24, &read_timestamp);
  1151. read_options.timestamp = &diff_read_ts;
  1152. PinnableWideColumns columns;
  1153. ASSERT_TRUE(txn2->GetEntityForUpdate(read_options, cfh, foo, &columns)
  1154. .IsInvalidArgument());
  1155. ASSERT_OK(txn2->SetCommitTimestamp(26));
  1156. ASSERT_OK(txn2->Commit());
  1157. }
  1158. }
  1159. // GetEntityForUpdate with validation timestamp set but no validation is not
  1160. // allowed
  1161. {
  1162. std::unique_ptr<Transaction> txn3(
  1163. NewTxn(WriteOptions(), TransactionOptions()));
  1164. ASSERT_OK(txn3->SetReadTimestampForValidation(27));
  1165. PinnableWideColumns columns;
  1166. ASSERT_TRUE(txn3->GetEntityForUpdate(ReadOptions(), cfh, foo, &columns,
  1167. /*exclusive=*/true,
  1168. /*do_validate=*/false)
  1169. .IsInvalidArgument());
  1170. ASSERT_OK(txn3->Rollback());
  1171. }
  1172. // GetEntityForUpdate with validation but no validation timestamp is not
  1173. // allowed
  1174. {
  1175. std::unique_ptr<Transaction> txn4(
  1176. NewTxn(WriteOptions(), TransactionOptions()));
  1177. // ReadOptions.timestamp is not set
  1178. {
  1179. PinnableWideColumns columns;
  1180. ASSERT_TRUE(txn4->GetEntityForUpdate(ReadOptions(), cfh, foo, &columns)
  1181. .IsInvalidArgument());
  1182. }
  1183. // ReadOptions.timestamp is set
  1184. {
  1185. ReadOptions read_options;
  1186. std::string read_timestamp;
  1187. Slice read_ts = EncodeU64Ts(27, &read_timestamp);
  1188. read_options.timestamp = &read_ts;
  1189. PinnableWideColumns columns;
  1190. ASSERT_TRUE(txn4->GetEntityForUpdate(read_options, cfh, foo, &columns)
  1191. .IsInvalidArgument());
  1192. }
  1193. ASSERT_OK(txn4->Rollback());
  1194. }
  1195. // Validation disabled
  1196. {
  1197. std::unique_ptr<Transaction> txn5(
  1198. NewTxn(WriteOptions(), TransactionOptions()));
  1199. // ReadOptions.timestamp is not set => success
  1200. {
  1201. PinnableWideColumns columns;
  1202. ASSERT_OK(txn5->GetEntityForUpdate(ReadOptions(), cfh, foo, &columns,
  1203. /*exclusive=*/true,
  1204. /*do_validate=*/false));
  1205. }
  1206. // ReadOptions.timestamp explicitly set to max timestamp => success
  1207. {
  1208. ReadOptions read_options;
  1209. Slice max_ts = MaxU64Ts();
  1210. read_options.timestamp = &max_ts;
  1211. PinnableWideColumns columns;
  1212. ASSERT_OK(txn5->GetEntityForUpdate(read_options, cfh, baz, &columns,
  1213. /*exclusive=*/true,
  1214. /*do_validate=*/false));
  1215. }
  1216. }
  1217. }
  1218. } // namespace ROCKSDB_NAMESPACE
  1219. int main(int argc, char** argv) {
  1220. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  1221. ::testing::InitGoogleTest(&argc, argv);
  1222. return RUN_ALL_TESTS();
  1223. }