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