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  * Provides BEGIN/COMMIT/ROLLBACK transactions.
12  *
13  * To use transactions, you must first create either an
14  * {@link OptimisticTransactionDB} or a {@link TransactionDB}
15  *
16  * To create a transaction, use
17  * {@link OptimisticTransactionDB#beginTransaction(org.rocksdb.WriteOptions)} or
18  * {@link TransactionDB#beginTransaction(org.rocksdb.WriteOptions)}
19  *
20  * It is up to the caller to synchronize access to this object.
21  *
22  * See samples/src/main/java/OptimisticTransactionSample.java and
23  * samples/src/main/java/TransactionSample.java for some simple
24  * examples.
25  */
26 public class Transaction extends RocksObject {
27 
28   private final RocksDB parent;
29 
30   /**
31    * Intentionally package private
32    * as this is called from
33    * {@link OptimisticTransactionDB#beginTransaction(org.rocksdb.WriteOptions)}
34    * or {@link TransactionDB#beginTransaction(org.rocksdb.WriteOptions)}
35    *
36    * @param parent This must be either {@link TransactionDB} or
37    *     {@link OptimisticTransactionDB}
38    * @param transactionHandle The native handle to the underlying C++
39    *     transaction object
40    */
Transaction(final RocksDB parent, final long transactionHandle)41   Transaction(final RocksDB parent, final long transactionHandle) {
42     super(transactionHandle);
43     this.parent = parent;
44   }
45 
46   /**
47    * If a transaction has a snapshot set, the transaction will ensure that
48    * any keys successfully written(or fetched via {@link #getForUpdate}) have
49    * not been modified outside of this transaction since the time the snapshot
50    * was set.
51    *
52    * If a snapshot has not been set, the transaction guarantees that keys have
53    * not been modified since the time each key was first written (or fetched via
54    * {@link #getForUpdate}).
55    *
56    * Using {@link #setSnapshot()} will provide stricter isolation guarantees
57    * at the expense of potentially more transaction failures due to conflicts
58    * with other writes.
59    *
60    * Calling {@link #setSnapshot()} has no effect on keys written before this
61    * function has been called.
62    *
63    * {@link #setSnapshot()} may be called multiple times if you would like to
64    * change the snapshot used for different operations in this transaction.
65    *
66    * Calling {@link #setSnapshot()} will not affect the version of Data returned
67    * by get(...) methods. See {@link #get} for more details.
68    */
setSnapshot()69   public void setSnapshot() {
70     assert(isOwningHandle());
71     setSnapshot(nativeHandle_);
72   }
73 
74   /**
75    * Similar to {@link #setSnapshot()}, but will not change the current snapshot
76    * until put/merge/delete/getForUpdate/multiGetForUpdate is called.
77    * By calling this function, the transaction will essentially call
78    * {@link #setSnapshot()} for you right before performing the next
79    * write/getForUpdate.
80    *
81    * Calling {@link #setSnapshotOnNextOperation()} will not affect what
82    * snapshot is returned by {@link #getSnapshot} until the next
83    * write/getForUpdate is executed.
84    *
85    * When the snapshot is created the notifier's snapshotCreated method will
86    * be called so that the caller can get access to the snapshot.
87    *
88    * This is an optimization to reduce the likelihood of conflicts that
89    * could occur in between the time {@link #setSnapshot()} is called and the
90    * first write/getForUpdate operation. i.e. this prevents the following
91    * race-condition:
92    *
93    *   txn1->setSnapshot();
94    *                             txn2->put("A", ...);
95    *                             txn2->commit();
96    *   txn1->getForUpdate(opts, "A", ...);  * FAIL!
97    */
setSnapshotOnNextOperation()98   public void setSnapshotOnNextOperation() {
99     assert(isOwningHandle());
100     setSnapshotOnNextOperation(nativeHandle_);
101   }
102 
103   /**
104    * Similar to {@link #setSnapshot()}, but will not change the current snapshot
105    * until put/merge/delete/getForUpdate/multiGetForUpdate is called.
106    * By calling this function, the transaction will essentially call
107    * {@link #setSnapshot()} for you right before performing the next
108    * write/getForUpdate.
109    *
110    * Calling {@link #setSnapshotOnNextOperation()} will not affect what
111    * snapshot is returned by {@link #getSnapshot} until the next
112    * write/getForUpdate is executed.
113    *
114    * When the snapshot is created the
115    * {@link AbstractTransactionNotifier#snapshotCreated(Snapshot)} method will
116    * be called so that the caller can get access to the snapshot.
117    *
118    * This is an optimization to reduce the likelihood of conflicts that
119    * could occur in between the time {@link #setSnapshot()} is called and the
120    * first write/getForUpdate operation. i.e. this prevents the following
121    * race-condition:
122    *
123    *   txn1->setSnapshot();
124    *                             txn2->put("A", ...);
125    *                             txn2->commit();
126    *   txn1->getForUpdate(opts, "A", ...);  * FAIL!
127    *
128    * @param transactionNotifier A handler for receiving snapshot notifications
129    *     for the transaction
130    *
131    */
setSnapshotOnNextOperation( final AbstractTransactionNotifier transactionNotifier)132   public void setSnapshotOnNextOperation(
133       final AbstractTransactionNotifier transactionNotifier) {
134     assert(isOwningHandle());
135     setSnapshotOnNextOperation(nativeHandle_, transactionNotifier.nativeHandle_);
136   }
137 
138  /**
139   * Returns the Snapshot created by the last call to {@link #setSnapshot()}.
140   *
141   * REQUIRED: The returned Snapshot is only valid up until the next time
142   * {@link #setSnapshot()}/{@link #setSnapshotOnNextOperation()} is called,
143   * {@link #clearSnapshot()} is called, or the Transaction is deleted.
144   *
145   * @return The snapshot or null if there is no snapshot
146   */
getSnapshot()147   public Snapshot getSnapshot() {
148     assert(isOwningHandle());
149     final long snapshotNativeHandle = getSnapshot(nativeHandle_);
150     if(snapshotNativeHandle == 0) {
151       return null;
152     } else {
153       final Snapshot snapshot = new Snapshot(snapshotNativeHandle);
154       return snapshot;
155     }
156   }
157 
158   /**
159    * Clears the current snapshot (i.e. no snapshot will be 'set')
160    *
161    * This removes any snapshot that currently exists or is set to be created
162    * on the next update operation ({@link #setSnapshotOnNextOperation()}).
163    *
164    * Calling {@link #clearSnapshot()} has no effect on keys written before this
165    * function has been called.
166    *
167    * If a reference to a snapshot was retrieved via {@link #getSnapshot()}, it
168    * will no longer be valid and should be discarded after a call to
169    * {@link #clearSnapshot()}.
170    */
clearSnapshot()171   public void clearSnapshot() {
172     assert(isOwningHandle());
173     clearSnapshot(nativeHandle_);
174   }
175 
176   /**
177    * Prepare the current transaction for 2PC
178    */
prepare()179   void prepare() throws RocksDBException {
180     //TODO(AR) consider a Java'ish version of this function, which returns an AutoCloseable (commit)
181     assert(isOwningHandle());
182     prepare(nativeHandle_);
183   }
184 
185   /**
186    * Write all batched keys to the db atomically.
187    *
188    * Returns OK on success.
189    *
190    * May return any error status that could be returned by DB:Write().
191    *
192    * If this transaction was created by an {@link OptimisticTransactionDB}
193    * Status::Busy() may be returned if the transaction could not guarantee
194    * that there are no write conflicts. Status::TryAgain() may be returned
195    * if the memtable history size is not large enough
196    *  (See max_write_buffer_number_to_maintain).
197    *
198    * If this transaction was created by a {@link TransactionDB},
199    * Status::Expired() may be returned if this transaction has lived for
200    * longer than {@link TransactionOptions#getExpiration()}.
201    *
202    * @throws RocksDBException if an error occurs when committing the transaction
203    */
commit()204   public void commit() throws RocksDBException {
205     assert(isOwningHandle());
206     commit(nativeHandle_);
207   }
208 
209   /**
210    * Discard all batched writes in this transaction.
211    *
212    * @throws RocksDBException if an error occurs when rolling back the transaction
213    */
rollback()214   public void rollback() throws RocksDBException {
215     assert(isOwningHandle());
216     rollback(nativeHandle_);
217   }
218 
219   /**
220    * Records the state of the transaction for future calls to
221    * {@link #rollbackToSavePoint()}.
222    *
223    * May be called multiple times to set multiple save points.
224    *
225    * @throws RocksDBException if an error occurs whilst setting a save point
226    */
setSavePoint()227   public void setSavePoint() throws RocksDBException {
228     assert(isOwningHandle());
229     setSavePoint(nativeHandle_);
230   }
231 
232   /**
233    * Undo all operations in this transaction (put, merge, delete, putLogData)
234    * since the most recent call to {@link #setSavePoint()} and removes the most
235    * recent {@link #setSavePoint()}.
236    *
237    * If there is no previous call to {@link #setSavePoint()},
238    * returns Status::NotFound()
239    *
240    * @throws RocksDBException if an error occurs when rolling back to a save point
241    */
rollbackToSavePoint()242   public void rollbackToSavePoint() throws RocksDBException {
243     assert(isOwningHandle());
244     rollbackToSavePoint(nativeHandle_);
245   }
246 
247   /**
248    * This function is similar to
249    * {@link RocksDB#get(ColumnFamilyHandle, ReadOptions, byte[])} except it will
250    * also read pending changes in this transaction.
251    * Currently, this function will return Status::MergeInProgress if the most
252    * recent write to the queried key in this batch is a Merge.
253    *
254    * If {@link ReadOptions#snapshot()} is not set, the current version of the
255    * key will be read. Calling {@link #setSnapshot()} does not affect the
256    * version of the data returned.
257    *
258    * Note that setting {@link ReadOptions#setSnapshot(Snapshot)} will affect
259    * what is read from the DB but will NOT change which keys are read from this
260    * transaction (the keys in this transaction do not yet belong to any snapshot
261    * and will be fetched regardless).
262    *
263    * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle} instance
264    * @param readOptions Read options.
265    * @param key the key to retrieve the value for.
266    *
267    * @return a byte array storing the value associated with the input key if
268    *     any. null if it does not find the specified key.
269    *
270    * @throws RocksDBException thrown if error happens in underlying native
271    *     library.
272    */
get(final ColumnFamilyHandle columnFamilyHandle, final ReadOptions readOptions, final byte[] key)273   public byte[] get(final ColumnFamilyHandle columnFamilyHandle,
274       final ReadOptions readOptions, final byte[] key) throws RocksDBException {
275     assert(isOwningHandle());
276     return get(nativeHandle_, readOptions.nativeHandle_, key, key.length,
277         columnFamilyHandle.nativeHandle_);
278   }
279 
280   /**
281    * This function is similar to
282    * {@link RocksDB#get(ReadOptions, byte[])} except it will
283    * also read pending changes in this transaction.
284    * Currently, this function will return Status::MergeInProgress if the most
285    * recent write to the queried key in this batch is a Merge.
286    *
287    * If {@link ReadOptions#snapshot()} is not set, the current version of the
288    * key will be read. Calling {@link #setSnapshot()} does not affect the
289    * version of the data returned.
290    *
291    * Note that setting {@link ReadOptions#setSnapshot(Snapshot)} will affect
292    * what is read from the DB but will NOT change which keys are read from this
293    * transaction (the keys in this transaction do not yet belong to any snapshot
294    * and will be fetched regardless).
295    *
296    * @param readOptions Read options.
297    * @param key the key to retrieve the value for.
298    *
299    * @return a byte array storing the value associated with the input key if
300    *     any. null if it does not find the specified key.
301    *
302    * @throws RocksDBException thrown if error happens in underlying native
303    *     library.
304    */
get(final ReadOptions readOptions, final byte[] key)305   public byte[] get(final ReadOptions readOptions, final byte[] key)
306       throws RocksDBException {
307     assert(isOwningHandle());
308     return get(nativeHandle_, readOptions.nativeHandle_, key, key.length);
309   }
310 
311   /**
312    * This function is similar to
313    * {@link RocksDB#multiGet(ReadOptions, List, List)} except it will
314    * also read pending changes in this transaction.
315    * Currently, this function will return Status::MergeInProgress if the most
316    * recent write to the queried key in this batch is a Merge.
317    *
318    * If {@link ReadOptions#snapshot()} is not set, the current version of the
319    * key will be read. Calling {@link #setSnapshot()} does not affect the
320    * version of the data returned.
321    *
322    * Note that setting {@link ReadOptions#setSnapshot(Snapshot)} will affect
323    * what is read from the DB but will NOT change which keys are read from this
324    * transaction (the keys in this transaction do not yet belong to any snapshot
325    * and will be fetched regardless).
326    *
327    * @param readOptions Read options.
328    * @param columnFamilyHandles {@link java.util.List} containing
329    *     {@link org.rocksdb.ColumnFamilyHandle} instances.
330    * @param keys of keys for which values need to be retrieved.
331    *
332    * @return Array of values, one for each key
333    *
334    * @throws RocksDBException thrown if error happens in underlying
335    *    native library.
336    * @throws IllegalArgumentException thrown if the size of passed keys is not
337    *    equal to the amount of passed column family handles.
338    */
multiGet(final ReadOptions readOptions, final List<ColumnFamilyHandle> columnFamilyHandles, final byte[][] keys)339   public byte[][] multiGet(final ReadOptions readOptions,
340       final List<ColumnFamilyHandle> columnFamilyHandles,
341       final byte[][] keys) throws RocksDBException {
342     assert(isOwningHandle());
343     // Check if key size equals cfList size. If not a exception must be
344     // thrown. If not a Segmentation fault happens.
345     if (keys.length != columnFamilyHandles.size()) {
346       throw new IllegalArgumentException(
347           "For each key there must be a ColumnFamilyHandle.");
348     }
349     if(keys.length == 0) {
350       return new byte[0][0];
351     }
352     final long[] cfHandles = new long[columnFamilyHandles.size()];
353     for (int i = 0; i < columnFamilyHandles.size(); i++) {
354       cfHandles[i] = columnFamilyHandles.get(i).nativeHandle_;
355     }
356 
357     return multiGet(nativeHandle_, readOptions.nativeHandle_,
358        keys, cfHandles);
359   }
360 
361   /**
362    * This function is similar to
363    * {@link RocksDB#multiGet(ReadOptions, List)} except it will
364    * also read pending changes in this transaction.
365    * Currently, this function will return Status::MergeInProgress if the most
366    * recent write to the queried key in this batch is a Merge.
367    *
368    * If {@link ReadOptions#snapshot()} is not set, the current version of the
369    * key will be read. Calling {@link #setSnapshot()} does not affect the
370    * version of the data returned.
371    *
372    * Note that setting {@link ReadOptions#setSnapshot(Snapshot)} will affect
373    * what is read from the DB but will NOT change which keys are read from this
374    * transaction (the keys in this transaction do not yet belong to any snapshot
375    * and will be fetched regardless).
376    *
377    * @param readOptions Read options.=
378    *     {@link org.rocksdb.ColumnFamilyHandle} instances.
379    * @param keys of keys for which values need to be retrieved.
380    *
381    * @return Array of values, one for each key
382    *
383    * @throws RocksDBException thrown if error happens in underlying
384    *    native library.
385    */
multiGet(final ReadOptions readOptions, final byte[][] keys)386   public byte[][] multiGet(final ReadOptions readOptions,
387       final byte[][] keys) throws RocksDBException {
388     assert(isOwningHandle());
389     if(keys.length == 0) {
390       return new byte[0][0];
391     }
392 
393     return multiGet(nativeHandle_, readOptions.nativeHandle_,
394         keys);
395   }
396 
397   /**
398    * Read this key and ensure that this transaction will only
399    * be able to be committed if this key is not written outside this
400    * transaction after it has first been read (or after the snapshot if a
401    * snapshot is set in this transaction). The transaction behavior is the
402    * same regardless of whether the key exists or not.
403    *
404    * Note: Currently, this function will return Status::MergeInProgress
405    * if the most recent write to the queried key in this batch is a Merge.
406    *
407    * The values returned by this function are similar to
408    * {@link RocksDB#get(ColumnFamilyHandle, ReadOptions, byte[])}.
409    * If value==nullptr, then this function will not read any data, but will
410    * still ensure that this key cannot be written to by outside of this
411    * transaction.
412    *
413    * If this transaction was created by an {@link OptimisticTransactionDB},
414    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)}
415    * could cause {@link #commit()} to fail. Otherwise, it could return any error
416    * that could be returned by
417    * {@link RocksDB#get(ColumnFamilyHandle, ReadOptions, byte[])}.
418    *
419    * If this transaction was created on a {@link TransactionDB}, an
420    * {@link RocksDBException} may be thrown with an accompanying {@link Status}
421    * when:
422    *     {@link Status.Code#Busy} if there is a write conflict,
423    *     {@link Status.Code#TimedOut} if a lock could not be acquired,
424    *     {@link Status.Code#TryAgain} if the memtable history size is not large
425    *         enough. See
426    *         {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
427    *     {@link Status.Code#MergeInProgress} if merge operations cannot be
428    *     resolved.
429    *
430    * @param readOptions Read options.
431    * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
432    *     instance
433    * @param key the key to retrieve the value for.
434    * @param exclusive true if the transaction should have exclusive access to
435    *     the key, otherwise false for shared access.
436    * @param doValidate true if it should validate the snapshot before doing the read
437    *
438    * @return a byte array storing the value associated with the input key if
439    *     any.  null if it does not find the specified key.
440    *
441    * @throws RocksDBException thrown if error happens in underlying
442    *    native library.
443    */
getForUpdate(final ReadOptions readOptions, final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final boolean exclusive, final boolean doValidate)444   public byte[] getForUpdate(final ReadOptions readOptions,
445       final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final boolean exclusive,
446       final boolean doValidate) throws RocksDBException {
447     assert (isOwningHandle());
448     return getForUpdate(nativeHandle_, readOptions.nativeHandle_, key, key.length,
449         columnFamilyHandle.nativeHandle_, exclusive, doValidate);
450   }
451 
452   /**
453    * Same as
454    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean, boolean)}
455    * with doValidate=true.
456    *
457    * @param readOptions Read options.
458    * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
459    *     instance
460    * @param key the key to retrieve the value for.
461    * @param exclusive true if the transaction should have exclusive access to
462    *     the key, otherwise false for shared access.
463    *
464    * @return a byte array storing the value associated with the input key if
465    *     any.  null if it does not find the specified key.
466    *
467    * @throws RocksDBException thrown if error happens in underlying
468    *    native library.
469    */
getForUpdate(final ReadOptions readOptions, final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final boolean exclusive)470   public byte[] getForUpdate(final ReadOptions readOptions,
471       final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
472       final boolean exclusive) throws RocksDBException {
473     assert(isOwningHandle());
474     return getForUpdate(nativeHandle_, readOptions.nativeHandle_, key, key.length,
475         columnFamilyHandle.nativeHandle_, exclusive, true /*doValidate*/);
476   }
477 
478   /**
479    * Read this key and ensure that this transaction will only
480    * be able to be committed if this key is not written outside this
481    * transaction after it has first been read (or after the snapshot if a
482    * snapshot is set in this transaction). The transaction behavior is the
483    * same regardless of whether the key exists or not.
484    *
485    * Note: Currently, this function will return Status::MergeInProgress
486    * if the most recent write to the queried key in this batch is a Merge.
487    *
488    * The values returned by this function are similar to
489    * {@link RocksDB#get(ReadOptions, byte[])}.
490    * If value==nullptr, then this function will not read any data, but will
491    * still ensure that this key cannot be written to by outside of this
492    * transaction.
493    *
494    * If this transaction was created on an {@link OptimisticTransactionDB},
495    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)}
496    * could cause {@link #commit()} to fail. Otherwise, it could return any error
497    * that could be returned by
498    * {@link RocksDB#get(ReadOptions, byte[])}.
499    *
500    * If this transaction was created on a {@link TransactionDB}, an
501    * {@link RocksDBException} may be thrown with an accompanying {@link Status}
502    * when:
503    *     {@link Status.Code#Busy} if there is a write conflict,
504    *     {@link Status.Code#TimedOut} if a lock could not be acquired,
505    *     {@link Status.Code#TryAgain} if the memtable history size is not large
506    *         enough. See
507    *         {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
508    *     {@link Status.Code#MergeInProgress} if merge operations cannot be
509    *     resolved.
510    *
511    * @param readOptions Read options.
512    * @param key the key to retrieve the value for.
513    * @param exclusive true if the transaction should have exclusive access to
514    *     the key, otherwise false for shared access.
515    *
516    * @return a byte array storing the value associated with the input key if
517    *     any.  null if it does not find the specified key.
518    *
519    * @throws RocksDBException thrown if error happens in underlying
520    *    native library.
521    */
getForUpdate(final ReadOptions readOptions, final byte[] key, final boolean exclusive)522   public byte[] getForUpdate(final ReadOptions readOptions, final byte[] key,
523       final boolean exclusive) throws RocksDBException {
524     assert(isOwningHandle());
525     return getForUpdate(
526         nativeHandle_, readOptions.nativeHandle_, key, key.length, exclusive, true /*doValidate*/);
527   }
528 
529   /**
530    * A multi-key version of
531    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)}.
532    *
533    *
534    * @param readOptions Read options.
535    * @param columnFamilyHandles {@link org.rocksdb.ColumnFamilyHandle}
536    *     instances
537    * @param keys the keys to retrieve the values for.
538    *
539    * @return Array of values, one for each key
540    *
541    * @throws RocksDBException thrown if error happens in underlying
542    *    native library.
543    */
multiGetForUpdate(final ReadOptions readOptions, final List<ColumnFamilyHandle> columnFamilyHandles, final byte[][] keys)544   public byte[][] multiGetForUpdate(final ReadOptions readOptions,
545       final List<ColumnFamilyHandle> columnFamilyHandles,
546       final byte[][] keys) throws RocksDBException {
547     assert(isOwningHandle());
548     // Check if key size equals cfList size. If not a exception must be
549     // thrown. If not a Segmentation fault happens.
550     if (keys.length != columnFamilyHandles.size()){
551       throw new IllegalArgumentException(
552           "For each key there must be a ColumnFamilyHandle.");
553     }
554     if(keys.length == 0) {
555       return new byte[0][0];
556     }
557     final long[] cfHandles = new long[columnFamilyHandles.size()];
558     for (int i = 0; i < columnFamilyHandles.size(); i++) {
559       cfHandles[i] = columnFamilyHandles.get(i).nativeHandle_;
560     }
561     return multiGetForUpdate(nativeHandle_, readOptions.nativeHandle_,
562         keys, cfHandles);
563   }
564 
565   /**
566    * A multi-key version of {@link #getForUpdate(ReadOptions, byte[], boolean)}.
567    *
568    *
569    * @param readOptions Read options.
570    * @param keys the keys to retrieve the values for.
571    *
572    * @return Array of values, one for each key
573    *
574    * @throws RocksDBException thrown if error happens in underlying
575    *    native library.
576    */
multiGetForUpdate(final ReadOptions readOptions, final byte[][] keys)577   public byte[][] multiGetForUpdate(final ReadOptions readOptions,
578       final byte[][] keys) throws RocksDBException {
579     assert(isOwningHandle());
580     if(keys.length == 0) {
581       return new byte[0][0];
582     }
583 
584     return multiGetForUpdate(nativeHandle_,
585         readOptions.nativeHandle_, keys);
586   }
587 
588   /**
589    * Returns an iterator that will iterate on all keys in the default
590    * column family including both keys in the DB and uncommitted keys in this
591    * transaction.
592    *
593    * Setting {@link ReadOptions#setSnapshot(Snapshot)} will affect what is read
594    * from the DB but will NOT change which keys are read from this transaction
595    * (the keys in this transaction do not yet belong to any snapshot and will be
596    * fetched regardless).
597    *
598    * Caller is responsible for deleting the returned Iterator.
599    *
600    * The returned iterator is only valid until {@link #commit()},
601    * {@link #rollback()}, or {@link #rollbackToSavePoint()} is called.
602    *
603    * @param readOptions Read options.
604    *
605    * @return instance of iterator object.
606    */
getIterator(final ReadOptions readOptions)607   public RocksIterator getIterator(final ReadOptions readOptions) {
608     assert(isOwningHandle());
609     return new RocksIterator(parent, getIterator(nativeHandle_,
610         readOptions.nativeHandle_));
611   }
612 
613   /**
614    * Returns an iterator that will iterate on all keys in the default
615    * column family including both keys in the DB and uncommitted keys in this
616    * transaction.
617    *
618    * Setting {@link ReadOptions#setSnapshot(Snapshot)} will affect what is read
619    * from the DB but will NOT change which keys are read from this transaction
620    * (the keys in this transaction do not yet belong to any snapshot and will be
621    * fetched regardless).
622    *
623    * Caller is responsible for calling {@link RocksIterator#close()} on
624    * the returned Iterator.
625    *
626    * The returned iterator is only valid until {@link #commit()},
627    * {@link #rollback()}, or {@link #rollbackToSavePoint()} is called.
628    *
629    * @param readOptions Read options.
630    * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
631    *     instance
632    *
633    * @return instance of iterator object.
634    */
getIterator(final ReadOptions readOptions, final ColumnFamilyHandle columnFamilyHandle)635   public RocksIterator getIterator(final ReadOptions readOptions,
636       final ColumnFamilyHandle columnFamilyHandle) {
637     assert(isOwningHandle());
638     return new RocksIterator(parent, getIterator(nativeHandle_,
639         readOptions.nativeHandle_, columnFamilyHandle.nativeHandle_));
640   }
641 
642   /**
643    * Similar to {@link RocksDB#put(ColumnFamilyHandle, byte[], byte[])}, but
644    * will also perform conflict checking on the keys be written.
645    *
646    * If this Transaction was created on an {@link OptimisticTransactionDB},
647    * these functions should always succeed.
648    *
649    * If this Transaction was created on a {@link TransactionDB}, an
650    * {@link RocksDBException} may be thrown with an accompanying {@link Status}
651    * when:
652    *     {@link Status.Code#Busy} if there is a write conflict,
653    *     {@link Status.Code#TimedOut} if a lock could not be acquired,
654    *     {@link Status.Code#TryAgain} if the memtable history size is not large
655    *         enough. See
656    *         {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
657    *
658    * @param columnFamilyHandle The column family to put the key/value into
659    * @param key the specified key to be inserted.
660    * @param value the value associated with the specified key.
661    * @param assumeTracked true when it is expected that the key is already
662    *     tracked. More specifically, it means the the key was previous tracked
663    *     in the same savepoint, with the same exclusive flag, and at a lower
664    *     sequence number. If valid then it skips ValidateSnapshot,
665    *     throws an error otherwise.
666    *
667    * @throws RocksDBException when one of the TransactionalDB conditions
668    *     described above occurs, or in the case of an unexpected error
669    */
put(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value, final boolean assumeTracked)670   public void put(final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
671       final byte[] value, final boolean assumeTracked) throws RocksDBException {
672     assert (isOwningHandle());
673     put(nativeHandle_, key, key.length, value, value.length,
674         columnFamilyHandle.nativeHandle_, assumeTracked);
675   }
676 
677   /**
678    * Similar to {@link #put(ColumnFamilyHandle, byte[], byte[], boolean)}
679    * but with {@code assumeTracked = false}.
680    *
681    * Will also perform conflict checking on the keys be written.
682    *
683    * If this Transaction was created on an {@link OptimisticTransactionDB},
684    * these functions should always succeed.
685    *
686    * If this Transaction was created on a {@link TransactionDB}, an
687    * {@link RocksDBException} may be thrown with an accompanying {@link Status}
688    * when:
689    *     {@link Status.Code#Busy} if there is a write conflict,
690    *     {@link Status.Code#TimedOut} if a lock could not be acquired,
691    *     {@link Status.Code#TryAgain} if the memtable history size is not large
692    *         enough. See
693    *         {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
694    *
695    * @param columnFamilyHandle The column family to put the key/value into
696    * @param key the specified key to be inserted.
697    * @param value the value associated with the specified key.
698    *
699    * @throws RocksDBException when one of the TransactionalDB conditions
700    *     described above occurs, or in the case of an unexpected error
701    */
put(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value)702   public void put(final ColumnFamilyHandle columnFamilyHandle, final byte[] key,
703       final byte[] value) throws RocksDBException {
704     assert(isOwningHandle());
705     put(nativeHandle_, key, key.length, value, value.length,
706         columnFamilyHandle.nativeHandle_, false);
707   }
708 
709   /**
710    * Similar to {@link RocksDB#put(byte[], byte[])}, but
711    * will also perform conflict checking on the keys be written.
712    *
713    * If this Transaction was created on an {@link OptimisticTransactionDB},
714    * these functions should always succeed.
715    *
716    *  If this Transaction was created on a {@link TransactionDB}, an
717    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
718    *  when:
719    *    {@link Status.Code#Busy} if there is a write conflict,
720    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
721    *    {@link Status.Code#TryAgain} if the memtable history size is not large
722    *       enough. See
723    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
724    *
725    * @param key the specified key to be inserted.
726    * @param value the value associated with the specified key.
727    *
728    * @throws RocksDBException when one of the TransactionalDB conditions
729    *     described above occurs, or in the case of an unexpected error
730    */
put(final byte[] key, final byte[] value)731   public void put(final byte[] key, final byte[] value)
732       throws RocksDBException {
733     assert(isOwningHandle());
734     put(nativeHandle_, key, key.length, value, value.length);
735   }
736 
737   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
738   /**
739    * Similar to {@link #put(ColumnFamilyHandle, byte[], byte[])} but allows
740    * you to specify the key and value in several parts that will be
741    * concatenated together.
742    *
743    * @param columnFamilyHandle The column family to put the key/value into
744    * @param keyParts the specified key to be inserted.
745    * @param valueParts the value associated with the specified key.
746    * @param assumeTracked true when it is expected that the key is already
747    *     tracked. More specifically, it means the the key was previous tracked
748    *     in the same savepoint, with the same exclusive flag, and at a lower
749    *     sequence number. If valid then it skips ValidateSnapshot,
750    *     throws an error otherwise.
751    *
752    * @throws RocksDBException when one of the TransactionalDB conditions
753    *     described above occurs, or in the case of an unexpected error
754    */
put(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts, final byte[][] valueParts, final boolean assumeTracked)755   public void put(final ColumnFamilyHandle columnFamilyHandle,
756       final byte[][] keyParts, final byte[][] valueParts,
757       final boolean assumeTracked) throws RocksDBException {
758     assert (isOwningHandle());
759     put(nativeHandle_, keyParts, keyParts.length, valueParts, valueParts.length,
760         columnFamilyHandle.nativeHandle_, assumeTracked);
761   }
762 
763   /**
764    * Similar to {@link #put(ColumnFamilyHandle, byte[][], byte[][], boolean)}
765    * but with with {@code assumeTracked = false}.
766    *
767    * Allows you to specify the key and value in several parts that will be
768    * concatenated together.
769    *
770    * @param columnFamilyHandle The column family to put the key/value into
771    * @param keyParts the specified key to be inserted.
772    * @param valueParts the value associated with the specified key.
773    *
774    * @throws RocksDBException when one of the TransactionalDB conditions
775    *     described above occurs, or in the case of an unexpected error
776    */
put(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts, final byte[][] valueParts)777   public void put(final ColumnFamilyHandle columnFamilyHandle,
778       final byte[][] keyParts, final byte[][] valueParts)
779       throws RocksDBException {
780     assert(isOwningHandle());
781     put(nativeHandle_, keyParts, keyParts.length, valueParts, valueParts.length,
782         columnFamilyHandle.nativeHandle_, false);
783   }
784 
785   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
786   /**
787    * Similar to {@link #put(byte[], byte[])} but allows
788    * you to specify the key and value in several parts that will be
789    * concatenated together
790    *
791    * @param keyParts the specified key to be inserted.
792    * @param valueParts the value associated with the specified key.
793    *
794    * @throws RocksDBException when one of the TransactionalDB conditions
795    *     described above occurs, or in the case of an unexpected error
796    */
put(final byte[][] keyParts, final byte[][] valueParts)797   public void put(final byte[][] keyParts, final byte[][] valueParts)
798       throws RocksDBException {
799     assert(isOwningHandle());
800     put(nativeHandle_, keyParts, keyParts.length, valueParts,
801         valueParts.length);
802   }
803 
804   /**
805    * Similar to {@link RocksDB#merge(ColumnFamilyHandle, byte[], byte[])}, but
806    * will also perform conflict checking on the keys be written.
807    *
808    * If this Transaction was created on an {@link OptimisticTransactionDB},
809    * these functions should always succeed.
810    *
811    *  If this Transaction was created on a {@link TransactionDB}, an
812    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
813    *  when:
814    *    {@link Status.Code#Busy} if there is a write conflict,
815    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
816    *    {@link Status.Code#TryAgain} if the memtable history size is not large
817    *       enough. See
818    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
819    *
820    * @param columnFamilyHandle The column family to merge the key/value into
821    * @param key the specified key to be merged.
822    * @param value the value associated with the specified key.
823    * @param assumeTracked true when it is expected that the key is already
824    *     tracked. More specifically, it means the the key was previous tracked
825    *     in the same savepoint, with the same exclusive flag, and at a lower
826    *     sequence number. If valid then it skips ValidateSnapshot,
827    *     throws an error otherwise.
828    *
829    * @throws RocksDBException when one of the TransactionalDB conditions
830    *     described above occurs, or in the case of an unexpected error
831    */
merge(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value, final boolean assumeTracked)832   public void merge(final ColumnFamilyHandle columnFamilyHandle,
833       final byte[] key, final byte[] value, final boolean assumeTracked)
834       throws RocksDBException {
835     assert (isOwningHandle());
836     merge(nativeHandle_, key, key.length, value, value.length,
837         columnFamilyHandle.nativeHandle_, assumeTracked);
838   }
839 
840   /**
841    * Similar to {@link #merge(ColumnFamilyHandle, byte[], byte[], boolean)}
842    * but with {@code assumeTracked = false}.
843    *
844    * Will also perform conflict checking on the keys be written.
845    *
846    * If this Transaction was created on an {@link OptimisticTransactionDB},
847    * these functions should always succeed.
848    *
849    *  If this Transaction was created on a {@link TransactionDB}, an
850    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
851    *  when:
852    *    {@link Status.Code#Busy} if there is a write conflict,
853    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
854    *    {@link Status.Code#TryAgain} if the memtable history size is not large
855    *       enough. See
856    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
857    *
858    * @param columnFamilyHandle The column family to merge the key/value into
859    * @param key the specified key to be merged.
860    * @param value the value associated with the specified key.
861    *
862    * @throws RocksDBException when one of the TransactionalDB conditions
863    *     described above occurs, or in the case of an unexpected error
864    */
merge(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value)865   public void merge(final ColumnFamilyHandle columnFamilyHandle,
866       final byte[] key, final byte[] value) throws RocksDBException {
867     assert(isOwningHandle());
868     merge(nativeHandle_, key, key.length, value, value.length,
869         columnFamilyHandle.nativeHandle_, false);
870   }
871 
872   /**
873    * Similar to {@link RocksDB#merge(byte[], byte[])}, but
874    * will also perform conflict checking on the keys be written.
875    *
876    * If this Transaction was created on an {@link OptimisticTransactionDB},
877    * these functions should always succeed.
878    *
879    *  If this Transaction was created on a {@link TransactionDB}, an
880    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
881    *  when:
882    *    {@link Status.Code#Busy} if there is a write conflict,
883    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
884    *    {@link Status.Code#TryAgain} if the memtable history size is not large
885    *       enough. See
886    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
887    *
888    * @param key the specified key to be merged.
889    * @param value the value associated with the specified key.
890    *
891    * @throws RocksDBException when one of the TransactionalDB conditions
892    *     described above occurs, or in the case of an unexpected error
893    */
merge(final byte[] key, final byte[] value)894   public void merge(final byte[] key, final byte[] value)
895       throws RocksDBException {
896     assert(isOwningHandle());
897     merge(nativeHandle_, key, key.length, value, value.length);
898   }
899 
900   /**
901    * Similar to {@link RocksDB#delete(ColumnFamilyHandle, byte[])}, but
902    * will also perform conflict checking on the keys be written.
903    *
904    * If this Transaction was created on an {@link OptimisticTransactionDB},
905    * these functions should always succeed.
906    *
907    *  If this Transaction was created on a {@link TransactionDB}, an
908    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
909    *  when:
910    *    {@link Status.Code#Busy} if there is a write conflict,
911    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
912    *    {@link Status.Code#TryAgain} if the memtable history size is not large
913    *       enough. See
914    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
915    *
916    * @param columnFamilyHandle The column family to delete the key/value from
917    * @param key the specified key to be deleted.
918    * @param assumeTracked true when it is expected that the key is already
919    *     tracked. More specifically, it means the the key was previous tracked
920    *     in the same savepoint, with the same exclusive flag, and at a lower
921    *     sequence number. If valid then it skips ValidateSnapshot,
922    *     throws an error otherwise.
923    *
924    * @throws RocksDBException when one of the TransactionalDB conditions
925    *     described above occurs, or in the case of an unexpected error
926    */
delete(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final boolean assumeTracked)927   public void delete(final ColumnFamilyHandle columnFamilyHandle,
928       final byte[] key, final boolean assumeTracked) throws RocksDBException {
929     assert (isOwningHandle());
930     delete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_,
931         assumeTracked);
932   }
933 
934   /**
935    * Similar to {@link #delete(ColumnFamilyHandle, byte[], boolean)}
936    * but with {@code assumeTracked = false}.
937    *
938    * Will also perform conflict checking on the keys be written.
939    *
940    * If this Transaction was created on an {@link OptimisticTransactionDB},
941    * these functions should always succeed.
942    *
943    *  If this Transaction was created on a {@link TransactionDB}, an
944    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
945    *  when:
946    *    {@link Status.Code#Busy} if there is a write conflict,
947    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
948    *    {@link Status.Code#TryAgain} if the memtable history size is not large
949    *       enough. See
950    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
951    *
952    * @param columnFamilyHandle The column family to delete the key/value from
953    * @param key the specified key to be deleted.
954    *
955    * @throws RocksDBException when one of the TransactionalDB conditions
956    *     described above occurs, or in the case of an unexpected error
957    */
delete(final ColumnFamilyHandle columnFamilyHandle, final byte[] key)958   public void delete(final ColumnFamilyHandle columnFamilyHandle,
959       final byte[] key) throws RocksDBException {
960     assert(isOwningHandle());
961     delete(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_,
962         /*assumeTracked*/ false);
963   }
964 
965   /**
966    * Similar to {@link RocksDB#delete(byte[])}, but
967    * will also perform conflict checking on the keys be written.
968    *
969    * If this Transaction was created on an {@link OptimisticTransactionDB},
970    * these functions should always succeed.
971    *
972    *  If this Transaction was created on a {@link TransactionDB}, an
973    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
974    *  when:
975    *    {@link Status.Code#Busy} if there is a write conflict,
976    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
977    *    {@link Status.Code#TryAgain} if the memtable history size is not large
978    *       enough. See
979    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
980    *
981    * @param key the specified key to be deleted.
982    *
983    * @throws RocksDBException when one of the TransactionalDB conditions
984    *     described above occurs, or in the case of an unexpected error
985    */
delete(final byte[] key)986   public void delete(final byte[] key) throws RocksDBException {
987     assert(isOwningHandle());
988     delete(nativeHandle_, key, key.length);
989   }
990 
991   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
992   /**
993    * Similar to {@link #delete(ColumnFamilyHandle, byte[])} but allows
994    * you to specify the key in several parts that will be
995    * concatenated together.
996    *
997    * @param columnFamilyHandle The column family to delete the key/value from
998    * @param keyParts the specified key to be deleted.
999    * @param assumeTracked true when it is expected that the key is already
1000    *     tracked. More specifically, it means the the key was previous tracked
1001    *     in the same savepoint, with the same exclusive flag, and at a lower
1002    *     sequence number. If valid then it skips ValidateSnapshot,
1003    *     throws an error otherwise.
1004    *
1005    * @throws RocksDBException when one of the TransactionalDB conditions
1006    *     described above occurs, or in the case of an unexpected error
1007    */
delete(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts, final boolean assumeTracked)1008   public void delete(final ColumnFamilyHandle columnFamilyHandle,
1009       final byte[][] keyParts, final boolean assumeTracked)
1010       throws RocksDBException {
1011     assert (isOwningHandle());
1012     delete(nativeHandle_, keyParts, keyParts.length,
1013         columnFamilyHandle.nativeHandle_, assumeTracked);
1014   }
1015 
1016   /**
1017    * Similar to{@link #delete(ColumnFamilyHandle, byte[][], boolean)}
1018    * but with {@code assumeTracked = false}.
1019    *
1020    * Allows you to specify the key in several parts that will be
1021    * concatenated together.
1022    *
1023    * @param columnFamilyHandle The column family to delete the key/value from
1024    * @param keyParts the specified key to be deleted.
1025    *
1026    * @throws RocksDBException when one of the TransactionalDB conditions
1027    *     described above occurs, or in the case of an unexpected error
1028    */
delete(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts)1029   public void delete(final ColumnFamilyHandle columnFamilyHandle,
1030       final byte[][] keyParts) throws RocksDBException {
1031     assert(isOwningHandle());
1032     delete(nativeHandle_, keyParts, keyParts.length,
1033         columnFamilyHandle.nativeHandle_, false);
1034   }
1035 
1036   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1037   /**
1038    * Similar to {@link #delete(byte[])} but allows
1039    * you to specify key the in several parts that will be
1040    * concatenated together.
1041    *
1042    * @param keyParts the specified key to be deleted
1043    *
1044    * @throws RocksDBException when one of the TransactionalDB conditions
1045    *     described above occurs, or in the case of an unexpected error
1046    */
delete(final byte[][] keyParts)1047   public void delete(final byte[][] keyParts) throws RocksDBException {
1048     assert(isOwningHandle());
1049     delete(nativeHandle_, keyParts, keyParts.length);
1050   }
1051 
1052   /**
1053    * Similar to {@link RocksDB#singleDelete(ColumnFamilyHandle, byte[])}, but
1054    * will also perform conflict checking on the keys be written.
1055    *
1056    * If this Transaction was created on an {@link OptimisticTransactionDB},
1057    * these functions should always succeed.
1058    *
1059    *  If this Transaction was created on a {@link TransactionDB}, an
1060    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
1061    *  when:
1062    *    {@link Status.Code#Busy} if there is a write conflict,
1063    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
1064    *    {@link Status.Code#TryAgain} if the memtable history size is not large
1065    *       enough. See
1066    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
1067    *
1068    * @param columnFamilyHandle The column family to delete the key/value from
1069    * @param key the specified key to be deleted.
1070    * @param assumeTracked true when it is expected that the key is already
1071    *     tracked. More specifically, it means the the key was previous tracked
1072    *     in the same savepoint, with the same exclusive flag, and at a lower
1073    *     sequence number. If valid then it skips ValidateSnapshot,
1074    *     throws an error otherwise.
1075    *
1076    * @throws RocksDBException when one of the TransactionalDB conditions
1077    *     described above occurs, or in the case of an unexpected error
1078    */
1079   @Experimental("Performance optimization for a very specific workload")
singleDelete(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final boolean assumeTracked)1080   public void singleDelete(final ColumnFamilyHandle columnFamilyHandle,
1081       final byte[] key, final boolean assumeTracked) throws RocksDBException {
1082     assert (isOwningHandle());
1083     singleDelete(nativeHandle_, key, key.length,
1084         columnFamilyHandle.nativeHandle_, assumeTracked);
1085   }
1086 
1087   /**
1088    * Similar to {@link #singleDelete(ColumnFamilyHandle, byte[], boolean)}
1089    * but with {@code assumeTracked = false}.
1090    *
1091    * will also perform conflict checking on the keys be written.
1092    *
1093    * If this Transaction was created on an {@link OptimisticTransactionDB},
1094    * these functions should always succeed.
1095    *
1096    *  If this Transaction was created on a {@link TransactionDB}, an
1097    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
1098    *  when:
1099    *    {@link Status.Code#Busy} if there is a write conflict,
1100    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
1101    *    {@link Status.Code#TryAgain} if the memtable history size is not large
1102    *       enough. See
1103    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
1104    *
1105    * @param columnFamilyHandle The column family to delete the key/value from
1106    * @param key the specified key to be deleted.
1107    *
1108    * @throws RocksDBException when one of the TransactionalDB conditions
1109    *     described above occurs, or in the case of an unexpected error
1110    */
1111   @Experimental("Performance optimization for a very specific workload")
singleDelete(final ColumnFamilyHandle columnFamilyHandle, final byte[] key)1112   public void singleDelete(final ColumnFamilyHandle columnFamilyHandle,
1113       final byte[] key) throws RocksDBException {
1114     assert(isOwningHandle());
1115     singleDelete(nativeHandle_, key, key.length,
1116         columnFamilyHandle.nativeHandle_, false);
1117   }
1118 
1119   /**
1120    * Similar to {@link RocksDB#singleDelete(byte[])}, but
1121    * will also perform conflict checking on the keys be written.
1122    *
1123    * If this Transaction was created on an {@link OptimisticTransactionDB},
1124    * these functions should always succeed.
1125    *
1126    *  If this Transaction was created on a {@link TransactionDB}, an
1127    *  {@link RocksDBException} may be thrown with an accompanying {@link Status}
1128    *  when:
1129    *    {@link Status.Code#Busy} if there is a write conflict,
1130    *    {@link Status.Code#TimedOut} if a lock could not be acquired,
1131    *    {@link Status.Code#TryAgain} if the memtable history size is not large
1132    *       enough. See
1133    *       {@link ColumnFamilyOptions#maxWriteBufferNumberToMaintain()}
1134    *
1135    * @param key the specified key to be deleted.
1136    *
1137    * @throws RocksDBException when one of the TransactionalDB conditions
1138    *     described above occurs, or in the case of an unexpected error
1139    */
1140   @Experimental("Performance optimization for a very specific workload")
singleDelete(final byte[] key)1141   public void singleDelete(final byte[] key) throws RocksDBException {
1142     assert(isOwningHandle());
1143     singleDelete(nativeHandle_, key, key.length);
1144   }
1145 
1146   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1147   /**
1148    * Similar to {@link #singleDelete(ColumnFamilyHandle, byte[])} but allows
1149    * you to specify the key in several parts that will be
1150    * concatenated together.
1151    *
1152    * @param columnFamilyHandle The column family to delete the key/value from
1153    * @param keyParts the specified key to be deleted.
1154    * @param assumeTracked true when it is expected that the key is already
1155    *     tracked. More specifically, it means the the key was previous tracked
1156    *     in the same savepoint, with the same exclusive flag, and at a lower
1157    *     sequence number. If valid then it skips ValidateSnapshot,
1158    *     throws an error otherwise.
1159    *
1160    * @throws RocksDBException when one of the TransactionalDB conditions
1161    *     described above occurs, or in the case of an unexpected error
1162    */
1163   @Experimental("Performance optimization for a very specific workload")
singleDelete(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts, final boolean assumeTracked)1164   public void singleDelete(final ColumnFamilyHandle columnFamilyHandle,
1165       final byte[][] keyParts, final boolean assumeTracked)
1166       throws RocksDBException {
1167     assert (isOwningHandle());
1168     singleDelete(nativeHandle_, keyParts, keyParts.length,
1169         columnFamilyHandle.nativeHandle_, assumeTracked);
1170   }
1171 
1172   /**
1173    * Similar to{@link #singleDelete(ColumnFamilyHandle, byte[][], boolean)}
1174    * but with {@code assumeTracked = false}.
1175    *
1176    * Allows you to specify the key in several parts that will be
1177    * concatenated together.
1178    *
1179    * @param columnFamilyHandle The column family to delete the key/value from
1180    * @param keyParts the specified key to be deleted.
1181    *
1182    * @throws RocksDBException when one of the TransactionalDB conditions
1183    *     described above occurs, or in the case of an unexpected error
1184    */
1185   @Experimental("Performance optimization for a very specific workload")
singleDelete(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts)1186   public void singleDelete(final ColumnFamilyHandle columnFamilyHandle,
1187       final byte[][] keyParts) throws RocksDBException {
1188     assert(isOwningHandle());
1189     singleDelete(nativeHandle_, keyParts, keyParts.length,
1190         columnFamilyHandle.nativeHandle_, false);
1191   }
1192 
1193   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1194   /**
1195    * Similar to {@link #singleDelete(byte[])} but allows
1196    * you to specify the key in several parts that will be
1197    * concatenated together.
1198    *
1199    * @param keyParts the specified key to be deleted.
1200    *
1201    * @throws RocksDBException when one of the TransactionalDB conditions
1202    *     described above occurs, or in the case of an unexpected error
1203    */
1204   @Experimental("Performance optimization for a very specific workload")
singleDelete(final byte[][] keyParts)1205   public void singleDelete(final byte[][] keyParts) throws RocksDBException {
1206     assert(isOwningHandle());
1207     singleDelete(nativeHandle_, keyParts, keyParts.length);
1208   }
1209 
1210   /**
1211    * Similar to {@link RocksDB#put(ColumnFamilyHandle, byte[], byte[])},
1212    * but operates on the transactions write batch. This write will only happen
1213    * if this transaction gets committed successfully.
1214    *
1215    * Unlike {@link #put(ColumnFamilyHandle, byte[], byte[])} no conflict
1216    * checking will be performed for this key.
1217    *
1218    * If this Transaction was created on a {@link TransactionDB}, this function
1219    * will still acquire locks necessary to make sure this write doesn't cause
1220    * conflicts in other transactions; This may cause a {@link RocksDBException}
1221    * with associated {@link Status.Code#Busy}.
1222    *
1223    * @param columnFamilyHandle The column family to put the key/value into
1224    * @param key the specified key to be inserted.
1225    * @param value the value associated with the specified key.
1226    *
1227    * @throws RocksDBException when one of the TransactionalDB conditions
1228    *     described above occurs, or in the case of an unexpected error
1229    */
putUntracked(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value)1230   public void putUntracked(final ColumnFamilyHandle columnFamilyHandle,
1231       final byte[] key, final byte[] value) throws RocksDBException {
1232     assert(isOwningHandle());
1233     putUntracked(nativeHandle_, key, key.length, value, value.length,
1234         columnFamilyHandle.nativeHandle_);
1235   }
1236 
1237   /**
1238    * Similar to {@link RocksDB#put(byte[], byte[])},
1239    * but operates on the transactions write batch. This write will only happen
1240    * if this transaction gets committed successfully.
1241    *
1242    * Unlike {@link #put(byte[], byte[])} no conflict
1243    * checking will be performed for this key.
1244    *
1245    * If this Transaction was created on a {@link TransactionDB}, this function
1246    * will still acquire locks necessary to make sure this write doesn't cause
1247    * conflicts in other transactions; This may cause a {@link RocksDBException}
1248    * with associated {@link Status.Code#Busy}.
1249    *
1250    * @param key the specified key to be inserted.
1251    * @param value the value associated with the specified key.
1252    *
1253    * @throws RocksDBException when one of the TransactionalDB conditions
1254    *     described above occurs, or in the case of an unexpected error
1255    */
putUntracked(final byte[] key, final byte[] value)1256   public void putUntracked(final byte[] key, final byte[] value)
1257       throws RocksDBException {
1258     assert(isOwningHandle());
1259     putUntracked(nativeHandle_, key, key.length, value, value.length);
1260   }
1261 
1262   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1263   /**
1264    * Similar to {@link #putUntracked(ColumnFamilyHandle, byte[], byte[])} but
1265    * allows you to specify the key and value in several parts that will be
1266    * concatenated together.
1267    *
1268    * @param columnFamilyHandle The column family to put the key/value into
1269    * @param keyParts the specified key to be inserted.
1270    * @param valueParts the value associated with the specified key.
1271    *
1272    * @throws RocksDBException when one of the TransactionalDB conditions
1273    *     described above occurs, or in the case of an unexpected error
1274    */
putUntracked(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts, final byte[][] valueParts)1275   public void putUntracked(final ColumnFamilyHandle columnFamilyHandle,
1276       final byte[][] keyParts, final byte[][] valueParts)
1277       throws RocksDBException {
1278     assert(isOwningHandle());
1279     putUntracked(nativeHandle_, keyParts, keyParts.length, valueParts,
1280         valueParts.length, columnFamilyHandle.nativeHandle_);
1281   }
1282 
1283   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1284   /**
1285    * Similar to {@link #putUntracked(byte[], byte[])} but
1286    * allows you to specify the key and value in several parts that will be
1287    * concatenated together.
1288    *
1289    * @param keyParts the specified key to be inserted.
1290    * @param valueParts the value associated with the specified key.
1291    *
1292    * @throws RocksDBException when one of the TransactionalDB conditions
1293    *     described above occurs, or in the case of an unexpected error
1294    */
putUntracked(final byte[][] keyParts, final byte[][] valueParts)1295   public void putUntracked(final byte[][] keyParts, final byte[][] valueParts)
1296       throws RocksDBException {
1297     assert(isOwningHandle());
1298     putUntracked(nativeHandle_, keyParts, keyParts.length, valueParts,
1299         valueParts.length);
1300   }
1301 
1302   /**
1303    * Similar to {@link RocksDB#merge(ColumnFamilyHandle, byte[], byte[])},
1304    * but operates on the transactions write batch. This write will only happen
1305    * if this transaction gets committed successfully.
1306    *
1307    * Unlike {@link #merge(ColumnFamilyHandle, byte[], byte[])} no conflict
1308    * checking will be performed for this key.
1309    *
1310    * If this Transaction was created on a {@link TransactionDB}, this function
1311    * will still acquire locks necessary to make sure this write doesn't cause
1312    * conflicts in other transactions; This may cause a {@link RocksDBException}
1313    * with associated {@link Status.Code#Busy}.
1314    *
1315    * @param columnFamilyHandle The column family to merge the key/value into
1316    * @param key the specified key to be merged.
1317    * @param value the value associated with the specified key.
1318    *
1319    * @throws RocksDBException when one of the TransactionalDB conditions
1320    *     described above occurs, or in the case of an unexpected error
1321    */
mergeUntracked(final ColumnFamilyHandle columnFamilyHandle, final byte[] key, final byte[] value)1322   public void mergeUntracked(final ColumnFamilyHandle columnFamilyHandle,
1323       final byte[] key, final byte[] value) throws RocksDBException {
1324     mergeUntracked(nativeHandle_, key, key.length, value, value.length,
1325         columnFamilyHandle.nativeHandle_);
1326   }
1327 
1328   /**
1329    * Similar to {@link RocksDB#merge(byte[], byte[])},
1330    * but operates on the transactions write batch. This write will only happen
1331    * if this transaction gets committed successfully.
1332    *
1333    * Unlike {@link #merge(byte[], byte[])} no conflict
1334    * checking will be performed for this key.
1335    *
1336    * If this Transaction was created on a {@link TransactionDB}, this function
1337    * will still acquire locks necessary to make sure this write doesn't cause
1338    * conflicts in other transactions; This may cause a {@link RocksDBException}
1339    * with associated {@link Status.Code#Busy}.
1340    *
1341    * @param key the specified key to be merged.
1342    * @param value the value associated with the specified key.
1343    *
1344    * @throws RocksDBException when one of the TransactionalDB conditions
1345    *     described above occurs, or in the case of an unexpected error
1346    */
mergeUntracked(final byte[] key, final byte[] value)1347   public void mergeUntracked(final byte[] key, final byte[] value)
1348       throws RocksDBException {
1349     assert(isOwningHandle());
1350     mergeUntracked(nativeHandle_, key, key.length, value, value.length);
1351   }
1352 
1353   /**
1354    * Similar to {@link RocksDB#delete(ColumnFamilyHandle, byte[])},
1355    * but operates on the transactions write batch. This write will only happen
1356    * if this transaction gets committed successfully.
1357    *
1358    * Unlike {@link #delete(ColumnFamilyHandle, byte[])} no conflict
1359    * checking will be performed for this key.
1360    *
1361    * If this Transaction was created on a {@link TransactionDB}, this function
1362    * will still acquire locks necessary to make sure this write doesn't cause
1363    * conflicts in other transactions; This may cause a {@link RocksDBException}
1364    * with associated {@link Status.Code#Busy}.
1365    *
1366    * @param columnFamilyHandle The column family to delete the key/value from
1367    * @param key the specified key to be deleted.
1368    *
1369    * @throws RocksDBException when one of the TransactionalDB conditions
1370    *     described above occurs, or in the case of an unexpected error
1371    */
deleteUntracked(final ColumnFamilyHandle columnFamilyHandle, final byte[] key)1372   public void deleteUntracked(final ColumnFamilyHandle columnFamilyHandle,
1373       final byte[] key) throws RocksDBException {
1374     assert(isOwningHandle());
1375     deleteUntracked(nativeHandle_, key, key.length,
1376         columnFamilyHandle.nativeHandle_);
1377   }
1378 
1379   /**
1380    * Similar to {@link RocksDB#delete(byte[])},
1381    * but operates on the transactions write batch. This write will only happen
1382    * if this transaction gets committed successfully.
1383    *
1384    * Unlike {@link #delete(byte[])} no conflict
1385    * checking will be performed for this key.
1386    *
1387    * If this Transaction was created on a {@link TransactionDB}, this function
1388    * will still acquire locks necessary to make sure this write doesn't cause
1389    * conflicts in other transactions; This may cause a {@link RocksDBException}
1390    * with associated {@link Status.Code#Busy}.
1391    *
1392    * @param key the specified key to be deleted.
1393    *
1394    * @throws RocksDBException when one of the TransactionalDB conditions
1395    *     described above occurs, or in the case of an unexpected error
1396    */
deleteUntracked(final byte[] key)1397   public void deleteUntracked(final byte[] key) throws RocksDBException {
1398     assert(isOwningHandle());
1399     deleteUntracked(nativeHandle_, key, key.length);
1400   }
1401 
1402   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1403   /**
1404    * Similar to {@link #deleteUntracked(ColumnFamilyHandle, byte[])} but allows
1405    * you to specify the key in several parts that will be
1406    * concatenated together.
1407    *
1408    * @param columnFamilyHandle The column family to delete the key/value from
1409    * @param keyParts the specified key to be deleted.
1410    *
1411    * @throws RocksDBException when one of the TransactionalDB conditions
1412    *     described above occurs, or in the case of an unexpected error
1413    */
deleteUntracked(final ColumnFamilyHandle columnFamilyHandle, final byte[][] keyParts)1414   public void deleteUntracked(final ColumnFamilyHandle columnFamilyHandle,
1415       final byte[][] keyParts) throws RocksDBException {
1416     assert(isOwningHandle());
1417     deleteUntracked(nativeHandle_, keyParts, keyParts.length,
1418         columnFamilyHandle.nativeHandle_);
1419   }
1420 
1421   //TODO(AR) refactor if we implement org.rocksdb.SliceParts in future
1422   /**
1423    * Similar to {@link #deleteUntracked(byte[])} but allows
1424    * you to specify the key in several parts that will be
1425    * concatenated together.
1426    *
1427    * @param keyParts the specified key to be deleted.
1428    *
1429    * @throws RocksDBException when one of the TransactionalDB conditions
1430    *     described above occurs, or in the case of an unexpected error
1431    */
deleteUntracked(final byte[][] keyParts)1432   public void deleteUntracked(final byte[][] keyParts) throws RocksDBException {
1433     assert(isOwningHandle());
1434     deleteUntracked(nativeHandle_, keyParts, keyParts.length);
1435   }
1436 
1437   /**
1438    * Similar to {@link WriteBatch#putLogData(byte[])}
1439    *
1440    * @param blob binary object to be inserted
1441    */
putLogData(final byte[] blob)1442   public void putLogData(final byte[] blob) {
1443     assert(isOwningHandle());
1444     putLogData(nativeHandle_, blob, blob.length);
1445   }
1446 
1447   /**
1448    * By default, all put/merge/delete operations will be indexed in the
1449    * transaction so that get/getForUpdate/getIterator can search for these
1450    * keys.
1451    *
1452    * If the caller does not want to fetch the keys about to be written,
1453    * they may want to avoid indexing as a performance optimization.
1454    * Calling {@link #disableIndexing()} will turn off indexing for all future
1455    * put/merge/delete operations until {@link #enableIndexing()} is called.
1456    *
1457    * If a key is put/merge/deleted after {@link #disableIndexing()} is called
1458    * and then is fetched via get/getForUpdate/getIterator, the result of the
1459    * fetch is undefined.
1460    */
disableIndexing()1461   public void disableIndexing() {
1462     assert(isOwningHandle());
1463     disableIndexing(nativeHandle_);
1464   }
1465 
1466   /**
1467    * Re-enables indexing after a previous call to {@link #disableIndexing()}
1468    */
enableIndexing()1469   public void enableIndexing() {
1470     assert(isOwningHandle());
1471     enableIndexing(nativeHandle_);
1472   }
1473 
1474   /**
1475    * Returns the number of distinct Keys being tracked by this transaction.
1476    * If this transaction was created by a {@link TransactionDB}, this is the
1477    * number of keys that are currently locked by this transaction.
1478    * If this transaction was created by an {@link OptimisticTransactionDB},
1479    * this is the number of keys that need to be checked for conflicts at commit
1480    * time.
1481    *
1482    * @return the number of distinct Keys being tracked by this transaction
1483    */
getNumKeys()1484   public long getNumKeys() {
1485     assert(isOwningHandle());
1486     return getNumKeys(nativeHandle_);
1487   }
1488 
1489   /**
1490    * Returns the number of puts that have been applied to this
1491    * transaction so far.
1492    *
1493    * @return the number of puts that have been applied to this transaction
1494    */
getNumPuts()1495   public long getNumPuts() {
1496     assert(isOwningHandle());
1497     return getNumPuts(nativeHandle_);
1498   }
1499 
1500   /**
1501    * Returns the number of deletes that have been applied to this
1502    * transaction so far.
1503    *
1504    * @return the number of deletes that have been applied to this transaction
1505    */
getNumDeletes()1506   public long getNumDeletes() {
1507     assert(isOwningHandle());
1508     return getNumDeletes(nativeHandle_);
1509   }
1510 
1511   /**
1512    * Returns the number of merges that have been applied to this
1513    * transaction so far.
1514    *
1515    * @return the number of merges that have been applied to this transaction
1516    */
getNumMerges()1517   public long getNumMerges() {
1518     assert(isOwningHandle());
1519     return getNumMerges(nativeHandle_);
1520   }
1521 
1522   /**
1523    * Returns the elapsed time in milliseconds since this Transaction began.
1524    *
1525    * @return the elapsed time in milliseconds since this transaction began.
1526    */
getElapsedTime()1527   public long getElapsedTime() {
1528     assert(isOwningHandle());
1529     return getElapsedTime(nativeHandle_);
1530   }
1531 
1532   /**
1533    * Fetch the underlying write batch that contains all pending changes to be
1534    * committed.
1535    *
1536    * Note: You should not write or delete anything from the batch directly and
1537    * should only use the functions in the {@link Transaction} class to
1538    * write to this transaction.
1539    *
1540    * @return The write batch
1541    */
getWriteBatch()1542   public WriteBatchWithIndex getWriteBatch() {
1543     assert(isOwningHandle());
1544     final WriteBatchWithIndex writeBatchWithIndex =
1545         new WriteBatchWithIndex(getWriteBatch(nativeHandle_));
1546     return writeBatchWithIndex;
1547   }
1548 
1549   /**
1550    * Change the value of {@link TransactionOptions#getLockTimeout()}
1551    * (in milliseconds) for this transaction.
1552    *
1553    * Has no effect on OptimisticTransactions.
1554    *
1555    * @param lockTimeout the timeout (in milliseconds) for locks used by this
1556    *     transaction.
1557    */
setLockTimeout(final long lockTimeout)1558   public void setLockTimeout(final long lockTimeout) {
1559     assert(isOwningHandle());
1560     setLockTimeout(nativeHandle_, lockTimeout);
1561   }
1562 
1563   /**
1564    * Return the WriteOptions that will be used during {@link #commit()}.
1565    *
1566    * @return the WriteOptions that will be used
1567    */
getWriteOptions()1568   public WriteOptions getWriteOptions() {
1569     assert(isOwningHandle());
1570     final WriteOptions writeOptions =
1571         new WriteOptions(getWriteOptions(nativeHandle_));
1572     return writeOptions;
1573   }
1574 
1575   /**
1576    * Reset the WriteOptions that will be used during {@link #commit()}.
1577    *
1578    * @param writeOptions The new WriteOptions
1579    */
setWriteOptions(final WriteOptions writeOptions)1580   public void setWriteOptions(final WriteOptions writeOptions) {
1581     assert(isOwningHandle());
1582     setWriteOptions(nativeHandle_, writeOptions.nativeHandle_);
1583   }
1584 
1585   /**
1586    * If this key was previously fetched in this transaction using
1587    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)}/
1588    * {@link #multiGetForUpdate(ReadOptions, List, byte[][])}, calling
1589    * {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])} will tell
1590    * the transaction that it no longer needs to do any conflict checking
1591    * for this key.
1592    *
1593    * If a key has been fetched N times via
1594    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)}/
1595    * {@link #multiGetForUpdate(ReadOptions, List, byte[][])}, then
1596    * {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])}  will only have an
1597    * effect if it is also called N times. If this key has been written to in
1598    * this transaction, {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])}
1599    * will have no effect.
1600    *
1601    * If {@link #setSavePoint()} has been called after the
1602    * {@link #getForUpdate(ReadOptions, ColumnFamilyHandle, byte[], boolean)},
1603    * {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])} will not have any
1604    * effect.
1605    *
1606    * If this Transaction was created by an {@link OptimisticTransactionDB},
1607    * calling {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])} can affect
1608    * whether this key is conflict checked at commit time.
1609    * If this Transaction was created by a {@link TransactionDB},
1610    * calling {@link #undoGetForUpdate(ColumnFamilyHandle, byte[])} may release
1611    * any held locks for this key.
1612    *
1613    * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
1614    *     instance
1615    * @param key the key to retrieve the value for.
1616    */
undoGetForUpdate(final ColumnFamilyHandle columnFamilyHandle, final byte[] key)1617   public void undoGetForUpdate(final ColumnFamilyHandle columnFamilyHandle,
1618       final byte[] key) {
1619     assert(isOwningHandle());
1620     undoGetForUpdate(nativeHandle_, key, key.length, columnFamilyHandle.nativeHandle_);
1621   }
1622 
1623   /**
1624    * If this key was previously fetched in this transaction using
1625    * {@link #getForUpdate(ReadOptions, byte[], boolean)}/
1626    * {@link #multiGetForUpdate(ReadOptions, List, byte[][])}, calling
1627    * {@link #undoGetForUpdate(byte[])} will tell
1628    * the transaction that it no longer needs to do any conflict checking
1629    * for this key.
1630    *
1631    * If a key has been fetched N times via
1632    * {@link #getForUpdate(ReadOptions, byte[], boolean)}/
1633    * {@link #multiGetForUpdate(ReadOptions, List, byte[][])}, then
1634    * {@link #undoGetForUpdate(byte[])}  will only have an
1635    * effect if it is also called N times. If this key has been written to in
1636    * this transaction, {@link #undoGetForUpdate(byte[])}
1637    * will have no effect.
1638    *
1639    * If {@link #setSavePoint()} has been called after the
1640    * {@link #getForUpdate(ReadOptions, byte[], boolean)},
1641    * {@link #undoGetForUpdate(byte[])} will not have any
1642    * effect.
1643    *
1644    * If this Transaction was created by an {@link OptimisticTransactionDB},
1645    * calling {@link #undoGetForUpdate(byte[])} can affect
1646    * whether this key is conflict checked at commit time.
1647    * If this Transaction was created by a {@link TransactionDB},
1648    * calling {@link #undoGetForUpdate(byte[])} may release
1649    * any held locks for this key.
1650    *
1651    * @param key the key to retrieve the value for.
1652    */
undoGetForUpdate(final byte[] key)1653   public void undoGetForUpdate(final byte[] key) {
1654     assert(isOwningHandle());
1655     undoGetForUpdate(nativeHandle_, key, key.length);
1656   }
1657 
1658   /**
1659    * Adds the keys from the WriteBatch to the transaction
1660    *
1661    * @param writeBatch The write batch to read from
1662    *
1663    * @throws RocksDBException if an error occurs whilst rebuilding from the
1664    *     write batch.
1665    */
rebuildFromWriteBatch(final WriteBatch writeBatch)1666   public void rebuildFromWriteBatch(final WriteBatch writeBatch)
1667       throws RocksDBException {
1668     assert(isOwningHandle());
1669     rebuildFromWriteBatch(nativeHandle_, writeBatch.nativeHandle_);
1670   }
1671 
1672   /**
1673    * Get the Commit time Write Batch.
1674    *
1675    * @return the commit time write batch.
1676    */
getCommitTimeWriteBatch()1677   public WriteBatch getCommitTimeWriteBatch() {
1678     assert(isOwningHandle());
1679     final WriteBatch writeBatch =
1680         new WriteBatch(getCommitTimeWriteBatch(nativeHandle_));
1681     return writeBatch;
1682   }
1683 
1684   /**
1685    * Set the log number.
1686    *
1687    * @param logNumber the log number
1688    */
setLogNumber(final long logNumber)1689   public void setLogNumber(final long logNumber) {
1690     assert(isOwningHandle());
1691     setLogNumber(nativeHandle_, logNumber);
1692   }
1693 
1694   /**
1695    * Get the log number.
1696    *
1697    * @return the log number
1698    */
getLogNumber()1699   public long getLogNumber() {
1700     assert(isOwningHandle());
1701     return getLogNumber(nativeHandle_);
1702   }
1703 
1704   /**
1705    * Set the name of the transaction.
1706    *
1707    * @param transactionName the name of the transaction
1708    *
1709    * @throws RocksDBException if an error occurs when setting the transaction
1710    *     name.
1711    */
setName(final String transactionName)1712   public void setName(final String transactionName) throws RocksDBException {
1713     assert(isOwningHandle());
1714     setName(nativeHandle_, transactionName);
1715   }
1716 
1717   /**
1718    * Get the name of the transaction.
1719    *
1720    * @return the name of the transaction
1721    */
getName()1722   public String getName() {
1723     assert(isOwningHandle());
1724     return getName(nativeHandle_);
1725   }
1726 
1727   /**
1728    * Get the ID of the transaction.
1729    *
1730    * @return the ID of the transaction.
1731    */
getID()1732   public long getID() {
1733     assert(isOwningHandle());
1734     return getID(nativeHandle_);
1735   }
1736 
1737   /**
1738    * Determine if a deadlock has been detected.
1739    *
1740    * @return true if a deadlock has been detected.
1741    */
isDeadlockDetect()1742   public boolean isDeadlockDetect() {
1743     assert(isOwningHandle());
1744     return isDeadlockDetect(nativeHandle_);
1745   }
1746 
1747   /**
1748    * Get the list of waiting transactions.
1749    *
1750    * @return The list of waiting transactions.
1751    */
getWaitingTxns()1752   public WaitingTransactions getWaitingTxns() {
1753     assert(isOwningHandle());
1754     return getWaitingTxns(nativeHandle_);
1755   }
1756 
1757   /**
1758    * Get the execution status of the transaction.
1759    *
1760    * NOTE: The execution status of an Optimistic Transaction
1761    * never changes. This is only useful for non-optimistic transactions!
1762    *
1763    * @return The execution status of the transaction
1764    */
getState()1765   public TransactionState getState() {
1766     assert(isOwningHandle());
1767     return TransactionState.getTransactionState(
1768         getState(nativeHandle_));
1769   }
1770 
1771   /**
1772    * The globally unique id with which the transaction is identified. This id
1773    * might or might not be set depending on the implementation. Similarly the
1774    * implementation decides the point in lifetime of a transaction at which it
1775    * assigns the id. Although currently it is the case, the id is not guaranteed
1776    * to remain the same across restarts.
1777    *
1778    * @return the transaction id.
1779    */
1780   @Experimental("NOTE: Experimental feature")
getId()1781   public long getId() {
1782     assert(isOwningHandle());
1783     return getId(nativeHandle_);
1784   }
1785 
1786   public enum TransactionState {
1787     STARTED((byte)0),
1788     AWAITING_PREPARE((byte)1),
1789     PREPARED((byte)2),
1790     AWAITING_COMMIT((byte)3),
1791     COMMITED((byte)4),
1792     AWAITING_ROLLBACK((byte)5),
1793     ROLLEDBACK((byte)6),
1794     LOCKS_STOLEN((byte)7);
1795 
1796     private final byte value;
1797 
TransactionState(final byte value)1798     TransactionState(final byte value) {
1799       this.value = value;
1800     }
1801 
1802     /**
1803      * Get TransactionState by byte value.
1804      *
1805      * @param value byte representation of TransactionState.
1806      *
1807      * @return {@link org.rocksdb.Transaction.TransactionState} instance or null.
1808      * @throws java.lang.IllegalArgumentException if an invalid
1809      *     value is provided.
1810      */
getTransactionState(final byte value)1811     public static TransactionState getTransactionState(final byte value) {
1812       for (final TransactionState transactionState : TransactionState.values()) {
1813         if (transactionState.value == value){
1814           return transactionState;
1815         }
1816       }
1817       throw new IllegalArgumentException(
1818           "Illegal value provided for TransactionState.");
1819     }
1820   }
1821 
1822   /**
1823    * Called from C++ native method {@link #getWaitingTxns(long)}
1824    * to construct a WaitingTransactions object.
1825    *
1826    * @param columnFamilyId The id of the {@link ColumnFamilyHandle}
1827    * @param key The key
1828    * @param transactionIds The transaction ids
1829    *
1830    * @return The waiting transactions
1831    */
newWaitingTransactions( final long columnFamilyId, final String key, final long[] transactionIds)1832   private WaitingTransactions newWaitingTransactions(
1833       final long columnFamilyId, final String key,
1834       final long[] transactionIds) {
1835     return new WaitingTransactions(columnFamilyId, key, transactionIds);
1836   }
1837 
1838   public static class WaitingTransactions {
1839     private final long columnFamilyId;
1840     private final String key;
1841     private final long[] transactionIds;
1842 
WaitingTransactions(final long columnFamilyId, final String key, final long[] transactionIds)1843     private WaitingTransactions(final long columnFamilyId, final String key,
1844         final long[] transactionIds) {
1845       this.columnFamilyId = columnFamilyId;
1846       this.key = key;
1847       this.transactionIds = transactionIds;
1848     }
1849 
1850     /**
1851      * Get the Column Family ID.
1852      *
1853      * @return The column family ID
1854      */
getColumnFamilyId()1855     public long getColumnFamilyId() {
1856       return columnFamilyId;
1857     }
1858 
1859     /**
1860      * Get the key on which the transactions are waiting.
1861      *
1862      * @return The key
1863      */
getKey()1864     public String getKey() {
1865       return key;
1866     }
1867 
1868     /**
1869      * Get the IDs of the waiting transactions.
1870      *
1871      * @return The IDs of the waiting transactions
1872      */
getTransactionIds()1873     public long[] getTransactionIds() {
1874       return transactionIds;
1875     }
1876   }
1877 
setSnapshot(final long handle)1878   private native void setSnapshot(final long handle);
setSnapshotOnNextOperation(final long handle)1879   private native void setSnapshotOnNextOperation(final long handle);
setSnapshotOnNextOperation(final long handle, final long transactionNotifierHandle)1880   private native void setSnapshotOnNextOperation(final long handle,
1881       final long transactionNotifierHandle);
getSnapshot(final long handle)1882   private native long getSnapshot(final long handle);
clearSnapshot(final long handle)1883   private native void clearSnapshot(final long handle);
prepare(final long handle)1884   private native void prepare(final long handle) throws RocksDBException;
commit(final long handle)1885   private native void commit(final long handle) throws RocksDBException;
rollback(final long handle)1886   private native void rollback(final long handle) throws RocksDBException;
setSavePoint(final long handle)1887   private native void setSavePoint(final long handle) throws RocksDBException;
rollbackToSavePoint(final long handle)1888   private native void rollbackToSavePoint(final long handle)
1889       throws RocksDBException;
get(final long handle, final long readOptionsHandle, final byte key[], final int keyLength, final long columnFamilyHandle)1890   private native byte[] get(final long handle, final long readOptionsHandle,
1891       final byte key[], final int keyLength, final long columnFamilyHandle)
1892       throws RocksDBException;
get(final long handle, final long readOptionsHandle, final byte key[], final int keyLen)1893   private native byte[] get(final long handle, final long readOptionsHandle,
1894       final byte key[], final int keyLen) throws RocksDBException;
multiGet(final long handle, final long readOptionsHandle, final byte[][] keys, final long[] columnFamilyHandles)1895   private native byte[][] multiGet(final long handle,
1896       final long readOptionsHandle, final byte[][] keys,
1897       final long[] columnFamilyHandles) throws RocksDBException;
multiGet(final long handle, final long readOptionsHandle, final byte[][] keys)1898   private native byte[][] multiGet(final long handle,
1899       final long readOptionsHandle, final byte[][] keys)
1900       throws RocksDBException;
getForUpdate(final long handle, final long readOptionsHandle, final byte key[], final int keyLength, final long columnFamilyHandle, final boolean exclusive, final boolean doValidate)1901   private native byte[] getForUpdate(final long handle, final long readOptionsHandle,
1902       final byte key[], final int keyLength, final long columnFamilyHandle, final boolean exclusive,
1903       final boolean doValidate) throws RocksDBException;
getForUpdate(final long handle, final long readOptionsHandle, final byte key[], final int keyLen, final boolean exclusive, final boolean doValidate)1904   private native byte[] getForUpdate(final long handle, final long readOptionsHandle,
1905       final byte key[], final int keyLen, final boolean exclusive, final boolean doValidate)
1906       throws RocksDBException;
multiGetForUpdate(final long handle, final long readOptionsHandle, final byte[][] keys, final long[] columnFamilyHandles)1907   private native byte[][] multiGetForUpdate(final long handle,
1908       final long readOptionsHandle, final byte[][] keys,
1909       final long[] columnFamilyHandles) throws RocksDBException;
multiGetForUpdate(final long handle, final long readOptionsHandle, final byte[][] keys)1910   private native byte[][] multiGetForUpdate(final long handle,
1911       final long readOptionsHandle, final byte[][] keys)
1912       throws RocksDBException;
getIterator(final long handle, final long readOptionsHandle)1913   private native long getIterator(final long handle,
1914       final long readOptionsHandle);
getIterator(final long handle, final long readOptionsHandle, final long columnFamilyHandle)1915   private native long getIterator(final long handle,
1916       final long readOptionsHandle, final long columnFamilyHandle);
put(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength, final long columnFamilyHandle, final boolean assumeTracked)1917   private native void put(final long handle, final byte[] key, final int keyLength,
1918       final byte[] value, final int valueLength, final long columnFamilyHandle,
1919       final boolean assumeTracked) throws RocksDBException;
put(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength)1920   private native void put(final long handle, final byte[] key,
1921       final int keyLength, final byte[] value, final int valueLength)
1922       throws RocksDBException;
put(final long handle, final byte[][] keys, final int keysLength, final byte[][] values, final int valuesLength, final long columnFamilyHandle, final boolean assumeTracked)1923   private native void put(final long handle, final byte[][] keys, final int keysLength,
1924       final byte[][] values, final int valuesLength, final long columnFamilyHandle,
1925       final boolean assumeTracked) throws RocksDBException;
put(final long handle, final byte[][] keys, final int keysLength, final byte[][] values, final int valuesLength)1926   private native void put(final long handle, final byte[][] keys,
1927       final int keysLength, final byte[][] values, final int valuesLength)
1928       throws RocksDBException;
merge(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength, final long columnFamilyHandle, final boolean assumeTracked)1929   private native void merge(final long handle, final byte[] key, final int keyLength,
1930       final byte[] value, final int valueLength, final long columnFamilyHandle,
1931       final boolean assumeTracked) throws RocksDBException;
merge(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength)1932   private native void merge(final long handle, final byte[] key,
1933       final int keyLength, final byte[] value, final int valueLength)
1934       throws RocksDBException;
delete(final long handle, final byte[] key, final int keyLength, final long columnFamilyHandle, final boolean assumeTracked)1935   private native void delete(final long handle, final byte[] key, final int keyLength,
1936       final long columnFamilyHandle, final boolean assumeTracked) throws RocksDBException;
delete(final long handle, final byte[] key, final int keyLength)1937   private native void delete(final long handle, final byte[] key,
1938       final int keyLength) throws RocksDBException;
delete(final long handle, final byte[][] keys, final int keysLength, final long columnFamilyHandle, final boolean assumeTracked)1939   private native void delete(final long handle, final byte[][] keys, final int keysLength,
1940       final long columnFamilyHandle, final boolean assumeTracked) throws RocksDBException;
delete(final long handle, final byte[][] keys, final int keysLength)1941   private native void delete(final long handle, final byte[][] keys,
1942       final int keysLength) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLength, final long columnFamilyHandle, final boolean assumeTracked)1943   private native void singleDelete(final long handle, final byte[] key, final int keyLength,
1944       final long columnFamilyHandle, final boolean assumeTracked) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLength)1945   private native void singleDelete(final long handle, final byte[] key,
1946       final int keyLength) throws RocksDBException;
singleDelete(final long handle, final byte[][] keys, final int keysLength, final long columnFamilyHandle, final boolean assumeTracked)1947   private native void singleDelete(final long handle, final byte[][] keys, final int keysLength,
1948       final long columnFamilyHandle, final boolean assumeTracked) throws RocksDBException;
singleDelete(final long handle, final byte[][] keys, final int keysLength)1949   private native void singleDelete(final long handle, final byte[][] keys,
1950       final int keysLength) throws RocksDBException;
putUntracked(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength, final long columnFamilyHandle)1951   private native void putUntracked(final long handle, final byte[] key,
1952       final int keyLength, final byte[] value, final int valueLength,
1953       final long columnFamilyHandle) throws RocksDBException;
putUntracked(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength)1954   private native void putUntracked(final long handle, final byte[] key,
1955       final int keyLength, final byte[] value, final int valueLength)
1956       throws RocksDBException;
putUntracked(final long handle, final byte[][] keys, final int keysLength, final byte[][] values, final int valuesLength, final long columnFamilyHandle)1957   private native void putUntracked(final long handle, final byte[][] keys,
1958       final int keysLength, final byte[][] values, final int valuesLength,
1959       final long columnFamilyHandle) throws RocksDBException;
putUntracked(final long handle, final byte[][] keys, final int keysLength, final byte[][] values, final int valuesLength)1960   private native void putUntracked(final long handle, final byte[][] keys,
1961       final int keysLength, final byte[][] values, final int valuesLength)
1962       throws RocksDBException;
mergeUntracked(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength, final long columnFamilyHandle)1963   private native void mergeUntracked(final long handle, final byte[] key,
1964       final int keyLength, final byte[] value, final int valueLength,
1965       final long columnFamilyHandle) throws RocksDBException;
mergeUntracked(final long handle, final byte[] key, final int keyLength, final byte[] value, final int valueLength)1966   private native void mergeUntracked(final long handle, final byte[] key,
1967       final int keyLength, final byte[] value, final int valueLength)
1968       throws RocksDBException;
deleteUntracked(final long handle, final byte[] key, final int keyLength, final long columnFamilyHandle)1969   private native void deleteUntracked(final long handle, final byte[] key,
1970       final int keyLength, final long columnFamilyHandle)
1971       throws RocksDBException;
deleteUntracked(final long handle, final byte[] key, final int keyLength)1972   private native void deleteUntracked(final long handle, final byte[] key,
1973       final int keyLength) throws RocksDBException;
deleteUntracked(final long handle, final byte[][] keys, final int keysLength, final long columnFamilyHandle)1974   private native void deleteUntracked(final long handle, final byte[][] keys,
1975       final int keysLength, final long columnFamilyHandle)
1976       throws RocksDBException;
deleteUntracked(final long handle, final byte[][] keys, final int keysLength)1977   private native void deleteUntracked(final long handle, final byte[][] keys,
1978       final int keysLength) throws RocksDBException;
putLogData(final long handle, final byte[] blob, final int blobLength)1979   private native void putLogData(final long handle, final byte[] blob,
1980       final int blobLength);
disableIndexing(final long handle)1981   private native void disableIndexing(final long handle);
enableIndexing(final long handle)1982   private native void enableIndexing(final long handle);
getNumKeys(final long handle)1983   private native long getNumKeys(final long handle);
getNumPuts(final long handle)1984   private native long getNumPuts(final long handle);
getNumDeletes(final long handle)1985   private native long getNumDeletes(final long handle);
getNumMerges(final long handle)1986   private native long getNumMerges(final long handle);
getElapsedTime(final long handle)1987   private native long getElapsedTime(final long handle);
getWriteBatch(final long handle)1988   private native long getWriteBatch(final long handle);
setLockTimeout(final long handle, final long lockTimeout)1989   private native void setLockTimeout(final long handle, final long lockTimeout);
getWriteOptions(final long handle)1990   private native long getWriteOptions(final long handle);
setWriteOptions(final long handle, final long writeOptionsHandle)1991   private native void setWriteOptions(final long handle,
1992       final long writeOptionsHandle);
undoGetForUpdate(final long handle, final byte[] key, final int keyLength, final long columnFamilyHandle)1993   private native void undoGetForUpdate(final long handle, final byte[] key,
1994       final int keyLength, final long columnFamilyHandle);
undoGetForUpdate(final long handle, final byte[] key, final int keyLength)1995   private native void undoGetForUpdate(final long handle, final byte[] key,
1996       final int keyLength);
rebuildFromWriteBatch(final long handle, final long writeBatchHandle)1997   private native void rebuildFromWriteBatch(final long handle,
1998       final long writeBatchHandle) throws RocksDBException;
getCommitTimeWriteBatch(final long handle)1999   private native long getCommitTimeWriteBatch(final long handle);
setLogNumber(final long handle, final long logNumber)2000   private native void setLogNumber(final long handle, final long logNumber);
getLogNumber(final long handle)2001   private native long getLogNumber(final long handle);
setName(final long handle, final String name)2002   private native void setName(final long handle, final String name)
2003       throws RocksDBException;
getName(final long handle)2004   private native String getName(final long handle);
getID(final long handle)2005   private native long getID(final long handle);
isDeadlockDetect(final long handle)2006   private native boolean isDeadlockDetect(final long handle);
getWaitingTxns(final long handle)2007   private native WaitingTransactions getWaitingTxns(final long handle);
getState(final long handle)2008   private native byte getState(final long handle);
getId(final long handle)2009   private native long getId(final long handle);
2010 
disposeInternal(final long handle)2011   @Override protected final native void disposeInternal(final long handle);
2012 }
2013