YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

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