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  * WriteBatch holds a collection of updates to apply atomically to a DB.
12  *
13  * The updates are applied in the order in which they are added
14  * to the WriteBatch.  For example, the value of "key" will be "v3"
15  * after the following batch is written:
16  *
17  *    batch.put("key", "v1");
18  *    batch.remove("key");
19  *    batch.put("key", "v2");
20  *    batch.put("key", "v3");
21  *
22  * Multiple threads can invoke const methods on a WriteBatch without
23  * external synchronization, but if any of the threads may call a
24  * non-const method, all threads accessing the same WriteBatch must use
25  * external synchronization.
26  */
27 public class WriteBatch extends AbstractWriteBatch {
28   /**
29    * Constructs a WriteBatch instance.
30    */
WriteBatch()31   public WriteBatch() {
32     this(0);
33   }
34 
35   /**
36    * Constructs a WriteBatch instance with a given size.
37    *
38    * @param reserved_bytes reserved size for WriteBatch
39    */
WriteBatch(final int reserved_bytes)40   public WriteBatch(final int reserved_bytes) {
41     super(newWriteBatch(reserved_bytes));
42   }
43 
44   /**
45    * Constructs a WriteBatch instance from a serialized representation
46    * as returned by {@link #data()}.
47    *
48    * @param serialized the serialized representation.
49    */
WriteBatch(final byte[] serialized)50   public WriteBatch(final byte[] serialized) {
51     super(newWriteBatch(serialized, serialized.length));
52   }
53 
54   /**
55    * Support for iterating over the contents of a batch.
56    *
57    * @param handler A handler that is called back for each
58    *                update present in the batch
59    *
60    * @throws RocksDBException If we cannot iterate over the batch
61    */
iterate(final Handler handler)62   public void iterate(final Handler handler) throws RocksDBException {
63     iterate(nativeHandle_, handler.nativeHandle_);
64   }
65 
66   /**
67    * Retrieve the serialized version of this batch.
68    *
69    * @return the serialized representation of this write batch.
70    *
71    * @throws RocksDBException if an error occurs whilst retrieving
72    *   the serialized batch data.
73    */
data()74   public byte[] data() throws RocksDBException {
75     return data(nativeHandle_);
76   }
77 
78   /**
79    * Retrieve data size of the batch.
80    *
81    * @return the serialized data size of the batch.
82    */
getDataSize()83   public long getDataSize() {
84     return getDataSize(nativeHandle_);
85   }
86 
87   /**
88    * Returns true if Put will be called during Iterate.
89    *
90    * @return true if Put will be called during Iterate.
91    */
hasPut()92   public boolean hasPut() {
93     return hasPut(nativeHandle_);
94   }
95 
96   /**
97    * Returns true if Delete will be called during Iterate.
98    *
99    * @return true if Delete will be called during Iterate.
100    */
hasDelete()101   public boolean hasDelete() {
102     return hasDelete(nativeHandle_);
103   }
104 
105   /**
106    * Returns true if SingleDelete will be called during Iterate.
107    *
108    * @return true if SingleDelete will be called during Iterate.
109    */
hasSingleDelete()110   public boolean hasSingleDelete() {
111     return hasSingleDelete(nativeHandle_);
112   }
113 
114   /**
115    * Returns true if DeleteRange will be called during Iterate.
116    *
117    * @return true if DeleteRange will be called during Iterate.
118    */
hasDeleteRange()119   public boolean hasDeleteRange() {
120     return hasDeleteRange(nativeHandle_);
121   }
122 
123   /**
124    * Returns true if Merge will be called during Iterate.
125    *
126    * @return true if Merge will be called during Iterate.
127    */
hasMerge()128   public boolean hasMerge() {
129     return hasMerge(nativeHandle_);
130   }
131 
132   /**
133    * Returns true if MarkBeginPrepare will be called during Iterate.
134    *
135    * @return true if MarkBeginPrepare will be called during Iterate.
136    */
hasBeginPrepare()137   public boolean hasBeginPrepare() {
138     return hasBeginPrepare(nativeHandle_);
139   }
140 
141   /**
142    * Returns true if MarkEndPrepare will be called during Iterate.
143    *
144    * @return true if MarkEndPrepare will be called during Iterate.
145    */
hasEndPrepare()146   public boolean hasEndPrepare() {
147     return hasEndPrepare(nativeHandle_);
148   }
149 
150   /**
151    * Returns true if MarkCommit will be called during Iterate.
152    *
153    * @return true if MarkCommit will be called during Iterate.
154    */
hasCommit()155   public boolean hasCommit() {
156     return hasCommit(nativeHandle_);
157   }
158 
159   /**
160    * Returns true if MarkRollback will be called during Iterate.
161    *
162    * @return true if MarkRollback will be called during Iterate.
163    */
hasRollback()164   public boolean hasRollback() {
165     return hasRollback(nativeHandle_);
166   }
167 
168   @Override
getWriteBatch()169   public WriteBatch getWriteBatch() {
170     return this;
171   }
172 
173   /**
174    * Marks this point in the WriteBatch as the last record to
175    * be inserted into the WAL, provided the WAL is enabled.
176    */
markWalTerminationPoint()177   public void markWalTerminationPoint() {
178     markWalTerminationPoint(nativeHandle_);
179   }
180 
181   /**
182    * Gets the WAL termination point.
183    *
184    * See {@link #markWalTerminationPoint()}
185    *
186    * @return the WAL termination point
187    */
getWalTerminationPoint()188   public SavePoint getWalTerminationPoint() {
189     return getWalTerminationPoint(nativeHandle_);
190   }
191 
192   @Override
getWriteBatch(final long handle)193   WriteBatch getWriteBatch(final long handle) {
194     return this;
195   }
196 
197   /**
198    * <p>Private WriteBatch constructor which is used to construct
199    * WriteBatch instances from C++ side. As the reference to this
200    * object is also managed from C++ side the handle will be disowned.</p>
201    *
202    * @param nativeHandle address of native instance.
203    */
WriteBatch(final long nativeHandle)204   WriteBatch(final long nativeHandle) {
205     this(nativeHandle, false);
206   }
207 
208   /**
209    * <p>Private WriteBatch constructor which is used to construct
210    * WriteBatch instances. </p>
211    *
212    * @param nativeHandle address of native instance.
213    * @param owningNativeHandle whether to own this reference from the C++ side or not
214    */
WriteBatch(final long nativeHandle, final boolean owningNativeHandle)215   WriteBatch(final long nativeHandle, final boolean owningNativeHandle) {
216     super(nativeHandle);
217     if(!owningNativeHandle)
218       disOwnNativeHandle();
219   }
220 
disposeInternal(final long handle)221   @Override protected final native void disposeInternal(final long handle);
count0(final long handle)222   @Override final native int count0(final long handle);
put(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen)223   @Override final native void put(final long handle, final byte[] key,
224       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)225   @Override final native void put(final long handle, final byte[] key,
226       final int keyLen, final byte[] value, final int valueLen,
227       final long cfHandle);
228   @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)229   final native void putDirect(final long handle, final ByteBuffer key, final int keyOffset,
230       final int keyLength, final ByteBuffer value, final int valueOffset, final int valueLength,
231       final long cfHandle);
merge(final long handle, final byte[] key, final int keyLen, final byte[] value, final int valueLen)232   @Override final native void merge(final long handle, final byte[] key,
233       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)234   @Override final native void merge(final long handle, final byte[] key,
235       final int keyLen, final byte[] value, final int valueLen,
236       final long cfHandle);
delete(final long handle, final byte[] key, final int keyLen)237   @Override final native void delete(final long handle, final byte[] key,
238       final int keyLen) throws RocksDBException;
delete(final long handle, final byte[] key, final int keyLen, final long cfHandle)239   @Override final native void delete(final long handle, final byte[] key,
240       final int keyLen, final long cfHandle) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLen)241   @Override final native void singleDelete(final long handle, final byte[] key,
242       final int keyLen) throws RocksDBException;
singleDelete(final long handle, final byte[] key, final int keyLen, final long cfHandle)243   @Override final native void singleDelete(final long handle, final byte[] key,
244       final int keyLen, final long cfHandle) throws RocksDBException;
245   @Override
removeDirect(final long handle, final ByteBuffer key, final int keyOffset, final int keyLength, final long cfHandle)246   final native void removeDirect(final long handle, final ByteBuffer key, final int keyOffset,
247       final int keyLength, final long cfHandle) throws RocksDBException;
248   @Override
deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen, final byte[] endKey, final int endKeyLen)249   final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
250       final byte[] endKey, final int endKeyLen);
251   @Override
deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen, final byte[] endKey, final int endKeyLen, final long cfHandle)252   final native void deleteRange(final long handle, final byte[] beginKey, final int beginKeyLen,
253       final byte[] endKey, final int endKeyLen, final long cfHandle);
putLogData(final long handle, final byte[] blob, final int blobLen)254   @Override final native void putLogData(final long handle,
255       final byte[] blob, final int blobLen) throws RocksDBException;
clear0(final long handle)256   @Override final native void clear0(final long handle);
setSavePoint0(final long handle)257   @Override final native void setSavePoint0(final long handle);
rollbackToSavePoint0(final long handle)258   @Override final native void rollbackToSavePoint0(final long handle);
popSavePoint(final long handle)259   @Override final native void popSavePoint(final long handle) throws RocksDBException;
setMaxBytes(final long nativeHandle, final long maxBytes)260   @Override final native void setMaxBytes(final long nativeHandle,
261     final long maxBytes);
262 
newWriteBatch(final int reserved_bytes)263   private native static long newWriteBatch(final int reserved_bytes);
newWriteBatch(final byte[] serialized, final int serializedLength)264   private native static long newWriteBatch(final byte[] serialized,
265       final int serializedLength);
iterate(final long handle, final long handlerHandle)266   private native void iterate(final long handle, final long handlerHandle)
267       throws RocksDBException;
data(final long nativeHandle)268   private native byte[] data(final long nativeHandle) throws RocksDBException;
getDataSize(final long nativeHandle)269   private native long getDataSize(final long nativeHandle);
hasPut(final long nativeHandle)270   private native boolean hasPut(final long nativeHandle);
hasDelete(final long nativeHandle)271   private native boolean hasDelete(final long nativeHandle);
hasSingleDelete(final long nativeHandle)272   private native boolean hasSingleDelete(final long nativeHandle);
hasDeleteRange(final long nativeHandle)273   private native boolean hasDeleteRange(final long nativeHandle);
hasMerge(final long nativeHandle)274   private native boolean hasMerge(final long nativeHandle);
hasBeginPrepare(final long nativeHandle)275   private native boolean hasBeginPrepare(final long nativeHandle);
hasEndPrepare(final long nativeHandle)276   private native boolean hasEndPrepare(final long nativeHandle);
hasCommit(final long nativeHandle)277   private native boolean hasCommit(final long nativeHandle);
hasRollback(final long nativeHandle)278   private native boolean hasRollback(final long nativeHandle);
markWalTerminationPoint(final long nativeHandle)279   private native void markWalTerminationPoint(final long nativeHandle);
getWalTerminationPoint(final long nativeHandle)280   private native SavePoint getWalTerminationPoint(final long nativeHandle);
281 
282   /**
283    * Handler callback for iterating over the contents of a batch.
284    */
285   public static abstract class Handler
286       extends RocksCallbackObject {
Handler()287     public Handler() {
288       super(null);
289     }
290 
291     @Override
initializeNative(final long... nativeParameterHandles)292     protected long initializeNative(final long... nativeParameterHandles) {
293       return createNewHandler0();
294     }
295 
put(final int columnFamilyId, final byte[] key, final byte[] value)296     public abstract void put(final int columnFamilyId, final byte[] key,
297         final byte[] value) throws RocksDBException;
put(final byte[] key, final byte[] value)298     public abstract void put(final byte[] key, final byte[] value);
merge(final int columnFamilyId, final byte[] key, final byte[] value)299     public abstract void merge(final int columnFamilyId, final byte[] key,
300         final byte[] value) throws RocksDBException;
merge(final byte[] key, final byte[] value)301     public abstract void merge(final byte[] key, final byte[] value);
delete(final int columnFamilyId, final byte[] key)302     public abstract void delete(final int columnFamilyId, final byte[] key)
303         throws RocksDBException;
delete(final byte[] key)304     public abstract void delete(final byte[] key);
singleDelete(final int columnFamilyId, final byte[] key)305     public abstract void singleDelete(final int columnFamilyId,
306         final byte[] key) throws RocksDBException;
singleDelete(final byte[] key)307     public abstract void singleDelete(final byte[] key);
deleteRange(final int columnFamilyId, final byte[] beginKey, final byte[] endKey)308     public abstract void deleteRange(final int columnFamilyId,
309         final byte[] beginKey, final byte[] endKey) throws RocksDBException;
deleteRange(final byte[] beginKey, final byte[] endKey)310     public abstract void deleteRange(final byte[] beginKey,
311         final byte[] endKey);
logData(final byte[] blob)312     public abstract void logData(final byte[] blob);
putBlobIndex(final int columnFamilyId, final byte[] key, final byte[] value)313     public abstract void putBlobIndex(final int columnFamilyId,
314         final byte[] key, final byte[] value) throws RocksDBException;
markBeginPrepare()315     public abstract void markBeginPrepare() throws RocksDBException;
markEndPrepare(final byte[] xid)316     public abstract void markEndPrepare(final byte[] xid)
317         throws RocksDBException;
markNoop(final boolean emptyBatch)318     public abstract void markNoop(final boolean emptyBatch)
319         throws RocksDBException;
markRollback(final byte[] xid)320     public abstract void markRollback(final byte[] xid)
321         throws RocksDBException;
markCommit(final byte[] xid)322     public abstract void markCommit(final byte[] xid)
323         throws RocksDBException;
324 
325     /**
326      * shouldContinue is called by the underlying iterator
327      * {@link WriteBatch#iterate(Handler)}. If it returns false,
328      * iteration is halted. Otherwise, it continues
329      * iterating. The default implementation always
330      * returns true.
331      *
332      * @return boolean value indicating if the
333      *     iteration is halted.
334      */
shouldContinue()335     public boolean shouldContinue() {
336       return true;
337     }
338 
createNewHandler0()339     private native long createNewHandler0();
340   }
341 
342   /**
343    * A structure for describing the save point in the Write Batch.
344    */
345   public static class SavePoint {
346     private long size;
347     private long count;
348     private long contentFlags;
349 
SavePoint(final long size, final long count, final long contentFlags)350     public SavePoint(final long size, final long count,
351         final long contentFlags) {
352       this.size = size;
353       this.count = count;
354       this.contentFlags = contentFlags;
355     }
356 
clear()357     public void clear() {
358       this.size = 0;
359       this.count = 0;
360       this.contentFlags = 0;
361     }
362 
363     /**
364      * Get the size of the serialized representation.
365      *
366      * @return the size of the serialized representation.
367      */
getSize()368     public long getSize() {
369       return size;
370     }
371 
372     /**
373      * Get the number of elements.
374      *
375      * @return the number of elements.
376      */
getCount()377     public long getCount() {
378       return count;
379     }
380 
381     /**
382      * Get the content flags.
383      *
384      * @return the content flags.
385      */
getContentFlags()386     public long getContentFlags() {
387       return contentFlags;
388     }
389 
isCleared()390     public boolean isCleared() {
391       return (size | count | contentFlags) == 0;
392     }
393   }
394 }
395