Merge pull request #1053 from adamretter/benchmark-java-comparator
Benchmark Java comparator vs C++ comparatormain
parent
f2c43a4a27
commit
200654067a
@ -0,0 +1,91 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
package org.rocksdb.util; |
||||
|
||||
import org.rocksdb.*; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
|
||||
/** |
||||
* This is a Java Native implementation of the C++ |
||||
* equivalent BytewiseComparatorImpl using {@link Slice} |
||||
* |
||||
* The performance of Comparators implemented in Java is always |
||||
* less than their C++ counterparts due to the bridging overhead, |
||||
* as such you likely don't want to use this apart from benchmarking |
||||
* and you most likely instead wanted |
||||
* {@link org.rocksdb.BuiltinComparator#BYTEWISE_COMPARATOR} |
||||
*/ |
||||
public class BytewiseComparator extends Comparator { |
||||
|
||||
public BytewiseComparator(final ComparatorOptions copt) { |
||||
super(copt); |
||||
} |
||||
|
||||
@Override |
||||
public String name() { |
||||
return "rocksdb.java.BytewiseComparator"; |
||||
} |
||||
|
||||
@Override |
||||
public int compare(final Slice a, final Slice b) { |
||||
return compare(a.data(), b.data()); |
||||
} |
||||
|
||||
@Override |
||||
public String findShortestSeparator(final String start, |
||||
final Slice limit) { |
||||
final byte[] startBytes = start.getBytes(); |
||||
final byte[] limitBytes = limit.data(); |
||||
|
||||
// Find length of common prefix
|
||||
final int min_length = Math.min(startBytes.length, limit.size()); |
||||
int diff_index = 0; |
||||
while ((diff_index < min_length) && |
||||
(startBytes[diff_index] == limitBytes[diff_index])) { |
||||
diff_index++; |
||||
} |
||||
|
||||
if (diff_index >= min_length) { |
||||
// Do not shorten if one string is a prefix of the other
|
||||
} else { |
||||
final byte diff_byte = startBytes[diff_index]; |
||||
if(diff_byte < 0xff && diff_byte + 1 < limitBytes[diff_index]) { |
||||
final byte shortest[] = new byte[diff_index + 1]; |
||||
System.arraycopy(startBytes, 0, shortest, 0, diff_index + 1); |
||||
shortest[diff_index]++; |
||||
assert(compare(shortest, limitBytes) < 0); |
||||
return new String(shortest); |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
private static int compare(final byte[] a, final byte[] b) { |
||||
return ByteBuffer.wrap(a).compareTo(ByteBuffer.wrap(b)); |
||||
} |
||||
|
||||
@Override |
||||
public String findShortSuccessor(final String key) { |
||||
final byte[] keyBytes = key.getBytes(); |
||||
|
||||
// Find first character that can be incremented
|
||||
final int n = keyBytes.length; |
||||
for (int i = 0; i < n; i++) { |
||||
final byte byt = keyBytes[i]; |
||||
if (byt != 0xff) { |
||||
final byte shortSuccessor[] = new byte[i + 1]; |
||||
System.arraycopy(keyBytes, 0, shortSuccessor, 0, i + 1); |
||||
shortSuccessor[i]++; |
||||
return new String(shortSuccessor); |
||||
} |
||||
} |
||||
// *key is a run of 0xffs. Leave it alone.
|
||||
|
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
package org.rocksdb.util; |
||||
|
||||
import org.rocksdb.ComparatorOptions; |
||||
import org.rocksdb.DirectComparator; |
||||
import org.rocksdb.DirectSlice; |
||||
|
||||
import java.nio.ByteBuffer; |
||||
|
||||
/** |
||||
* This is a Java Native implementation of the C++ |
||||
* equivalent BytewiseComparatorImpl using {@link DirectSlice} |
||||
* |
||||
* The performance of Comparators implemented in Java is always |
||||
* less than their C++ counterparts due to the bridging overhead, |
||||
* as such you likely don't want to use this apart from benchmarking |
||||
* and you most likely instead wanted |
||||
* {@link org.rocksdb.BuiltinComparator#BYTEWISE_COMPARATOR} |
||||
*/ |
||||
public class DirectBytewiseComparator extends DirectComparator { |
||||
|
||||
public DirectBytewiseComparator(final ComparatorOptions copt) { |
||||
super(copt); |
||||
} |
||||
|
||||
@Override |
||||
public String name() { |
||||
return "rocksdb.java.DirectBytewiseComparator"; |
||||
} |
||||
|
||||
@Override |
||||
public int compare(final DirectSlice a, final DirectSlice b) { |
||||
return a.data().compareTo(b.data()); |
||||
} |
||||
|
||||
@Override |
||||
public String findShortestSeparator(final String start, |
||||
final DirectSlice limit) { |
||||
final byte[] startBytes = start.getBytes(); |
||||
|
||||
// Find length of common prefix
|
||||
final int min_length = Math.min(startBytes.length, limit.size()); |
||||
int diff_index = 0; |
||||
while ((diff_index < min_length) && |
||||
(startBytes[diff_index] == limit.get(diff_index))) { |
||||
diff_index++; |
||||
} |
||||
|
||||
if (diff_index >= min_length) { |
||||
// Do not shorten if one string is a prefix of the other
|
||||
} else { |
||||
final byte diff_byte = startBytes[diff_index]; |
||||
if(diff_byte < 0xff && diff_byte + 1 < limit.get(diff_index)) { |
||||
final byte shortest[] = new byte[diff_index + 1]; |
||||
System.arraycopy(startBytes, 0, shortest, 0, diff_index + 1); |
||||
shortest[diff_index]++; |
||||
assert(ByteBuffer.wrap(shortest).compareTo(limit.data()) < 0); |
||||
return new String(shortest); |
||||
} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
@Override |
||||
public String findShortSuccessor(final String key) { |
||||
final byte[] keyBytes = key.getBytes(); |
||||
|
||||
// Find first character that can be incremented
|
||||
final int n = keyBytes.length; |
||||
for (int i = 0; i < n; i++) { |
||||
final byte byt = keyBytes[i]; |
||||
if (byt != 0xff) { |
||||
final byte shortSuccessor[] = new byte[i + 1]; |
||||
System.arraycopy(keyBytes, 0, shortSuccessor, 0, i + 1); |
||||
shortSuccessor[i]++; |
||||
return new String(shortSuccessor); |
||||
} |
||||
} |
||||
// *key is a run of 0xffs. Leave it alone.
|
||||
|
||||
return null; |
||||
} |
||||
} |
@ -0,0 +1,37 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
package org.rocksdb.util; |
||||
|
||||
import org.rocksdb.BuiltinComparator; |
||||
import org.rocksdb.ComparatorOptions; |
||||
import org.rocksdb.Slice; |
||||
|
||||
/** |
||||
* This is a Java Native implementation of the C++ |
||||
* equivalent ReverseBytewiseComparatorImpl using {@link Slice} |
||||
* |
||||
* The performance of Comparators implemented in Java is always |
||||
* less than their C++ counterparts due to the bridging overhead, |
||||
* as such you likely don't want to use this apart from benchmarking |
||||
* and you most likely instead wanted |
||||
* {@link BuiltinComparator#REVERSE_BYTEWISE_COMPARATOR} |
||||
*/ |
||||
public class ReverseBytewiseComparator extends BytewiseComparator { |
||||
|
||||
public ReverseBytewiseComparator(final ComparatorOptions copt) { |
||||
super(copt); |
||||
} |
||||
|
||||
@Override |
||||
public String name() { |
||||
return "rocksdb.java.ReverseBytewiseComparator"; |
||||
} |
||||
|
||||
@Override |
||||
public int compare(final Slice a, final Slice b) { |
||||
return -super.compare(a, b); |
||||
} |
||||
} |
@ -0,0 +1,480 @@ |
||||
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
|
||||
// This source code is licensed under the BSD-style license found in the
|
||||
// LICENSE file in the root directory of this source tree. An additional grant
|
||||
// of patent rights can be found in the PATENTS file in the same directory.
|
||||
|
||||
package org.rocksdb.util; |
||||
|
||||
import org.junit.Test; |
||||
import org.rocksdb.*; |
||||
import org.rocksdb.Comparator; |
||||
|
||||
import java.io.IOException; |
||||
import java.nio.charset.StandardCharsets; |
||||
import java.nio.file.FileVisitResult; |
||||
import java.nio.file.Files; |
||||
import java.nio.file.Path; |
||||
import java.nio.file.SimpleFileVisitor; |
||||
import java.nio.file.attribute.BasicFileAttributes; |
||||
import java.util.*; |
||||
|
||||
import static org.junit.Assert.*; |
||||
|
||||
/** |
||||
* This is a direct port of various C++ |
||||
* tests from db/comparator_db_test.cc |
||||
* and some code to adapt it to RocksJava |
||||
*/ |
||||
public class BytewiseComparatorTest { |
||||
|
||||
/** |
||||
* Open the database using the C++ BytewiseComparatorImpl |
||||
* and test the results against our Java BytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_cpp_bytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, |
||||
BuiltinComparator.BYTEWISE_COMPARATOR)) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator(new BytewiseComparator(new ComparatorOptions())), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using the Java BytewiseComparator |
||||
* and test the results against another Java BytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_java_bytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, new BytewiseComparator( |
||||
new ComparatorOptions()))) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator(new BytewiseComparator(new ComparatorOptions())), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using the C++ BytewiseComparatorImpl |
||||
* and test the results against our Java DirectBytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_cpp_directBytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, |
||||
BuiltinComparator.BYTEWISE_COMPARATOR)) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator(new DirectBytewiseComparator( |
||||
new ComparatorOptions()) |
||||
), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using the Java DirectBytewiseComparator |
||||
* and test the results against another Java DirectBytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_java_directBytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, new DirectBytewiseComparator( |
||||
new ComparatorOptions()))) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator(new DirectBytewiseComparator( |
||||
new ComparatorOptions()) |
||||
), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using the C++ ReverseBytewiseComparatorImpl |
||||
* and test the results against our Java ReverseBytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_cpp_reverseBytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, |
||||
BuiltinComparator.REVERSE_BYTEWISE_COMPARATOR)) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator( |
||||
new ReverseBytewiseComparator(new ComparatorOptions()) |
||||
), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using the Java ReverseBytewiseComparator |
||||
* and test the results against another Java ReverseBytewiseComparator |
||||
*/ |
||||
@Test |
||||
public void java_vs_java_reverseBytewiseComparator() |
||||
throws IOException, RocksDBException { |
||||
|
||||
for(int rand_seed = 301; rand_seed < 306; rand_seed++) { |
||||
final Path dbDir = Files.createTempDirectory("comparator_db_test"); |
||||
try(final RocksDB db = openDatabase(dbDir, new ReverseBytewiseComparator( |
||||
new ComparatorOptions()))) { |
||||
final Random rnd = new Random(rand_seed); |
||||
doRandomIterationTest( |
||||
db, |
||||
toJavaComparator( |
||||
new ReverseBytewiseComparator(new ComparatorOptions()) |
||||
), |
||||
Arrays.asList("a", "b", "c", "d", "e", "f", "g", "h", "i"), |
||||
rnd, |
||||
8, 100, 3 |
||||
); |
||||
} finally { |
||||
removeData(dbDir); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void doRandomIterationTest( |
||||
final RocksDB db, final java.util.Comparator<String> javaComparator, |
||||
final List<String> source_strings, final Random rnd, |
||||
final int num_writes, final int num_iter_ops, |
||||
final int num_trigger_flush) throws RocksDBException { |
||||
|
||||
final TreeMap<String, String> map = new TreeMap<>(javaComparator); |
||||
|
||||
for (int i = 0; i < num_writes; i++) { |
||||
if (num_trigger_flush > 0 && i != 0 && i % num_trigger_flush == 0) { |
||||
db.flush(new FlushOptions()); |
||||
} |
||||
|
||||
final int type = rnd.nextInt(2); |
||||
final int index = rnd.nextInt(source_strings.size()); |
||||
final String key = source_strings.get(index); |
||||
switch (type) { |
||||
case 0: |
||||
// put
|
||||
map.put(key, key); |
||||
db.put(new WriteOptions(), bytes(key), bytes(key)); |
||||
break; |
||||
case 1: |
||||
// delete
|
||||
if (map.containsKey(key)) { |
||||
map.remove(key); |
||||
} |
||||
db.remove(new WriteOptions(), bytes(key)); |
||||
break; |
||||
|
||||
default: |
||||
fail("Should not be able to generate random outside range 1..2"); |
||||
} |
||||
} |
||||
|
||||
try(final RocksIterator iter = db.newIterator(new ReadOptions())) { |
||||
final KVIter<String, String> result_iter = new KVIter(map); |
||||
|
||||
boolean is_valid = false; |
||||
for (int i = 0; i < num_iter_ops; i++) { |
||||
// Random walk and make sure iter and result_iter returns the
|
||||
// same key and value
|
||||
final int type = rnd.nextInt(6); |
||||
iter.status(); |
||||
switch (type) { |
||||
case 0: |
||||
// Seek to First
|
||||
iter.seekToFirst(); |
||||
result_iter.seekToFirst(); |
||||
break; |
||||
case 1: |
||||
// Seek to last
|
||||
iter.seekToLast(); |
||||
result_iter.seekToLast(); |
||||
break; |
||||
case 2: { |
||||
// Seek to random key
|
||||
final int key_idx = rnd.nextInt(source_strings.size()); |
||||
final String key = source_strings.get(key_idx); |
||||
iter.seek(bytes(key)); |
||||
result_iter.seek(bytes(key)); |
||||
break; |
||||
} |
||||
case 3: |
||||
// Next
|
||||
if (is_valid) { |
||||
iter.next(); |
||||
result_iter.next(); |
||||
} else { |
||||
continue; |
||||
} |
||||
break; |
||||
case 4: |
||||
// Prev
|
||||
if (is_valid) { |
||||
iter.prev(); |
||||
result_iter.prev(); |
||||
} else { |
||||
continue; |
||||
} |
||||
break; |
||||
default: { |
||||
assert (type == 5); |
||||
final int key_idx = rnd.nextInt(source_strings.size()); |
||||
final String key = source_strings.get(key_idx); |
||||
final byte[] result = db.get(new ReadOptions(), bytes(key)); |
||||
if (!map.containsKey(key)) { |
||||
assertNull(result); |
||||
} else { |
||||
assertArrayEquals(bytes(map.get(key)), result); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
assertEquals(result_iter.isValid(), iter.isValid()); |
||||
|
||||
is_valid = iter.isValid(); |
||||
|
||||
if (is_valid) { |
||||
assertArrayEquals(bytes(result_iter.key()), iter.key()); |
||||
|
||||
//note that calling value on a non-valid iterator from the Java API
|
||||
//results in a SIGSEGV
|
||||
assertArrayEquals(bytes(result_iter.value()), iter.value()); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Open the database using a C++ Comparator |
||||
*/ |
||||
private RocksDB openDatabase( |
||||
final Path dbDir, final BuiltinComparator cppComparator) |
||||
throws IOException, RocksDBException { |
||||
final Options options = new Options() |
||||
.setCreateIfMissing(true) |
||||
.setComparator(cppComparator); |
||||
return RocksDB.open(options, dbDir.toAbsolutePath().toString()); |
||||
} |
||||
|
||||
/** |
||||
* Open the database using a Java Comparator |
||||
*/ |
||||
private RocksDB openDatabase( |
||||
final Path dbDir, |
||||
final AbstractComparator<? extends AbstractSlice<?>> javaComparator) |
||||
throws IOException, RocksDBException { |
||||
final Options options = new Options() |
||||
.setCreateIfMissing(true) |
||||
.setComparator(javaComparator); |
||||
return RocksDB.open(options, dbDir.toAbsolutePath().toString()); |
||||
} |
||||
|
||||
private void closeDatabase(final RocksDB db) { |
||||
db.close(); |
||||
} |
||||
|
||||
private void removeData(final Path dbDir) throws IOException { |
||||
Files.walkFileTree(dbDir, new SimpleFileVisitor<Path>() { |
||||
@Override |
||||
public FileVisitResult visitFile( |
||||
final Path file, final BasicFileAttributes attrs) |
||||
throws IOException { |
||||
Files.delete(file); |
||||
return FileVisitResult.CONTINUE; |
||||
} |
||||
|
||||
@Override |
||||
public FileVisitResult postVisitDirectory( |
||||
final Path dir, final IOException exc) throws IOException { |
||||
Files.delete(dir); |
||||
return FileVisitResult.CONTINUE; |
||||
} |
||||
}); |
||||
} |
||||
|
||||
private byte[] bytes(final String s) { |
||||
return s.getBytes(StandardCharsets.UTF_8); |
||||
} |
||||
|
||||
private java.util.Comparator<String> toJavaComparator( |
||||
final Comparator rocksComparator) { |
||||
return new java.util.Comparator<String>() { |
||||
@Override |
||||
public int compare(final String s1, final String s2) { |
||||
return rocksComparator.compare(new Slice(s1), new Slice(s2)); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
private java.util.Comparator<String> toJavaComparator( |
||||
final DirectComparator rocksComparator) { |
||||
return new java.util.Comparator<String>() { |
||||
@Override |
||||
public int compare(final String s1, final String s2) { |
||||
return rocksComparator.compare(new DirectSlice(s1), |
||||
new DirectSlice(s2)); |
||||
} |
||||
}; |
||||
} |
||||
|
||||
private class KVIter<K, V> implements RocksIteratorInterface { |
||||
|
||||
private final List<Map.Entry<K, V>> entries; |
||||
private final java.util.Comparator<? super K> comparator; |
||||
private int offset = -1; |
||||
|
||||
private int lastPrefixMatchIdx = -1; |
||||
private int lastPrefixMatch = 0; |
||||
|
||||
public KVIter(final TreeMap<K, V> map) { |
||||
this.entries = new ArrayList<>(); |
||||
final Iterator<Map.Entry<K, V>> iterator = map.entrySet().iterator(); |
||||
while(iterator.hasNext()) { |
||||
entries.add(iterator.next()); |
||||
} |
||||
this.comparator = map.comparator(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public boolean isValid() { |
||||
return offset > -1 && offset < entries.size(); |
||||
} |
||||
|
||||
@Override |
||||
public void seekToFirst() { |
||||
offset = 0; |
||||
} |
||||
|
||||
@Override |
||||
public void seekToLast() { |
||||
offset = entries.size() - 1; |
||||
} |
||||
|
||||
@Override |
||||
public void seek(final byte[] target) { |
||||
for(offset = 0; offset < entries.size(); offset++) { |
||||
if(comparator.compare(entries.get(offset).getKey(), |
||||
(K)new String(target, StandardCharsets.UTF_8)) >= 0) { |
||||
return; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Is `a` a prefix of `b` |
||||
* |
||||
* @return The length of the matching prefix, or 0 if it is not a prefix |
||||
*/ |
||||
private int isPrefix(final byte[] a, final byte[] b) { |
||||
if(b.length >= a.length) { |
||||
for(int i = 0; i < a.length; i++) { |
||||
if(a[i] != b[i]) { |
||||
return i; |
||||
} |
||||
} |
||||
return a.length; |
||||
} else { |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void next() { |
||||
if(offset < entries.size()) { |
||||
offset++; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void prev() { |
||||
if(offset >= 0) { |
||||
offset--; |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void status() throws RocksDBException { |
||||
if(offset < 0 || offset >= entries.size()) { |
||||
throw new RocksDBException("Index out of bounds. Size is: " + |
||||
entries.size() + ", offset is: " + offset); |
||||
} |
||||
} |
||||
|
||||
public K key() { |
||||
if(!isValid()) { |
||||
if(entries.isEmpty()) { |
||||
return (K)""; |
||||
} else if(offset == -1){ |
||||
return entries.get(0).getKey(); |
||||
} else if(offset == entries.size()) { |
||||
return entries.get(offset - 1).getKey(); |
||||
} else { |
||||
return (K)""; |
||||
} |
||||
} else { |
||||
return entries.get(offset).getKey(); |
||||
} |
||||
} |
||||
|
||||
public V value() { |
||||
if(!isValid()) { |
||||
return (V)""; |
||||
} else { |
||||
return entries.get(offset).getValue(); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue