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.nio.ByteBuffer;
9 
10 /**
11  * Similar to {@link org.rocksdb.WriteBatch} but with a binary searchable
12  * index built for all the keys inserted.
13  *
14  * Calling put, merge, remove or putLogData calls the same function
15  * as with {@link org.rocksdb.WriteBatch} whilst also building an index.
16  *
17  * A user can call {@link org.rocksdb.WriteBatchWithIndex#newIterator()} to
18  * create an iterator over the write batch or
19  * {@link org.rocksdb.WriteBatchWithIndex#newIteratorWithBase(org.rocksdb.RocksIterator)}
20  * to get an iterator for the database with Read-Your-Own-Writes like capability
21  */
22 public class WriteBatchWithIndex extends AbstractWriteBatch {
23   /**
24    * Creates a WriteBatchWithIndex where no bytes
25    * are reserved up-front, bytewise comparison is
26    * used for fallback key comparisons,
27    * and duplicate keys operations are retained
28    */
WriteBatchWithIndex()29   public WriteBatchWithIndex() {
30     super(newWriteBatchWithIndex());
31   }
32 
33 
34   /**
35    * Creates a WriteBatchWithIndex where no bytes
36    * are reserved up-front, bytewise comparison is
37    * used for fallback key comparisons, and duplicate key
38    * assignment is determined by the constructor argument
39    *
40    * @param overwriteKey if true, overwrite the key in the index when
41    *   inserting a duplicate key, in this way an iterator will never
42    *   show two entries with the same key.
43    */
WriteBatchWithIndex(final boolean overwriteKey)44   public WriteBatchWithIndex(final boolean overwriteKey) {
45     super(newWriteBatchWithIndex(overwriteKey));
46   }
47 
48   /**
49    * Creates a WriteBatchWithIndex
50    *
51    * @param fallbackIndexComparator We fallback to this comparator
52    *  to compare keys within a column family if we cannot determine
53    *  the column family and so look up it's comparator.
54    *
55    * @param reservedBytes reserved bytes in underlying WriteBatch
56    *
57    * @param overwriteKey if true, overwrite the key in the index when
58    *   inserting a duplicate key, in this way an iterator will never
59    *   show two entries with the same key.
60    */
WriteBatchWithIndex( final AbstractComparator fallbackIndexComparator, final int reservedBytes, final boolean overwriteKey)61   public WriteBatchWithIndex(
62       final AbstractComparator
63           fallbackIndexComparator, final int reservedBytes,
64       final boolean overwriteKey) {
65     super(newWriteBatchWithIndex(fallbackIndexComparator.nativeHandle_,
66         fallbackIndexComparator.getComparatorType().getValue(), reservedBytes,
67         overwriteKey));
68   }
69 
70   /**
71    * <p>Private WriteBatchWithIndex constructor which is used to construct
72    * WriteBatchWithIndex instances from C++ side. As the reference to this
73    * object is also managed from C++ side the handle will be disowned.</p>
74    *
75    * @param nativeHandle address of native instance.
76    */
WriteBatchWithIndex(final long nativeHandle)77   WriteBatchWithIndex(final long nativeHandle) {
78     super(nativeHandle);
79     disOwnNativeHandle();
80   }
81 
82   /**
83    * Create an iterator of a column family. User can call
84    * {@link org.rocksdb.RocksIteratorInterface#seek(byte[])} to
85    * search to the next entry of or after a key. Keys will be iterated in the
86    * order given by index_comparator. For multiple updates on the same key,
87    * each update will be returned as a separate entry, in the order of update
88    * time.
89    *
90    * @param columnFamilyHandle The column family to iterate over
91    * @return An iterator for the Write Batch contents, restricted to the column
92    * family
93    */
newIterator( final ColumnFamilyHandle columnFamilyHandle)94   public WBWIRocksIterator newIterator(
95       final ColumnFamilyHandle columnFamilyHandle) {
96     return new WBWIRocksIterator(this, iterator1(nativeHandle_,
97             columnFamilyHandle.nativeHandle_));
98   }
99 
100   /**
101    * Create an iterator of the default column family. User can call
102    * {@link org.rocksdb.RocksIteratorInterface#seek(byte[])} to
103    * search to the next entry of or after a key. Keys will be iterated in the
104    * order given by index_comparator. For multiple updates on the same key,
105    * each update will be returned as a separate entry, in the order of update
106    * time.
107    *
108    * @return An iterator for the Write Batch contents
109    */
newIterator()110   public WBWIRocksIterator newIterator() {
111     return new WBWIRocksIterator(this, iterator0(nativeHandle_));
112   }
113 
114   /**
115    * Provides Read-Your-Own-Writes like functionality by
116    * creating a new Iterator that will use {@link org.rocksdb.WBWIRocksIterator}
117    * as a delta and baseIterator as a base
118    *
119    * Updating write batch with the current key of the iterator is not safe.
120    * We strongly recommand users not to do it. It will invalidate the current
121    * key() and value() of the iterator. This invalidation happens even before
122    * the write batch update finishes. The state may recover after Next() is
123    * called.
124    *
125    * @param columnFamilyHandle The column family to iterate over
126    * @param baseIterator The base iterator,
127    *   e.g. {@link org.rocksdb.RocksDB#newIterator()}
128    * @return An iterator which shows a view comprised of both the database
129    * point-in-time from baseIterator and modifications made in this write batch.
130    */
newIteratorWithBase( final ColumnFamilyHandle columnFamilyHandle, final RocksIterator baseIterator)131   public RocksIterator newIteratorWithBase(
132       final ColumnFamilyHandle columnFamilyHandle,
133       final RocksIterator baseIterator) {
134     RocksIterator iterator = new RocksIterator(baseIterator.parent_,
135         iteratorWithBase(
136             nativeHandle_, columnFamilyHandle.nativeHandle_, baseIterator.nativeHandle_));
137     // when the iterator is deleted it will also delete the baseIterator
138     baseIterator.disOwnNativeHandle();
139     return iterator;
140   }
141 
142   /**
143    * Provides Read-Your-Own-Writes like functionality by
144    * creating a new Iterator that will use {@link org.rocksdb.WBWIRocksIterator}
145    * as a delta and baseIterator as a base. Operates on the default column
146    * family.
147    *
148    * @param baseIterator The base iterator,
149    *   e.g. {@link org.rocksdb.RocksDB#newIterator()}
150    * @return An iterator which shows a view comprised of both the database
151    * point-in-timefrom baseIterator and modifications made in this write batch.
152    */
newIteratorWithBase(final RocksIterator baseIterator)153   public RocksIterator newIteratorWithBase(final RocksIterator baseIterator) {
154     return newIteratorWithBase(baseIterator.parent_.getDefaultColumnFamily(), baseIterator);
155   }
156 
157   /**
158    * Similar to {@link RocksDB#get(ColumnFamilyHandle, byte[])} but will only
159    * read the key from this batch.
160    *
161    * @param columnFamilyHandle The column family to retrieve the value from
162    * @param options The database options to use
163    * @param key The key to read the value for
164    *
165    * @return a byte array storing the value associated with the input key if
166    *     any. null if it does not find the specified key.
167    *
168    * @throws RocksDBException if the batch does not have enough data to resolve
169    * Merge operations, MergeInProgress status may be returned.
170    */
getFromBatch(final ColumnFamilyHandle columnFamilyHandle, final DBOptions options, final byte[] key)171   public byte[] getFromBatch(final ColumnFamilyHandle columnFamilyHandle,
172       final DBOptions options, final byte[] key) throws RocksDBException {
173     return getFromBatch(nativeHandle_, options.nativeHandle_,
174         key, key.length, columnFamilyHandle.nativeHandle_);
175   }
176 
177   /**
178    * Similar to {@link RocksDB#get(byte[])} but will only
179    * read the key from this batch.
180    *
181    * @param options The database options to use
182    * @param key The key to read the value for
183    *
184    * @return a byte array storing the value associated with the input key if
185    *     any. null if it does not find the specified key.
186    *
187    * @throws RocksDBException if the batch does not have enough data to resolve
188    * Merge operations, MergeInProgress status may be returned.
189    */
getFromBatch(final DBOptions options, final byte[] key)190   public byte[] getFromBatch(final DBOptions options, final byte[] key)
191       throws RocksDBException {
192     return getFromBatch(nativeHandle_, options.nativeHandle_, key, key.length);
193   }
194 
195   /**
196    * Similar to {@link RocksDB#get(ColumnFamilyHandle, byte[])} but will also
197    * read writes from this batch.
198    *
199    * This function will query both this batch and the DB and then merge
200    * the results using the DB's merge operator (if the batch contains any
201    * merge requests).
202    *
203    * Setting {@link ReadOptions#setSnapshot(long, long)} will affect what is
204    * read from the DB but will NOT change which keys are read from the batch
205    * (the keys in this batch do not yet belong to any snapshot and will be
206    * fetched regardless).
207    *
208    * @param db The Rocks database
209    * @param columnFamilyHandle The column family to retrieve the value from
210    * @param options The read options to use
211    * @param key The key to read the value for
212    *
213    * @return a byte array storing the value associated with the input key if
214    *     any. null if it does not find the specified key.
215    *
216    * @throws RocksDBException if the value for the key cannot be read
217    */
getFromBatchAndDB(final RocksDB db, final ColumnFamilyHandle columnFamilyHandle, final ReadOptions options, final byte[] key)218   public byte[] getFromBatchAndDB(final RocksDB db, final ColumnFamilyHandle columnFamilyHandle,
219       final ReadOptions options, final byte[] key) throws RocksDBException {
220     return getFromBatchAndDB(nativeHandle_, db.nativeHandle_,
221         options.nativeHandle_, key, key.length,
222         columnFamilyHandle.nativeHandle_);
223   }
224 
225   /**
226    * Similar to {@link RocksDB#get(byte[])} but will also
227    * read writes from this batch.
228    *
229    * This function will query both this batch and the DB and then merge
230    * the results using the DB's merge operator (if the batch contains any
231    * merge requests).
232    *
233    * Setting {@link ReadOptions#setSnapshot(long, long)} will affect what is
234    * read from the DB but will NOT change which keys are read from the batch
235    * (the keys in this batch do not yet belong to any snapshot and will be
236    * fetched regardless).
237    *
238    * @param db The Rocks database
239    * @param options The read options to use
240    * @param key The key to read the value for
241    *
242    * @return a byte array storing the value associated with the input key if
243    *     any. null if it does not find the specified key.
244    *
245    * @throws RocksDBException if the value for the key cannot be read
246    */
getFromBatchAndDB(final RocksDB db, final ReadOptions options, final byte[] key)247   public byte[] getFromBatchAndDB(final RocksDB db, final ReadOptions options,
248       final byte[] key) throws RocksDBException {
249     return getFromBatchAndDB(nativeHandle_, db.nativeHandle_,
250         options.nativeHandle_, key, key.length);
251   }
252 
disposeInternal(final long handle)253   @Override protected final native void disposeInternal(final long handle);
count0(final long handle)254   @Override final native int count0(final long handle);
put(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen)255   @Override final native void put(final long handle, final byte[] key,
256       final int keyLen, final byte[] value, final int valueLen);
put(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen, final long cfHandle)257   @Override final native void put(final long handle, final byte[] key,
258       final int keyLen, final byte[] value, final int valueLen,
259       final long cfHandle);
260   @Override
putDirect(final long handle, final ByteBuffer key, final int keyOffset, final int keyLength, final ByteBuffer value, final int valueOffset, final int valueLength, final long cfHandle)261   final native void putDirect(final long handle, final ByteBuffer key, final int keyOffset,
262       final int keyLength, final ByteBuffer value, final int valueOffset, final int valueLength,
263       final long cfHandle);
merge(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen)264   @Override final native void merge(final long handle, final byte[] key,
265       final int keyLen, final byte[] value, final int valueLen);
merge(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen, final long cfHandle)266   @Override final native void merge(final long handle, final byte[] key,
267       final int keyLen, final byte[] value, final int valueLen,
268       final long cfHandle);
delete(final long handle, final byte[] key, final int keyLen)269   @Override final native void delete(final long handle, final byte[] key,
270       final int keyLen) throws RocksDBException;
delete(final long handle, final byte[] key, final int keyLen, final long cfHandle)271   @Override final native void delete(final long handle, final byte[] key,
272       final int keyLen, final long cfHandle) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLen)273   @Override final native void singleDelete(final long handle, final byte[] key,
274       final int keyLen) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLen, final long cfHandle)275   @Override final native void singleDelete(final long handle, final byte[] key,
276       final int keyLen, final long cfHandle) throws RocksDBException;
277   @Override
removeDirect(final long handle, final ByteBuffer key, final int keyOffset, final int keyLength, final long cfHandle)278   final native void removeDirect(final long handle, final ByteBuffer key, final int keyOffset,
279       final int keyLength, final long cfHandle) throws RocksDBException;
280   // DO NOT USE - `WriteBatchWithIndex::deleteRange` is not yet supported
281   @Override
deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen, final byte[] endKey, final int endKeyLen)282   final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
283       final byte[] endKey, final int endKeyLen);
284   // DO NOT USE - `WriteBatchWithIndex::deleteRange` is not yet supported
285   @Override
deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen, final byte[] endKey, final int endKeyLen, final long cfHandle)286   final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
287       final byte[] endKey, final int endKeyLen, final long cfHandle);
putLogData(final long handle, final byte[] blob, final int blobLen)288   @Override final native void putLogData(final long handle, final byte[] blob,
289       final int blobLen) throws RocksDBException;
clear0(final long handle)290   @Override final native void clear0(final long handle);
setSavePoint0(final long handle)291   @Override final native void setSavePoint0(final long handle);
rollbackToSavePoint0(final long handle)292   @Override final native void rollbackToSavePoint0(final long handle);
popSavePoint(final long handle)293   @Override final native void popSavePoint(final long handle) throws RocksDBException;
setMaxBytes(final long nativeHandle, final long maxBytes)294   @Override final native void setMaxBytes(final long nativeHandle,
295       final long maxBytes);
getWriteBatch(final long handle)296   @Override final native WriteBatch getWriteBatch(final long handle);
297 
newWriteBatchWithIndex()298   private native static long newWriteBatchWithIndex();
newWriteBatchWithIndex(final boolean overwriteKey)299   private native static long newWriteBatchWithIndex(final boolean overwriteKey);
newWriteBatchWithIndex( final long fallbackIndexComparatorHandle, final byte comparatorType, final int reservedBytes, final boolean overwriteKey)300   private native static long newWriteBatchWithIndex(
301       final long fallbackIndexComparatorHandle,
302       final byte comparatorType, final int reservedBytes,
303       final boolean overwriteKey);
iterator0(final long handle)304   private native long iterator0(final long handle);
iterator1(final long handle, final long cfHandle)305   private native long iterator1(final long handle, final long cfHandle);
iteratorWithBase( final long handle, final long baseIteratorHandle, final long cfHandle)306   private native long iteratorWithBase(
307       final long handle, final long baseIteratorHandle, final long cfHandle);
getFromBatch(final long handle, final long optHandle, final byte[] key, final int keyLen)308   private native byte[] getFromBatch(final long handle, final long optHandle,
309       final byte[] key, final int keyLen);
getFromBatch(final long handle, final long optHandle, final byte[] key, final int keyLen, final long cfHandle)310   private native byte[] getFromBatch(final long handle, final long optHandle,
311       final byte[] key, final int keyLen, final long cfHandle);
getFromBatchAndDB(final long handle, final long dbHandle, final long readOptHandle, final byte[] key, final int keyLen)312   private native byte[] getFromBatchAndDB(final long handle,
313       final long dbHandle,  final long readOptHandle, final byte[] key,
314       final int keyLen);
getFromBatchAndDB(final long handle, final long dbHandle, final long readOptHandle, final byte[] key, final int keyLen, final long cfHandle)315   private native byte[] getFromBatchAndDB(final long handle,
316       final long dbHandle, final long readOptHandle, final byte[] key,
317       final int keyLen, final long cfHandle);
318 }
319