Skip to content

Commit 51e7603

Browse files
committed
Throw exception for multiGet operation on corrupted database.
1 parent a34683b commit 51e7603

3 files changed

Lines changed: 78 additions & 0 deletions

File tree

java/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ set(JAVA_TEST_CLASSES
359359
src/test/java/org/rocksdb/MergeVariantsTest.java
360360
src/test/java/org/rocksdb/MixedOptionsTest.java
361361
src/test/java/org/rocksdb/MultiColumnRegressionTest.java
362+
src/test/java/org/rocksdb/MultiGetCorruptionTest.java
362363
src/test/java/org/rocksdb/MultiGetManyKeysTest.java
363364
src/test/java/org/rocksdb/MultiGetTest.java
364365
src/test/java/org/rocksdb/MutableColumnFamilyOptionsTest.java
@@ -477,6 +478,7 @@ set(JAVA_TEST_RUNNING_CLASSES
477478
org.rocksdb.MergeVariantsTest
478479
org.rocksdb.MixedOptionsTest
479480
org.rocksdb.MultiColumnRegressionTest
481+
org.rocksdb.MultiGetCorruptionTest
480482
org.rocksdb.MultiGetManyKeysTest
481483
org.rocksdb.MultiGetTest
482484
org.rocksdb.MutableColumnFamilyOptionsTest

java/rocksjni/jni_multiget_helpers.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ jobjectArray MultiGetJNIValues::byteArrays(
165165
// retain this behaviour. To change it, we need to do the following:
166166
// ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s[i]);
167167
// return nullptr;
168+
} else if (s[i].code() == ROCKSDB_NAMESPACE::Status::Code::kCorruption) {
169+
ROCKSDB_NAMESPACE::RocksDBExceptionJni::ThrowNew(env, s[i]);
170+
return nullptr;
168171
}
169172
}
170173
return jresults;
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.rocksdb;
2+
3+
import static java.nio.charset.StandardCharsets.UTF_8;
4+
import static org.assertj.core.api.Assertions.assertThat;
5+
6+
import java.io.*;
7+
import java.util.ArrayList;
8+
import java.util.List;
9+
import org.junit.ClassRule;
10+
import org.junit.Rule;
11+
import org.junit.Test;
12+
import org.junit.rules.ExpectedException;
13+
import org.junit.rules.TemporaryFolder;
14+
15+
public class MultiGetCorruptionTest {
16+
private static final byte[] KEY = "key".getBytes(UTF_8);
17+
private static final byte[] VALUE;
18+
19+
static {
20+
StringBuilder sb = new StringBuilder();
21+
for (int i = 0; i < 100; i++) {
22+
sb.append("value" + i + "\n");
23+
}
24+
VALUE = sb.toString().getBytes(UTF_8);
25+
}
26+
27+
@ClassRule
28+
public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
29+
new RocksNativeLibraryResource();
30+
31+
@Rule public TemporaryFolder dbFolder = new TemporaryFolder();
32+
33+
@Rule public ExpectedException exception = ExpectedException.none();
34+
35+
@Test
36+
public void getKeyException() throws RocksDBException, IOException {
37+
createCorruptedDatabase();
38+
try (Options options = new Options().setCreateIfMissing(true).setParanoidChecks(true);
39+
RocksDB db = RocksDB.openReadOnly(options, dbFolder.getRoot().getAbsolutePath())) {
40+
exception.expect(RocksDBException.class); // We need to be sure, exception is thrown only
41+
db.get(KEY); // on GET operation. Require careful data corruption.
42+
}
43+
}
44+
45+
@Test
46+
public void multiGetKeyException() throws RocksDBException, IOException {
47+
createCorruptedDatabase();
48+
try (Options options = new Options().setCreateIfMissing(true).setParanoidChecks(true);
49+
RocksDB db = RocksDB.openReadOnly(options, dbFolder.getRoot().getAbsolutePath())) {
50+
// exception.expect(RocksDBException.class);
51+
List<byte[]> keys = new ArrayList<>();
52+
keys.add(KEY);
53+
List<byte[]> result = db.multiGetAsList(keys);
54+
assertThat(result).isNotNull();
55+
}
56+
}
57+
58+
private void createCorruptedDatabase() throws RocksDBException, IOException {
59+
try (Options options = new Options().setCreateIfMissing(true).setParanoidChecks(true);
60+
RocksDB db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath())) {
61+
db.put(KEY, VALUE);
62+
db.flush(new FlushOptions().setWaitForFlush(true));
63+
}
64+
65+
File[] files = dbFolder.getRoot().listFiles((dir, name) -> name.endsWith("sst"));
66+
assertThat(files).hasSize(1);
67+
68+
try (RandomAccessFile file = new RandomAccessFile(files[0], "rw")) {
69+
file.seek(30);
70+
file.write("corrupted".getBytes(UTF_8));
71+
}
72+
}
73+
}

0 commit comments

Comments
 (0)