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 
6 #ifndef ROCKSDB_LITE
7 
8 #include "rocksdb/db.h"
9 #include "rocksdb/options.h"
10 #include "rocksdb/slice.h"
11 #include "rocksdb/utilities/transaction.h"
12 #include "rocksdb/utilities/optimistic_transaction_db.h"
13 
14 using namespace ROCKSDB_NAMESPACE;
15 
16 std::string kDBPath = "/tmp/rocksdb_transaction_example";
17 
main()18 int main() {
19   // open DB
20   Options options;
21   options.create_if_missing = true;
22   DB* db;
23   OptimisticTransactionDB* txn_db;
24 
25   Status s = OptimisticTransactionDB::Open(options, kDBPath, &txn_db);
26   assert(s.ok());
27   db = txn_db->GetBaseDB();
28 
29   WriteOptions write_options;
30   ReadOptions read_options;
31   OptimisticTransactionOptions txn_options;
32   std::string value;
33 
34   ////////////////////////////////////////////////////////
35   //
36   // Simple OptimisticTransaction Example ("Read Committed")
37   //
38   ////////////////////////////////////////////////////////
39 
40   // Start a transaction
41   Transaction* txn = txn_db->BeginTransaction(write_options);
42   assert(txn);
43 
44   // Read a key in this transaction
45   s = txn->Get(read_options, "abc", &value);
46   assert(s.IsNotFound());
47 
48   // Write a key in this transaction
49   s = txn->Put("abc", "xyz");
50   assert(s.ok());
51 
52   // Read a key OUTSIDE this transaction. Does not affect txn.
53   s = db->Get(read_options, "abc", &value);
54   assert(s.IsNotFound());
55 
56   // Write a key OUTSIDE of this transaction.
57   // Does not affect txn since this is an unrelated key.  If we wrote key 'abc'
58   // here, the transaction would fail to commit.
59   s = db->Put(write_options, "xyz", "zzz");
60   assert(s.ok());
61   s = db->Put(write_options, "abc", "def");
62   assert(s.ok());
63 
64   // Commit transaction
65   s = txn->Commit();
66   assert(s.IsBusy());
67   delete txn;
68 
69   s = db->Get(read_options, "xyz", &value);
70   assert(s.ok());
71   assert(value == "zzz");
72 
73   s = db->Get(read_options, "abc", &value);
74   assert(s.ok());
75   assert(value == "def");
76 
77   ////////////////////////////////////////////////////////
78   //
79   // "Repeatable Read" (Snapshot Isolation) Example
80   //   -- Using a single Snapshot
81   //
82   ////////////////////////////////////////////////////////
83 
84   // Set a snapshot at start of transaction by setting set_snapshot=true
85   txn_options.set_snapshot = true;
86   txn = txn_db->BeginTransaction(write_options, txn_options);
87 
88   const Snapshot* snapshot = txn->GetSnapshot();
89 
90   // Write a key OUTSIDE of transaction
91   s = db->Put(write_options, "abc", "xyz");
92   assert(s.ok());
93 
94   // Read a key using the snapshot
95   read_options.snapshot = snapshot;
96   s = txn->GetForUpdate(read_options, "abc", &value);
97   assert(s.ok());
98   assert(value == "def");
99 
100   // Attempt to commit transaction
101   s = txn->Commit();
102 
103   // Transaction could not commit since the write outside of the txn conflicted
104   // with the read!
105   assert(s.IsBusy());
106 
107   delete txn;
108   // Clear snapshot from read options since it is no longer valid
109   read_options.snapshot = nullptr;
110   snapshot = nullptr;
111 
112   s = db->Get(read_options, "abc", &value);
113   assert(s.ok());
114   assert(value == "xyz");
115 
116   ////////////////////////////////////////////////////////
117   //
118   // "Read Committed" (Monotonic Atomic Views) Example
119   //   --Using multiple Snapshots
120   //
121   ////////////////////////////////////////////////////////
122 
123   // In this example, we set the snapshot multiple times.  This is probably
124   // only necessary if you have very strict isolation requirements to
125   // implement.
126 
127   // Set a snapshot at start of transaction
128   txn_options.set_snapshot = true;
129   txn = txn_db->BeginTransaction(write_options, txn_options);
130 
131   // Do some reads and writes to key "x"
132   read_options.snapshot = db->GetSnapshot();
133   s = txn->Get(read_options, "x", &value);
134   assert(s.IsNotFound());
135   s = txn->Put("x", "x");
136   assert(s.ok());
137 
138   // The transaction hasn't committed, so the write is not visible
139   // outside of txn.
140   s = db->Get(read_options, "x", &value);
141   assert(s.IsNotFound());
142 
143   // Do a write outside of the transaction to key "y"
144   s = db->Put(write_options, "y", "z");
145   assert(s.ok());
146 
147   // Set a new snapshot in the transaction
148   txn->SetSnapshot();
149   read_options.snapshot = db->GetSnapshot();
150 
151   // Do some reads and writes to key "y"
152   s = txn->GetForUpdate(read_options, "y", &value);
153   assert(s.ok());
154   assert(value == "z");
155   txn->Put("y", "y");
156 
157   // Commit.  Since the snapshot was advanced, the write done outside of the
158   // transaction does not prevent this transaction from Committing.
159   s = txn->Commit();
160   assert(s.ok());
161   delete txn;
162   // Clear snapshot from read options since it is no longer valid
163   read_options.snapshot = nullptr;
164 
165   // txn is committed, read the latest values.
166   s = db->Get(read_options, "x", &value);
167   assert(s.ok());
168   assert(value == "x");
169 
170   s = db->Get(read_options, "y", &value);
171   assert(s.ok());
172   assert(value == "y");
173 
174   // Cleanup
175   delete txn_db;
176   DestroyDB(kDBPath, options);
177   return 0;
178 }
179 
180 #endif  // ROCKSDB_LITE
181