]> git.proxmox.com Git - ceph.git/blame - ceph/src/rocksdb/utilities/transactions/optimistic_transaction_test.cc
import 14.2.4 nautilus point release
[ceph.git] / ceph / src / rocksdb / utilities / transactions / optimistic_transaction_test.cc
CommitLineData
7c673cae 1// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
11fdf7f2
TL
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).
7c673cae
FG
5
6#ifndef ROCKSDB_LITE
7
8#include <functional>
9#include <string>
10#include <thread>
11
12#include "rocksdb/db.h"
13#include "rocksdb/utilities/optimistic_transaction_db.h"
14#include "rocksdb/utilities/transaction.h"
15#include "util/crc32c.h"
16#include "util/logging.h"
17#include "util/random.h"
18#include "util/testharness.h"
19#include "util/transaction_test_util.h"
20#include "port/port.h"
21
22using std::string;
23
24namespace rocksdb {
25
26class OptimisticTransactionTest : public testing::Test {
27 public:
28 OptimisticTransactionDB* txn_db;
7c673cae
FG
29 string dbname;
30 Options options;
31
32 OptimisticTransactionTest() {
33 options.create_if_missing = true;
34 options.max_write_buffer_number = 2;
11fdf7f2 35 dbname = test::PerThreadDBPath("optimistic_transaction_testdb");
7c673cae
FG
36
37 DestroyDB(dbname, options);
38 Open();
39 }
494da23a 40 ~OptimisticTransactionTest() override {
7c673cae
FG
41 delete txn_db;
42 DestroyDB(dbname, options);
43 }
44
45 void Reopen() {
46 delete txn_db;
11fdf7f2 47 txn_db = nullptr;
7c673cae
FG
48 Open();
49 }
50
51private:
52 void Open() {
53 Status s = OptimisticTransactionDB::Open(options, dbname, &txn_db);
54 assert(s.ok());
11fdf7f2 55 assert(txn_db != nullptr);
7c673cae
FG
56 }
57};
58
59TEST_F(OptimisticTransactionTest, SuccessTest) {
60 WriteOptions write_options;
61 ReadOptions read_options;
62 string value;
63 Status s;
64
11fdf7f2
TL
65 txn_db->Put(write_options, Slice("foo"), Slice("bar"));
66 txn_db->Put(write_options, Slice("foo2"), Slice("bar"));
7c673cae
FG
67
68 Transaction* txn = txn_db->BeginTransaction(write_options);
69 ASSERT_TRUE(txn);
70
71 txn->GetForUpdate(read_options, "foo", &value);
72 ASSERT_EQ(value, "bar");
73
74 txn->Put(Slice("foo"), Slice("bar2"));
75
76 txn->GetForUpdate(read_options, "foo", &value);
77 ASSERT_EQ(value, "bar2");
78
79 s = txn->Commit();
80 ASSERT_OK(s);
81
11fdf7f2 82 txn_db->Get(read_options, "foo", &value);
7c673cae
FG
83 ASSERT_EQ(value, "bar2");
84
85 delete txn;
86}
87
88TEST_F(OptimisticTransactionTest, WriteConflictTest) {
89 WriteOptions write_options;
90 ReadOptions read_options;
91 string value;
92 Status s;
93
11fdf7f2
TL
94 txn_db->Put(write_options, "foo", "bar");
95 txn_db->Put(write_options, "foo2", "bar");
7c673cae
FG
96
97 Transaction* txn = txn_db->BeginTransaction(write_options);
98 ASSERT_TRUE(txn);
99
100 txn->Put("foo", "bar2");
101
102 // This Put outside of a transaction will conflict with the previous write
11fdf7f2 103 s = txn_db->Put(write_options, "foo", "barz");
7c673cae
FG
104 ASSERT_OK(s);
105
11fdf7f2 106 s = txn_db->Get(read_options, "foo", &value);
7c673cae
FG
107 ASSERT_EQ(value, "barz");
108 ASSERT_EQ(1, txn->GetNumKeys());
109
110 s = txn->Commit();
111 ASSERT_TRUE(s.IsBusy()); // Txn should not commit
112
113 // Verify that transaction did not write anything
11fdf7f2 114 txn_db->Get(read_options, "foo", &value);
7c673cae 115 ASSERT_EQ(value, "barz");
11fdf7f2 116 txn_db->Get(read_options, "foo2", &value);
7c673cae
FG
117 ASSERT_EQ(value, "bar");
118
119 delete txn;
120}
121
122TEST_F(OptimisticTransactionTest, WriteConflictTest2) {
123 WriteOptions write_options;
124 ReadOptions read_options;
125 OptimisticTransactionOptions txn_options;
126 string value;
127 Status s;
128
11fdf7f2
TL
129 txn_db->Put(write_options, "foo", "bar");
130 txn_db->Put(write_options, "foo2", "bar");
7c673cae
FG
131
132 txn_options.set_snapshot = true;
133 Transaction* txn = txn_db->BeginTransaction(write_options, txn_options);
134 ASSERT_TRUE(txn);
135
136 // This Put outside of a transaction will conflict with a later write
11fdf7f2 137 s = txn_db->Put(write_options, "foo", "barz");
7c673cae
FG
138 ASSERT_OK(s);
139
140 txn->Put("foo", "bar2"); // Conflicts with write done after snapshot taken
141
11fdf7f2 142 s = txn_db->Get(read_options, "foo", &value);
7c673cae
FG
143 ASSERT_EQ(value, "barz");
144
145 s = txn->Commit();
146 ASSERT_TRUE(s.IsBusy()); // Txn should not commit
147
148 // Verify that transaction did not write anything
11fdf7f2 149 txn_db->Get(read_options, "foo", &value);
7c673cae 150 ASSERT_EQ(value, "barz");
11fdf7f2 151 txn_db->Get(read_options, "foo2", &value);
7c673cae
FG
152 ASSERT_EQ(value, "bar");
153
154 delete txn;
155}
156
157TEST_F(OptimisticTransactionTest, ReadConflictTest) {
158 WriteOptions write_options;
159 ReadOptions read_options, snapshot_read_options;
160 OptimisticTransactionOptions txn_options;
161 string value;
162 Status s;
163
11fdf7f2
TL
164 txn_db->Put(write_options, "foo", "bar");
165 txn_db->Put(write_options, "foo2", "bar");
7c673cae
FG
166
167 txn_options.set_snapshot = true;
168 Transaction* txn = txn_db->BeginTransaction(write_options, txn_options);
169 ASSERT_TRUE(txn);
170
171 txn->SetSnapshot();
172 snapshot_read_options.snapshot = txn->GetSnapshot();
173
174 txn->GetForUpdate(snapshot_read_options, "foo", &value);
175 ASSERT_EQ(value, "bar");
176
177 // This Put outside of a transaction will conflict with the previous read
11fdf7f2 178 s = txn_db->Put(write_options, "foo", "barz");
7c673cae
FG
179 ASSERT_OK(s);
180
11fdf7f2 181 s = txn_db->Get(read_options, "foo", &value);
7c673cae
FG
182 ASSERT_EQ(value, "barz");
183
184 s = txn->Commit();
185 ASSERT_TRUE(s.IsBusy()); // Txn should not commit
186
187 // Verify that transaction did not write anything
188 txn->GetForUpdate(read_options, "foo", &value);
189 ASSERT_EQ(value, "barz");
190 txn->GetForUpdate(read_options, "foo2", &value);
191 ASSERT_EQ(value, "bar");
192
193 delete txn;
194}
195
196TEST_F(OptimisticTransactionTest, TxnOnlyTest) {
197 // Test to make sure transactions work when there are no other writes in an
198 // empty db.
199
200 WriteOptions write_options;
201 ReadOptions read_options;
202 string value;
203 Status s;
204
205 Transaction* txn = txn_db->BeginTransaction(write_options);
206 ASSERT_TRUE(txn);
207
208 txn->Put("x", "y");
209
210 s = txn->Commit();
211 ASSERT_OK(s);
212
213 delete txn;
214}
215
216TEST_F(OptimisticTransactionTest, FlushTest) {
217 WriteOptions write_options;
218 ReadOptions read_options, snapshot_read_options;
219 string value;
220 Status s;
221
11fdf7f2
TL
222 txn_db->Put(write_options, Slice("foo"), Slice("bar"));
223 txn_db->Put(write_options, Slice("foo2"), Slice("bar"));
7c673cae
FG
224
225 Transaction* txn = txn_db->BeginTransaction(write_options);
226 ASSERT_TRUE(txn);
227
228 snapshot_read_options.snapshot = txn->GetSnapshot();
229
230 txn->GetForUpdate(snapshot_read_options, "foo", &value);
231 ASSERT_EQ(value, "bar");
232
233 txn->Put(Slice("foo"), Slice("bar2"));
234
235 txn->GetForUpdate(snapshot_read_options, "foo", &value);
236 ASSERT_EQ(value, "bar2");
237
238 // Put a random key so we have a memtable to flush
11fdf7f2 239 s = txn_db->Put(write_options, "dummy", "dummy");
7c673cae
FG
240 ASSERT_OK(s);
241
242 // force a memtable flush
243 FlushOptions flush_ops;
11fdf7f2 244 txn_db->Flush(flush_ops);
7c673cae
FG
245
246 s = txn->Commit();
247 // txn should commit since the flushed table is still in MemtableList History
248 ASSERT_OK(s);
249
11fdf7f2 250 txn_db->Get(read_options, "foo", &value);
7c673cae
FG
251 ASSERT_EQ(value, "bar2");
252
253 delete txn;
254}
255
256TEST_F(OptimisticTransactionTest, FlushTest2) {
257 WriteOptions write_options;
258 ReadOptions read_options, snapshot_read_options;
259 string value;
260 Status s;
261
11fdf7f2
TL
262 txn_db->Put(write_options, Slice("foo"), Slice("bar"));
263 txn_db->Put(write_options, Slice("foo2"), Slice("bar"));
7c673cae
FG
264
265 Transaction* txn = txn_db->BeginTransaction(write_options);
266 ASSERT_TRUE(txn);
267
268 snapshot_read_options.snapshot = txn->GetSnapshot();
269
270 txn->GetForUpdate(snapshot_read_options, "foo", &value);
271 ASSERT_EQ(value, "bar");
272
273 txn->Put(Slice("foo"), Slice("bar2"));
274
275 txn->GetForUpdate(snapshot_read_options, "foo", &value);
276 ASSERT_EQ(value, "bar2");
277
278 // Put a random key so we have a MemTable to flush
11fdf7f2 279 s = txn_db->Put(write_options, "dummy", "dummy");
7c673cae
FG
280 ASSERT_OK(s);
281
282 // force a memtable flush
283 FlushOptions flush_ops;
11fdf7f2 284 txn_db->Flush(flush_ops);
7c673cae
FG
285
286 // Put a random key so we have a MemTable to flush
11fdf7f2 287 s = txn_db->Put(write_options, "dummy", "dummy2");
7c673cae
FG
288 ASSERT_OK(s);
289
290 // force a memtable flush
11fdf7f2 291 txn_db->Flush(flush_ops);
7c673cae 292
11fdf7f2 293 s = txn_db->Put(write_options, "dummy", "dummy3");
7c673cae
FG
294 ASSERT_OK(s);
295
296 // force a memtable flush
297 // Since our test db has max_write_buffer_number=2, this flush will cause
298 // the first memtable to get purged from the MemtableList history.
11fdf7f2 299 txn_db->Flush(flush_ops);
7c673cae
FG
300
301 s = txn->Commit();
302 // txn should not commit since MemTableList History is not large enough
303 ASSERT_TRUE(s.IsTryAgain());
304
11fdf7f2 305 txn_db->Get(read_options, "foo", &value);
7c673cae
FG
306 ASSERT_EQ(value, "bar");
307
308 delete txn;
309}
310
311TEST_F(OptimisticTransactionTest, NoSnapshotTest) {
312 WriteOptions write_options;
313 ReadOptions read_options;
314 string value;
315 Status s;
316
11fdf7f2 317 txn_db->Put(write_options, "AAA", "bar");
7c673cae
FG
318
319 Transaction* txn = txn_db->BeginTransaction(write_options);
320 ASSERT_TRUE(txn);
321
322 // Modify key after transaction start
11fdf7f2 323 txn_db->Put(write_options, "AAA", "bar1");
7c673cae
FG
324
325 // Read and write without a snapshot
326 txn->GetForUpdate(read_options, "AAA", &value);
327 ASSERT_EQ(value, "bar1");
328 txn->Put("AAA", "bar2");
329
330 // Should commit since read/write was done after data changed
331 s = txn->Commit();
332 ASSERT_OK(s);
333
334 txn->GetForUpdate(read_options, "AAA", &value);
335 ASSERT_EQ(value, "bar2");
336
337 delete txn;
338}
339
340TEST_F(OptimisticTransactionTest, MultipleSnapshotTest) {
341 WriteOptions write_options;
342 ReadOptions read_options, snapshot_read_options;
343 string value;
344 Status s;
345
11fdf7f2
TL
346 txn_db->Put(write_options, "AAA", "bar");
347 txn_db->Put(write_options, "BBB", "bar");
348 txn_db->Put(write_options, "CCC", "bar");
7c673cae
FG
349
350 Transaction* txn = txn_db->BeginTransaction(write_options);
351 ASSERT_TRUE(txn);
352
11fdf7f2 353 txn_db->Put(write_options, "AAA", "bar1");
7c673cae
FG
354
355 // Read and write without a snapshot
356 txn->GetForUpdate(read_options, "AAA", &value);
357 ASSERT_EQ(value, "bar1");
358 txn->Put("AAA", "bar2");
359
360 // Modify BBB before snapshot is taken
11fdf7f2 361 txn_db->Put(write_options, "BBB", "bar1");
7c673cae
FG
362
363 txn->SetSnapshot();
364 snapshot_read_options.snapshot = txn->GetSnapshot();
365
366 // Read and write with snapshot
367 txn->GetForUpdate(snapshot_read_options, "BBB", &value);
368 ASSERT_EQ(value, "bar1");
369 txn->Put("BBB", "bar2");
370
11fdf7f2 371 txn_db->Put(write_options, "CCC", "bar1");
7c673cae
FG
372
373 // Set a new snapshot
374 txn->SetSnapshot();
375 snapshot_read_options.snapshot = txn->GetSnapshot();
376
377 // Read and write with snapshot
378 txn->GetForUpdate(snapshot_read_options, "CCC", &value);
379 ASSERT_EQ(value, "bar1");
380 txn->Put("CCC", "bar2");
381
382 s = txn->GetForUpdate(read_options, "AAA", &value);
383 ASSERT_OK(s);
384 ASSERT_EQ(value, "bar2");
385 s = txn->GetForUpdate(read_options, "BBB", &value);
386 ASSERT_OK(s);
387 ASSERT_EQ(value, "bar2");
388 s = txn->GetForUpdate(read_options, "CCC", &value);
389 ASSERT_OK(s);
390 ASSERT_EQ(value, "bar2");
391
11fdf7f2 392 s = txn_db->Get(read_options, "AAA", &value);
7c673cae
FG
393 ASSERT_OK(s);
394 ASSERT_EQ(value, "bar1");
11fdf7f2 395 s = txn_db->Get(read_options, "BBB", &value);
7c673cae
FG
396 ASSERT_OK(s);
397 ASSERT_EQ(value, "bar1");
11fdf7f2 398 s = txn_db->Get(read_options, "CCC", &value);
7c673cae
FG
399 ASSERT_OK(s);
400 ASSERT_EQ(value, "bar1");
401
402 s = txn->Commit();
403 ASSERT_OK(s);
404
11fdf7f2 405 s = txn_db->Get(read_options, "AAA", &value);
7c673cae
FG
406 ASSERT_OK(s);
407 ASSERT_EQ(value, "bar2");
11fdf7f2 408 s = txn_db->Get(read_options, "BBB", &value);
7c673cae
FG
409 ASSERT_OK(s);
410 ASSERT_EQ(value, "bar2");
11fdf7f2 411 s = txn_db->Get(read_options, "CCC", &value);
7c673cae
FG
412 ASSERT_OK(s);
413 ASSERT_EQ(value, "bar2");
414
415 // verify that we track multiple writes to the same key at different snapshots
416 delete txn;
417 txn = txn_db->BeginTransaction(write_options);
418
419 // Potentially conflicting writes
11fdf7f2
TL
420 txn_db->Put(write_options, "ZZZ", "zzz");
421 txn_db->Put(write_options, "XXX", "xxx");
7c673cae
FG
422
423 txn->SetSnapshot();
424
425 OptimisticTransactionOptions txn_options;
426 txn_options.set_snapshot = true;
427 Transaction* txn2 = txn_db->BeginTransaction(write_options, txn_options);
428 txn2->SetSnapshot();
429
430 // This should not conflict in txn since the snapshot is later than the
431 // previous write (spoiler alert: it will later conflict with txn2).
432 txn->Put("ZZZ", "zzzz");
433 s = txn->Commit();
434 ASSERT_OK(s);
435
436 delete txn;
437
438 // This will conflict since the snapshot is earlier than another write to ZZZ
439 txn2->Put("ZZZ", "xxxxx");
440
441 s = txn2->Commit();
442 ASSERT_TRUE(s.IsBusy());
443
444 delete txn2;
445}
446
447TEST_F(OptimisticTransactionTest, ColumnFamiliesTest) {
448 WriteOptions write_options;
449 ReadOptions read_options, snapshot_read_options;
450 OptimisticTransactionOptions txn_options;
451 string value;
452 Status s;
453
454 ColumnFamilyHandle *cfa, *cfb;
455 ColumnFamilyOptions cf_options;
456
457 // Create 2 new column families
11fdf7f2 458 s = txn_db->CreateColumnFamily(cf_options, "CFA", &cfa);
7c673cae 459 ASSERT_OK(s);
11fdf7f2 460 s = txn_db->CreateColumnFamily(cf_options, "CFB", &cfb);
7c673cae
FG
461 ASSERT_OK(s);
462
463 delete cfa;
464 delete cfb;
465 delete txn_db;
11fdf7f2 466 txn_db = nullptr;
7c673cae
FG
467
468 // open DB with three column families
469 std::vector<ColumnFamilyDescriptor> column_families;
470 // have to open default column family
471 column_families.push_back(
472 ColumnFamilyDescriptor(kDefaultColumnFamilyName, ColumnFamilyOptions()));
473 // open the new column families
474 column_families.push_back(
475 ColumnFamilyDescriptor("CFA", ColumnFamilyOptions()));
476 column_families.push_back(
477 ColumnFamilyDescriptor("CFB", ColumnFamilyOptions()));
478 std::vector<ColumnFamilyHandle*> handles;
479 s = OptimisticTransactionDB::Open(options, dbname, column_families, &handles,
480 &txn_db);
481 ASSERT_OK(s);
11fdf7f2 482 assert(txn_db != nullptr);
7c673cae
FG
483
484 Transaction* txn = txn_db->BeginTransaction(write_options);
485 ASSERT_TRUE(txn);
486
487 txn->SetSnapshot();
488 snapshot_read_options.snapshot = txn->GetSnapshot();
489
490 txn_options.set_snapshot = true;
491 Transaction* txn2 = txn_db->BeginTransaction(write_options, txn_options);
492 ASSERT_TRUE(txn2);
493
494 // Write some data to the db
495 WriteBatch batch;
496 batch.Put("foo", "foo");
497 batch.Put(handles[1], "AAA", "bar");
498 batch.Put(handles[1], "AAAZZZ", "bar");
11fdf7f2 499 s = txn_db->Write(write_options, &batch);
7c673cae 500 ASSERT_OK(s);
11fdf7f2 501 txn_db->Delete(write_options, handles[1], "AAAZZZ");
7c673cae
FG
502
503 // These keys do no conflict with existing writes since they're in
504 // different column families
505 txn->Delete("AAA");
506 txn->GetForUpdate(snapshot_read_options, handles[1], "foo", &value);
507 Slice key_slice("AAAZZZ");
508 Slice value_slices[2] = {Slice("bar"), Slice("bar")};
509 txn->Put(handles[2], SliceParts(&key_slice, 1), SliceParts(value_slices, 2));
510
511 ASSERT_EQ(3, txn->GetNumKeys());
512
513 // Txn should commit
514 s = txn->Commit();
515 ASSERT_OK(s);
11fdf7f2 516 s = txn_db->Get(read_options, "AAA", &value);
7c673cae 517 ASSERT_TRUE(s.IsNotFound());
11fdf7f2 518 s = txn_db->Get(read_options, handles[2], "AAAZZZ", &value);
7c673cae
FG
519 ASSERT_EQ(value, "barbar");
520
521 Slice key_slices[3] = {Slice("AAA"), Slice("ZZ"), Slice("Z")};
522 Slice value_slice("barbarbar");
523 // This write will cause a conflict with the earlier batch write
524 txn2->Put(handles[1], SliceParts(key_slices, 3), SliceParts(&value_slice, 1));
525
526 txn2->Delete(handles[2], "XXX");
527 txn2->Delete(handles[1], "XXX");
528 s = txn2->GetForUpdate(snapshot_read_options, handles[1], "AAA", &value);
529 ASSERT_TRUE(s.IsNotFound());
530
531 // Verify txn did not commit
532 s = txn2->Commit();
533 ASSERT_TRUE(s.IsBusy());
11fdf7f2 534 s = txn_db->Get(read_options, handles[1], "AAAZZZ", &value);
7c673cae
FG
535 ASSERT_EQ(value, "barbar");
536
537 delete txn;
538 delete txn2;
539
540 txn = txn_db->BeginTransaction(write_options, txn_options);
541 snapshot_read_options.snapshot = txn->GetSnapshot();
542
543 txn2 = txn_db->BeginTransaction(write_options, txn_options);
544 ASSERT_TRUE(txn);
545
546 std::vector<ColumnFamilyHandle*> multiget_cfh = {handles[1], handles[2],
547 handles[0], handles[2]};
548 std::vector<Slice> multiget_keys = {"AAA", "AAAZZZ", "foo", "foo"};
549 std::vector<std::string> values(4);
550
551 std::vector<Status> results = txn->MultiGetForUpdate(
552 snapshot_read_options, multiget_cfh, multiget_keys, &values);
553 ASSERT_OK(results[0]);
554 ASSERT_OK(results[1]);
555 ASSERT_OK(results[2]);
556 ASSERT_TRUE(results[3].IsNotFound());
557 ASSERT_EQ(values[0], "bar");
558 ASSERT_EQ(values[1], "barbar");
559 ASSERT_EQ(values[2], "foo");
560
561 txn->Delete(handles[2], "ZZZ");
562 txn->Put(handles[2], "ZZZ", "YYY");
563 txn->Put(handles[2], "ZZZ", "YYYY");
564 txn->Delete(handles[2], "ZZZ");
565 txn->Put(handles[2], "AAAZZZ", "barbarbar");
566
567 ASSERT_EQ(5, txn->GetNumKeys());
568
569 // Txn should commit
570 s = txn->Commit();
571 ASSERT_OK(s);
11fdf7f2 572 s = txn_db->Get(read_options, handles[2], "ZZZ", &value);
7c673cae
FG
573 ASSERT_TRUE(s.IsNotFound());
574
575 // Put a key which will conflict with the next txn using the previous snapshot
11fdf7f2 576 txn_db->Put(write_options, handles[2], "foo", "000");
7c673cae
FG
577
578 results = txn2->MultiGetForUpdate(snapshot_read_options, multiget_cfh,
579 multiget_keys, &values);
580 ASSERT_OK(results[0]);
581 ASSERT_OK(results[1]);
582 ASSERT_OK(results[2]);
583 ASSERT_TRUE(results[3].IsNotFound());
584 ASSERT_EQ(values[0], "bar");
585 ASSERT_EQ(values[1], "barbar");
586 ASSERT_EQ(values[2], "foo");
587
588 // Verify Txn Did not Commit
589 s = txn2->Commit();
590 ASSERT_TRUE(s.IsBusy());
591
11fdf7f2 592 s = txn_db->DropColumnFamily(handles[1]);
7c673cae 593 ASSERT_OK(s);
11fdf7f2 594 s = txn_db->DropColumnFamily(handles[2]);
7c673cae
FG
595 ASSERT_OK(s);
596
597 delete txn;
598 delete txn2;
599
600 for (auto handle : handles) {
601 delete handle;
602 }
603}
604
605TEST_F(OptimisticTransactionTest, EmptyTest) {
606 WriteOptions write_options;
607 ReadOptions read_options;
608 string value;
609 Status s;
610
11fdf7f2 611 s = txn_db->Put(write_options, "aaa", "aaa");
7c673cae
FG
612 ASSERT_OK(s);
613
614 Transaction* txn = txn_db->BeginTransaction(write_options);
615 s = txn->Commit();
616 ASSERT_OK(s);
617 delete txn;
618
619 txn = txn_db->BeginTransaction(write_options);
620 txn->Rollback();
621 delete txn;
622
623 txn = txn_db->BeginTransaction(write_options);
624 s = txn->GetForUpdate(read_options, "aaa", &value);
625 ASSERT_EQ(value, "aaa");
626
627 s = txn->Commit();
628 ASSERT_OK(s);
629 delete txn;
630
631 txn = txn_db->BeginTransaction(write_options);
632 txn->SetSnapshot();
633 s = txn->GetForUpdate(read_options, "aaa", &value);
634 ASSERT_EQ(value, "aaa");
635
11fdf7f2 636 s = txn_db->Put(write_options, "aaa", "xxx");
7c673cae
FG
637 s = txn->Commit();
638 ASSERT_TRUE(s.IsBusy());
639 delete txn;
640}
641
642TEST_F(OptimisticTransactionTest, PredicateManyPreceders) {
643 WriteOptions write_options;
644 ReadOptions read_options1, read_options2;
645 OptimisticTransactionOptions txn_options;
646 string value;
647 Status s;
648
649 txn_options.set_snapshot = true;
650 Transaction* txn1 = txn_db->BeginTransaction(write_options, txn_options);
651 read_options1.snapshot = txn1->GetSnapshot();
652
653 Transaction* txn2 = txn_db->BeginTransaction(write_options);
654 txn2->SetSnapshot();
655 read_options2.snapshot = txn2->GetSnapshot();
656
657 std::vector<Slice> multiget_keys = {"1", "2", "3"};
658 std::vector<std::string> multiget_values;
659
660 std::vector<Status> results =
661 txn1->MultiGetForUpdate(read_options1, multiget_keys, &multiget_values);
662 ASSERT_TRUE(results[1].IsNotFound());
663
664 txn2->Put("2", "x");
665
666 s = txn2->Commit();
667 ASSERT_OK(s);
668
669 multiget_values.clear();
670 results =
671 txn1->MultiGetForUpdate(read_options1, multiget_keys, &multiget_values);
672 ASSERT_TRUE(results[1].IsNotFound());
673
674 // should not commit since txn2 wrote a key txn has read
675 s = txn1->Commit();
676 ASSERT_TRUE(s.IsBusy());
677
678 delete txn1;
679 delete txn2;
680
681 txn1 = txn_db->BeginTransaction(write_options, txn_options);
682 read_options1.snapshot = txn1->GetSnapshot();
683
684 txn2 = txn_db->BeginTransaction(write_options, txn_options);
685 read_options2.snapshot = txn2->GetSnapshot();
686
687 txn1->Put("4", "x");
688
689 txn2->Delete("4");
690
691 // txn1 can commit since txn2's delete hasn't happened yet (it's just batched)
692 s = txn1->Commit();
693 ASSERT_OK(s);
694
695 s = txn2->GetForUpdate(read_options2, "4", &value);
696 ASSERT_TRUE(s.IsNotFound());
697
698 // txn2 cannot commit since txn1 changed "4"
699 s = txn2->Commit();
700 ASSERT_TRUE(s.IsBusy());
701
702 delete txn1;
703 delete txn2;
704}
705
706TEST_F(OptimisticTransactionTest, LostUpdate) {
707 WriteOptions write_options;
708 ReadOptions read_options, read_options1, read_options2;
709 OptimisticTransactionOptions txn_options;
710 string value;
711 Status s;
712
713 // Test 2 transactions writing to the same key in multiple orders and
714 // with/without snapshots
715
716 Transaction* txn1 = txn_db->BeginTransaction(write_options);
717 Transaction* txn2 = txn_db->BeginTransaction(write_options);
718
719 txn1->Put("1", "1");
720 txn2->Put("1", "2");
721
722 s = txn1->Commit();
723 ASSERT_OK(s);
724
725 s = txn2->Commit();
726 ASSERT_TRUE(s.IsBusy());
727
728 delete txn1;
729 delete txn2;
730
731 txn_options.set_snapshot = true;
732 txn1 = txn_db->BeginTransaction(write_options, txn_options);
733 read_options1.snapshot = txn1->GetSnapshot();
734
735 txn2 = txn_db->BeginTransaction(write_options, txn_options);
736 read_options2.snapshot = txn2->GetSnapshot();
737
738 txn1->Put("1", "3");
739 txn2->Put("1", "4");
740
741 s = txn1->Commit();
742 ASSERT_OK(s);
743
744 s = txn2->Commit();
745 ASSERT_TRUE(s.IsBusy());
746
747 delete txn1;
748 delete txn2;
749
750 txn1 = txn_db->BeginTransaction(write_options, txn_options);
751 read_options1.snapshot = txn1->GetSnapshot();
752
753 txn2 = txn_db->BeginTransaction(write_options, txn_options);
754 read_options2.snapshot = txn2->GetSnapshot();
755
756 txn1->Put("1", "5");
757 s = txn1->Commit();
758 ASSERT_OK(s);
759
760 txn2->Put("1", "6");
761 s = txn2->Commit();
762 ASSERT_TRUE(s.IsBusy());
763
764 delete txn1;
765 delete txn2;
766
767 txn1 = txn_db->BeginTransaction(write_options, txn_options);
768 read_options1.snapshot = txn1->GetSnapshot();
769
770 txn2 = txn_db->BeginTransaction(write_options, txn_options);
771 read_options2.snapshot = txn2->GetSnapshot();
772
773 txn1->Put("1", "5");
774 s = txn1->Commit();
775 ASSERT_OK(s);
776
777 txn2->SetSnapshot();
778 txn2->Put("1", "6");
779 s = txn2->Commit();
780 ASSERT_OK(s);
781
782 delete txn1;
783 delete txn2;
784
785 txn1 = txn_db->BeginTransaction(write_options);
786 txn2 = txn_db->BeginTransaction(write_options);
787
788 txn1->Put("1", "7");
789 s = txn1->Commit();
790 ASSERT_OK(s);
791
792 txn2->Put("1", "8");
793 s = txn2->Commit();
794 ASSERT_OK(s);
795
796 delete txn1;
797 delete txn2;
798
11fdf7f2 799 s = txn_db->Get(read_options, "1", &value);
7c673cae
FG
800 ASSERT_OK(s);
801 ASSERT_EQ(value, "8");
802}
803
804TEST_F(OptimisticTransactionTest, UntrackedWrites) {
805 WriteOptions write_options;
806 ReadOptions read_options;
807 string value;
808 Status s;
809
810 // Verify transaction rollback works for untracked keys.
811 Transaction* txn = txn_db->BeginTransaction(write_options);
812 txn->PutUntracked("untracked", "0");
813 txn->Rollback();
11fdf7f2 814 s = txn_db->Get(read_options, "untracked", &value);
7c673cae
FG
815 ASSERT_TRUE(s.IsNotFound());
816
817 delete txn;
818 txn = txn_db->BeginTransaction(write_options);
819
820 txn->Put("tracked", "1");
821 txn->PutUntracked("untracked", "1");
822 txn->MergeUntracked("untracked", "2");
823 txn->DeleteUntracked("untracked");
824
825 // Write to the untracked key outside of the transaction and verify
826 // it doesn't prevent the transaction from committing.
11fdf7f2 827 s = txn_db->Put(write_options, "untracked", "x");
7c673cae
FG
828 ASSERT_OK(s);
829
830 s = txn->Commit();
831 ASSERT_OK(s);
832
11fdf7f2 833 s = txn_db->Get(read_options, "untracked", &value);
7c673cae
FG
834 ASSERT_TRUE(s.IsNotFound());
835
836 delete txn;
837 txn = txn_db->BeginTransaction(write_options);
838
839 txn->Put("tracked", "10");
840 txn->PutUntracked("untracked", "A");
841
842 // Write to tracked key outside of the transaction and verify that the
843 // untracked keys are not written when the commit fails.
11fdf7f2 844 s = txn_db->Delete(write_options, "tracked");
7c673cae
FG
845
846 s = txn->Commit();
847 ASSERT_TRUE(s.IsBusy());
848
11fdf7f2 849 s = txn_db->Get(read_options, "untracked", &value);
7c673cae
FG
850 ASSERT_TRUE(s.IsNotFound());
851
852 delete txn;
853}
854
855TEST_F(OptimisticTransactionTest, IteratorTest) {
856 WriteOptions write_options;
857 ReadOptions read_options, snapshot_read_options;
858 OptimisticTransactionOptions txn_options;
859 string value;
860 Status s;
861
862 // Write some keys to the db
11fdf7f2 863 s = txn_db->Put(write_options, "A", "a");
7c673cae
FG
864 ASSERT_OK(s);
865
11fdf7f2 866 s = txn_db->Put(write_options, "G", "g");
7c673cae
FG
867 ASSERT_OK(s);
868
11fdf7f2 869 s = txn_db->Put(write_options, "F", "f");
7c673cae
FG
870 ASSERT_OK(s);
871
11fdf7f2 872 s = txn_db->Put(write_options, "C", "c");
7c673cae
FG
873 ASSERT_OK(s);
874
11fdf7f2 875 s = txn_db->Put(write_options, "D", "d");
7c673cae
FG
876 ASSERT_OK(s);
877
878 Transaction* txn = txn_db->BeginTransaction(write_options);
879 ASSERT_TRUE(txn);
880
881 // Write some keys in a txn
882 s = txn->Put("B", "b");
883 ASSERT_OK(s);
884
885 s = txn->Put("H", "h");
886 ASSERT_OK(s);
887
888 s = txn->Delete("D");
889 ASSERT_OK(s);
890
891 s = txn->Put("E", "e");
892 ASSERT_OK(s);
893
894 txn->SetSnapshot();
895 const Snapshot* snapshot = txn->GetSnapshot();
896
897 // Write some keys to the db after the snapshot
11fdf7f2 898 s = txn_db->Put(write_options, "BB", "xx");
7c673cae
FG
899 ASSERT_OK(s);
900
11fdf7f2 901 s = txn_db->Put(write_options, "C", "xx");
7c673cae
FG
902 ASSERT_OK(s);
903
904 read_options.snapshot = snapshot;
905 Iterator* iter = txn->GetIterator(read_options);
906 ASSERT_OK(iter->status());
907 iter->SeekToFirst();
908
909 // Read all keys via iter and lock them all
910 std::string results[] = {"a", "b", "c", "e", "f", "g", "h"};
911 for (int i = 0; i < 7; i++) {
912 ASSERT_OK(iter->status());
913 ASSERT_TRUE(iter->Valid());
914 ASSERT_EQ(results[i], iter->value().ToString());
915
916 s = txn->GetForUpdate(read_options, iter->key(), nullptr);
917 ASSERT_OK(s);
918
919 iter->Next();
920 }
921 ASSERT_FALSE(iter->Valid());
922
923 iter->Seek("G");
924 ASSERT_OK(iter->status());
925 ASSERT_TRUE(iter->Valid());
926 ASSERT_EQ("g", iter->value().ToString());
927
928 iter->Prev();
929 ASSERT_OK(iter->status());
930 ASSERT_TRUE(iter->Valid());
931 ASSERT_EQ("f", iter->value().ToString());
932
933 iter->Seek("D");
934 ASSERT_OK(iter->status());
935 ASSERT_TRUE(iter->Valid());
936 ASSERT_EQ("e", iter->value().ToString());
937
938 iter->Seek("C");
939 ASSERT_OK(iter->status());
940 ASSERT_TRUE(iter->Valid());
941 ASSERT_EQ("c", iter->value().ToString());
942
943 iter->Next();
944 ASSERT_OK(iter->status());
945 ASSERT_TRUE(iter->Valid());
946 ASSERT_EQ("e", iter->value().ToString());
947
948 iter->Seek("");
949 ASSERT_OK(iter->status());
950 ASSERT_TRUE(iter->Valid());
951 ASSERT_EQ("a", iter->value().ToString());
952
953 iter->Seek("X");
954 ASSERT_OK(iter->status());
955 ASSERT_FALSE(iter->Valid());
956
957 iter->SeekToLast();
958 ASSERT_OK(iter->status());
959 ASSERT_TRUE(iter->Valid());
960 ASSERT_EQ("h", iter->value().ToString());
961
962 // key "C" was modified in the db after txn's snapshot. txn will not commit.
963 s = txn->Commit();
964 ASSERT_TRUE(s.IsBusy());
965
966 delete iter;
967 delete txn;
968}
969
970TEST_F(OptimisticTransactionTest, SavepointTest) {
971 WriteOptions write_options;
972 ReadOptions read_options, snapshot_read_options;
973 OptimisticTransactionOptions txn_options;
974 string value;
975 Status s;
976
977 Transaction* txn = txn_db->BeginTransaction(write_options);
978 ASSERT_TRUE(txn);
979
980 s = txn->RollbackToSavePoint();
981 ASSERT_TRUE(s.IsNotFound());
982
983 txn->SetSavePoint(); // 1
984
985 ASSERT_OK(txn->RollbackToSavePoint()); // Rollback to beginning of txn
986 s = txn->RollbackToSavePoint();
987 ASSERT_TRUE(s.IsNotFound());
988
989 s = txn->Put("B", "b");
990 ASSERT_OK(s);
991
992 s = txn->Commit();
993 ASSERT_OK(s);
994
11fdf7f2 995 s = txn_db->Get(read_options, "B", &value);
7c673cae
FG
996 ASSERT_OK(s);
997 ASSERT_EQ("b", value);
998
999 delete txn;
1000 txn = txn_db->BeginTransaction(write_options);
1001 ASSERT_TRUE(txn);
1002
1003 s = txn->Put("A", "a");
1004 ASSERT_OK(s);
1005
1006 s = txn->Put("B", "bb");
1007 ASSERT_OK(s);
1008
1009 s = txn->Put("C", "c");
1010 ASSERT_OK(s);
1011
1012 txn->SetSavePoint(); // 2
1013
1014 s = txn->Delete("B");
1015 ASSERT_OK(s);
1016
1017 s = txn->Put("C", "cc");
1018 ASSERT_OK(s);
1019
1020 s = txn->Put("D", "d");
1021 ASSERT_OK(s);
1022
1023 ASSERT_OK(txn->RollbackToSavePoint()); // Rollback to 2
1024
1025 s = txn->Get(read_options, "A", &value);
1026 ASSERT_OK(s);
1027 ASSERT_EQ("a", value);
1028
1029 s = txn->Get(read_options, "B", &value);
1030 ASSERT_OK(s);
1031 ASSERT_EQ("bb", value);
1032
1033 s = txn->Get(read_options, "C", &value);
1034 ASSERT_OK(s);
1035 ASSERT_EQ("c", value);
1036
1037 s = txn->Get(read_options, "D", &value);
1038 ASSERT_TRUE(s.IsNotFound());
1039
1040 s = txn->Put("A", "a");
1041 ASSERT_OK(s);
1042
1043 s = txn->Put("E", "e");
1044 ASSERT_OK(s);
1045
1046 // Rollback to beginning of txn
1047 s = txn->RollbackToSavePoint();
1048 ASSERT_TRUE(s.IsNotFound());
1049 txn->Rollback();
1050
1051 s = txn->Get(read_options, "A", &value);
1052 ASSERT_TRUE(s.IsNotFound());
1053
1054 s = txn->Get(read_options, "B", &value);
1055 ASSERT_OK(s);
1056 ASSERT_EQ("b", value);
1057
1058 s = txn->Get(read_options, "D", &value);
1059 ASSERT_TRUE(s.IsNotFound());
1060
1061 s = txn->Get(read_options, "D", &value);
1062 ASSERT_TRUE(s.IsNotFound());
1063
1064 s = txn->Get(read_options, "E", &value);
1065 ASSERT_TRUE(s.IsNotFound());
1066
1067 s = txn->Put("A", "aa");
1068 ASSERT_OK(s);
1069
1070 s = txn->Put("F", "f");
1071 ASSERT_OK(s);
1072
1073 txn->SetSavePoint(); // 3
1074 txn->SetSavePoint(); // 4
1075
1076 s = txn->Put("G", "g");
1077 ASSERT_OK(s);
1078
1079 s = txn->Delete("F");
1080 ASSERT_OK(s);
1081
1082 s = txn->Delete("B");
1083 ASSERT_OK(s);
1084
1085 s = txn->Get(read_options, "A", &value);
1086 ASSERT_OK(s);
1087 ASSERT_EQ("aa", value);
1088
1089 s = txn->Get(read_options, "F", &value);
1090 ASSERT_TRUE(s.IsNotFound());
1091
1092 s = txn->Get(read_options, "B", &value);
1093 ASSERT_TRUE(s.IsNotFound());
1094
1095 ASSERT_OK(txn->RollbackToSavePoint()); // Rollback to 3
1096
1097 s = txn->Get(read_options, "F", &value);
1098 ASSERT_OK(s);
1099 ASSERT_EQ("f", value);
1100
1101 s = txn->Get(read_options, "G", &value);
1102 ASSERT_TRUE(s.IsNotFound());
1103
1104 s = txn->Commit();
1105 ASSERT_OK(s);
1106
11fdf7f2 1107 s = txn_db->Get(read_options, "F", &value);
7c673cae
FG
1108 ASSERT_OK(s);
1109 ASSERT_EQ("f", value);
1110
11fdf7f2 1111 s = txn_db->Get(read_options, "G", &value);
7c673cae
FG
1112 ASSERT_TRUE(s.IsNotFound());
1113
11fdf7f2 1114 s = txn_db->Get(read_options, "A", &value);
7c673cae
FG
1115 ASSERT_OK(s);
1116 ASSERT_EQ("aa", value);
1117
11fdf7f2 1118 s = txn_db->Get(read_options, "B", &value);
7c673cae
FG
1119 ASSERT_OK(s);
1120 ASSERT_EQ("b", value);
1121
11fdf7f2 1122 s = txn_db->Get(read_options, "C", &value);
7c673cae
FG
1123 ASSERT_TRUE(s.IsNotFound());
1124
11fdf7f2 1125 s = txn_db->Get(read_options, "D", &value);
7c673cae
FG
1126 ASSERT_TRUE(s.IsNotFound());
1127
11fdf7f2 1128 s = txn_db->Get(read_options, "E", &value);
7c673cae
FG
1129 ASSERT_TRUE(s.IsNotFound());
1130
1131 delete txn;
1132}
1133
1134TEST_F(OptimisticTransactionTest, UndoGetForUpdateTest) {
1135 WriteOptions write_options;
1136 ReadOptions read_options, snapshot_read_options;
1137 OptimisticTransactionOptions txn_options;
1138 string value;
1139 Status s;
1140
11fdf7f2 1141 txn_db->Put(write_options, "A", "");
7c673cae
FG
1142
1143 Transaction* txn1 = txn_db->BeginTransaction(write_options);
1144 ASSERT_TRUE(txn1);
1145
1146 s = txn1->GetForUpdate(read_options, "A", &value);
1147 ASSERT_OK(s);
1148
1149 txn1->UndoGetForUpdate("A");
1150
1151 Transaction* txn2 = txn_db->BeginTransaction(write_options);
1152 txn2->Put("A", "x");
1153 s = txn2->Commit();
1154 ASSERT_OK(s);
1155 delete txn2;
1156
1157 // Verify that txn1 can commit since A isn't conflict checked
1158 s = txn1->Commit();
1159 ASSERT_OK(s);
1160 delete txn1;
1161
1162 txn1 = txn_db->BeginTransaction(write_options);
1163 txn1->Put("A", "a");
1164
1165 s = txn1->GetForUpdate(read_options, "A", &value);
1166 ASSERT_OK(s);
1167
1168 txn1->UndoGetForUpdate("A");
1169
1170 txn2 = txn_db->BeginTransaction(write_options);
1171 txn2->Put("A", "x");
1172 s = txn2->Commit();
1173 ASSERT_OK(s);
1174 delete txn2;
1175
1176 // Verify that txn1 cannot commit since A will still be conflict checked
1177 s = txn1->Commit();
1178 ASSERT_TRUE(s.IsBusy());
1179 delete txn1;
1180
1181 txn1 = txn_db->BeginTransaction(write_options);
1182
1183 s = txn1->GetForUpdate(read_options, "A", &value);
1184 ASSERT_OK(s);
1185 s = txn1->GetForUpdate(read_options, "A", &value);
1186 ASSERT_OK(s);
1187
1188 txn1->UndoGetForUpdate("A");
1189
1190 txn2 = txn_db->BeginTransaction(write_options);
1191 txn2->Put("A", "x");
1192 s = txn2->Commit();
1193 ASSERT_OK(s);
1194 delete txn2;
1195
1196 // Verify that txn1 cannot commit since A will still be conflict checked
1197 s = txn1->Commit();
1198 ASSERT_TRUE(s.IsBusy());
1199 delete txn1;
1200
1201 txn1 = txn_db->BeginTransaction(write_options);
1202
1203 s = txn1->GetForUpdate(read_options, "A", &value);
1204 ASSERT_OK(s);
1205 s = txn1->GetForUpdate(read_options, "A", &value);
1206 ASSERT_OK(s);
1207
1208 txn1->UndoGetForUpdate("A");
1209 txn1->UndoGetForUpdate("A");
1210
1211 txn2 = txn_db->BeginTransaction(write_options);
1212 txn2->Put("A", "x");
1213 s = txn2->Commit();
1214 ASSERT_OK(s);
1215 delete txn2;
1216
1217 // Verify that txn1 can commit since A isn't conflict checked
1218 s = txn1->Commit();
1219 ASSERT_OK(s);
1220 delete txn1;
1221
1222 txn1 = txn_db->BeginTransaction(write_options);
1223
1224 s = txn1->GetForUpdate(read_options, "A", &value);
1225 ASSERT_OK(s);
1226
1227 txn1->SetSavePoint();
1228 txn1->UndoGetForUpdate("A");
1229
1230 txn2 = txn_db->BeginTransaction(write_options);
1231 txn2->Put("A", "x");
1232 s = txn2->Commit();
1233 ASSERT_OK(s);
1234 delete txn2;
1235
1236 // Verify that txn1 cannot commit since A will still be conflict checked
1237 s = txn1->Commit();
1238 ASSERT_TRUE(s.IsBusy());
1239 delete txn1;
1240
1241 txn1 = txn_db->BeginTransaction(write_options);
1242
1243 s = txn1->GetForUpdate(read_options, "A", &value);
1244 ASSERT_OK(s);
1245
1246 txn1->SetSavePoint();
1247 s = txn1->GetForUpdate(read_options, "A", &value);
1248 ASSERT_OK(s);
1249 txn1->UndoGetForUpdate("A");
1250
1251 txn2 = txn_db->BeginTransaction(write_options);
1252 txn2->Put("A", "x");
1253 s = txn2->Commit();
1254 ASSERT_OK(s);
1255 delete txn2;
1256
1257 // Verify that txn1 cannot commit since A will still be conflict checked
1258 s = txn1->Commit();
1259 ASSERT_TRUE(s.IsBusy());
1260 delete txn1;
1261
1262 txn1 = txn_db->BeginTransaction(write_options);
1263
1264 s = txn1->GetForUpdate(read_options, "A", &value);
1265 ASSERT_OK(s);
1266
1267 txn1->SetSavePoint();
1268 s = txn1->GetForUpdate(read_options, "A", &value);
1269 ASSERT_OK(s);
1270 txn1->UndoGetForUpdate("A");
1271
1272 txn1->RollbackToSavePoint();
1273 txn1->UndoGetForUpdate("A");
1274
1275 txn2 = txn_db->BeginTransaction(write_options);
1276 txn2->Put("A", "x");
1277 s = txn2->Commit();
1278 ASSERT_OK(s);
1279 delete txn2;
1280
1281 // Verify that txn1 can commit since A isn't conflict checked
1282 s = txn1->Commit();
1283 ASSERT_OK(s);
1284 delete txn1;
1285}
1286
1287namespace {
1288Status OptimisticTransactionStressTestInserter(OptimisticTransactionDB* db,
1289 const size_t num_transactions,
1290 const size_t num_sets,
1291 const size_t num_keys_per_set) {
1292 size_t seed = std::hash<std::thread::id>()(std::this_thread::get_id());
1293 Random64 _rand(seed);
1294 WriteOptions write_options;
1295 ReadOptions read_options;
1296 OptimisticTransactionOptions txn_options;
1297 txn_options.set_snapshot = true;
1298
1299 RandomTransactionInserter inserter(&_rand, write_options, read_options,
1300 num_keys_per_set,
1301 static_cast<uint16_t>(num_sets));
1302
1303 for (size_t t = 0; t < num_transactions; t++) {
1304 bool success = inserter.OptimisticTransactionDBInsert(db, txn_options);
1305 if (!success) {
1306 // unexpected failure
1307 return inserter.GetLastStatus();
1308 }
1309 }
1310
1311 // Make sure at least some of the transactions succeeded. It's ok if
1312 // some failed due to write-conflicts.
1313 if (inserter.GetFailureCount() > num_transactions / 2) {
1314 return Status::TryAgain("Too many transactions failed! " +
1315 std::to_string(inserter.GetFailureCount()) + " / " +
1316 std::to_string(num_transactions));
1317 }
1318
1319 return Status::OK();
1320}
1321} // namespace
1322
1323TEST_F(OptimisticTransactionTest, OptimisticTransactionStressTest) {
1324 const size_t num_threads = 4;
1325 const size_t num_transactions_per_thread = 10000;
1326 const size_t num_sets = 3;
1327 const size_t num_keys_per_set = 100;
1328 // Setting the key-space to be 100 keys should cause enough write-conflicts
1329 // to make this test interesting.
1330
1331 std::vector<port::Thread> threads;
1332
1333 std::function<void()> call_inserter = [&] {
1334 ASSERT_OK(OptimisticTransactionStressTestInserter(
1335 txn_db, num_transactions_per_thread, num_sets, num_keys_per_set));
1336 };
1337
1338 // Create N threads that use RandomTransactionInserter to write
1339 // many transactions.
1340 for (uint32_t i = 0; i < num_threads; i++) {
1341 threads.emplace_back(call_inserter);
1342 }
1343
1344 // Wait for all threads to run
1345 for (auto& t : threads) {
1346 t.join();
1347 }
1348
1349 // Verify that data is consistent
11fdf7f2 1350 Status s = RandomTransactionInserter::Verify(txn_db, num_sets);
7c673cae
FG
1351 ASSERT_OK(s);
1352}
1353
1354TEST_F(OptimisticTransactionTest, SequenceNumberAfterRecoverTest) {
1355 WriteOptions write_options;
1356 OptimisticTransactionOptions transaction_options;
1357
1358 Transaction* transaction(txn_db->BeginTransaction(write_options, transaction_options));
1359 Status s = transaction->Put("foo", "val");
1360 ASSERT_OK(s);
1361 s = transaction->Put("foo2", "val");
1362 ASSERT_OK(s);
1363 s = transaction->Put("foo3", "val");
1364 ASSERT_OK(s);
1365 s = transaction->Commit();
1366 ASSERT_OK(s);
1367 delete transaction;
1368
1369 Reopen();
1370 transaction = txn_db->BeginTransaction(write_options, transaction_options);
1371 s = transaction->Put("bar", "val");
1372 ASSERT_OK(s);
1373 s = transaction->Put("bar2", "val");
1374 ASSERT_OK(s);
1375 s = transaction->Commit();
1376 ASSERT_OK(s);
1377
1378 delete transaction;
1379}
1380
1381} // namespace rocksdb
1382
1383int main(int argc, char** argv) {
1384 ::testing::InitGoogleTest(&argc, argv);
1385 return RUN_ALL_TESTS();
1386}
1387
1388#else
1389#include <stdio.h>
1390
11fdf7f2 1391int main(int /*argc*/, char** /*argv*/) {
7c673cae
FG
1392 fprintf(
1393 stderr,
1394 "SKIPPED as optimistic_transaction is not supported in ROCKSDB_LITE\n");
1395 return 0;
1396}
1397
1398#endif // !ROCKSDB_LITE