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