1 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2 //  This source code is licensed under both the GPLv2 (found in the
3 //  COPYING file in the root directory) and Apache 2.0 License
4 //  (found in the LICENSE.Apache file in the root directory).
5 //
6 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
7 // Use of this source code is governed by a BSD-style license that can be
8 // found in the LICENSE file. See the AUTHORS file for names of contributors.
9 
10 package org.rocksdb;
11 
12 import static java.nio.charset.StandardCharsets.UTF_8;
13 import static org.assertj.core.api.Assertions.assertThat;
14 
15 import java.nio.ByteBuffer;
16 import java.util.ArrayList;
17 import java.util.Arrays;
18 import java.util.List;
19 import org.junit.ClassRule;
20 import org.junit.Rule;
21 import org.junit.Test;
22 import org.junit.rules.TemporaryFolder;
23 
24 public class WriteBatchWithIndexTest {
25 
26   @ClassRule
27   public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE =
28       new RocksNativeLibraryResource();
29 
30   @Rule
31   public TemporaryFolder dbFolder = new TemporaryFolder();
32 
33   @Test
readYourOwnWrites()34   public void readYourOwnWrites() throws RocksDBException {
35     try (final Options options = new Options().setCreateIfMissing(true);
36          final RocksDB db = RocksDB.open(options,
37              dbFolder.getRoot().getAbsolutePath())) {
38 
39       final byte[] k1 = "key1".getBytes();
40       final byte[] v1 = "value1".getBytes();
41       final byte[] k2 = "key2".getBytes();
42       final byte[] v2 = "value2".getBytes();
43 
44       db.put(k1, v1);
45       db.put(k2, v2);
46 
47       try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true);
48            final RocksIterator base = db.newIterator();
49            final RocksIterator it = wbwi.newIteratorWithBase(base)) {
50         it.seek(k1);
51         assertThat(it.isValid()).isTrue();
52         assertThat(it.key()).isEqualTo(k1);
53         assertThat(it.value()).isEqualTo(v1);
54 
55         it.seek(k2);
56         assertThat(it.isValid()).isTrue();
57         assertThat(it.key()).isEqualTo(k2);
58         assertThat(it.value()).isEqualTo(v2);
59 
60         //put data to the write batch and make sure we can read it.
61         final byte[] k3 = "key3".getBytes();
62         final byte[] v3 = "value3".getBytes();
63         wbwi.put(k3, v3);
64         it.seek(k3);
65         assertThat(it.isValid()).isTrue();
66         assertThat(it.key()).isEqualTo(k3);
67         assertThat(it.value()).isEqualTo(v3);
68 
69         //update k2 in the write batch and check the value
70         final byte[] v2Other = "otherValue2".getBytes();
71         wbwi.put(k2, v2Other);
72         it.seek(k2);
73         assertThat(it.isValid()).isTrue();
74         assertThat(it.key()).isEqualTo(k2);
75         assertThat(it.value()).isEqualTo(v2Other);
76 
77         //delete k1 and make sure we can read back the write
78         wbwi.delete(k1);
79         it.seek(k1);
80         assertThat(it.key()).isNotEqualTo(k1);
81 
82         //reinsert k1 and make sure we see the new value
83         final byte[] v1Other = "otherValue1".getBytes();
84         wbwi.put(k1, v1Other);
85         it.seek(k1);
86         assertThat(it.isValid()).isTrue();
87         assertThat(it.key()).isEqualTo(k1);
88         assertThat(it.value()).isEqualTo(v1Other);
89 
90         //single remove k3 and make sure we can read back the write
91         wbwi.singleDelete(k3);
92         it.seek(k3);
93         assertThat(it.isValid()).isEqualTo(false);
94 
95         //reinsert k3 and make sure we see the new value
96         final byte[] v3Other = "otherValue3".getBytes();
97         wbwi.put(k3, v3Other);
98         it.seek(k3);
99         assertThat(it.isValid()).isTrue();
100         assertThat(it.key()).isEqualTo(k3);
101         assertThat(it.value()).isEqualTo(v3Other);
102       }
103     }
104   }
105 
106   @Test
readYourOwnWritesCf()107   public void readYourOwnWritesCf() throws RocksDBException {
108     final List<ColumnFamilyDescriptor> cfNames =
109         Arrays.asList(new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY),
110             new ColumnFamilyDescriptor("new_cf".getBytes()));
111 
112     final List<ColumnFamilyHandle> columnFamilyHandleList = new ArrayList<>();
113 
114     // Test open database with column family names
115     try (final DBOptions options =
116              new DBOptions().setCreateIfMissing(true).setCreateMissingColumnFamilies(true);
117          final RocksDB db = RocksDB.open(
118              options, dbFolder.getRoot().getAbsolutePath(), cfNames, columnFamilyHandleList)) {
119       final ColumnFamilyHandle newCf = columnFamilyHandleList.get(1);
120 
121       try {
122         final byte[] k1 = "key1".getBytes();
123         final byte[] v1 = "value1".getBytes();
124         final byte[] k2 = "key2".getBytes();
125         final byte[] v2 = "value2".getBytes();
126 
127         db.put(newCf, k1, v1);
128         db.put(newCf, k2, v2);
129 
130         try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true);
131              final ReadOptions readOptions = new ReadOptions();
132              final RocksIterator base = db.newIterator(newCf, readOptions);
133              final RocksIterator it = wbwi.newIteratorWithBase(newCf, base, readOptions)) {
134           it.seek(k1);
135           assertThat(it.isValid()).isTrue();
136           assertThat(it.key()).isEqualTo(k1);
137           assertThat(it.value()).isEqualTo(v1);
138 
139           it.seek(k2);
140           assertThat(it.isValid()).isTrue();
141           assertThat(it.key()).isEqualTo(k2);
142           assertThat(it.value()).isEqualTo(v2);
143 
144           // put data to the write batch and make sure we can read it.
145           final byte[] k3 = "key3".getBytes();
146           final byte[] v3 = "value3".getBytes();
147           wbwi.put(newCf, k3, v3);
148           it.seek(k3);
149           assertThat(it.isValid()).isTrue();
150           assertThat(it.key()).isEqualTo(k3);
151           assertThat(it.value()).isEqualTo(v3);
152 
153           // update k2 in the write batch and check the value
154           final byte[] v2Other = "otherValue2".getBytes();
155           wbwi.put(newCf, k2, v2Other);
156           it.seek(k2);
157           assertThat(it.isValid()).isTrue();
158           assertThat(it.key()).isEqualTo(k2);
159           assertThat(it.value()).isEqualTo(v2Other);
160 
161           // delete k1 and make sure we can read back the write
162           wbwi.delete(newCf, k1);
163           it.seek(k1);
164           assertThat(it.key()).isNotEqualTo(k1);
165 
166           // reinsert k1 and make sure we see the new value
167           final byte[] v1Other = "otherValue1".getBytes();
168           wbwi.put(newCf, k1, v1Other);
169           it.seek(k1);
170           assertThat(it.isValid()).isTrue();
171           assertThat(it.key()).isEqualTo(k1);
172           assertThat(it.value()).isEqualTo(v1Other);
173 
174           // single remove k3 and make sure we can read back the write
175           wbwi.singleDelete(newCf, k3);
176           it.seek(k3);
177           assertThat(it.isValid()).isEqualTo(false);
178 
179           // reinsert k3 and make sure we see the new value
180           final byte[] v3Other = "otherValue3".getBytes();
181           wbwi.put(newCf, k3, v3Other);
182           it.seek(k3);
183           assertThat(it.isValid()).isTrue();
184           assertThat(it.key()).isEqualTo(k3);
185           assertThat(it.value()).isEqualTo(v3Other);
186         }
187       } finally {
188         for (final ColumnFamilyHandle columnFamilyHandle : columnFamilyHandleList) {
189           columnFamilyHandle.close();
190         }
191       }
192     }
193   }
194 
195   @Test
writeBatchWithIndex()196   public void writeBatchWithIndex() throws RocksDBException {
197     try (final Options options = new Options().setCreateIfMissing(true);
198          final RocksDB db = RocksDB.open(options,
199              dbFolder.getRoot().getAbsolutePath())) {
200 
201       final byte[] k1 = "key1".getBytes();
202       final byte[] v1 = "value1".getBytes();
203       final byte[] k2 = "key2".getBytes();
204       final byte[] v2 = "value2".getBytes();
205 
206       try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex();
207            final WriteOptions wOpt = new WriteOptions()) {
208         wbwi.put(k1, v1);
209         wbwi.put(k2, v2);
210 
211         db.write(wOpt, wbwi);
212       }
213 
214       assertThat(db.get(k1)).isEqualTo(v1);
215       assertThat(db.get(k2)).isEqualTo(v2);
216     }
217   }
218 
219   @Test
write_writeBatchWithIndexDirect()220   public void write_writeBatchWithIndexDirect() throws RocksDBException {
221     try (final Options options = new Options().setCreateIfMissing(true);
222          final RocksDB db = RocksDB.open(options, dbFolder.getRoot().getAbsolutePath())) {
223       ByteBuffer k1 = ByteBuffer.allocateDirect(16);
224       ByteBuffer v1 = ByteBuffer.allocateDirect(16);
225       ByteBuffer k2 = ByteBuffer.allocateDirect(16);
226       ByteBuffer v2 = ByteBuffer.allocateDirect(16);
227       k1.put("key1".getBytes()).flip();
228       v1.put("value1".getBytes()).flip();
229       k2.put("key2".getBytes()).flip();
230       v2.put("value2".getBytes()).flip();
231 
232       try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
233         wbwi.put(k1, v1);
234         assertThat(k1.position()).isEqualTo(4);
235         assertThat(k1.limit()).isEqualTo(4);
236         assertThat(v1.position()).isEqualTo(6);
237         assertThat(v1.limit()).isEqualTo(6);
238 
239         wbwi.put(k2, v2);
240 
241         db.write(new WriteOptions(), wbwi);
242       }
243 
244       assertThat(db.get("key1".getBytes())).isEqualTo("value1".getBytes());
245       assertThat(db.get("key2".getBytes())).isEqualTo("value2".getBytes());
246     }
247   }
248 
249   @Test
iterator()250   public void iterator() throws RocksDBException {
251     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true)) {
252 
253       final String k1 = "key1";
254       final String v1 = "value1";
255       final String k2 = "key2";
256       final String v2 = "value2";
257       final String k3 = "key3";
258       final String v3 = "value3";
259       final String k4 = "key4";
260       final String k5 = "key5";
261       final String k6 = "key6";
262       final String k7 = "key7";
263       final String v8 = "value8";
264       final byte[] k1b = k1.getBytes(UTF_8);
265       final byte[] v1b = v1.getBytes(UTF_8);
266       final byte[] k2b = k2.getBytes(UTF_8);
267       final byte[] v2b = v2.getBytes(UTF_8);
268       final byte[] k3b = k3.getBytes(UTF_8);
269       final byte[] v3b = v3.getBytes(UTF_8);
270       final byte[] k4b = k4.getBytes(UTF_8);
271       final byte[] k5b = k5.getBytes(UTF_8);
272       final byte[] k6b = k6.getBytes(UTF_8);
273       final byte[] k7b = k7.getBytes(UTF_8);
274       final byte[] v8b = v8.getBytes(UTF_8);
275 
276       // add put records
277       wbwi.put(k1b, v1b);
278       wbwi.put(k2b, v2b);
279       wbwi.put(k3b, v3b);
280 
281       // add a deletion record
282       wbwi.delete(k4b);
283 
284       // add a single deletion record
285       wbwi.singleDelete(k5b);
286 
287       // add a log record
288       wbwi.putLogData(v8b);
289 
290       final WBWIRocksIterator.WriteEntry[] expected = {
291           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
292               new DirectSlice(k1), new DirectSlice(v1)),
293           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
294               new DirectSlice(k2), new DirectSlice(v2)),
295           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
296               new DirectSlice(k3), new DirectSlice(v3)),
297           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.DELETE,
298               new DirectSlice(k4), DirectSlice.NONE),
299           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.SINGLE_DELETE,
300               new DirectSlice(k5), DirectSlice.NONE),
301       };
302 
303       try (final WBWIRocksIterator it = wbwi.newIterator()) {
304         //direct access - seek to key offsets
305         final int[] testOffsets = {2, 0, 3, 4, 1};
306 
307         for (int i = 0; i < testOffsets.length; i++) {
308           final int testOffset = testOffsets[i];
309           final byte[] key = toArray(expected[testOffset].getKey().data());
310 
311           it.seek(key);
312           assertThat(it.isValid()).isTrue();
313 
314           final WBWIRocksIterator.WriteEntry entry = it.entry();
315           assertThat(entry).isEqualTo(expected[testOffset]);
316 
317           // Direct buffer seek
318           expected[testOffset].getKey().data().mark();
319           ByteBuffer db = expected[testOffset].getKey().data();
320           it.seek(db);
321           assertThat(db.position()).isEqualTo(key.length);
322           assertThat(it.isValid()).isTrue();
323         }
324 
325         //forward iterative access
326         int i = 0;
327         for (it.seekToFirst(); it.isValid(); it.next()) {
328           assertThat(it.entry()).isEqualTo(expected[i++]);
329         }
330 
331         //reverse iterative access
332         i = expected.length - 1;
333         for (it.seekToLast(); it.isValid(); it.prev()) {
334           assertThat(it.entry()).isEqualTo(expected[i--]);
335         }
336       }
337     }
338   }
339 
340   @Test
zeroByteTests()341   public void zeroByteTests() throws RocksDBException {
342     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true)) {
343       final byte[] zeroByteValue = new byte[]{0, 0};
344       //add zero byte value
345       wbwi.put(zeroByteValue, zeroByteValue);
346 
347       final ByteBuffer buffer = ByteBuffer.allocateDirect(zeroByteValue.length);
348       buffer.put(zeroByteValue);
349 
350       final WBWIRocksIterator.WriteEntry expected =
351           new WBWIRocksIterator.WriteEntry(WBWIRocksIterator.WriteType.PUT,
352               new DirectSlice(buffer, zeroByteValue.length),
353               new DirectSlice(buffer, zeroByteValue.length));
354 
355       try (final WBWIRocksIterator it = wbwi.newIterator()) {
356         it.seekToFirst();
357         final WBWIRocksIterator.WriteEntry actual = it.entry();
358         assertThat(actual.equals(expected)).isTrue();
359         assertThat(it.entry().hashCode() == expected.hashCode()).isTrue();
360       }
361     }
362   }
363 
364   @Test
savePoints()365   public void savePoints() throws RocksDBException {
366     try (final Options options = new Options().setCreateIfMissing(true);
367          final RocksDB db = RocksDB.open(options,
368              dbFolder.getRoot().getAbsolutePath())) {
369       try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true);
370            final ReadOptions readOptions = new ReadOptions()) {
371         wbwi.put("k1".getBytes(), "v1".getBytes());
372         wbwi.put("k2".getBytes(), "v2".getBytes());
373         wbwi.put("k3".getBytes(), "v3".getBytes());
374 
375         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k1"))
376             .isEqualTo("v1");
377         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k2"))
378             .isEqualTo("v2");
379         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k3"))
380             .isEqualTo("v3");
381 
382 
383         wbwi.setSavePoint();
384 
385         wbwi.delete("k2".getBytes());
386         wbwi.put("k3".getBytes(), "v3-2".getBytes());
387 
388         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k2"))
389             .isNull();
390         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k3"))
391             .isEqualTo("v3-2");
392 
393 
394         wbwi.setSavePoint();
395 
396         wbwi.put("k3".getBytes(), "v3-3".getBytes());
397         wbwi.put("k4".getBytes(), "v4".getBytes());
398 
399         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k3"))
400             .isEqualTo("v3-3");
401         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k4"))
402             .isEqualTo("v4");
403 
404 
405         wbwi.rollbackToSavePoint();
406 
407         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k2"))
408             .isNull();
409         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k3"))
410             .isEqualTo("v3-2");
411         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k4"))
412             .isNull();
413 
414 
415         wbwi.rollbackToSavePoint();
416 
417         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k1"))
418             .isEqualTo("v1");
419         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k2"))
420             .isEqualTo("v2");
421         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k3"))
422             .isEqualTo("v3");
423         assertThat(getFromWriteBatchWithIndex(db, readOptions, wbwi, "k4"))
424             .isNull();
425       }
426     }
427   }
428 
429   @Test
restorePoints()430   public void restorePoints() throws RocksDBException {
431     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
432 
433       wbwi.put("k1".getBytes(UTF_8), "v1".getBytes(UTF_8));
434       wbwi.put("k2".getBytes(UTF_8), "v2".getBytes(UTF_8));
435 
436       wbwi.setSavePoint();
437 
438       wbwi.put("k1".getBytes(UTF_8), "123456789".getBytes(UTF_8));
439       wbwi.delete("k2".getBytes(UTF_8));
440 
441       wbwi.rollbackToSavePoint();
442 
443       try(final DBOptions options = new DBOptions()) {
444         assertThat(wbwi.getFromBatch(options,"k1".getBytes(UTF_8))).isEqualTo("v1".getBytes());
445         assertThat(wbwi.getFromBatch(options,"k2".getBytes(UTF_8))).isEqualTo("v2".getBytes());
446       }
447     }
448   }
449 
450   @Test(expected = RocksDBException.class)
restorePoints_withoutSavePoints()451   public void restorePoints_withoutSavePoints() throws RocksDBException {
452     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
453       wbwi.rollbackToSavePoint();
454     }
455   }
456 
457   @Test(expected = RocksDBException.class)
restorePoints_withoutSavePoints_nested()458   public void restorePoints_withoutSavePoints_nested() throws RocksDBException {
459     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
460 
461       wbwi.setSavePoint();
462       wbwi.rollbackToSavePoint();
463 
464       // without previous corresponding setSavePoint
465       wbwi.rollbackToSavePoint();
466     }
467   }
468 
469   @Test
popSavePoint()470   public void popSavePoint() throws RocksDBException {
471     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
472 
473       wbwi.put("k1".getBytes(), "v1".getBytes());
474       wbwi.put("k2".getBytes(), "v2".getBytes());
475 
476       wbwi.setSavePoint();
477 
478       wbwi.put("k1".getBytes(), "123456789".getBytes());
479       wbwi.delete("k2".getBytes());
480 
481       wbwi.setSavePoint();
482 
483       wbwi.popSavePoint();
484 
485       wbwi.rollbackToSavePoint();
486 
487       try(final DBOptions options = new DBOptions()) {
488         assertThat(wbwi.getFromBatch(options,"k1".getBytes(UTF_8))).isEqualTo("v1".getBytes());
489         assertThat(wbwi.getFromBatch(options,"k2".getBytes(UTF_8))).isEqualTo("v2".getBytes());
490       }
491     }
492   }
493 
494   @Test(expected = RocksDBException.class)
popSavePoint_withoutSavePoints()495   public void popSavePoint_withoutSavePoints() throws RocksDBException {
496     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
497       wbwi.popSavePoint();
498     }
499   }
500 
501   @Test(expected = RocksDBException.class)
popSavePoint_withoutSavePoints_nested()502   public void popSavePoint_withoutSavePoints_nested() throws RocksDBException {
503     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
504 
505       wbwi.setSavePoint();
506       wbwi.popSavePoint();
507 
508       // without previous corresponding setSavePoint
509       wbwi.popSavePoint();
510     }
511   }
512 
513   @Test
maxBytes()514   public void maxBytes() throws RocksDBException {
515     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
516       wbwi.setMaxBytes(19);
517 
518       wbwi.put("k1".getBytes(), "v1".getBytes());
519     }
520   }
521 
522   @Test(expected = RocksDBException.class)
maxBytes_over()523   public void maxBytes_over() throws RocksDBException {
524     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
525       wbwi.setMaxBytes(1);
526 
527       wbwi.put("k1".getBytes(), "v1".getBytes());
528     }
529   }
530 
531   @Test
getWriteBatch()532   public void getWriteBatch() {
533     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex()) {
534 
535       final WriteBatch wb = wbwi.getWriteBatch();
536       assertThat(wb).isNotNull();
537       assertThat(wb.isOwningHandle()).isFalse();
538     }
539   }
540 
getFromWriteBatchWithIndex(final RocksDB db, final ReadOptions readOptions, final WriteBatchWithIndex wbwi, final String skey)541   private static String getFromWriteBatchWithIndex(final RocksDB db,
542       final ReadOptions readOptions, final WriteBatchWithIndex wbwi,
543       final String skey) {
544     final byte[] key = skey.getBytes();
545     try (final RocksIterator baseIterator = db.newIterator(readOptions);
546          final RocksIterator iterator = wbwi.newIteratorWithBase(baseIterator)) {
547       iterator.seek(key);
548 
549       // Arrays.equals(key, iterator.key()) ensures an exact match in Rocks,
550       // instead of a nearest match
551       return iterator.isValid() &&
552           Arrays.equals(key, iterator.key()) ?
553           new String(iterator.value()) : null;
554     }
555   }
556 
557   @Test
getFromBatch()558   public void getFromBatch() throws RocksDBException {
559     final byte[] k1 = "k1".getBytes();
560     final byte[] k2 = "k2".getBytes();
561     final byte[] k3 = "k3".getBytes();
562     final byte[] k4 = "k4".getBytes();
563 
564     final byte[] v1 = "v1".getBytes();
565     final byte[] v2 = "v2".getBytes();
566     final byte[] v3 = "v3".getBytes();
567 
568     try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true);
569          final DBOptions dbOptions = new DBOptions()) {
570       wbwi.put(k1, v1);
571       wbwi.put(k2, v2);
572       wbwi.put(k3, v3);
573 
574       assertThat(wbwi.getFromBatch(dbOptions, k1)).isEqualTo(v1);
575       assertThat(wbwi.getFromBatch(dbOptions, k2)).isEqualTo(v2);
576       assertThat(wbwi.getFromBatch(dbOptions, k3)).isEqualTo(v3);
577       assertThat(wbwi.getFromBatch(dbOptions, k4)).isNull();
578 
579       wbwi.delete(k2);
580 
581       assertThat(wbwi.getFromBatch(dbOptions, k2)).isNull();
582     }
583   }
584 
585   @Test
getFromBatchAndDB()586   public void getFromBatchAndDB() throws RocksDBException {
587     final byte[] k1 = "k1".getBytes();
588     final byte[] k2 = "k2".getBytes();
589     final byte[] k3 = "k3".getBytes();
590     final byte[] k4 = "k4".getBytes();
591 
592     final byte[] v1 = "v1".getBytes();
593     final byte[] v2 = "v2".getBytes();
594     final byte[] v3 = "v3".getBytes();
595     final byte[] v4 = "v4".getBytes();
596 
597     try (final Options options = new Options().setCreateIfMissing(true);
598          final RocksDB db = RocksDB.open(options,
599              dbFolder.getRoot().getAbsolutePath())) {
600 
601       db.put(k1, v1);
602       db.put(k2, v2);
603       db.put(k4, v4);
604 
605       try (final WriteBatchWithIndex wbwi = new WriteBatchWithIndex(true);
606            final DBOptions dbOptions = new DBOptions();
607            final ReadOptions readOptions = new ReadOptions()) {
608 
609         assertThat(wbwi.getFromBatch(dbOptions, k1)).isNull();
610         assertThat(wbwi.getFromBatch(dbOptions, k2)).isNull();
611         assertThat(wbwi.getFromBatch(dbOptions, k4)).isNull();
612 
613         wbwi.put(k3, v3);
614 
615         assertThat(wbwi.getFromBatch(dbOptions, k3)).isEqualTo(v3);
616 
617         assertThat(wbwi.getFromBatchAndDB(db, readOptions, k1)).isEqualTo(v1);
618         assertThat(wbwi.getFromBatchAndDB(db, readOptions, k2)).isEqualTo(v2);
619         assertThat(wbwi.getFromBatchAndDB(db, readOptions, k3)).isEqualTo(v3);
620         assertThat(wbwi.getFromBatchAndDB(db, readOptions, k4)).isEqualTo(v4);
621 
622         wbwi.delete(k4);
623 
624         assertThat(wbwi.getFromBatchAndDB(db, readOptions, k4)).isNull();
625       }
626     }
627   }
toArray(final ByteBuffer buf)628   private byte[] toArray(final ByteBuffer buf) {
629     final byte[] ary = new byte[buf.remaining()];
630     buf.get(ary);
631     return ary;
632   }
633 
634   @Test
deleteRange()635   public void deleteRange() throws RocksDBException {
636     try (final RocksDB db = RocksDB.open(dbFolder.getRoot().getAbsolutePath());
637          final WriteBatch batch = new WriteBatch();
638          final WriteOptions wOpt = new WriteOptions()) {
639       db.put("key1".getBytes(), "value".getBytes());
640       db.put("key2".getBytes(), "12345678".getBytes());
641       db.put("key3".getBytes(), "abcdefg".getBytes());
642       db.put("key4".getBytes(), "xyz".getBytes());
643       assertThat(db.get("key1".getBytes())).isEqualTo("value".getBytes());
644       assertThat(db.get("key2".getBytes())).isEqualTo("12345678".getBytes());
645       assertThat(db.get("key3".getBytes())).isEqualTo("abcdefg".getBytes());
646       assertThat(db.get("key4".getBytes())).isEqualTo("xyz".getBytes());
647 
648       batch.deleteRange("key2".getBytes(), "key4".getBytes());
649       db.write(wOpt, batch);
650 
651       assertThat(db.get("key1".getBytes())).isEqualTo("value".getBytes());
652       assertThat(db.get("key2".getBytes())).isNull();
653       assertThat(db.get("key3".getBytes())).isNull();
654       assertThat(db.get("key4".getBytes())).isEqualTo("xyz".getBytes());
655     }
656   }
657 }
658