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 import org.rocksdb.*;
7 
8 import static java.nio.charset.StandardCharsets.UTF_8;
9 
10 /**
11  * Demonstrates using Transactions on a TransactionDB with
12  * varying isolation guarantees
13  */
14 public class TransactionSample {
15   private static final String dbPath = "/tmp/rocksdb_transaction_example";
16 
main(final String args[])17   public static final void main(final String args[]) throws RocksDBException {
18 
19     try(final Options options = new Options()
20         .setCreateIfMissing(true);
21         final TransactionDBOptions txnDbOptions = new TransactionDBOptions();
22         final TransactionDB txnDb =
23             TransactionDB.open(options, txnDbOptions, dbPath)) {
24 
25       try (final WriteOptions writeOptions = new WriteOptions();
26            final ReadOptions readOptions = new ReadOptions()) {
27 
28         ////////////////////////////////////////////////////////
29         //
30         // Simple Transaction Example ("Read Committed")
31         //
32         ////////////////////////////////////////////////////////
33         readCommitted(txnDb, writeOptions, readOptions);
34 
35 
36         ////////////////////////////////////////////////////////
37         //
38         // "Repeatable Read" (Snapshot Isolation) Example
39         //   -- Using a single Snapshot
40         //
41         ////////////////////////////////////////////////////////
42         repeatableRead(txnDb, writeOptions, readOptions);
43 
44 
45         ////////////////////////////////////////////////////////
46         //
47         // "Read Committed" (Monotonic Atomic Views) Example
48         //   --Using multiple Snapshots
49         //
50         ////////////////////////////////////////////////////////
51         readCommitted_monotonicAtomicViews(txnDb, writeOptions, readOptions);
52       }
53     }
54   }
55 
56   /**
57    * Demonstrates "Read Committed" isolation
58    */
readCommitted(final TransactionDB txnDb, final WriteOptions writeOptions, final ReadOptions readOptions)59   private static void readCommitted(final TransactionDB txnDb,
60       final WriteOptions writeOptions, final ReadOptions readOptions)
61       throws RocksDBException {
62     final byte key1[] = "abc".getBytes(UTF_8);
63     final byte value1[] = "def".getBytes(UTF_8);
64 
65     final byte key2[] = "xyz".getBytes(UTF_8);
66     final byte value2[] = "zzz".getBytes(UTF_8);
67 
68     // Start a transaction
69     try(final Transaction txn = txnDb.beginTransaction(writeOptions)) {
70       // Read a key in this transaction
71       byte[] value = txn.get(readOptions, key1);
72       assert(value == null);
73 
74       // Write a key in this transaction
75       txn.put(key1, value1);
76 
77       // Read a key OUTSIDE this transaction. Does not affect txn.
78       value = txnDb.get(readOptions, key1);
79       assert(value == null);
80 
81       // Write a key OUTSIDE of this transaction.
82       // Does not affect txn since this is an unrelated key.
83       // If we wrote key 'abc' here, the transaction would fail to commit.
84       txnDb.put(writeOptions, key2, value2);
85 
86       // Commit transaction
87       txn.commit();
88     }
89   }
90 
91   /**
92    * Demonstrates "Repeatable Read" (Snapshot Isolation) isolation
93    */
repeatableRead(final TransactionDB txnDb, final WriteOptions writeOptions, final ReadOptions readOptions)94   private static void repeatableRead(final TransactionDB txnDb,
95       final WriteOptions writeOptions, final ReadOptions readOptions)
96       throws RocksDBException {
97 
98     final byte key1[] = "ghi".getBytes(UTF_8);
99     final byte value1[] = "jkl".getBytes(UTF_8);
100 
101     // Set a snapshot at start of transaction by setting setSnapshot(true)
102     try(final TransactionOptions txnOptions = new TransactionOptions()
103           .setSetSnapshot(true);
104         final Transaction txn =
105             txnDb.beginTransaction(writeOptions, txnOptions)) {
106 
107       final Snapshot snapshot = txn.getSnapshot();
108 
109       // Write a key OUTSIDE of transaction
110       txnDb.put(writeOptions, key1, value1);
111 
112       // Attempt to read a key using the snapshot.  This will fail since
113       // the previous write outside this txn conflicts with this read.
114       readOptions.setSnapshot(snapshot);
115 
116       try {
117         final byte[] value = txn.getForUpdate(readOptions, key1, true);
118         throw new IllegalStateException();
119       } catch(final RocksDBException e) {
120         assert(e.getStatus().getCode() == Status.Code.Busy);
121       }
122 
123       txn.rollback();
124     } finally {
125       // Clear snapshot from read options since it is no longer valid
126       readOptions.setSnapshot(null);
127     }
128   }
129 
130   /**
131    * Demonstrates "Read Committed" (Monotonic Atomic Views) isolation
132    *
133    * In this example, we set the snapshot multiple times.  This is probably
134    * only necessary if you have very strict isolation requirements to
135    * implement.
136    */
readCommitted_monotonicAtomicViews( final TransactionDB txnDb, final WriteOptions writeOptions, final ReadOptions readOptions)137   private static void readCommitted_monotonicAtomicViews(
138       final TransactionDB txnDb, final WriteOptions writeOptions,
139       final ReadOptions readOptions) throws RocksDBException {
140 
141     final byte keyX[] = "x".getBytes(UTF_8);
142     final byte valueX[] = "x".getBytes(UTF_8);
143 
144     final byte keyY[] = "y".getBytes(UTF_8);
145     final byte valueY[] = "y".getBytes(UTF_8);
146 
147     try (final TransactionOptions txnOptions = new TransactionOptions()
148         .setSetSnapshot(true);
149          final Transaction txn =
150              txnDb.beginTransaction(writeOptions, txnOptions)) {
151 
152       // Do some reads and writes to key "x"
153       Snapshot snapshot = txnDb.getSnapshot();
154       readOptions.setSnapshot(snapshot);
155       byte[] value = txn.get(readOptions, keyX);
156       txn.put(valueX, valueX);
157 
158       // Do a write outside of the transaction to key "y"
159       txnDb.put(writeOptions, keyY, valueY);
160 
161       // Set a new snapshot in the transaction
162       txn.setSnapshot();
163       txn.setSavePoint();
164       snapshot = txnDb.getSnapshot();
165       readOptions.setSnapshot(snapshot);
166 
167       // Do some reads and writes to key "y"
168       // Since the snapshot was advanced, the write done outside of the
169       // transaction does not conflict.
170       value = txn.getForUpdate(readOptions, keyY, true);
171       txn.put(keyY, valueY);
172 
173       // Decide we want to revert the last write from this transaction.
174       txn.rollbackToSavePoint();
175 
176       // Commit.
177       txn.commit();
178     } finally {
179       // Clear snapshot from read options since it is no longer valid
180       readOptions.setSnapshot(null);
181     }
182   }
183 }
184