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/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 TransactionDBOptions txn_db_options;
22 options.create_if_missing = true;
23 TransactionDB* txn_db;
24
25 Status s = TransactionDB::Open(options, txn_db_options, kDBPath, &txn_db);
26 assert(s.ok());
27
28 WriteOptions write_options;
29 ReadOptions read_options;
30 TransactionOptions txn_options;
31 std::string value;
32
33 ////////////////////////////////////////////////////////
34 //
35 // Simple Transaction Example ("Read Committed")
36 //
37 ////////////////////////////////////////////////////////
38
39 // Start a transaction
40 Transaction* txn = txn_db->BeginTransaction(write_options);
41 assert(txn);
42
43 // Read a key in this transaction
44 s = txn->Get(read_options, "abc", &value);
45 assert(s.IsNotFound());
46
47 // Write a key in this transaction
48 s = txn->Put("abc", "def");
49 assert(s.ok());
50
51 // Read a key OUTSIDE this transaction. Does not affect txn.
52 s = txn_db->Get(read_options, "abc", &value);
53 assert(s.IsNotFound());
54
55 // Write a key OUTSIDE of this transaction.
56 // Does not affect txn since this is an unrelated key.
57 s = txn_db->Put(write_options, "xyz", "zzz");
58 assert(s.ok());
59
60 // Write a key OUTSIDE of this transaction.
61 // Fail because the key conflicts with the key written in txn.
62 s = txn_db->Put(write_options, "abc", "def");
63 assert(s.subcode() == Status::kLockTimeout);
64
65 // Value for key "xyz" has been committed, can be read in txn.
66 s = txn->Get(read_options, "xyz", &value);
67 assert(s.ok());
68 assert(value == "zzz");
69
70 // Commit transaction
71 s = txn->Commit();
72 assert(s.ok());
73 delete txn;
74
75 // Value is committed, can be read now.
76 s = txn_db->Get(read_options, "abc", &value);
77 assert(s.ok());
78 assert(value == "def");
79
80 ////////////////////////////////////////////////////////
81 //
82 // "Repeatable Read" (Snapshot Isolation) Example
83 // -- Using a single Snapshot
84 //
85 ////////////////////////////////////////////////////////
86
87 // Set a snapshot at start of transaction by setting set_snapshot=true
88 txn_options.set_snapshot = true;
89 txn = txn_db->BeginTransaction(write_options, txn_options);
90
91 const Snapshot* snapshot = txn->GetSnapshot();
92
93 // Write a key OUTSIDE of transaction
94 s = txn_db->Put(write_options, "abc", "xyz");
95 assert(s.ok());
96
97 // Read the latest committed value.
98 s = txn->Get(read_options, "abc", &value);
99 assert(s.ok());
100 assert(value == "xyz");
101
102 // Read the snapshotted value.
103 read_options.snapshot = snapshot;
104 s = txn->Get(read_options, "abc", &value);
105 assert(s.ok());
106 assert(value == "def");
107
108 // Attempt to read a key using the snapshot. This will fail since
109 // the previous write outside this txn conflicts with this read.
110 s = txn->GetForUpdate(read_options, "abc", &value);
111 assert(s.IsBusy());
112
113 txn->Rollback();
114
115 // Snapshot will be released upon deleting the transaction.
116 delete txn;
117 // Clear snapshot from read options since it is no longer valid
118 read_options.snapshot = nullptr;
119 snapshot = nullptr;
120
121 ////////////////////////////////////////////////////////
122 //
123 // "Read Committed" (Monotonic Atomic Views) Example
124 // --Using multiple Snapshots
125 //
126 ////////////////////////////////////////////////////////
127
128 // In this example, we set the snapshot multiple times. This is probably
129 // only necessary if you have very strict isolation requirements to
130 // implement.
131
132 // Set a snapshot at start of transaction
133 txn_options.set_snapshot = true;
134 txn = txn_db->BeginTransaction(write_options, txn_options);
135
136 // Do some reads and writes to key "x"
137 read_options.snapshot = txn_db->GetSnapshot();
138 s = txn->Get(read_options, "x", &value);
139 assert(s.IsNotFound());
140 s = txn->Put("x", "x");
141 assert(s.ok());
142
143 // Do a write outside of the transaction to key "y"
144 s = txn_db->Put(write_options, "y", "y1");
145 assert(s.ok());
146
147 // Set a new snapshot in the transaction
148 txn->SetSnapshot();
149 txn->SetSavePoint();
150 read_options.snapshot = txn_db->GetSnapshot();
151
152 // Do some reads and writes to key "y"
153 // Since the snapshot was advanced, the write done outside of the
154 // transaction does not conflict.
155 s = txn->GetForUpdate(read_options, "y", &value);
156 assert(s.ok());
157 assert(value == "y1");
158 s = txn->Put("y", "y2");
159 assert(s.ok());
160
161 // Decide we want to revert the last write from this transaction.
162 txn->RollbackToSavePoint();
163
164 // Commit.
165 s = txn->Commit();
166 assert(s.ok());
167 delete txn;
168 // Clear snapshot from read options since it is no longer valid
169 read_options.snapshot = nullptr;
170
171 // db state is at the save point.
172 s = txn_db->Get(read_options, "x", &value);
173 assert(s.ok());
174 assert(value == "x");
175
176 s = txn_db->Get(read_options, "y", &value);
177 assert(s.ok());
178 assert(value == "y1");
179
180 // Cleanup
181 delete txn_db;
182 DestroyDB(kDBPath, options);
183 return 0;
184 }
185
186 #endif // ROCKSDB_LITE
187