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 package org.rocksdb;
7 
8 import java.util.List;
9 
10 /**
11  * Database with Transaction support.
12  */
13 public class OptimisticTransactionDB extends RocksDB
14     implements TransactionalDB<OptimisticTransactionOptions> {
15 
16   /**
17    * Private constructor.
18    *
19    * @param nativeHandle The native handle of the C++ OptimisticTransactionDB
20    *     object
21    */
OptimisticTransactionDB(final long nativeHandle)22   private OptimisticTransactionDB(final long nativeHandle) {
23     super(nativeHandle);
24   }
25 
26   /**
27    * Open an OptimisticTransactionDB similar to
28    * {@link RocksDB#open(Options, String)}.
29    *
30    * @param options {@link org.rocksdb.Options} instance.
31    * @param path the path to the rocksdb.
32    *
33    * @return a {@link OptimisticTransactionDB} instance on success, null if the
34    * specified {@link OptimisticTransactionDB} can not be opened.
35    *
36    * @throws RocksDBException if an error occurs whilst opening the database.
37    */
open(final Options options, final String path)38   public static OptimisticTransactionDB open(final Options options,
39       final String path) throws RocksDBException {
40     final OptimisticTransactionDB otdb = new OptimisticTransactionDB(open(
41         options.nativeHandle_, path));
42 
43     // when non-default Options is used, keeping an Options reference
44     // in RocksDB can prevent Java to GC during the life-time of
45     // the currently-created RocksDB.
46     otdb.storeOptionsInstance(options);
47 
48     return otdb;
49   }
50 
51   /**
52    * Open an OptimisticTransactionDB similar to
53    * {@link RocksDB#open(DBOptions, String, List, List)}.
54    *
55    * @param dbOptions {@link org.rocksdb.DBOptions} instance.
56    * @param path the path to the rocksdb.
57    * @param columnFamilyDescriptors list of column family descriptors
58    * @param columnFamilyHandles will be filled with ColumnFamilyHandle instances
59    *
60    * @return a {@link OptimisticTransactionDB} instance on success, null if the
61    *     specified {@link OptimisticTransactionDB} can not be opened.
62    *
63    * @throws RocksDBException if an error occurs whilst opening the database.
64    */
open(final DBOptions dbOptions, final String path, final List<ColumnFamilyDescriptor> columnFamilyDescriptors, final List<ColumnFamilyHandle> columnFamilyHandles)65   public static OptimisticTransactionDB open(final DBOptions dbOptions,
66       final String path,
67       final List<ColumnFamilyDescriptor> columnFamilyDescriptors,
68       final List<ColumnFamilyHandle> columnFamilyHandles)
69       throws RocksDBException {
70 
71     final byte[][] cfNames = new byte[columnFamilyDescriptors.size()][];
72     final long[] cfOptionHandles = new long[columnFamilyDescriptors.size()];
73     for (int i = 0; i < columnFamilyDescriptors.size(); i++) {
74       final ColumnFamilyDescriptor cfDescriptor = columnFamilyDescriptors
75           .get(i);
76       cfNames[i] = cfDescriptor.getName();
77       cfOptionHandles[i] = cfDescriptor.getOptions().nativeHandle_;
78     }
79 
80     final long[] handles = open(dbOptions.nativeHandle_, path, cfNames,
81         cfOptionHandles);
82     final OptimisticTransactionDB otdb =
83         new OptimisticTransactionDB(handles[0]);
84 
85     // when non-default Options is used, keeping an Options reference
86     // in RocksDB can prevent Java to GC during the life-time of
87     // the currently-created RocksDB.
88     otdb.storeOptionsInstance(dbOptions);
89 
90     for (int i = 1; i < handles.length; i++) {
91       columnFamilyHandles.add(new ColumnFamilyHandle(otdb, handles[i]));
92     }
93 
94     return otdb;
95   }
96 
97 
98   /**
99    * This is similar to {@link #close()} except that it
100    * throws an exception if any error occurs.
101    *
102    * This will not fsync the WAL files.
103    * If syncing is required, the caller must first call {@link #syncWal()}
104    * or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
105    * with {@link WriteOptions#setSync(boolean)} set to true.
106    *
107    * See also {@link #close()}.
108    *
109    * @throws RocksDBException if an error occurs whilst closing.
110    */
closeE()111   public void closeE() throws RocksDBException {
112     if (owningHandle_.compareAndSet(true, false)) {
113       try {
114         closeDatabase(nativeHandle_);
115       } finally {
116         disposeInternal();
117       }
118     }
119   }
120 
121   /**
122    * This is similar to {@link #closeE()} except that it
123    * silently ignores any errors.
124    *
125    * This will not fsync the WAL files.
126    * If syncing is required, the caller must first call {@link #syncWal()}
127    * or {@link #write(WriteOptions, WriteBatch)} using an empty write batch
128    * with {@link WriteOptions#setSync(boolean)} set to true.
129    *
130    * See also {@link #close()}.
131    */
132   @Override
close()133   public void close() {
134     if (owningHandle_.compareAndSet(true, false)) {
135       try {
136         closeDatabase(nativeHandle_);
137       } catch (final RocksDBException e) {
138         // silently ignore the error report
139       } finally {
140         disposeInternal();
141       }
142     }
143   }
144 
145   @Override
beginTransaction(final WriteOptions writeOptions)146   public Transaction beginTransaction(final WriteOptions writeOptions) {
147     return new Transaction(this, beginTransaction(nativeHandle_,
148         writeOptions.nativeHandle_));
149   }
150 
151   @Override
beginTransaction(final WriteOptions writeOptions, final OptimisticTransactionOptions optimisticTransactionOptions)152   public Transaction beginTransaction(final WriteOptions writeOptions,
153       final OptimisticTransactionOptions optimisticTransactionOptions) {
154     return new Transaction(this, beginTransaction(nativeHandle_,
155         writeOptions.nativeHandle_,
156         optimisticTransactionOptions.nativeHandle_));
157   }
158 
159   // TODO(AR) consider having beingTransaction(... oldTransaction) set a
160   // reference count inside Transaction, so that we can always call
161   // Transaction#close but the object is only disposed when there are as many
162   // closes as beginTransaction. Makes the try-with-resources paradigm easier for
163   // java developers
164 
165   @Override
beginTransaction(final WriteOptions writeOptions, final Transaction oldTransaction)166   public Transaction beginTransaction(final WriteOptions writeOptions,
167       final Transaction oldTransaction) {
168     final long jtxn_handle = beginTransaction_withOld(nativeHandle_,
169         writeOptions.nativeHandle_, oldTransaction.nativeHandle_);
170 
171     // RocksJava relies on the assumption that
172     // we do not allocate a new Transaction object
173     // when providing an old_txn
174     assert(jtxn_handle == oldTransaction.nativeHandle_);
175 
176     return oldTransaction;
177   }
178 
179   @Override
beginTransaction(final WriteOptions writeOptions, final OptimisticTransactionOptions optimisticTransactionOptions, final Transaction oldTransaction)180   public Transaction beginTransaction(final WriteOptions writeOptions,
181       final OptimisticTransactionOptions optimisticTransactionOptions,
182       final Transaction oldTransaction) {
183     final long jtxn_handle = beginTransaction_withOld(nativeHandle_,
184         writeOptions.nativeHandle_, optimisticTransactionOptions.nativeHandle_,
185         oldTransaction.nativeHandle_);
186 
187     // RocksJava relies on the assumption that
188     // we do not allocate a new Transaction object
189     // when providing an old_txn
190     assert(jtxn_handle == oldTransaction.nativeHandle_);
191 
192     return oldTransaction;
193   }
194 
195   /**
196    * Get the underlying database that was opened.
197    *
198    * @return The underlying database that was opened.
199    */
getBaseDB()200   public RocksDB getBaseDB() {
201     final RocksDB db = new RocksDB(getBaseDB(nativeHandle_));
202     db.disOwnNativeHandle();
203     return db;
204   }
205 
disposeInternal(final long handle)206   @Override protected final native void disposeInternal(final long handle);
207 
open(final long optionsHandle, final String path)208   protected static native long open(final long optionsHandle,
209       final String path) throws RocksDBException;
open(final long handle, final String path, final byte[][] columnFamilyNames, final long[] columnFamilyOptions)210   protected static native long[] open(final long handle, final String path,
211       final byte[][] columnFamilyNames, final long[] columnFamilyOptions);
closeDatabase(final long handle)212   private native static void closeDatabase(final long handle)
213       throws RocksDBException;
beginTransaction(final long handle, final long writeOptionsHandle)214   private native long beginTransaction(final long handle,
215       final long writeOptionsHandle);
beginTransaction(final long handle, final long writeOptionsHandle, final long optimisticTransactionOptionsHandle)216   private native long beginTransaction(final long handle,
217       final long writeOptionsHandle,
218       final long optimisticTransactionOptionsHandle);
beginTransaction_withOld(final long handle, final long writeOptionsHandle, final long oldTransactionHandle)219   private native long beginTransaction_withOld(final long handle,
220       final long writeOptionsHandle, final long oldTransactionHandle);
beginTransaction_withOld(final long handle, final long writeOptionsHandle, final long optimisticTransactionOptionsHandle, final long oldTransactionHandle)221   private native long beginTransaction_withOld(final long handle,
222       final long writeOptionsHandle,
223       final long optimisticTransactionOptionsHandle,
224       final long oldTransactionHandle);
getBaseDB(final long handle)225   private native long getBaseDB(final long handle);
226 }
227