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