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