package org.rocksdb;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
* indicates sth wrong at the RocksDB library side and the call failed.
*/
public class RocksDB extends RocksObject {
- public static final byte[] DEFAULT_COLUMN_FAMILY = "default".getBytes();
+ public static final byte[] DEFAULT_COLUMN_FAMILY = "default".getBytes(UTF_8);
public static final int NOT_FOUND = -1;
private enum LibraryState {
LOADED
}
- private static AtomicReference<LibraryState> libraryLoaded
- = new AtomicReference<>(LibraryState.NOT_LOADED);
+ private static final AtomicReference<LibraryState> libraryLoaded =
+ new AtomicReference<>(LibraryState.NOT_LOADED);
static {
RocksDB.loadLibrary();
}
- private List<ColumnFamilyHandle> ownedColumnFamilyHandles = new ArrayList<>();
+ private final List<ColumnFamilyHandle> ownedColumnFamilyHandles = new ArrayList<>();
/**
* Loads the necessary library files.
vOffset, vLen, columnFamilyHandle.nativeHandle_);
}
- /**
- * Remove the database entry (if any) for "key". Returns OK on
- * success, and a non-OK status on error. It is not an error if "key"
- * did not exist in the database.
- *
- * @param key Key to delete within database
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Use {@link #delete(byte[])}
- */
- @Deprecated
- public void remove(final byte[] key) throws RocksDBException {
- delete(key);
- }
-
/**
* Delete the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
delete(nativeHandle_, key, offset, len);
}
- /**
- * Remove the database entry (if any) for "key". Returns OK on
- * success, and a non-OK status on error. It is not an error if "key"
- * did not exist in the database.
- *
- * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
- * instance
- * @param key Key to delete within database
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Use {@link #delete(ColumnFamilyHandle, byte[])}
- */
- @Deprecated
- public void remove(final ColumnFamilyHandle columnFamilyHandle,
- final byte[] key) throws RocksDBException {
- delete(columnFamilyHandle, key);
- }
-
/**
* Delete the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
delete(nativeHandle_, key, offset, len, columnFamilyHandle.nativeHandle_);
}
- /**
- * Remove the database entry (if any) for "key". Returns OK on
- * success, and a non-OK status on error. It is not an error if "key"
- * did not exist in the database.
- *
- * @param writeOpt WriteOptions to be used with delete operation
- * @param key Key to delete within database
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Use {@link #delete(WriteOptions, byte[])}
- */
- @Deprecated
- public void remove(final WriteOptions writeOpt, final byte[] key)
- throws RocksDBException {
- delete(writeOpt, key);
- }
-
/**
* Delete the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
delete(nativeHandle_, writeOpt.nativeHandle_, key, offset, len);
}
- /**
- * Remove the database entry (if any) for "key". Returns OK on
- * success, and a non-OK status on error. It is not an error if "key"
- * did not exist in the database.
- *
- * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
- * instance
- * @param writeOpt WriteOptions to be used with delete operation
- * @param key Key to delete within database
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Use {@link #delete(ColumnFamilyHandle, WriteOptions, byte[])}
- */
- @Deprecated
- public void remove(final ColumnFamilyHandle columnFamilyHandle,
- final WriteOptions writeOpt, final byte[] key) throws RocksDBException {
- delete(columnFamilyHandle, writeOpt, key);
- }
-
/**
* Delete the database entry (if any) for "key". Returns OK on
* success, and a non-OK status on error. It is not an error if "key"
columnFamilyHandle.nativeHandle_);
}
- /**
- * Returns a map of keys for which values were found in DB.
- *
- * @param keys List of keys for which values need to be retrieved.
- * @return Map where key of map is the key passed by user and value for map
- * entry is the corresponding value in DB.
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Consider {@link #multiGetAsList(List)} instead.
- */
- @Deprecated
- public Map<byte[], byte[]> multiGet(final List<byte[]> keys)
- throws RocksDBException {
- assert(keys.size() != 0);
-
- final byte[][] keysArray = keys.toArray(new byte[0][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
- for(int i = 0; i < keyLengths.length; i++) {
- keyLengths[i] = keysArray[i].length;
- }
-
- final byte[][] values = multiGet(nativeHandle_, keysArray, keyOffsets,
- keyLengths);
-
- final Map<byte[], byte[]> keyValueMap =
- new HashMap<>(computeCapacityHint(values.length));
- for(int i = 0; i < values.length; i++) {
- if(values[i] == null) {
- continue;
- }
-
- keyValueMap.put(keys.get(i), values[i]);
- }
-
- return keyValueMap;
- }
-
- /**
- * Returns a map of keys for which values were found in DB.
- * <p>
- * Note: Every key needs to have a related column family name in
- * {@code columnFamilyHandleList}.
- * </p>
- *
- * @param columnFamilyHandleList {@link java.util.List} containing
- * {@link org.rocksdb.ColumnFamilyHandle} instances.
- * @param keys List of keys for which values need to be retrieved.
- * @return Map where key of map is the key passed by user and value for map
- * entry is the corresponding value in DB.
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- * @throws IllegalArgumentException thrown if the size of passed keys is not
- * equal to the amount of passed column family handles.
- *
- * @deprecated Consider {@link #multiGetAsList(List, List)} instead.
- */
- @Deprecated
- public Map<byte[], byte[]> multiGet(
- final List<ColumnFamilyHandle> columnFamilyHandleList,
- final List<byte[]> keys) throws RocksDBException,
- IllegalArgumentException {
- assert(keys.size() != 0);
- // Check if key size equals cfList size. If not a exception must be
- // thrown. If not a Segmentation fault happens.
- if (keys.size() != columnFamilyHandleList.size()) {
- throw new IllegalArgumentException(
- "For each key there must be a ColumnFamilyHandle.");
- }
- final long[] cfHandles = new long[columnFamilyHandleList.size()];
- for (int i = 0; i < columnFamilyHandleList.size(); i++) {
- cfHandles[i] = columnFamilyHandleList.get(i).nativeHandle_;
- }
-
- final byte[][] keysArray = keys.toArray(new byte[0][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
- for(int i = 0; i < keyLengths.length; i++) {
- keyLengths[i] = keysArray[i].length;
- }
-
- final byte[][] values = multiGet(nativeHandle_, keysArray, keyOffsets,
- keyLengths, cfHandles);
-
- final Map<byte[], byte[]> keyValueMap =
- new HashMap<>(computeCapacityHint(values.length));
- for(int i = 0; i < values.length; i++) {
- if (values[i] == null) {
- continue;
- }
- keyValueMap.put(keys.get(i), values[i]);
- }
- return keyValueMap;
- }
-
- /**
- * Returns a map of keys for which values were found in DB.
- *
- * @param opt Read options.
- * @param keys of keys for which values need to be retrieved.
- * @return Map where key of map is the key passed by user and value for map
- * entry is the corresponding value in DB.
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- *
- * @deprecated Consider {@link #multiGetAsList(ReadOptions, List)} instead.
- */
- @Deprecated
- public Map<byte[], byte[]> multiGet(final ReadOptions opt,
- final List<byte[]> keys) throws RocksDBException {
- assert(keys.size() != 0);
-
- final byte[][] keysArray = keys.toArray(new byte[0][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
- for(int i = 0; i < keyLengths.length; i++) {
- keyLengths[i] = keysArray[i].length;
- }
-
- final byte[][] values = multiGet(nativeHandle_, opt.nativeHandle_,
- keysArray, keyOffsets, keyLengths);
-
- final Map<byte[], byte[]> keyValueMap =
- new HashMap<>(computeCapacityHint(values.length));
- for(int i = 0; i < values.length; i++) {
- if(values[i] == null) {
- continue;
- }
-
- keyValueMap.put(keys.get(i), values[i]);
- }
-
- return keyValueMap;
- }
-
- /**
- * Returns a map of keys for which values were found in DB.
- * <p>
- * Note: Every key needs to have a related column family name in
- * {@code columnFamilyHandleList}.
- * </p>
- *
- * @param opt Read options.
- * @param columnFamilyHandleList {@link java.util.List} containing
- * {@link org.rocksdb.ColumnFamilyHandle} instances.
- * @param keys of keys for which values need to be retrieved.
- * @return Map where key of map is the key passed by user and value for map
- * entry is the corresponding value in DB.
- *
- * @throws RocksDBException thrown if error happens in underlying
- * native library.
- * @throws IllegalArgumentException thrown if the size of passed keys is not
- * equal to the amount of passed column family handles.
- *
- * @deprecated Consider {@link #multiGetAsList(ReadOptions, List, List)}
- * instead.
- */
- @Deprecated
- public Map<byte[], byte[]> multiGet(final ReadOptions opt,
- final List<ColumnFamilyHandle> columnFamilyHandleList,
- final List<byte[]> keys) throws RocksDBException {
- assert(keys.size() != 0);
- // Check if key size equals cfList size. If not a exception must be
- // thrown. If not a Segmentation fault happens.
- if (keys.size()!=columnFamilyHandleList.size()){
- throw new IllegalArgumentException(
- "For each key there must be a ColumnFamilyHandle.");
- }
- final long[] cfHandles = new long[columnFamilyHandleList.size()];
- for (int i = 0; i < columnFamilyHandleList.size(); i++) {
- cfHandles[i] = columnFamilyHandleList.get(i).nativeHandle_;
- }
-
- final byte[][] keysArray = keys.toArray(new byte[0][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
- for(int i = 0; i < keyLengths.length; i++) {
- keyLengths[i] = keysArray[i].length;
- }
-
- final byte[][] values = multiGet(nativeHandle_, opt.nativeHandle_,
- keysArray, keyOffsets, keyLengths, cfHandles);
-
- final Map<byte[], byte[]> keyValueMap
- = new HashMap<>(computeCapacityHint(values.length));
- for(int i = 0; i < values.length; i++) {
- if(values[i] == null) {
- continue;
- }
- keyValueMap.put(keys.get(i), values[i]);
- }
-
- return keyValueMap;
- }
-
/**
* Takes a list of keys, and returns a list of values for the given list of
* keys. List will contain null for keys which could not be found.
assert(keys.size() != 0);
final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
+ final int[] keyOffsets = new int[keysArray.length];
+ final int[] keyLengths = new int[keysArray.length];
for(int i = 0; i < keyLengths.length; i++) {
keyLengths[i] = keysArray[i].length;
}
}
final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
+ final int[] keyOffsets = new int[keysArray.length];
+ final int[] keyLengths = new int[keysArray.length];
for(int i = 0; i < keyLengths.length; i++) {
keyLengths[i] = keysArray[i].length;
}
assert(keys.size() != 0);
final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
+ final int[] keyOffsets = new int[keysArray.length];
+ final int[] keyLengths = new int[keysArray.length];
for(int i = 0; i < keyLengths.length; i++) {
keyLengths[i] = keysArray[i].length;
}
}
final byte[][] keysArray = keys.toArray(new byte[keys.size()][]);
- final int keyOffsets[] = new int[keysArray.length];
- final int keyLengths[] = new int[keysArray.length];
+ final int[] keyOffsets = new int[keysArray.length];
+ final int[] keyLengths = new int[keysArray.length];
for(int i = 0; i < keyLengths.length; i++) {
keyLengths[i] = keysArray[i].length;
}
keysArray, keyOffsets, keyLengths, cfHandles));
}
+ /**
+ * Fetches a list of values for the given list of keys, all from the default column family.
+ *
+ * @param keys list of keys for which values need to be retrieved.
+ * @param values list of buffers to return retrieved values in
+ * @return list of number of bytes in DB for each requested key
+ * this can be more than the size of the corresponding buffer; then the buffer will be filled
+ * with the appropriate truncation of the database value.
+ * @throws RocksDBException if error happens in underlying native library.
+ * @throws IllegalArgumentException thrown if the number of passed keys and passed values
+ * do not match.
+ */
+ public List<ByteBufferGetStatus> multiGetByteBuffers(
+ final List<ByteBuffer> keys, final List<ByteBuffer> values) throws RocksDBException {
+ final ReadOptions readOptions = new ReadOptions();
+ final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(1);
+ columnFamilyHandleList.add(getDefaultColumnFamily());
+ return multiGetByteBuffers(readOptions, columnFamilyHandleList, keys, values);
+ }
+
+ /**
+ * Fetches a list of values for the given list of keys, all from the default column family.
+ *
+ * @param readOptions Read options
+ * @param keys list of keys for which values need to be retrieved.
+ * @param values list of buffers to return retrieved values in
+ * @throws RocksDBException if error happens in underlying native library.
+ * @throws IllegalArgumentException thrown if the number of passed keys and passed values
+ * do not match.
+ * @return the list of values for the given list of keys
+ */
+ public List<ByteBufferGetStatus> multiGetByteBuffers(final ReadOptions readOptions,
+ final List<ByteBuffer> keys, final List<ByteBuffer> values) throws RocksDBException {
+ final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>(1);
+ columnFamilyHandleList.add(getDefaultColumnFamily());
+ return multiGetByteBuffers(readOptions, columnFamilyHandleList, keys, values);
+ }
+
+ /**
+ * Fetches a list of values for the given list of keys.
+ * <p>
+ * Note: Every key needs to have a related column family name in
+ * {@code columnFamilyHandleList}.
+ * </p>
+ *
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @param keys list of keys for which values need to be retrieved.
+ * @param values list of buffers to return retrieved values in
+ * @throws RocksDBException if error happens in underlying native library.
+ * @throws IllegalArgumentException thrown if the number of passed keys, passed values and
+ * passed column family handles do not match.
+ * @return the list of values for the given list of keys
+ */
+ public List<ByteBufferGetStatus> multiGetByteBuffers(
+ final List<ColumnFamilyHandle> columnFamilyHandleList, final List<ByteBuffer> keys,
+ final List<ByteBuffer> values) throws RocksDBException {
+ final ReadOptions readOptions = new ReadOptions();
+ return multiGetByteBuffers(readOptions, columnFamilyHandleList, keys, values);
+ }
+
+ /**
+ * Fetches a list of values for the given list of keys.
+ * <p>
+ * Note: Every key needs to have a related column family name in
+ * {@code columnFamilyHandleList}.
+ * </p>
+ *
+ * @param readOptions Read options
+ * @param columnFamilyHandleList {@link java.util.List} containing
+ * {@link org.rocksdb.ColumnFamilyHandle} instances.
+ * @param keys list of keys for which values need to be retrieved.
+ * @param values list of buffers to return retrieved values in
+ * @throws RocksDBException if error happens in underlying native library.
+ * @throws IllegalArgumentException thrown if the number of passed keys, passed values and
+ * passed column family handles do not match.
+ * @return the list of values for the given list of keys
+ */
+ public List<ByteBufferGetStatus> multiGetByteBuffers(final ReadOptions readOptions,
+ final List<ColumnFamilyHandle> columnFamilyHandleList, final List<ByteBuffer> keys,
+ final List<ByteBuffer> values) throws RocksDBException {
+ assert (keys.size() != 0);
+
+ // Check if key size equals cfList size. If not a exception must be
+ // thrown. If not a Segmentation fault happens.
+ if (keys.size() != columnFamilyHandleList.size() && columnFamilyHandleList.size() > 1) {
+ throw new IllegalArgumentException(
+ "Wrong number of ColumnFamilyHandle(s) supplied. Provide 0, 1, or as many as there are key/value(s)");
+ }
+
+ // Check if key size equals cfList size. If not a exception must be
+ // thrown. If not a Segmentation fault happens.
+ if (values.size() != keys.size()) {
+ throw new IllegalArgumentException("For each key there must be a corresponding value.");
+ }
+
+ // TODO (AP) support indirect buffers
+ for (final ByteBuffer key : keys) {
+ if (!key.isDirect()) {
+ throw new IllegalArgumentException("All key buffers must be direct byte buffers");
+ }
+ }
+
+ // TODO (AP) support indirect buffers, though probably via a less efficient code path
+ for (final ByteBuffer value : values) {
+ if (!value.isDirect()) {
+ throw new IllegalArgumentException("All value buffers must be direct byte buffers");
+ }
+ }
+
+ final int numCFHandles = columnFamilyHandleList.size();
+ final long[] cfHandles = new long[numCFHandles];
+ for (int i = 0; i < numCFHandles; i++) {
+ cfHandles[i] = columnFamilyHandleList.get(i).nativeHandle_;
+ }
+
+ final int numValues = keys.size();
+
+ final ByteBuffer[] keysArray = keys.toArray(new ByteBuffer[0]);
+ final int[] keyOffsets = new int[numValues];
+ final int[] keyLengths = new int[numValues];
+ for (int i = 0; i < numValues; i++) {
+ // TODO (AP) add keysArray[i].arrayOffset() if the buffer is indirect
+ // TODO (AP) because in that case we have to pass the array directly,
+ // so that the JNI C++ code will not know to compensate for the array offset
+ keyOffsets[i] = keysArray[i].position();
+ keyLengths[i] = keysArray[i].limit();
+ }
+ final ByteBuffer[] valuesArray = values.toArray(new ByteBuffer[0]);
+ final int[] valuesSizeArray = new int[numValues];
+ final Status[] statusArray = new Status[numValues];
+
+ multiGet(nativeHandle_, readOptions.nativeHandle_, cfHandles, keysArray, keyOffsets, keyLengths,
+ valuesArray, valuesSizeArray, statusArray);
+
+ final List<ByteBufferGetStatus> results = new ArrayList<>();
+ for (int i = 0; i < numValues; i++) {
+ final Status status = statusArray[i];
+ if (status.getCode() == Status.Code.Ok) {
+ final ByteBuffer value = valuesArray[i];
+ value.position(Math.min(valuesSizeArray[i], value.capacity()));
+ value.flip(); // prepare for read out
+ results.add(new ByteBufferGetStatus(status, valuesSizeArray[i], value));
+ } else {
+ results.add(new ByteBufferGetStatus(status));
+ }
+ }
+
+ return results;
+ }
+
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a true negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a true negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a true negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
/**
* If the key definitely does not exist in the database, then this method
- * returns null, else it returns an instance of KeyMayExistResult
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
*
* If the caller wants to obtain value when the key
* is found in memory, then {@code valueHolder} must be set.
}
}
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
+ *
+ * @param key bytebuffer containing the value of the key
+ * @return false if the key definitely does not exist in the database,
+ * otherwise true.
+ */
+ public boolean keyMayExist(final ByteBuffer key) {
+ return keyMayExist(null, (ReadOptions) null, key);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
+ *
+ * @param columnFamilyHandle the {@link ColumnFamilyHandle} to look for the key in
+ * @param key bytebuffer containing the value of the key
+ * @return false if the key definitely does not exist in the database,
+ * otherwise true.
+ */
+ public boolean keyMayExist(final ColumnFamilyHandle columnFamilyHandle, final ByteBuffer key) {
+ return keyMayExist(columnFamilyHandle, (ReadOptions) null, key);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
+ *
+ * @param readOptions the {@link ReadOptions} to use when reading the key/value
+ * @param key bytebuffer containing the value of the key
+ * @return false if the key definitely does not exist in the database,
+ * otherwise true.
+ */
+ public boolean keyMayExist(final ReadOptions readOptions, final ByteBuffer key) {
+ return keyMayExist(null, readOptions, key);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns {@link KeyMayExist.KeyMayExistEnum#kNotExist},
+ * otherwise if it can with best effort retreive the value, it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithValue} otherwise it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithoutValue}. The choice not to return a value which might
+ * exist is at the discretion of the implementation; the only guarantee is that {@link
+ * KeyMayExist.KeyMayExistEnum#kNotExist} is an assurance that the key does not exist.
+ *
+ * @param key bytebuffer containing the value of the key
+ * @param value bytebuffer which will receive a value if the key exists and a value is known
+ * @return a {@link KeyMayExist} object reporting if key may exist and if a value is provided
+ */
+ public KeyMayExist keyMayExist(final ByteBuffer key, final ByteBuffer value) {
+ return keyMayExist(null, null, key, value);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns {@link KeyMayExist.KeyMayExistEnum#kNotExist},
+ * otherwise if it can with best effort retreive the value, it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithValue} otherwise it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithoutValue}. The choice not to return a value which might
+ * exist is at the discretion of the implementation; the only guarantee is that {@link
+ * KeyMayExist.KeyMayExistEnum#kNotExist} is an assurance that the key does not exist.
+ *
+ * @param columnFamilyHandle the {@link ColumnFamilyHandle} to look for the key in
+ * @param key bytebuffer containing the value of the key
+ * @param value bytebuffer which will receive a value if the key exists and a value is known
+ * @return a {@link KeyMayExist} object reporting if key may exist and if a value is provided
+ */
+ public KeyMayExist keyMayExist(
+ final ColumnFamilyHandle columnFamilyHandle, final ByteBuffer key, final ByteBuffer value) {
+ return keyMayExist(columnFamilyHandle, null, key, value);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns {@link KeyMayExist.KeyMayExistEnum#kNotExist},
+ * otherwise if it can with best effort retreive the value, it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithValue} otherwise it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithoutValue}. The choice not to return a value which might
+ * exist is at the discretion of the implementation; the only guarantee is that {@link
+ * KeyMayExist.KeyMayExistEnum#kNotExist} is an assurance that the key does not exist.
+ *
+ * @param readOptions the {@link ReadOptions} to use when reading the key/value
+ * @param key bytebuffer containing the value of the key
+ * @param value bytebuffer which will receive a value if the key exists and a value is known
+ * @return a {@link KeyMayExist} object reporting if key may exist and if a value is provided
+ */
+ public KeyMayExist keyMayExist(
+ final ReadOptions readOptions, final ByteBuffer key, final ByteBuffer value) {
+ return keyMayExist(null, readOptions, key, value);
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns false, otherwise it returns true if the key might exist.
+ * That is to say that this method is probabilistic and may return false
+ * positives, but never a false negative.
+ *
+ * @param columnFamilyHandle the {@link ColumnFamilyHandle} to look for the key in
+ * @param readOptions the {@link ReadOptions} to use when reading the key/value
+ * @param key bytebuffer containing the value of the key
+ * @return false if the key definitely does not exist in the database,
+ * otherwise true.
+ */
+ public boolean keyMayExist(final ColumnFamilyHandle columnFamilyHandle,
+ final ReadOptions readOptions, final ByteBuffer key) {
+ assert key != null : "key ByteBuffer parameter cannot be null";
+ assert key.isDirect() : "key parameter must be a direct ByteBuffer";
+ return keyMayExistDirect(nativeHandle_,
+ columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
+ readOptions == null ? 0 : readOptions.nativeHandle_, key, key.position(), key.limit());
+ }
+
+ /**
+ * If the key definitely does not exist in the database, then this method
+ * returns {@link KeyMayExist.KeyMayExistEnum#kNotExist},
+ * otherwise if it can with best effort retreive the value, it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithValue} otherwise it returns {@link
+ * KeyMayExist.KeyMayExistEnum#kExistsWithoutValue}. The choice not to return a value which might
+ * exist is at the discretion of the implementation; the only guarantee is that {@link
+ * KeyMayExist.KeyMayExistEnum#kNotExist} is an assurance that the key does not exist.
+ *
+ * @param columnFamilyHandle the {@link ColumnFamilyHandle} to look for the key in
+ * @param readOptions the {@link ReadOptions} to use when reading the key/value
+ * @param key bytebuffer containing the value of the key
+ * @param value bytebuffer which will receive a value if the key exists and a value is known
+ * @return a {@link KeyMayExist} object reporting if key may exist and if a value is provided
+ */
+ public KeyMayExist keyMayExist(final ColumnFamilyHandle columnFamilyHandle,
+ final ReadOptions readOptions, final ByteBuffer key, final ByteBuffer value) {
+ assert key != null : "key ByteBuffer parameter cannot be null";
+ assert key.isDirect() : "key parameter must be a direct ByteBuffer";
+ assert value
+ != null
+ : "value ByteBuffer parameter cannot be null. If you do not need the value, use a different version of the method";
+ assert value.isDirect() : "value parameter must be a direct ByteBuffer";
+
+ final int[] result = keyMayExistDirectFoundValue(nativeHandle_,
+ columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
+ readOptions == null ? 0 : readOptions.nativeHandle_, key, key.position(), key.remaining(),
+ value, value.position(), value.remaining());
+ final int valueLength = result[1];
+ value.limit(value.position() + Math.min(valueLength, value.remaining()));
+ return new KeyMayExist(KeyMayExist.KeyMayExistEnum.values()[result[0]], valueLength);
+ }
+
/**
* <p>Return a heap-allocated iterator over the contents of the
* database. The result of newIterator() is initially invalid
}
/**
- * <p>Return a heap-allocated iterator over the contents of the
- * database. The result of newIterator() is initially invalid
+ * <p>Return a heap-allocated iterator over the contents of a
+ * ColumnFamily. The result of newIterator() is initially invalid
* (caller must call one of the Seek methods on the iterator
* before using it).</p>
*
}
/**
- * <p>Return a heap-allocated iterator over the contents of the
- * database. The result of newIterator() is initially invalid
+ * <p>Return a heap-allocated iterator over the contents of a
+ * ColumnFamily. The result of newIterator() is initially invalid
* (caller must call one of the Seek methods on the iterator
* before using it).</p>
*
*
* <p><strong>See also</strong></p>
* <ul>
- * <li>{@link #compactRange(boolean, int, int)}</li>
* <li>{@link #compactRange(byte[], byte[])}</li>
- * <li>{@link #compactRange(byte[], byte[], boolean, int, int)}</li>
* </ul>
*
* @throws RocksDBException thrown if an error occurs within the native
* <p><strong>See also</strong></p>
* <ul>
* <li>
- * {@link #compactRange(ColumnFamilyHandle, boolean, int, int)}
- * </li>
- * <li>
* {@link #compactRange(ColumnFamilyHandle, byte[], byte[])}
* </li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, byte[], byte[],
- * boolean, int, int)}
- * </li>
* </ul>
*
* @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
* <p><strong>See also</strong></p>
* <ul>
* <li>{@link #compactRange()}</li>
- * <li>{@link #compactRange(boolean, int, int)}</li>
- * <li>{@link #compactRange(byte[], byte[], boolean, int, int)}</li>
* </ul>
*
* @param begin start of key range (included in range)
* <p><strong>See also</strong></p>
* <ul>
* <li>{@link #compactRange(ColumnFamilyHandle)}</li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, boolean, int, int)}
- * </li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, byte[], byte[],
- * boolean, int, int)}
- * </li>
* </ul>
*
* @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
0, columnFamilyHandle == null ? 0: columnFamilyHandle.nativeHandle_);
}
- /**
- * <p>Range compaction of database.</p>
- * <p><strong>Note</strong>: After the database has been compacted,
- * all data will have been pushed down to the last level containing
- * any data.</p>
- *
- * <p>Compaction outputs should be placed in options.db_paths
- * [target_path_id]. Behavior is undefined if target_path_id is
- * out of range.</p>
- *
- * <p><strong>See also</strong></p>
- * <ul>
- * <li>{@link #compactRange()}</li>
- * <li>{@link #compactRange(byte[], byte[])}</li>
- * <li>{@link #compactRange(byte[], byte[], boolean, int, int)}</li>
- * </ul>
- *
- * @deprecated Use {@link #compactRange(ColumnFamilyHandle, byte[], byte[], CompactRangeOptions)} instead
- *
- * @param changeLevel reduce level after compaction
- * @param targetLevel target level to compact to
- * @param targetPathId the target path id of output path
- *
- * @throws RocksDBException thrown if an error occurs within the native
- * part of the library.
- */
- @Deprecated
- public void compactRange(final boolean changeLevel, final int targetLevel,
- final int targetPathId) throws RocksDBException {
- compactRange(null, changeLevel, targetLevel, targetPathId);
- }
-
- /**
- * <p>Range compaction of column family.</p>
- * <p><strong>Note</strong>: After the database has been compacted,
- * all data will have been pushed down to the last level containing
- * any data.</p>
- *
- * <p>Compaction outputs should be placed in options.db_paths
- * [target_path_id]. Behavior is undefined if target_path_id is
- * out of range.</p>
- *
- * <p><strong>See also</strong></p>
- * <ul>
- * <li>{@link #compactRange(ColumnFamilyHandle)}</li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, byte[], byte[])}
- * </li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, byte[], byte[],
- * boolean, int, int)}
- * </li>
- * </ul>
- *
- * @deprecated Use {@link #compactRange(ColumnFamilyHandle, byte[], byte[], CompactRangeOptions)} instead
- *
- * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
- * instance, or null for the default column family.
- * @param changeLevel reduce level after compaction
- * @param targetLevel target level to compact to
- * @param targetPathId the target path id of output path
- *
- * @throws RocksDBException thrown if an error occurs within the native
- * part of the library.
- */
- @Deprecated
- public void compactRange(
- /* @Nullable */ final ColumnFamilyHandle columnFamilyHandle,
- final boolean changeLevel, final int targetLevel, final int targetPathId)
- throws RocksDBException {
- final CompactRangeOptions options = new CompactRangeOptions();
- options.setChangeLevel(changeLevel);
- options.setTargetLevel(targetLevel);
- options.setTargetPathId(targetPathId);
- compactRange(nativeHandle_,
- null, -1,
- null, -1,
- options.nativeHandle_,
- columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_);
- }
-
- /**
- * <p>Range compaction of database.</p>
- * <p><strong>Note</strong>: After the database has been compacted,
- * all data will have been pushed down to the last level containing
- * any data.</p>
- *
- * <p>Compaction outputs should be placed in options.db_paths
- * [target_path_id]. Behavior is undefined if target_path_id is
- * out of range.</p>
- *
- * <p><strong>See also</strong></p>
- * <ul>
- * <li>{@link #compactRange()}</li>
- * <li>{@link #compactRange(boolean, int, int)}</li>
- * <li>{@link #compactRange(byte[], byte[])}</li>
- * </ul>
- *
- * @deprecated Use {@link #compactRange(ColumnFamilyHandle, byte[], byte[], CompactRangeOptions)}
- * instead
- *
- * @param begin start of key range (included in range)
- * @param end end of key range (excluded from range)
- * @param changeLevel reduce level after compaction
- * @param targetLevel target level to compact to
- * @param targetPathId the target path id of output path
- *
- * @throws RocksDBException thrown if an error occurs within the native
- * part of the library.
- */
- @Deprecated
- public void compactRange(final byte[] begin, final byte[] end,
- final boolean changeLevel, final int targetLevel,
- final int targetPathId) throws RocksDBException {
- compactRange(null, begin, end, changeLevel, targetLevel, targetPathId);
- }
-
- /**
- * <p>Range compaction of column family.</p>
- * <p><strong>Note</strong>: After the database has been compacted,
- * all data will have been pushed down to the last level containing
- * any data.</p>
- *
- * <p>Compaction outputs should be placed in options.db_paths
- * [target_path_id]. Behavior is undefined if target_path_id is
- * out of range.</p>
- *
- * <p><strong>See also</strong></p>
- * <ul>
- * <li>{@link #compactRange(ColumnFamilyHandle)}</li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, boolean, int, int)}
- * </li>
- * <li>
- * {@link #compactRange(ColumnFamilyHandle, byte[], byte[])}
- * </li>
- * </ul>
- *
- * @deprecated Use {@link #compactRange(ColumnFamilyHandle, byte[], byte[], CompactRangeOptions)} instead
- *
- * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
- * instance.
- * @param begin start of key range (included in range)
- * @param end end of key range (excluded from range)
- * @param changeLevel reduce level after compaction
- * @param targetLevel target level to compact to
- * @param targetPathId the target path id of output path
- *
- * @throws RocksDBException thrown if an error occurs within the native
- * part of the library.
- */
- @Deprecated
- public void compactRange(
- /* @Nullable */ final ColumnFamilyHandle columnFamilyHandle,
- final byte[] begin, final byte[] end, final boolean changeLevel,
- final int targetLevel, final int targetPathId)
- throws RocksDBException {
- final CompactRangeOptions options = new CompactRangeOptions();
- options.setChangeLevel(changeLevel);
- options.setTargetLevel(targetLevel);
- options.setTargetPathId(targetPathId);
- compactRange(nativeHandle_,
- begin, begin == null ? -1 : begin.length,
- end, end == null ? -1 : end.length,
- options.nativeHandle_,
- columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_);
- }
-
/**
* <p>Range compaction of column family.</p>
* <p><strong>Note</strong>: After the database has been compacted,
/* @Nullable */final ColumnFamilyHandle columnFamilyHandle,
final MutableColumnFamilyOptions mutableColumnFamilyOptions)
throws RocksDBException {
- setOptions(nativeHandle_, columnFamilyHandle.nativeHandle_,
- mutableColumnFamilyOptions.getKeys(),
- mutableColumnFamilyOptions.getValues());
+ setOptions(nativeHandle_, columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_,
+ mutableColumnFamilyOptions.getKeys(), mutableColumnFamilyOptions.getValues());
+ }
+
+ /**
+ * Get the options for the column family handle
+ *
+ * @param columnFamilyHandle {@link org.rocksdb.ColumnFamilyHandle}
+ * instance, or null for the default column family.
+ *
+ * @return the options parsed from the options string return by RocksDB
+ *
+ * @throws RocksDBException if an error occurs while getting the options string, or parsing the
+ * resulting options string into options
+ */
+ public MutableColumnFamilyOptions.MutableColumnFamilyOptionsBuilder getOptions(
+ /* @Nullable */ final ColumnFamilyHandle columnFamilyHandle) throws RocksDBException {
+ String optionsString = getOptions(
+ nativeHandle_, columnFamilyHandle == null ? 0 : columnFamilyHandle.nativeHandle_);
+ return MutableColumnFamilyOptions.parse(optionsString, true);
+ }
+
+ /**
+ * Default column family options
+ *
+ * @return the options parsed from the options string return by RocksDB
+ *
+ * @throws RocksDBException if an error occurs while getting the options string, or parsing the
+ * resulting options string into options
+ */
+ public MutableColumnFamilyOptions.MutableColumnFamilyOptionsBuilder getOptions()
+ throws RocksDBException {
+ return getOptions(null);
+ }
+
+ /**
+ * Get the database options
+ *
+ * @return the DB options parsed from the options string return by RocksDB
+ *
+ * @throws RocksDBException if an error occurs while getting the options string, or parsing the
+ * resulting options string into options
+ */
+ public MutableDBOptions.MutableDBOptionsBuilder getDBOptions() throws RocksDBException {
+ String optionsString = getDBOptions(nativeHandle_);
+ return MutableDBOptions.parse(optionsString, true);
}
/**
return getLatestSequenceNumber(nativeHandle_);
}
- /**
- * Instructs DB to preserve deletes with sequence numbers >= sequenceNumber.
- *
- * Has no effect if DBOptions#preserveDeletes() is set to false.
- *
- * This function assumes that user calls this function with monotonically
- * increasing seqnums (otherwise we can't guarantee that a particular delete
- * hasn't been already processed).
- *
- * @param sequenceNumber the minimum sequence number to preserve
- *
- * @return true if the value was successfully updated,
- * false if user attempted to call if with
- * sequenceNumber <= current value.
- */
- public boolean setPreserveDeletesSequenceNumber(final long sequenceNumber) {
- return setPreserveDeletesSequenceNumber(nativeHandle_, sequenceNumber);
- }
-
/**
* <p>Prevent file deletions. Compactions will continue to occur,
* but no obsolete files will be deleted. Calling this multiple
return rangeSliceHandles;
}
- protected void storeOptionsInstance(DBOptionsInterface options) {
+ protected void storeOptionsInstance(DBOptionsInterface<?> options) {
options_ = options;
}
private native byte[][] multiGet(final long dbHandle, final long rOptHandle,
final byte[][] keys, final int[] keyOffsets, final int[] keyLengths,
final long[] columnFamilyHandles);
+
+ private native void multiGet(final long dbHandle, final long rOptHandle,
+ final long[] columnFamilyHandles, final ByteBuffer[] keysArray, final int[] keyOffsets,
+ final int[] keyLengths, final ByteBuffer[] valuesArray, final int[] valuesSizeArray,
+ final Status[] statusArray);
+
private native boolean keyMayExist(
final long handle, final long cfHandle, final long readOptHandle,
final byte[] key, final int keyOffset, final int keyLength);
private native int getDirect(long handle, long readOptHandle, ByteBuffer key, int keyOffset,
int keyLength, ByteBuffer value, int valueOffset, int valueLength, long cfHandle)
throws RocksDBException;
+ private native boolean keyMayExistDirect(final long handle, final long cfHhandle,
+ final long readOptHandle, final ByteBuffer key, final int keyOffset, final int keyLength);
+ private native int[] keyMayExistDirectFoundValue(final long handle, final long cfHhandle,
+ final long readOptHandle, final ByteBuffer key, final int keyOffset, final int keyLength,
+ final ByteBuffer value, final int valueOffset, final int valueLength);
private native void deleteDirect(long handle, long optHandle, ByteBuffer key, int keyOffset,
int keyLength, long cfHandle) throws RocksDBException;
private native long getLongProperty(final long nativeHandle,
private native long[] getApproximateSizes(final long nativeHandle,
final long columnFamilyHandle, final long[] rangeSliceHandles,
final byte includeFlags);
- private final native long[] getApproximateMemTableStats(
- final long nativeHandle, final long columnFamilyHandle,
- final long rangeStartSliceHandle, final long rangeLimitSliceHandle);
+ private native long[] getApproximateMemTableStats(final long nativeHandle,
+ final long columnFamilyHandle, final long rangeStartSliceHandle,
+ final long rangeLimitSliceHandle);
private native void compactRange(final long handle,
/* @Nullable */ final byte[] begin, final int beginLen,
/* @Nullable */ final byte[] end, final int endLen,
throws RocksDBException;
private native void setOptions(final long handle, final long cfHandle,
final String[] keys, final String[] values) throws RocksDBException;
+ private native String getOptions(final long handle, final long cfHandle);
private native void setDBOptions(final long handle,
final String[] keys, final String[] values) throws RocksDBException;
+ private native String getDBOptions(final long handle);
private native String[] compactFiles(final long handle,
final long compactionOptionsHandle,
final long columnFamilyHandle,
throws RocksDBException;
private native void syncWal(final long handle) throws RocksDBException;
private native long getLatestSequenceNumber(final long handle);
- private native boolean setPreserveDeletesSequenceNumber(final long handle,
- final long sequenceNumber);
private native void disableFileDeletions(long handle) throws RocksDBException;
private native void enableFileDeletions(long handle, boolean force)
throws RocksDBException;
private native static int version();
- protected DBOptionsInterface options_;
+ protected DBOptionsInterface<?> options_;
private static Version version;
public static class Version {