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 package org.rocksdb;
6 
7 import org.junit.*;
8 import org.junit.rules.ExpectedException;
9 import org.junit.rules.TemporaryFolder;
10 
11 import java.nio.ByteBuffer;
12 import java.util.*;
13 
14 import static java.nio.charset.StandardCharsets.UTF_8;
15 import static org.assertj.core.api.Assertions.assertThat;
16 import static org.junit.Assert.fail;
17 
18 public class RocksDBTest {
19 
20   @ClassRule
21   public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
22       new RocksNativeLibraryResource();
23 
24   @Rule
25   public TemporaryFolder dbFolder = new TemporaryFolder();
26 
27   public static final Random rand = PlatformRandomHelper.
28       getPlatformSpecificRandomFactory();
29 
30   @Test
open()31   public void open() throws RocksDBException {
32     try (final RocksDB db =
33              RocksDB.open(dbFolder.getRoot().getAbsolutePath())) {
34       assertThat(db).isNotNull();
35     }
36   }
37 
38   @Test
open_opt()39   public void open_opt() throws RocksDBException {
40     try (final Options opt = new Options().setCreateIfMissing(true);
41          final RocksDB db = RocksDB.open(opt,
42              dbFolder.getRoot().getAbsolutePath())) {
43       assertThat(db).isNotNull();
44     }
45   }
46 
47   @Test
openWhenOpen()48   public void openWhenOpen() throws RocksDBException {
49     final String dbPath = dbFolder.getRoot().getAbsolutePath();
50 
51     try (final RocksDB db1 = RocksDB.open(dbPath)) {
52       try (final RocksDB db2 = RocksDB.open(dbPath)) {
53         fail("Should have thrown an exception when opening the same db twice");
54       } catch (final RocksDBException e) {
55         assertThat(e.getStatus().getCode()).isEqualTo(Status.Code.IOError);
56         assertThat(e.getStatus().getSubCode()).isEqualTo(Status.SubCode.None);
57         assertThat(e.getStatus().getState()).contains("lock ");
58       }
59     }
60   }
61 
62   @Test
createColumnFamily()63   public void createColumnFamily() throws RocksDBException {
64       final byte[] col1Name = "col1".getBytes(UTF_8);
65 
66       try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
67            final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()
68       ) {
69         try (final ColumnFamilyHandle col1 =
70             db.createColumnFamily(new ColumnFamilyDescriptor(col1Name, cfOpts))) {
71           assertThat(col1).isNotNull();
72           assertThat(col1.getName()).isEqualTo(col1Name);
73         }
74       }
75 
76       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
77       try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath(),
78         Arrays.asList(
79             new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
80             new ColumnFamilyDescriptor(col1Name)),
81             cfHandles)) {
82         try {
83           assertThat(cfHandles.size()).isEqualTo(2);
84           assertThat(cfHandles.get(1)).isNotNull();
85           assertThat(cfHandles.get(1).getName()).isEqualTo(col1Name);
86         } finally {
87           for (final ColumnFamilyHandle cfHandle :
88               cfHandles) {
89             cfHandle.close();
90           }
91         }
92       }
93   }
94 
95 
96   @Test
createColumnFamilies()97   public void createColumnFamilies() throws RocksDBException {
98     final byte[] col1Name = "col1".getBytes(UTF_8);
99     final byte[] col2Name = "col2".getBytes(UTF_8);
100 
101     List<ColumnFamilyHandle> cfHandles;
102     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
103          final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()
104     ) {
105       cfHandles =
106           db.createColumnFamilies(cfOpts, Arrays.asList(col1Name, col2Name));
107       try {
108         assertThat(cfHandles).isNotNull();
109         assertThat(cfHandles.size()).isEqualTo(2);
110         assertThat(cfHandles.get(0).getName()).isEqualTo(col1Name);
111         assertThat(cfHandles.get(1).getName()).isEqualTo(col2Name);
112       } finally {
113         for (final ColumnFamilyHandle cfHandle : cfHandles) {
114           cfHandle.close();
115         }
116       }
117     }
118 
119     cfHandles = new ArrayList<>();
120     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath(),
121         Arrays.asList(
122             new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
123             new ColumnFamilyDescriptor(col1Name),
124             new ColumnFamilyDescriptor(col2Name)),
125         cfHandles)) {
126       try {
127         assertThat(cfHandles.size()).isEqualTo(3);
128         assertThat(cfHandles.get(1)).isNotNull();
129         assertThat(cfHandles.get(1).getName()).isEqualTo(col1Name);
130         assertThat(cfHandles.get(2)).isNotNull();
131         assertThat(cfHandles.get(2).getName()).isEqualTo(col2Name);
132       } finally {
133         for (final ColumnFamilyHandle cfHandle : cfHandles) {
134           cfHandle.close();
135         }
136       }
137     }
138   }
139 
140   @Test
createColumnFamiliesfromDescriptors()141   public void createColumnFamiliesfromDescriptors() throws RocksDBException {
142     final byte[] col1Name = "col1".getBytes(UTF_8);
143     final byte[] col2Name = "col2".getBytes(UTF_8);
144 
145     List<ColumnFamilyHandle> cfHandles;
146     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
147          final ColumnFamilyOptions cfOpts = new ColumnFamilyOptions()
148     ) {
149       cfHandles =
150           db.createColumnFamilies(Arrays.asList(
151               new ColumnFamilyDescriptor(col1Name, cfOpts),
152               new ColumnFamilyDescriptor(col2Name, cfOpts)));
153       try {
154         assertThat(cfHandles).isNotNull();
155         assertThat(cfHandles.size()).isEqualTo(2);
156         assertThat(cfHandles.get(0).getName()).isEqualTo(col1Name);
157         assertThat(cfHandles.get(1).getName()).isEqualTo(col2Name);
158       } finally {
159         for (final ColumnFamilyHandle cfHandle : cfHandles) {
160           cfHandle.close();
161         }
162       }
163     }
164 
165     cfHandles = new ArrayList<>();
166     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath(),
167         Arrays.asList(
168             new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
169             new ColumnFamilyDescriptor(col1Name),
170             new ColumnFamilyDescriptor(col2Name)),
171         cfHandles)) {
172       try {
173         assertThat(cfHandles.size()).isEqualTo(3);
174         assertThat(cfHandles.get(1)).isNotNull();
175         assertThat(cfHandles.get(1).getName()).isEqualTo(col1Name);
176         assertThat(cfHandles.get(2)).isNotNull();
177         assertThat(cfHandles.get(2).getName()).isEqualTo(col2Name);
178       } finally {
179         for (final ColumnFamilyHandle cfHandle : cfHandles) {
180           cfHandle.close();
181         }
182       }
183     }
184   }
185 
186   @Test
put()187   public void put() throws RocksDBException {
188     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
189          final WriteOptions opt = new WriteOptions(); final ReadOptions optr = new ReadOptions()) {
190       db.put("key1".getBytes(), "value".getBytes());
191       db.put(opt, "key2".getBytes(), "12345678".getBytes());
192       assertThat(db.get("key1".getBytes())).isEqualTo(
193           "value".getBytes());
194       assertThat(db.get("key2".getBytes())).isEqualTo(
195           "12345678".getBytes());
196 
197       ByteBuffer key = ByteBuffer.allocateDirect(12);
198       ByteBuffer value = ByteBuffer.allocateDirect(12);
199       key.position(4);
200       key.put("key3".getBytes());
201       key.position(4).limit(8);
202       value.position(4);
203       value.put("val3".getBytes());
204       value.position(4).limit(8);
205 
206       db.put(opt, key, value);
207 
208       assertThat(key.position()).isEqualTo(8);
209       assertThat(key.limit()).isEqualTo(8);
210 
211       assertThat(value.position()).isEqualTo(8);
212       assertThat(value.limit()).isEqualTo(8);
213 
214       key.position(4);
215 
216       ByteBuffer result = ByteBuffer.allocateDirect(12);
217       assertThat(db.get(optr, key, result)).isEqualTo(4);
218       assertThat(result.position()).isEqualTo(0);
219       assertThat(result.limit()).isEqualTo(4);
220       assertThat(key.position()).isEqualTo(8);
221       assertThat(key.limit()).isEqualTo(8);
222 
223       byte[] tmp = new byte[4];
224       result.get(tmp);
225       assertThat(tmp).isEqualTo("val3".getBytes());
226 
227       key.position(4);
228 
229       result.clear().position(9);
230       assertThat(db.get(optr, key, result)).isEqualTo(4);
231       assertThat(result.position()).isEqualTo(9);
232       assertThat(result.limit()).isEqualTo(12);
233       assertThat(key.position()).isEqualTo(8);
234       assertThat(key.limit()).isEqualTo(8);
235       byte[] tmp2 = new byte[3];
236       result.get(tmp2);
237       assertThat(tmp2).isEqualTo("val".getBytes());
238 
239       // put
240       Segment key3 = sliceSegment("key3");
241       Segment key4 = sliceSegment("key4");
242       Segment value0 = sliceSegment("value 0");
243       Segment value1 = sliceSegment("value 1");
244       db.put(key3.data, key3.offset, key3.len, value0.data, value0.offset, value0.len);
245       db.put(opt, key4.data, key4.offset, key4.len, value1.data, value1.offset, value1.len);
246 
247       // compare
248       Assert.assertTrue(value0.isSamePayload(db.get(key3.data, key3.offset, key3.len)));
249       Assert.assertTrue(value1.isSamePayload(db.get(key4.data, key4.offset, key4.len)));
250     }
251   }
252 
sliceSegment(String key)253   private static Segment sliceSegment(String key) {
254     ByteBuffer rawKey = ByteBuffer.allocate(key.length() + 4);
255     rawKey.put((byte)0);
256     rawKey.put((byte)0);
257     rawKey.put(key.getBytes());
258 
259     return new Segment(rawKey.array(), 2, key.length());
260   }
261 
262   private static class Segment {
263     final byte[] data;
264     final int offset;
265     final int len;
266 
isSamePayload(byte[] value)267     public boolean isSamePayload(byte[] value) {
268       if (value == null) {
269         return false;
270       }
271       if (value.length != len) {
272         return false;
273       }
274 
275       for (int i = 0; i < value.length; i++) {
276         if (data[i + offset] != value[i]) {
277           return false;
278         }
279       }
280 
281       return true;
282     }
283 
Segment(byte[] value, int offset, int len)284     public Segment(byte[] value, int offset, int len) {
285       this.data = value;
286       this.offset = offset;
287       this.len = len;
288     }
289   }
290 
291   @Test
write()292   public void write() throws RocksDBException {
293     try (final StringAppendOperator stringAppendOperator = new StringAppendOperator();
294          final Options options = new Options()
295              .setMergeOperator(stringAppendOperator)
296              .setCreateIfMissing(true);
297          final RocksDB db = RocksDB.open(options,
298              dbFolder.getRoot().getAbsolutePath());
299          final WriteOptions opts = new WriteOptions()) {
300 
301       try (final WriteBatch wb1 = new WriteBatch()) {
302         wb1.put("key1".getBytes(), "aa".getBytes());
303         wb1.merge("key1".getBytes(), "bb".getBytes());
304 
305         try (final WriteBatch wb2 = new WriteBatch()) {
306           wb2.put("key2".getBytes(), "xx".getBytes());
307           wb2.merge("key2".getBytes(), "yy".getBytes());
308           db.write(opts, wb1);
309           db.write(opts, wb2);
310         }
311       }
312 
313       assertThat(db.get("key1".getBytes())).isEqualTo(
314           "aa,bb".getBytes());
315       assertThat(db.get("key2".getBytes())).isEqualTo(
316           "xx,yy".getBytes());
317     }
318   }
319 
320   @Test
getWithOutValue()321   public void getWithOutValue() throws RocksDBException {
322     try (final RocksDB db =
323              RocksDB.open(dbFolder.getRoot().getAbsolutePath())) {
324       db.put("key1".getBytes(), "value".getBytes());
325       db.put("key2".getBytes(), "12345678".getBytes());
326       byte[] outValue = new byte[5];
327       // not found value
328       int getResult = db.get("keyNotFound".getBytes(), outValue);
329       assertThat(getResult).isEqualTo(RocksDB.NOT_FOUND);
330       // found value which fits in outValue
331       getResult = db.get("key1".getBytes(), outValue);
332       assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
333       assertThat(outValue).isEqualTo("value".getBytes());
334       // found value which fits partially
335       getResult = db.get("key2".getBytes(), outValue);
336       assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
337       assertThat(outValue).isEqualTo("12345".getBytes());
338     }
339   }
340 
341   @Test
getWithOutValueReadOptions()342   public void getWithOutValueReadOptions() throws RocksDBException {
343     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
344          final ReadOptions rOpt = new ReadOptions()) {
345       db.put("key1".getBytes(), "value".getBytes());
346       db.put("key2".getBytes(), "12345678".getBytes());
347       byte[] outValue = new byte[5];
348       // not found value
349       int getResult = db.get(rOpt, "keyNotFound".getBytes(),
350           outValue);
351       assertThat(getResult).isEqualTo(RocksDB.NOT_FOUND);
352       // found value which fits in outValue
353       getResult = db.get(rOpt, "key1".getBytes(), outValue);
354       assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
355       assertThat(outValue).isEqualTo("value".getBytes());
356       // found value which fits partially
357       getResult = db.get(rOpt, "key2".getBytes(), outValue);
358       assertThat(getResult).isNotEqualTo(RocksDB.NOT_FOUND);
359       assertThat(outValue).isEqualTo("12345".getBytes());
360     }
361   }
362 
363   @Rule
364   public ExpectedException thrown = ExpectedException.none();
365 
366   @Test
getOutOfArrayMaxSizeValue()367   public void getOutOfArrayMaxSizeValue() throws RocksDBException {
368     final int numberOfValueSplits = 10;
369     final int splitSize = Integer.MAX_VALUE / numberOfValueSplits;
370 
371     Runtime runtime = Runtime.getRuntime();
372     long neededMemory = ((long)(splitSize)) * (((long)numberOfValueSplits) + 3);
373     boolean isEnoughMemory = runtime.maxMemory() - runtime.totalMemory() > neededMemory;
374     Assume.assumeTrue(isEnoughMemory);
375 
376     final byte[] valueSplit = new byte[splitSize];
377     final byte[] key = "key".getBytes();
378 
379     thrown.expect(RocksDBException.class);
380     thrown.expectMessage("Requested array size exceeds VM limit");
381 
382     // merge (numberOfValueSplits + 1) valueSplit's to get value size exceeding Integer.MAX_VALUE
383     try (final StringAppendOperator stringAppendOperator = new StringAppendOperator();
384          final Options opt = new Options()
385                  .setCreateIfMissing(true)
386                  .setMergeOperator(stringAppendOperator);
387          final RocksDB db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath())) {
388       db.put(key, valueSplit);
389       for (int i = 0; i < numberOfValueSplits; i++) {
390         db.merge(key, valueSplit);
391       }
392       db.get(key);
393     }
394   }
395 
396   @SuppressWarnings("deprecated")
397   @Test
multiGet()398   public void multiGet() throws RocksDBException {
399     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
400          final ReadOptions rOpt = new ReadOptions()) {
401       db.put("key1".getBytes(), "value".getBytes());
402       db.put("key2".getBytes(), "12345678".getBytes());
403       List<byte[]> lookupKeys = new ArrayList<>();
404       lookupKeys.add("key1".getBytes());
405       lookupKeys.add("key2".getBytes());
406       Map<byte[], byte[]> results = db.multiGet(lookupKeys);
407       assertThat(results).isNotNull();
408       assertThat(results.values()).isNotNull();
409       assertThat(results.values()).
410           contains("value".getBytes(), "12345678".getBytes());
411       // test same method with ReadOptions
412       results = db.multiGet(rOpt, lookupKeys);
413       assertThat(results).isNotNull();
414       assertThat(results.values()).isNotNull();
415       assertThat(results.values()).
416           contains("value".getBytes(), "12345678".getBytes());
417 
418       // remove existing key
419       lookupKeys.remove("key2".getBytes());
420       // add non existing key
421       lookupKeys.add("key3".getBytes());
422       results = db.multiGet(lookupKeys);
423       assertThat(results).isNotNull();
424       assertThat(results.values()).isNotNull();
425       assertThat(results.values()).
426           contains("value".getBytes());
427       // test same call with readOptions
428       results = db.multiGet(rOpt, lookupKeys);
429       assertThat(results).isNotNull();
430       assertThat(results.values()).isNotNull();
431       assertThat(results.values()).
432           contains("value".getBytes());
433     }
434   }
435 
436   @Test
multiGetAsList()437   public void multiGetAsList() throws RocksDBException {
438     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
439          final ReadOptions rOpt = new ReadOptions()) {
440       db.put("key1".getBytes(), "value".getBytes());
441       db.put("key2".getBytes(), "12345678".getBytes());
442       List<byte[]> lookupKeys = new ArrayList<>();
443       lookupKeys.add("key1".getBytes());
444       lookupKeys.add("key2".getBytes());
445       List<byte[]> results = db.multiGetAsList(lookupKeys);
446       assertThat(results).isNotNull();
447       assertThat(results).hasSize(lookupKeys.size());
448       assertThat(results).
449           containsExactly("value".getBytes(), "12345678".getBytes());
450       // test same method with ReadOptions
451       results = db.multiGetAsList(rOpt, lookupKeys);
452       assertThat(results).isNotNull();
453       assertThat(results).
454           contains("value".getBytes(), "12345678".getBytes());
455 
456       // remove existing key
457       lookupKeys.remove(1);
458       // add non existing key
459       lookupKeys.add("key3".getBytes());
460       results = db.multiGetAsList(lookupKeys);
461       assertThat(results).isNotNull();
462       assertThat(results).
463           containsExactly("value".getBytes(), null);
464       // test same call with readOptions
465       results = db.multiGetAsList(rOpt, lookupKeys);
466       assertThat(results).isNotNull();
467       assertThat(results).contains("value".getBytes());
468     }
469   }
470 
471   @Test
merge()472   public void merge() throws RocksDBException {
473     try (final StringAppendOperator stringAppendOperator = new StringAppendOperator();
474          final Options opt = new Options()
475             .setCreateIfMissing(true)
476             .setMergeOperator(stringAppendOperator);
477          final WriteOptions wOpt = new WriteOptions();
478          final RocksDB db = RocksDB.open(opt,
479              dbFolder.getRoot().getAbsolutePath())
480     ) {
481       db.put("key1".getBytes(), "value".getBytes());
482       assertThat(db.get("key1".getBytes())).isEqualTo(
483           "value".getBytes());
484       // merge key1 with another value portion
485       db.merge("key1".getBytes(), "value2".getBytes());
486       assertThat(db.get("key1".getBytes())).isEqualTo(
487           "value,value2".getBytes());
488       // merge key1 with another value portion
489       db.merge(wOpt, "key1".getBytes(), "value3".getBytes());
490       assertThat(db.get("key1".getBytes())).isEqualTo(
491           "value,value2,value3".getBytes());
492       // merge on non existent key shall insert the value
493       db.merge(wOpt, "key2".getBytes(), "xxxx".getBytes());
494       assertThat(db.get("key2".getBytes())).isEqualTo(
495           "xxxx".getBytes());
496 
497       Segment key3 = sliceSegment("key3");
498       Segment key4 = sliceSegment("key4");
499       Segment value0 = sliceSegment("value 0");
500       Segment value1 = sliceSegment("value 1");
501 
502       db.merge(key3.data, key3.offset, key3.len, value0.data, value0.offset, value0.len);
503       db.merge(wOpt, key4.data, key4.offset, key4.len, value1.data, value1.offset, value1.len);
504 
505       // compare
506       Assert.assertTrue(value0.isSamePayload(db.get(key3.data, key3.offset, key3.len)));
507       Assert.assertTrue(value1.isSamePayload(db.get(key4.data, key4.offset, key4.len)));
508     }
509   }
510 
511   @Test
delete()512   public void delete() throws RocksDBException {
513     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
514          final WriteOptions wOpt = new WriteOptions()) {
515       db.put("key1".getBytes(), "value".getBytes());
516       db.put("key2".getBytes(), "12345678".getBytes());
517       db.put("key3".getBytes(), "33".getBytes());
518       assertThat(db.get("key1".getBytes())).isEqualTo(
519           "value".getBytes());
520       assertThat(db.get("key2".getBytes())).isEqualTo(
521           "12345678".getBytes());
522       assertThat(db.get("key3".getBytes())).isEqualTo("33".getBytes());
523       db.delete("key1".getBytes());
524       db.delete(wOpt, "key2".getBytes());
525       ByteBuffer key = ByteBuffer.allocateDirect(16);
526       key.put("key3".getBytes()).flip();
527       db.delete(wOpt, key);
528       assertThat(key.position()).isEqualTo(4);
529       assertThat(key.limit()).isEqualTo(4);
530 
531       assertThat(db.get("key1".getBytes())).isNull();
532       assertThat(db.get("key2".getBytes())).isNull();
533 
534       Segment key3 = sliceSegment("key3");
535       Segment key4 = sliceSegment("key4");
536       db.put("key3".getBytes(), "key3 value".getBytes());
537       db.put("key4".getBytes(), "key4 value".getBytes());
538 
539       db.delete(key3.data, key3.offset, key3.len);
540       db.delete(wOpt, key4.data, key4.offset, key4.len);
541 
542       assertThat(db.get("key3".getBytes())).isNull();
543       assertThat(db.get("key4".getBytes())).isNull();
544     }
545   }
546 
547   @Test
singleDelete()548   public void singleDelete() throws RocksDBException {
549     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
550          final WriteOptions wOpt = new WriteOptions()) {
551       db.put("key1".getBytes(), "value".getBytes());
552       db.put("key2".getBytes(), "12345678".getBytes());
553       assertThat(db.get("key1".getBytes())).isEqualTo(
554           "value".getBytes());
555       assertThat(db.get("key2".getBytes())).isEqualTo(
556           "12345678".getBytes());
557       db.singleDelete("key1".getBytes());
558       db.singleDelete(wOpt, "key2".getBytes());
559       assertThat(db.get("key1".getBytes())).isNull();
560       assertThat(db.get("key2".getBytes())).isNull();
561     }
562   }
563 
564   @Test
singleDelete_nonExisting()565   public void singleDelete_nonExisting() throws RocksDBException {
566     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
567          final WriteOptions wOpt = new WriteOptions()) {
568       db.singleDelete("key1".getBytes());
569       db.singleDelete(wOpt, "key2".getBytes());
570       assertThat(db.get("key1".getBytes())).isNull();
571       assertThat(db.get("key2".getBytes())).isNull();
572     }
573   }
574 
575   @Test
deleteRange()576   public void deleteRange() throws RocksDBException {
577     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath())) {
578       db.put("key1".getBytes(), "value".getBytes());
579       db.put("key2".getBytes(), "12345678".getBytes());
580       db.put("key3".getBytes(), "abcdefg".getBytes());
581       db.put("key4".getBytes(), "xyz".getBytes());
582       assertThat(db.get("key1".getBytes())).isEqualTo("value".getBytes());
583       assertThat(db.get("key2".getBytes())).isEqualTo("12345678".getBytes());
584       assertThat(db.get("key3".getBytes())).isEqualTo("abcdefg".getBytes());
585       assertThat(db.get("key4".getBytes())).isEqualTo("xyz".getBytes());
586       db.deleteRange("key2".getBytes(), "key4".getBytes());
587       assertThat(db.get("key1".getBytes())).isEqualTo("value".getBytes());
588       assertThat(db.get("key2".getBytes())).isNull();
589       assertThat(db.get("key3".getBytes())).isNull();
590       assertThat(db.get("key4".getBytes())).isEqualTo("xyz".getBytes());
591     }
592   }
593 
594   @Test
getIntProperty()595   public void getIntProperty() throws RocksDBException {
596     try (
597         final Options options = new Options()
598             .setCreateIfMissing(true)
599             .setMaxWriteBufferNumber(10)
600             .setMinWriteBufferNumberToMerge(10);
601         final RocksDB db = RocksDB.open(options,
602             dbFolder.getRoot().getAbsolutePath());
603         final WriteOptions wOpt = new WriteOptions().setDisableWAL(true)
604     ) {
605       db.put(wOpt, "key1".getBytes(), "value1".getBytes());
606       db.put(wOpt, "key2".getBytes(), "value2".getBytes());
607       db.put(wOpt, "key3".getBytes(), "value3".getBytes());
608       db.put(wOpt, "key4".getBytes(), "value4".getBytes());
609       assertThat(db.getLongProperty("rocksdb.num-entries-active-mem-table"))
610           .isGreaterThan(0);
611       assertThat(db.getLongProperty("rocksdb.cur-size-active-mem-table"))
612           .isGreaterThan(0);
613     }
614   }
615 
616   @Test
fullCompactRange()617   public void fullCompactRange() throws RocksDBException {
618     try (final Options opt = new Options().
619         setCreateIfMissing(true).
620         setDisableAutoCompactions(true).
621         setCompactionStyle(CompactionStyle.LEVEL).
622         setNumLevels(4).
623         setWriteBufferSize(100 << 10).
624         setLevelZeroFileNumCompactionTrigger(3).
625         setTargetFileSizeBase(200 << 10).
626         setTargetFileSizeMultiplier(1).
627         setMaxBytesForLevelBase(500 << 10).
628         setMaxBytesForLevelMultiplier(1).
629         setDisableAutoCompactions(false);
630          final RocksDB db = RocksDB.open(opt,
631              dbFolder.getRoot().getAbsolutePath())) {
632       // fill database with key/value pairs
633       byte[] b = new byte[10000];
634       for (int i = 0; i < 200; i++) {
635         rand.nextBytes(b);
636         db.put((String.valueOf(i)).getBytes(), b);
637       }
638       db.compactRange();
639     }
640   }
641 
642   @Test
fullCompactRangeColumnFamily()643   public void fullCompactRangeColumnFamily()
644       throws RocksDBException {
645     try (
646         final DBOptions opt = new DBOptions().
647             setCreateIfMissing(true).
648             setCreateMissingColumnFamilies(true);
649         final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions().
650             setDisableAutoCompactions(true).
651             setCompactionStyle(CompactionStyle.LEVEL).
652             setNumLevels(4).
653             setWriteBufferSize(100 << 10).
654             setLevelZeroFileNumCompactionTrigger(3).
655             setTargetFileSizeBase(200 << 10).
656             setTargetFileSizeMultiplier(1).
657             setMaxBytesForLevelBase(500 << 10).
658             setMaxBytesForLevelMultiplier(1).
659             setDisableAutoCompactions(false)
660     ) {
661       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
662           Arrays.asList(
663               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
664               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts));
665 
666       // open database
667       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
668       try (final RocksDB db = RocksDB.open(opt,
669           dbFolder.getRoot().getAbsolutePath(),
670           columnFamilyDescriptors,
671           columnFamilyHandles)) {
672         try {
673           // fill database with key/value pairs
674           byte[] b = new byte[10000];
675           for (int i = 0; i < 200; i++) {
676             rand.nextBytes(b);
677             db.put(columnFamilyHandles.get(1),
678                 String.valueOf(i).getBytes(), b);
679           }
680           db.compactRange(columnFamilyHandles.get(1));
681         } finally {
682           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
683             handle.close();
684           }
685         }
686       }
687     }
688   }
689 
690   @Test
compactRangeWithKeys()691   public void compactRangeWithKeys()
692       throws RocksDBException {
693     try (final Options opt = new Options().
694         setCreateIfMissing(true).
695         setDisableAutoCompactions(true).
696         setCompactionStyle(CompactionStyle.LEVEL).
697         setNumLevels(4).
698         setWriteBufferSize(100 << 10).
699         setLevelZeroFileNumCompactionTrigger(3).
700         setTargetFileSizeBase(200 << 10).
701         setTargetFileSizeMultiplier(1).
702         setMaxBytesForLevelBase(500 << 10).
703         setMaxBytesForLevelMultiplier(1).
704         setDisableAutoCompactions(false);
705          final RocksDB db = RocksDB.open(opt,
706              dbFolder.getRoot().getAbsolutePath())) {
707       // fill database with key/value pairs
708       byte[] b = new byte[10000];
709       for (int i = 0; i < 200; i++) {
710         rand.nextBytes(b);
711         db.put((String.valueOf(i)).getBytes(), b);
712       }
713       db.compactRange("0".getBytes(), "201".getBytes());
714     }
715   }
716 
717   @Test
compactRangeWithKeysReduce()718   public void compactRangeWithKeysReduce()
719       throws RocksDBException {
720     try (
721         final Options opt = new Options().
722             setCreateIfMissing(true).
723             setDisableAutoCompactions(true).
724             setCompactionStyle(CompactionStyle.LEVEL).
725             setNumLevels(4).
726             setWriteBufferSize(100 << 10).
727             setLevelZeroFileNumCompactionTrigger(3).
728             setTargetFileSizeBase(200 << 10).
729             setTargetFileSizeMultiplier(1).
730             setMaxBytesForLevelBase(500 << 10).
731             setMaxBytesForLevelMultiplier(1).
732             setDisableAutoCompactions(false);
733         final RocksDB db = RocksDB.open(opt,
734             dbFolder.getRoot().getAbsolutePath())) {
735       // fill database with key/value pairs
736       byte[] b = new byte[10000];
737       for (int i = 0; i < 200; i++) {
738         rand.nextBytes(b);
739         db.put((String.valueOf(i)).getBytes(), b);
740       }
741       db.flush(new FlushOptions().setWaitForFlush(true));
742       try (final CompactRangeOptions compactRangeOpts = new CompactRangeOptions()
743             .setChangeLevel(true)
744             .setTargetLevel(-1)
745             .setTargetPathId(0)) {
746         db.compactRange(null, "0".getBytes(), "201".getBytes(),
747             compactRangeOpts);
748       }
749     }
750   }
751 
752   @Test
compactRangeWithKeysColumnFamily()753   public void compactRangeWithKeysColumnFamily()
754       throws RocksDBException {
755     try (final DBOptions opt = new DBOptions().
756         setCreateIfMissing(true).
757         setCreateMissingColumnFamilies(true);
758          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions().
759              setDisableAutoCompactions(true).
760              setCompactionStyle(CompactionStyle.LEVEL).
761              setNumLevels(4).
762              setWriteBufferSize(100 << 10).
763              setLevelZeroFileNumCompactionTrigger(3).
764              setTargetFileSizeBase(200 << 10).
765              setTargetFileSizeMultiplier(1).
766              setMaxBytesForLevelBase(500 << 10).
767              setMaxBytesForLevelMultiplier(1).
768              setDisableAutoCompactions(false)
769     ) {
770       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
771           Arrays.asList(
772               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
773               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)
774           );
775 
776       // open database
777       final List<ColumnFamilyHandle> columnFamilyHandles =
778           new ArrayList<>();
779       try (final RocksDB db = RocksDB.open(opt,
780           dbFolder.getRoot().getAbsolutePath(),
781           columnFamilyDescriptors,
782           columnFamilyHandles)) {
783         try {
784           // fill database with key/value pairs
785           byte[] b = new byte[10000];
786           for (int i = 0; i < 200; i++) {
787             rand.nextBytes(b);
788             db.put(columnFamilyHandles.get(1),
789                 String.valueOf(i).getBytes(), b);
790           }
791           db.compactRange(columnFamilyHandles.get(1),
792               "0".getBytes(), "201".getBytes());
793         } finally {
794           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
795             handle.close();
796           }
797         }
798       }
799     }
800   }
801 
802   @Test
compactRangeWithKeysReduceColumnFamily()803   public void compactRangeWithKeysReduceColumnFamily()
804       throws RocksDBException {
805     try (final DBOptions opt = new DBOptions().
806         setCreateIfMissing(true).
807         setCreateMissingColumnFamilies(true);
808          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions().
809              setDisableAutoCompactions(true).
810              setCompactionStyle(CompactionStyle.LEVEL).
811              setNumLevels(4).
812              setWriteBufferSize(100 << 10).
813              setLevelZeroFileNumCompactionTrigger(3).
814              setTargetFileSizeBase(200 << 10).
815              setTargetFileSizeMultiplier(1).
816              setMaxBytesForLevelBase(500 << 10).
817              setMaxBytesForLevelMultiplier(1).
818              setDisableAutoCompactions(false)
819     ) {
820       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
821           Arrays.asList(
822               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
823               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)
824           );
825 
826       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
827       // open database
828       try (final RocksDB db = RocksDB.open(opt,
829           dbFolder.getRoot().getAbsolutePath(),
830           columnFamilyDescriptors,
831           columnFamilyHandles)) {
832         try (final CompactRangeOptions compactRangeOpts = new CompactRangeOptions()
833             .setChangeLevel(true)
834             .setTargetLevel(-1)
835             .setTargetPathId(0)) {
836           // fill database with key/value pairs
837           byte[] b = new byte[10000];
838           for (int i = 0; i < 200; i++) {
839             rand.nextBytes(b);
840             db.put(columnFamilyHandles.get(1),
841                 String.valueOf(i).getBytes(), b);
842           }
843           db.compactRange(columnFamilyHandles.get(1), "0".getBytes(),
844               "201".getBytes(), compactRangeOpts);
845         } finally {
846           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
847             handle.close();
848           }
849         }
850       }
851     }
852   }
853 
854   @Test
compactRangeToLevel()855   public void compactRangeToLevel()
856       throws RocksDBException, InterruptedException {
857     final int NUM_KEYS_PER_L0_FILE = 100;
858     final int KEY_SIZE = 20;
859     final int VALUE_SIZE = 300;
860     final int L0_FILE_SIZE =
861         NUM_KEYS_PER_L0_FILE * (KEY_SIZE + VALUE_SIZE);
862     final int NUM_L0_FILES = 10;
863     final int TEST_SCALE = 5;
864     final int KEY_INTERVAL = 100;
865     try (final Options opt = new Options().
866         setCreateIfMissing(true).
867         setCompactionStyle(CompactionStyle.LEVEL).
868         setNumLevels(5).
869         // a slightly bigger write buffer than L0 file
870         // so that we can ensure manual flush always
871         // go before background flush happens.
872             setWriteBufferSize(L0_FILE_SIZE * 2).
873         // Disable auto L0 -> L1 compaction
874             setLevelZeroFileNumCompactionTrigger(20).
875             setTargetFileSizeBase(L0_FILE_SIZE * 100).
876             setTargetFileSizeMultiplier(1).
877         // To disable auto compaction
878             setMaxBytesForLevelBase(NUM_L0_FILES * L0_FILE_SIZE * 100).
879             setMaxBytesForLevelMultiplier(2).
880             setDisableAutoCompactions(true);
881          final RocksDB db = RocksDB.open(opt,
882              dbFolder.getRoot().getAbsolutePath())
883     ) {
884       // fill database with key/value pairs
885       byte[] value = new byte[VALUE_SIZE];
886       int int_key = 0;
887       for (int round = 0; round < 5; ++round) {
888         int initial_key = int_key;
889         for (int f = 1; f <= NUM_L0_FILES; ++f) {
890           for (int i = 0; i < NUM_KEYS_PER_L0_FILE; ++i) {
891             int_key += KEY_INTERVAL;
892             rand.nextBytes(value);
893 
894             db.put(String.format("%020d", int_key).getBytes(),
895                 value);
896           }
897           db.flush(new FlushOptions().setWaitForFlush(true));
898           // Make sure we do create one more L0 files.
899           assertThat(
900               db.getProperty("rocksdb.num-files-at-level0")).
901               isEqualTo("" + f);
902         }
903 
904         // Compact all L0 files we just created
905         db.compactRange(
906             String.format("%020d", initial_key).getBytes(),
907             String.format("%020d", int_key - 1).getBytes());
908         // Making sure there isn't any L0 files.
909         assertThat(
910             db.getProperty("rocksdb.num-files-at-level0")).
911             isEqualTo("0");
912         // Making sure there are some L1 files.
913         // Here we only use != 0 instead of a specific number
914         // as we don't want the test make any assumption on
915         // how compaction works.
916         assertThat(
917             db.getProperty("rocksdb.num-files-at-level1")).
918             isNotEqualTo("0");
919         // Because we only compacted those keys we issued
920         // in this round, there shouldn't be any L1 -> L2
921         // compaction.  So we expect zero L2 files here.
922         assertThat(
923             db.getProperty("rocksdb.num-files-at-level2")).
924             isEqualTo("0");
925       }
926     }
927   }
928 
929   @Test
deleteFilesInRange()930   public void deleteFilesInRange() throws RocksDBException, InterruptedException {
931     final int KEY_SIZE = 20;
932     final int VALUE_SIZE = 1000;
933     final int FILE_SIZE = 64000;
934     final int NUM_FILES = 10;
935 
936     final int KEY_INTERVAL = 10000;
937     /*
938      * Intention of these options is to end up reliably with 10 files
939      * we will be deleting using deleteFilesInRange.
940      * It is writing roughly number of keys that will fit in 10 files (target size)
941      * It is writing interleaved so that files from memory on L0 will overlap
942      * Then compaction cleans everything and we should end up with 10 files
943      */
944     try (final Options opt = new Options()
945                                  .setCreateIfMissing(true)
946                                  .setCompressionType(CompressionType.NO_COMPRESSION)
947                                  .setTargetFileSizeBase(FILE_SIZE)
948                                  .setWriteBufferSize(FILE_SIZE / 2)
949                                  .setDisableAutoCompactions(true);
950          final RocksDB db = RocksDB.open(opt, dbFolder.getRoot().getAbsolutePath())) {
951       int records = FILE_SIZE / (KEY_SIZE + VALUE_SIZE);
952 
953       // fill database with key/value pairs
954       byte[] value = new byte[VALUE_SIZE];
955       int key_init = 0;
956       for (int o = 0; o < NUM_FILES; ++o) {
957         int int_key = key_init++;
958         for (int i = 0; i < records; ++i) {
959           int_key += KEY_INTERVAL;
960           rand.nextBytes(value);
961 
962           db.put(String.format("%020d", int_key).getBytes(), value);
963         }
964       }
965       db.flush(new FlushOptions().setWaitForFlush(true));
966       db.compactRange();
967       // Make sure we do create one more L0 files.
968       assertThat(db.getProperty("rocksdb.num-files-at-level0")).isEqualTo("0");
969 
970       // Should be 10, but we are OK with asserting +- 2
971       int files = Integer.parseInt(db.getProperty("rocksdb.num-files-at-level1"));
972       assertThat(files).isBetween(8, 12);
973 
974       // Delete lower 60% (roughly). Result should be 5, but we are OK with asserting +- 2
975       // Important is that we know something was deleted (JNI call did something)
976       // Exact assertions are done in C++ unit tests
977       db.deleteFilesInRanges(null,
978           Arrays.asList(null, String.format("%020d", records * KEY_INTERVAL * 6 / 10).getBytes()),
979           false);
980       files = Integer.parseInt(db.getProperty("rocksdb.num-files-at-level1"));
981       assertThat(files).isBetween(3, 7);
982     }
983   }
984 
985   @Test
compactRangeToLevelColumnFamily()986   public void compactRangeToLevelColumnFamily()
987       throws RocksDBException {
988     final int NUM_KEYS_PER_L0_FILE = 100;
989     final int KEY_SIZE = 20;
990     final int VALUE_SIZE = 300;
991     final int L0_FILE_SIZE =
992         NUM_KEYS_PER_L0_FILE * (KEY_SIZE + VALUE_SIZE);
993     final int NUM_L0_FILES = 10;
994     final int TEST_SCALE = 5;
995     final int KEY_INTERVAL = 100;
996 
997     try (final DBOptions opt = new DBOptions().
998         setCreateIfMissing(true).
999         setCreateMissingColumnFamilies(true);
1000          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions().
1001              setCompactionStyle(CompactionStyle.LEVEL).
1002              setNumLevels(5).
1003              // a slightly bigger write buffer than L0 file
1004              // so that we can ensure manual flush always
1005              // go before background flush happens.
1006                  setWriteBufferSize(L0_FILE_SIZE * 2).
1007              // Disable auto L0 -> L1 compaction
1008                  setLevelZeroFileNumCompactionTrigger(20).
1009                  setTargetFileSizeBase(L0_FILE_SIZE * 100).
1010                  setTargetFileSizeMultiplier(1).
1011              // To disable auto compaction
1012                  setMaxBytesForLevelBase(NUM_L0_FILES * L0_FILE_SIZE * 100).
1013                  setMaxBytesForLevelMultiplier(2).
1014                  setDisableAutoCompactions(true)
1015     ) {
1016       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
1017           Arrays.asList(
1018               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
1019               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)
1020           );
1021 
1022       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
1023       // open database
1024       try (final RocksDB db = RocksDB.open(opt,
1025           dbFolder.getRoot().getAbsolutePath(),
1026           columnFamilyDescriptors,
1027           columnFamilyHandles)) {
1028         try {
1029           // fill database with key/value pairs
1030           byte[] value = new byte[VALUE_SIZE];
1031           int int_key = 0;
1032           for (int round = 0; round < 5; ++round) {
1033             int initial_key = int_key;
1034             for (int f = 1; f <= NUM_L0_FILES; ++f) {
1035               for (int i = 0; i < NUM_KEYS_PER_L0_FILE; ++i) {
1036                 int_key += KEY_INTERVAL;
1037                 rand.nextBytes(value);
1038 
1039                 db.put(columnFamilyHandles.get(1),
1040                     String.format("%020d", int_key).getBytes(),
1041                     value);
1042               }
1043               db.flush(new FlushOptions().setWaitForFlush(true),
1044                   columnFamilyHandles.get(1));
1045               // Make sure we do create one more L0 files.
1046               assertThat(
1047                   db.getProperty(columnFamilyHandles.get(1),
1048                       "rocksdb.num-files-at-level0")).
1049                   isEqualTo("" + f);
1050             }
1051 
1052             // Compact all L0 files we just created
1053             db.compactRange(
1054                 columnFamilyHandles.get(1),
1055                 String.format("%020d", initial_key).getBytes(),
1056                 String.format("%020d", int_key - 1).getBytes());
1057             // Making sure there isn't any L0 files.
1058             assertThat(
1059                 db.getProperty(columnFamilyHandles.get(1),
1060                     "rocksdb.num-files-at-level0")).
1061                 isEqualTo("0");
1062             // Making sure there are some L1 files.
1063             // Here we only use != 0 instead of a specific number
1064             // as we don't want the test make any assumption on
1065             // how compaction works.
1066             assertThat(
1067                 db.getProperty(columnFamilyHandles.get(1),
1068                     "rocksdb.num-files-at-level1")).
1069                 isNotEqualTo("0");
1070             // Because we only compacted those keys we issued
1071             // in this round, there shouldn't be any L1 -> L2
1072             // compaction.  So we expect zero L2 files here.
1073             assertThat(
1074                 db.getProperty(columnFamilyHandles.get(1),
1075                     "rocksdb.num-files-at-level2")).
1076                 isEqualTo("0");
1077           }
1078         } finally {
1079           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
1080             handle.close();
1081           }
1082         }
1083       }
1084     }
1085   }
1086 
1087   @Test
continueBackgroundWorkAfterCancelAllBackgroundWork()1088   public void continueBackgroundWorkAfterCancelAllBackgroundWork() throws RocksDBException {
1089     final int KEY_SIZE = 20;
1090     final int VALUE_SIZE = 300;
1091     try (final DBOptions opt = new DBOptions().
1092         setCreateIfMissing(true).
1093         setCreateMissingColumnFamilies(true);
1094          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions()
1095     ) {
1096       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
1097           Arrays.asList(
1098               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
1099               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)
1100           );
1101 
1102       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
1103       // open the database
1104       try (final RocksDB db = RocksDB.open(opt,
1105           dbFolder.getRoot().getAbsolutePath(),
1106           columnFamilyDescriptors,
1107           columnFamilyHandles)) {
1108         try {
1109           db.cancelAllBackgroundWork(true);
1110           try {
1111             db.put(new byte[KEY_SIZE], new byte[VALUE_SIZE]);
1112             db.flush(new FlushOptions().setWaitForFlush(true));
1113             fail("Expected RocksDBException to be thrown if we attempt to trigger a flush after" +
1114                 " all background work is cancelled.");
1115           } catch (RocksDBException ignored) { }
1116         } finally {
1117           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
1118             handle.close();
1119           }
1120         }
1121       }
1122     }
1123   }
1124 
1125   @Test
cancelAllBackgroundWorkTwice()1126   public void cancelAllBackgroundWorkTwice() throws RocksDBException {
1127     try (final Options options = new Options().setCreateIfMissing(true);
1128          final RocksDB db = RocksDB.open(options,
1129              dbFolder.getRoot().getAbsolutePath())
1130     ) {
1131       // Cancel all background work synchronously
1132       db.cancelAllBackgroundWork(true);
1133       // Cancel all background work asynchronously
1134       db.cancelAllBackgroundWork(false);
1135     }
1136   }
1137 
1138   @Test
pauseContinueBackgroundWork()1139   public void pauseContinueBackgroundWork() throws RocksDBException {
1140     try (final Options options = new Options().setCreateIfMissing(true);
1141          final RocksDB db = RocksDB.open(options,
1142              dbFolder.getRoot().getAbsolutePath())
1143     ) {
1144       db.pauseBackgroundWork();
1145       db.continueBackgroundWork();
1146       db.pauseBackgroundWork();
1147       db.continueBackgroundWork();
1148     }
1149   }
1150 
1151   @Test
enableDisableFileDeletions()1152   public void enableDisableFileDeletions() throws RocksDBException {
1153     try (final Options options = new Options().setCreateIfMissing(true);
1154          final RocksDB db = RocksDB.open(options,
1155              dbFolder.getRoot().getAbsolutePath())
1156     ) {
1157       db.disableFileDeletions();
1158       db.enableFileDeletions(false);
1159       db.disableFileDeletions();
1160       db.enableFileDeletions(true);
1161     }
1162   }
1163 
1164   @Test
setOptions()1165   public void setOptions() throws RocksDBException {
1166     try (final DBOptions options = new DBOptions()
1167              .setCreateIfMissing(true)
1168              .setCreateMissingColumnFamilies(true);
1169          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions()
1170              .setWriteBufferSize(4096)) {
1171 
1172       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
1173           Arrays.asList(
1174               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
1175               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts));
1176 
1177       // open database
1178       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
1179       try (final RocksDB db = RocksDB.open(options,
1180           dbFolder.getRoot().getAbsolutePath(), columnFamilyDescriptors, columnFamilyHandles)) {
1181         try {
1182           final MutableColumnFamilyOptions mutableOptions =
1183               MutableColumnFamilyOptions.builder()
1184                   .setWriteBufferSize(2048)
1185                   .build();
1186 
1187           db.setOptions(columnFamilyHandles.get(1), mutableOptions);
1188 
1189         } finally {
1190           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
1191             handle.close();
1192           }
1193         }
1194       }
1195     }
1196   }
1197 
1198   @Test
destroyDB()1199   public void destroyDB() throws RocksDBException {
1200     try (final Options options = new Options().setCreateIfMissing(true)) {
1201       String dbPath = dbFolder.getRoot().getAbsolutePath();
1202       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1203         db.put("key1".getBytes(), "value".getBytes());
1204       }
1205       assertThat(dbFolder.getRoot().exists() && dbFolder.getRoot().listFiles().length != 0)
1206           .isTrue();
1207       RocksDB.destroyDB(dbPath, options);
1208       assertThat(dbFolder.getRoot().exists() && dbFolder.getRoot().listFiles().length != 0)
1209           .isFalse();
1210     }
1211   }
1212 
1213   @Test(expected = RocksDBException.class)
destroyDBFailIfOpen()1214   public void destroyDBFailIfOpen() throws RocksDBException {
1215     try (final Options options = new Options().setCreateIfMissing(true)) {
1216       String dbPath = dbFolder.getRoot().getAbsolutePath();
1217       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1218         // Fails as the db is open and locked.
1219         RocksDB.destroyDB(dbPath, options);
1220       }
1221     }
1222   }
1223 
1224   @Test
getApproximateSizes()1225   public void getApproximateSizes() throws RocksDBException {
1226     final byte key1[] = "key1".getBytes(UTF_8);
1227     final byte key2[] = "key2".getBytes(UTF_8);
1228     final byte key3[] = "key3".getBytes(UTF_8);
1229     try (final Options options = new Options().setCreateIfMissing(true)) {
1230       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1231       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1232         db.put(key1, key1);
1233         db.put(key2, key2);
1234         db.put(key3, key3);
1235 
1236         final long[] sizes = db.getApproximateSizes(
1237             Arrays.asList(
1238                 new Range(new Slice(key1), new Slice(key1)),
1239                 new Range(new Slice(key2), new Slice(key3))
1240             ),
1241             SizeApproximationFlag.INCLUDE_FILES,
1242             SizeApproximationFlag.INCLUDE_MEMTABLES);
1243 
1244         assertThat(sizes.length).isEqualTo(2);
1245         assertThat(sizes[0]).isEqualTo(0);
1246         assertThat(sizes[1]).isGreaterThanOrEqualTo(1);
1247       }
1248     }
1249   }
1250 
1251   @Test
getApproximateMemTableStats()1252   public void getApproximateMemTableStats() throws RocksDBException {
1253     final byte key1[] = "key1".getBytes(UTF_8);
1254     final byte key2[] = "key2".getBytes(UTF_8);
1255     final byte key3[] = "key3".getBytes(UTF_8);
1256     try (final Options options = new Options().setCreateIfMissing(true)) {
1257       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1258       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1259         db.put(key1, key1);
1260         db.put(key2, key2);
1261         db.put(key3, key3);
1262 
1263         final RocksDB.CountAndSize stats =
1264             db.getApproximateMemTableStats(
1265                 new Range(new Slice(key1), new Slice(key3)));
1266 
1267         assertThat(stats).isNotNull();
1268         assertThat(stats.count).isGreaterThan(1);
1269         assertThat(stats.size).isGreaterThan(1);
1270       }
1271     }
1272   }
1273 
1274   @Test
getApproximateMemTableStatsSingleKey()1275   public void getApproximateMemTableStatsSingleKey() throws RocksDBException {
1276     final byte key1[] = "key1".getBytes(UTF_8);
1277     final byte key2[] = "key2".getBytes(UTF_8);
1278     final byte key3[] = "key3".getBytes(UTF_8);
1279     try (final Options options = new Options().setCreateIfMissing(true)) {
1280       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1281       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1282         db.put(key1, key1);
1283 
1284         final RocksDB.CountAndSize stats =
1285             db.getApproximateMemTableStats(new Range(new Slice(key1), new Slice(key3)));
1286 
1287         assertThat(stats).isNotNull();
1288         assertThat(stats.count).isEqualTo(1);
1289         assertThat(stats.size).isGreaterThan(1);
1290       }
1291     }
1292   }
1293 
1294   @Ignore("TODO(AR) re-enable when ready!")
1295   @Test
compactFiles()1296   public void compactFiles() throws RocksDBException {
1297     final int kTestKeySize = 16;
1298     final int kTestValueSize = 984;
1299     final int kEntrySize = kTestKeySize + kTestValueSize;
1300     final int kEntriesPerBuffer = 100;
1301     final int writeBufferSize = kEntrySize * kEntriesPerBuffer;
1302     final byte[] cfName = "pikachu".getBytes(UTF_8);
1303 
1304     try (final Options options = new Options()
1305         .setCreateIfMissing(true)
1306         .setWriteBufferSize(writeBufferSize)
1307         .setCompactionStyle(CompactionStyle.LEVEL)
1308         .setTargetFileSizeBase(writeBufferSize)
1309         .setMaxBytesForLevelBase(writeBufferSize * 2)
1310         .setLevel0StopWritesTrigger(2)
1311         .setMaxBytesForLevelMultiplier(2)
1312         .setCompressionType(CompressionType.NO_COMPRESSION)
1313         .setMaxSubcompactions(4)) {
1314       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1315       try (final RocksDB db = RocksDB.open(options, dbPath);
1316            final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions(options)) {
1317         db.createColumnFamily(new ColumnFamilyDescriptor(cfName,
1318             cfOptions)).close();
1319       }
1320 
1321       try (final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions(options)) {
1322         final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList(
1323             new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOptions),
1324             new ColumnFamilyDescriptor(cfName, cfOptions)
1325         );
1326         final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1327         try (final DBOptions dbOptions = new DBOptions(options);
1328             final RocksDB db = RocksDB.open(dbOptions, dbPath, cfDescriptors,
1329                 cfHandles);
1330         ) {
1331           try (final FlushOptions flushOptions = new FlushOptions()
1332                 .setWaitForFlush(true)
1333                 .setAllowWriteStall(true);
1334                final CompactionOptions compactionOptions = new CompactionOptions()) {
1335             final Random rnd = new Random(301);
1336             for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) {
1337               final byte[] value = new byte[kTestValueSize];
1338               rnd.nextBytes(value);
1339               db.put(cfHandles.get(1), Integer.toString(key).getBytes(UTF_8),
1340                   value);
1341             }
1342             db.flush(flushOptions, cfHandles);
1343 
1344             final RocksDB.LiveFiles liveFiles = db.getLiveFiles();
1345             final List<String> compactedFiles =
1346                 db.compactFiles(compactionOptions, cfHandles.get(1),
1347                     liveFiles.files, 1, -1, null);
1348             assertThat(compactedFiles).isNotEmpty();
1349           } finally {
1350             for (final ColumnFamilyHandle cfHandle : cfHandles) {
1351               cfHandle.close();
1352             }
1353           }
1354         }
1355       }
1356     }
1357   }
1358 
1359   @Test
enableAutoCompaction()1360   public void enableAutoCompaction() throws RocksDBException {
1361     try (final DBOptions options = new DBOptions()
1362         .setCreateIfMissing(true)) {
1363       final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList(
1364           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY)
1365       );
1366       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1367       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1368       try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) {
1369         try {
1370           db.enableAutoCompaction(cfHandles);
1371         } finally {
1372           for (final ColumnFamilyHandle cfHandle : cfHandles) {
1373             cfHandle.close();
1374           }
1375         }
1376       }
1377     }
1378   }
1379 
1380   @Test
numberLevels()1381   public void numberLevels() throws RocksDBException {
1382     try (final Options options = new Options().setCreateIfMissing(true)) {
1383       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1384       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1385         assertThat(db.numberLevels()).isEqualTo(7);
1386       }
1387     }
1388   }
1389 
1390   @Test
maxMemCompactionLevel()1391   public void maxMemCompactionLevel() throws RocksDBException {
1392     try (final Options options = new Options().setCreateIfMissing(true)) {
1393       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1394       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1395         assertThat(db.maxMemCompactionLevel()).isEqualTo(0);
1396       }
1397     }
1398   }
1399 
1400   @Test
level0StopWriteTrigger()1401   public void level0StopWriteTrigger() throws RocksDBException {
1402     try (final Options options = new Options().setCreateIfMissing(true)) {
1403       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1404       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1405         assertThat(db.level0StopWriteTrigger()).isEqualTo(36);
1406       }
1407     }
1408   }
1409 
1410   @Test
getName()1411   public void getName() throws RocksDBException {
1412     try (final Options options = new Options().setCreateIfMissing(true)) {
1413       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1414       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1415         assertThat(db.getName()).isEqualTo(dbPath);
1416       }
1417     }
1418   }
1419 
1420   @Test
getEnv()1421   public void getEnv() throws RocksDBException {
1422     try (final Options options = new Options().setCreateIfMissing(true)) {
1423       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1424       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1425         assertThat(db.getEnv()).isEqualTo(Env.getDefault());
1426       }
1427     }
1428   }
1429 
1430   @Test
flush()1431   public void flush() throws RocksDBException {
1432     try (final Options options = new Options().setCreateIfMissing(true)) {
1433       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1434       try (final RocksDB db = RocksDB.open(options, dbPath);
1435         final FlushOptions flushOptions = new FlushOptions()) {
1436         db.flush(flushOptions);
1437       }
1438     }
1439   }
1440 
1441   @Test
flushWal()1442   public void flushWal() throws RocksDBException {
1443     try (final Options options = new Options().setCreateIfMissing(true)) {
1444       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1445       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1446         db.flushWal(true);
1447       }
1448     }
1449   }
1450 
1451   @Test
syncWal()1452   public void syncWal() throws RocksDBException {
1453     try (final Options options = new Options().setCreateIfMissing(true)) {
1454       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1455       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1456         db.syncWal();
1457       }
1458     }
1459   }
1460 
1461   @Test
setPreserveDeletesSequenceNumber()1462   public void setPreserveDeletesSequenceNumber() throws RocksDBException {
1463     try (final Options options = new Options().setCreateIfMissing(true)) {
1464       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1465       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1466         assertThat(db.setPreserveDeletesSequenceNumber(db.getLatestSequenceNumber()))
1467             .isFalse();
1468       }
1469     }
1470   }
1471 
1472   @Test
getLiveFiles()1473   public void getLiveFiles() throws RocksDBException {
1474     try (final Options options = new Options().setCreateIfMissing(true)) {
1475       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1476       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1477         final RocksDB.LiveFiles livefiles = db.getLiveFiles(true);
1478         assertThat(livefiles).isNotNull();
1479         assertThat(livefiles.manifestFileSize).isEqualTo(57);
1480         assertThat(livefiles.files.size()).isEqualTo(3);
1481         assertThat(livefiles.files.get(0)).isEqualTo("/CURRENT");
1482         assertThat(livefiles.files.get(1)).isEqualTo("/MANIFEST-000004");
1483         assertThat(livefiles.files.get(2)).isEqualTo("/OPTIONS-000007");
1484       }
1485     }
1486   }
1487 
1488   @Test
getSortedWalFiles()1489   public void getSortedWalFiles() throws RocksDBException {
1490     try (final Options options = new Options().setCreateIfMissing(true)) {
1491       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1492       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1493         db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1494         final List<LogFile> logFiles = db.getSortedWalFiles();
1495         assertThat(logFiles).isNotNull();
1496         assertThat(logFiles.size()).isEqualTo(1);
1497         assertThat(logFiles.get(0).type())
1498             .isEqualTo(WalFileType.kAliveLogFile);
1499       }
1500     }
1501   }
1502 
1503   @Test
deleteFile()1504   public void deleteFile() throws RocksDBException {
1505     try (final Options options = new Options().setCreateIfMissing(true)) {
1506       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1507       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1508         db.deleteFile("unknown");
1509       }
1510     }
1511   }
1512 
1513   @Test
getLiveFilesMetaData()1514   public void getLiveFilesMetaData() throws RocksDBException {
1515     try (final Options options = new Options().setCreateIfMissing(true)) {
1516       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1517       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1518         db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1519         final List<LiveFileMetaData> liveFilesMetaData
1520             = db.getLiveFilesMetaData();
1521         assertThat(liveFilesMetaData).isEmpty();
1522       }
1523     }
1524   }
1525 
1526   @Test
getColumnFamilyMetaData()1527   public void getColumnFamilyMetaData() throws RocksDBException {
1528     try (final DBOptions options = new DBOptions()
1529         .setCreateIfMissing(true)) {
1530       final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList(
1531           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY)
1532       );
1533       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1534       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1535       try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) {
1536         db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1537         try {
1538           final ColumnFamilyMetaData cfMetadata =
1539               db.getColumnFamilyMetaData(cfHandles.get(0));
1540           assertThat(cfMetadata).isNotNull();
1541           assertThat(cfMetadata.name()).isEqualTo(RocksDB.DEFAULT_COLUMN_FAMILY);
1542           assertThat(cfMetadata.levels().size()).isEqualTo(7);
1543         } finally {
1544           for (final ColumnFamilyHandle cfHandle : cfHandles) {
1545             cfHandle.close();
1546           }
1547         }
1548       }
1549     }
1550   }
1551 
1552   @Test
verifyChecksum()1553   public void verifyChecksum() throws RocksDBException {
1554     try (final Options options = new Options().setCreateIfMissing(true)) {
1555       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1556       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1557         db.verifyChecksum();
1558       }
1559     }
1560   }
1561 
1562   @Test
getPropertiesOfAllTables()1563   public void getPropertiesOfAllTables() throws RocksDBException {
1564     try (final DBOptions options = new DBOptions()
1565         .setCreateIfMissing(true)) {
1566       final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList(
1567           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY)
1568       );
1569       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1570       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1571       try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) {
1572         db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1573         try {
1574           final Map<String, TableProperties> properties =
1575               db.getPropertiesOfAllTables(cfHandles.get(0));
1576           assertThat(properties).isNotNull();
1577         } finally {
1578           for (final ColumnFamilyHandle cfHandle : cfHandles) {
1579             cfHandle.close();
1580           }
1581         }
1582       }
1583     }
1584   }
1585 
1586   @Test
getPropertiesOfTablesInRange()1587   public void getPropertiesOfTablesInRange() throws RocksDBException {
1588     try (final DBOptions options = new DBOptions()
1589         .setCreateIfMissing(true)) {
1590       final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList(
1591           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY)
1592       );
1593       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1594       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1595       try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) {
1596         db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1597         db.put(cfHandles.get(0), "key2".getBytes(UTF_8), "value2".getBytes(UTF_8));
1598         db.put(cfHandles.get(0), "key3".getBytes(UTF_8), "value3".getBytes(UTF_8));
1599         try {
1600           final Range range = new Range(
1601               new Slice("key1".getBytes(UTF_8)),
1602               new Slice("key3".getBytes(UTF_8)));
1603           final Map<String, TableProperties> properties =
1604               db.getPropertiesOfTablesInRange(
1605                   cfHandles.get(0), Arrays.asList(range));
1606           assertThat(properties).isNotNull();
1607         } finally {
1608           for (final ColumnFamilyHandle cfHandle : cfHandles) {
1609             cfHandle.close();
1610           }
1611         }
1612       }
1613     }
1614   }
1615 
1616   @Test
suggestCompactRange()1617   public void suggestCompactRange() throws RocksDBException {
1618     try (final DBOptions options = new DBOptions()
1619         .setCreateIfMissing(true)) {
1620       final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList(
1621           new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY)
1622       );
1623       final List<ColumnFamilyHandle> cfHandles = new ArrayList<>();
1624       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1625       try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) {
1626         db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1627         db.put(cfHandles.get(0), "key2".getBytes(UTF_8), "value2".getBytes(UTF_8));
1628         db.put(cfHandles.get(0), "key3".getBytes(UTF_8), "value3".getBytes(UTF_8));
1629         try {
1630           final Range range =  db.suggestCompactRange(cfHandles.get(0));
1631           assertThat(range).isNotNull();
1632         } finally {
1633           for (final ColumnFamilyHandle cfHandle : cfHandles) {
1634             cfHandle.close();
1635           }
1636         }
1637       }
1638     }
1639   }
1640 
1641   @Test
promoteL0()1642   public void promoteL0() throws RocksDBException {
1643     try (final Options options = new Options().setCreateIfMissing(true)) {
1644       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1645       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1646         db.promoteL0(2);
1647       }
1648     }
1649   }
1650 
1651   @Test
startTrace()1652   public void startTrace() throws RocksDBException {
1653     try (final Options options = new Options().setCreateIfMissing(true)) {
1654       final String dbPath = dbFolder.getRoot().getAbsolutePath();
1655       try (final RocksDB db = RocksDB.open(options, dbPath)) {
1656         final TraceOptions traceOptions = new TraceOptions();
1657 
1658         try (final InMemoryTraceWriter traceWriter = new InMemoryTraceWriter()) {
1659           db.startTrace(traceOptions, traceWriter);
1660 
1661           db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8));
1662 
1663           db.endTrace();
1664 
1665           final List<byte[]> writes = traceWriter.getWrites();
1666           assertThat(writes.size()).isGreaterThan(0);
1667         }
1668       }
1669     }
1670   }
1671 
1672   @Test
setDBOptions()1673   public void setDBOptions() throws RocksDBException {
1674     try (final DBOptions options = new DBOptions()
1675         .setCreateIfMissing(true)
1676         .setCreateMissingColumnFamilies(true);
1677          final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions()
1678              .setWriteBufferSize(4096)) {
1679 
1680       final List<ColumnFamilyDescriptor> columnFamilyDescriptors =
1681           Arrays.asList(
1682               new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
1683               new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts));
1684 
1685       // open database
1686       final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>();
1687       try (final RocksDB db = RocksDB.open(options,
1688           dbFolder.getRoot().getAbsolutePath(), columnFamilyDescriptors, columnFamilyHandles)) {
1689         try {
1690           final MutableDBOptions mutableOptions =
1691               MutableDBOptions.builder()
1692                   .setBytesPerSync(1024 * 1027 * 7)
1693                   .setAvoidFlushDuringShutdown(false)
1694                   .build();
1695 
1696           db.setDBOptions(mutableOptions);
1697         } finally {
1698           for (final ColumnFamilyHandle handle : columnFamilyHandles) {
1699             handle.close();
1700           }
1701         }
1702       }
1703     }
1704   }
1705 
1706   @Test
rocksdbVersion()1707   public void rocksdbVersion() {
1708     final RocksDB.Version version = RocksDB.rocksdbVersion();
1709     assertThat(version).isNotNull();
1710     assertThat(version.getMajor()).isGreaterThan(1);
1711   }
1712 
1713   private static class InMemoryTraceWriter extends AbstractTraceWriter {
1714     private final List<byte[]> writes = new ArrayList<>();
1715     private volatile boolean closed = false;
1716 
1717     @Override
write(final Slice slice)1718     public void write(final Slice slice) {
1719       if (closed) {
1720         return;
1721       }
1722       final byte[] data = slice.data();
1723       final byte[] dataCopy = new byte[data.length];
1724       System.arraycopy(data, 0, dataCopy, 0, data.length);
1725       writes.add(dataCopy);
1726     }
1727 
1728     @Override
closeWriter()1729     public void closeWriter() {
1730       closed = true;
1731     }
1732 
1733     @Override
getFileSize()1734     public long getFileSize() {
1735       long size = 0;
1736       for (int i = 0; i < writes.size(); i++) {
1737         size += writes.get(i).length;
1738       }
1739       return size;
1740     }
1741 
getWrites()1742     public List<byte[]> getWrites() {
1743       return writes;
1744     }
1745   }
1746 }
1747