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).
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.
11 import org
.junit
.ClassRule
;
12 import org
.junit
.Rule
;
13 import org
.junit
.Test
;
14 import org
.junit
.rules
.TemporaryFolder
;
15 import org
.rocksdb
.util
.CapturingWriteBatchHandler
;
16 import org
.rocksdb
.util
.CapturingWriteBatchHandler
.Event
;
17 import org
.rocksdb
.util
.WriteBatchGetter
;
19 import static org
.assertj
.core
.api
.Assertions
.assertThat
;
20 import static org
.rocksdb
.util
.CapturingWriteBatchHandler
.Action
.*;
21 import static java
.nio
.charset
.StandardCharsets
.UTF_8
;
24 * This class mimics the db/write_batch_test.cc
25 * in the c++ rocksdb library.
27 public class WriteBatchTest
{
29 public static final RocksMemoryResource rocksMemoryResource
=
30 new RocksMemoryResource();
33 public TemporaryFolder dbFolder
= new TemporaryFolder();
36 public void emptyWriteBatch() {
37 try (final WriteBatch batch
= new WriteBatch()) {
38 assertThat(batch
.count()).isEqualTo(0);
43 public void multipleBatchOperations()
44 throws RocksDBException
{
46 final byte[] foo
= "foo".getBytes(UTF_8
);
47 final byte[] bar
= "bar".getBytes(UTF_8
);
48 final byte[] box
= "box".getBytes(UTF_8
);
49 final byte[] baz
= "baz".getBytes(UTF_8
);
50 final byte[] boo
= "boo".getBytes(UTF_8
);
51 final byte[] hoo
= "hoo".getBytes(UTF_8
);
52 final byte[] hello
= "hello".getBytes(UTF_8
);
54 try (final WriteBatch batch
= new WriteBatch()) {
58 batch
.merge(baz
, hoo
);
59 batch
.singleDelete(foo
);
60 batch
.deleteRange(baz
, foo
);
61 batch
.putLogData(hello
);
63 try(final CapturingWriteBatchHandler handler
=
64 new CapturingWriteBatchHandler()) {
65 batch
.iterate(handler
);
67 assertThat(handler
.getEvents().size()).isEqualTo(7);
69 assertThat(handler
.getEvents().get(0)).isEqualTo(new Event(PUT
, foo
, bar
));
70 assertThat(handler
.getEvents().get(1)).isEqualTo(new Event(DELETE
, box
, null));
71 assertThat(handler
.getEvents().get(2)).isEqualTo(new Event(PUT
, baz
, boo
));
72 assertThat(handler
.getEvents().get(3)).isEqualTo(new Event(MERGE
, baz
, hoo
));
73 assertThat(handler
.getEvents().get(4)).isEqualTo(new Event(SINGLE_DELETE
, foo
, null));
74 assertThat(handler
.getEvents().get(5)).isEqualTo(new Event(DELETE_RANGE
, baz
, foo
));
75 assertThat(handler
.getEvents().get(6)).isEqualTo(new Event(LOG
, null, hello
));
81 public void testAppendOperation()
82 throws RocksDBException
{
83 try (final WriteBatch b1
= new WriteBatch();
84 final WriteBatch b2
= new WriteBatch()) {
85 WriteBatchTestInternalHelper
.setSequence(b1
, 200);
86 WriteBatchTestInternalHelper
.setSequence(b2
, 300);
87 WriteBatchTestInternalHelper
.append(b1
, b2
);
88 assertThat(getContents(b1
).length
).isEqualTo(0);
89 assertThat(b1
.count()).isEqualTo(0);
90 b2
.put("a".getBytes(UTF_8
), "va".getBytes(UTF_8
));
91 WriteBatchTestInternalHelper
.append(b1
, b2
);
92 assertThat("Put(a, va)@200".equals(new String(getContents(b1
),
94 assertThat(b1
.count()).isEqualTo(1);
96 b2
.put("b".getBytes(UTF_8
), "vb".getBytes(UTF_8
));
97 WriteBatchTestInternalHelper
.append(b1
, b2
);
98 assertThat(("Put(a, va)@200" +
100 .equals(new String(getContents(b1
), UTF_8
)));
101 assertThat(b1
.count()).isEqualTo(2);
102 b2
.delete("foo".getBytes(UTF_8
));
103 WriteBatchTestInternalHelper
.append(b1
, b2
);
104 assertThat(("Put(a, va)@200" +
108 .equals(new String(getContents(b1
), UTF_8
)));
109 assertThat(b1
.count()).isEqualTo(4);
114 public void blobOperation()
115 throws RocksDBException
{
116 try (final WriteBatch batch
= new WriteBatch()) {
117 batch
.put("k1".getBytes(UTF_8
), "v1".getBytes(UTF_8
));
118 batch
.put("k2".getBytes(UTF_8
), "v2".getBytes(UTF_8
));
119 batch
.put("k3".getBytes(UTF_8
), "v3".getBytes(UTF_8
));
120 batch
.putLogData("blob1".getBytes(UTF_8
));
121 batch
.delete("k2".getBytes(UTF_8
));
122 batch
.putLogData("blob2".getBytes(UTF_8
));
123 batch
.merge("foo".getBytes(UTF_8
), "bar".getBytes(UTF_8
));
124 assertThat(batch
.count()).isEqualTo(5);
125 assertThat(("Merge(foo, bar)@4" +
130 .equals(new String(getContents(batch
), UTF_8
)));
135 public void savePoints()
136 throws RocksDBException
{
137 try (final WriteBatch batch
= new WriteBatch()) {
138 batch
.put("k1".getBytes(UTF_8
), "v1".getBytes(UTF_8
));
139 batch
.put("k2".getBytes(UTF_8
), "v2".getBytes(UTF_8
));
140 batch
.put("k3".getBytes(UTF_8
), "v3".getBytes(UTF_8
));
142 assertThat(getFromWriteBatch(batch
, "k1")).isEqualTo("v1");
143 assertThat(getFromWriteBatch(batch
, "k2")).isEqualTo("v2");
144 assertThat(getFromWriteBatch(batch
, "k3")).isEqualTo("v3");
146 batch
.setSavePoint();
148 batch
.delete("k2".getBytes(UTF_8
));
149 batch
.put("k3".getBytes(UTF_8
), "v3-2".getBytes(UTF_8
));
151 assertThat(getFromWriteBatch(batch
, "k2")).isNull();
152 assertThat(getFromWriteBatch(batch
, "k3")).isEqualTo("v3-2");
155 batch
.setSavePoint();
157 batch
.put("k3".getBytes(UTF_8
), "v3-3".getBytes(UTF_8
));
158 batch
.put("k4".getBytes(UTF_8
), "v4".getBytes(UTF_8
));
160 assertThat(getFromWriteBatch(batch
, "k3")).isEqualTo("v3-3");
161 assertThat(getFromWriteBatch(batch
, "k4")).isEqualTo("v4");
164 batch
.rollbackToSavePoint();
166 assertThat(getFromWriteBatch(batch
, "k2")).isNull();
167 assertThat(getFromWriteBatch(batch
, "k3")).isEqualTo("v3-2");
168 assertThat(getFromWriteBatch(batch
, "k4")).isNull();
171 batch
.rollbackToSavePoint();
173 assertThat(getFromWriteBatch(batch
, "k1")).isEqualTo("v1");
174 assertThat(getFromWriteBatch(batch
, "k2")).isEqualTo("v2");
175 assertThat(getFromWriteBatch(batch
, "k3")).isEqualTo("v3");
176 assertThat(getFromWriteBatch(batch
, "k4")).isNull();
181 public void deleteRange() throws RocksDBException
{
182 try (final RocksDB db
= RocksDB
.open(dbFolder
.getRoot().getAbsolutePath());
183 final WriteBatch batch
= new WriteBatch();
184 final WriteOptions wOpt
= new WriteOptions()) {
185 db
.put("key1".getBytes(), "value".getBytes());
186 db
.put("key2".getBytes(), "12345678".getBytes());
187 db
.put("key3".getBytes(), "abcdefg".getBytes());
188 db
.put("key4".getBytes(), "xyz".getBytes());
189 assertThat(db
.get("key1".getBytes())).isEqualTo("value".getBytes());
190 assertThat(db
.get("key2".getBytes())).isEqualTo("12345678".getBytes());
191 assertThat(db
.get("key3".getBytes())).isEqualTo("abcdefg".getBytes());
192 assertThat(db
.get("key4".getBytes())).isEqualTo("xyz".getBytes());
194 batch
.deleteRange("key2".getBytes(), "key4".getBytes());
195 db
.write(wOpt
, batch
);
197 assertThat(db
.get("key1".getBytes())).isEqualTo("value".getBytes());
198 assertThat(db
.get("key2".getBytes())).isNull();
199 assertThat(db
.get("key3".getBytes())).isNull();
200 assertThat(db
.get("key4".getBytes())).isEqualTo("xyz".getBytes());
205 public void restorePoints() throws RocksDBException
{
206 try (final WriteBatch batch
= new WriteBatch()) {
208 batch
.put("k1".getBytes(), "v1".getBytes());
209 batch
.put("k2".getBytes(), "v2".getBytes());
211 batch
.setSavePoint();
213 batch
.put("k1".getBytes(), "123456789".getBytes());
214 batch
.delete("k2".getBytes());
216 batch
.rollbackToSavePoint();
218 try(final CapturingWriteBatchHandler handler
= new CapturingWriteBatchHandler()) {
219 batch
.iterate(handler
);
221 assertThat(handler
.getEvents().size()).isEqualTo(2);
222 assertThat(handler
.getEvents().get(0)).isEqualTo(new Event(PUT
, "k1".getBytes(), "v1".getBytes()));
223 assertThat(handler
.getEvents().get(1)).isEqualTo(new Event(PUT
, "k2".getBytes(), "v2".getBytes()));
228 @Test(expected
= RocksDBException
.class)
229 public void restorePoints_withoutSavePoints() throws RocksDBException
{
230 try (final WriteBatch batch
= new WriteBatch()) {
231 batch
.rollbackToSavePoint();
235 @Test(expected
= RocksDBException
.class)
236 public void restorePoints_withoutSavePoints_nested() throws RocksDBException
{
237 try (final WriteBatch batch
= new WriteBatch()) {
239 batch
.setSavePoint();
240 batch
.rollbackToSavePoint();
242 // without previous corresponding setSavePoint
243 batch
.rollbackToSavePoint();
248 public void popSavePoint() throws RocksDBException
{
249 try (final WriteBatch batch
= new WriteBatch()) {
251 batch
.put("k1".getBytes(), "v1".getBytes());
252 batch
.put("k2".getBytes(), "v2".getBytes());
254 batch
.setSavePoint();
256 batch
.put("k1".getBytes(), "123456789".getBytes());
257 batch
.delete("k2".getBytes());
259 batch
.setSavePoint();
261 batch
.popSavePoint();
263 batch
.rollbackToSavePoint();
265 try(final CapturingWriteBatchHandler handler
= new CapturingWriteBatchHandler()) {
266 batch
.iterate(handler
);
268 assertThat(handler
.getEvents().size()).isEqualTo(2);
269 assertThat(handler
.getEvents().get(0)).isEqualTo(new Event(PUT
, "k1".getBytes(), "v1".getBytes()));
270 assertThat(handler
.getEvents().get(1)).isEqualTo(new Event(PUT
, "k2".getBytes(), "v2".getBytes()));
275 @Test(expected
= RocksDBException
.class)
276 public void popSavePoint_withoutSavePoints() throws RocksDBException
{
277 try (final WriteBatch batch
= new WriteBatch()) {
278 batch
.popSavePoint();
282 @Test(expected
= RocksDBException
.class)
283 public void popSavePoint_withoutSavePoints_nested() throws RocksDBException
{
284 try (final WriteBatch batch
= new WriteBatch()) {
286 batch
.setSavePoint();
287 batch
.popSavePoint();
289 // without previous corresponding setSavePoint
290 batch
.popSavePoint();
295 public void maxBytes() throws RocksDBException
{
296 try (final WriteBatch batch
= new WriteBatch()) {
297 batch
.setMaxBytes(19);
299 batch
.put("k1".getBytes(), "v1".getBytes());
303 @Test(expected
= RocksDBException
.class)
304 public void maxBytes_over() throws RocksDBException
{
305 try (final WriteBatch batch
= new WriteBatch()) {
306 batch
.setMaxBytes(1);
308 batch
.put("k1".getBytes(), "v1".getBytes());
313 public void data() throws RocksDBException
{
314 try (final WriteBatch batch1
= new WriteBatch()) {
315 batch1
.delete("k0".getBytes());
316 batch1
.put("k1".getBytes(), "v1".getBytes());
317 batch1
.put("k2".getBytes(), "v2".getBytes());
318 batch1
.put("k3".getBytes(), "v3".getBytes());
319 batch1
.putLogData("log1".getBytes());
320 batch1
.merge("k2".getBytes(), "v22".getBytes());
321 batch1
.delete("k3".getBytes());
323 final byte[] serialized
= batch1
.data();
325 try(final WriteBatch batch2
= new WriteBatch(serialized
)) {
326 assertThat(batch2
.count()).isEqualTo(batch1
.count());
328 try(final CapturingWriteBatchHandler handler1
= new CapturingWriteBatchHandler()) {
329 batch1
.iterate(handler1
);
331 try (final CapturingWriteBatchHandler handler2
= new CapturingWriteBatchHandler()) {
332 batch2
.iterate(handler2
);
334 assertThat(handler1
.getEvents().equals(handler2
.getEvents())).isTrue();
342 public void dataSize() throws RocksDBException
{
343 try (final WriteBatch batch
= new WriteBatch()) {
344 batch
.put("k1".getBytes(), "v1".getBytes());
346 assertThat(batch
.getDataSize()).isEqualTo(19);
351 public void hasPut() throws RocksDBException
{
352 try (final WriteBatch batch
= new WriteBatch()) {
353 assertThat(batch
.hasPut()).isFalse();
355 batch
.put("k1".getBytes(), "v1".getBytes());
357 assertThat(batch
.hasPut()).isTrue();
362 public void hasDelete() throws RocksDBException
{
363 try (final WriteBatch batch
= new WriteBatch()) {
364 assertThat(batch
.hasDelete()).isFalse();
366 batch
.delete("k1".getBytes());
368 assertThat(batch
.hasDelete()).isTrue();
373 public void hasSingleDelete() throws RocksDBException
{
374 try (final WriteBatch batch
= new WriteBatch()) {
375 assertThat(batch
.hasSingleDelete()).isFalse();
377 batch
.singleDelete("k1".getBytes());
379 assertThat(batch
.hasSingleDelete()).isTrue();
384 public void hasDeleteRange() throws RocksDBException
{
385 try (final WriteBatch batch
= new WriteBatch()) {
386 assertThat(batch
.hasDeleteRange()).isFalse();
388 batch
.deleteRange("k1".getBytes(), "k2".getBytes());
390 assertThat(batch
.hasDeleteRange()).isTrue();
395 public void hasBeginPrepareRange() throws RocksDBException
{
396 try (final WriteBatch batch
= new WriteBatch()) {
397 assertThat(batch
.hasBeginPrepare()).isFalse();
402 public void hasEndPrepareRange() throws RocksDBException
{
403 try (final WriteBatch batch
= new WriteBatch()) {
404 assertThat(batch
.hasEndPrepare()).isFalse();
409 public void hasCommit() throws RocksDBException
{
410 try (final WriteBatch batch
= new WriteBatch()) {
411 assertThat(batch
.hasCommit()).isFalse();
416 public void hasRollback() throws RocksDBException
{
417 try (final WriteBatch batch
= new WriteBatch()) {
418 assertThat(batch
.hasRollback()).isFalse();
423 public void walTerminationPoint() throws RocksDBException
{
424 try (final WriteBatch batch
= new WriteBatch()) {
425 WriteBatch
.SavePoint walTerminationPoint
= batch
.getWalTerminationPoint();
426 assertThat(walTerminationPoint
.isCleared()).isTrue();
428 batch
.put("k1".getBytes(UTF_8
), "v1".getBytes(UTF_8
));
430 batch
.markWalTerminationPoint();
432 walTerminationPoint
= batch
.getWalTerminationPoint();
433 assertThat(walTerminationPoint
.getSize()).isEqualTo(19);
434 assertThat(walTerminationPoint
.getCount()).isEqualTo(1);
435 assertThat(walTerminationPoint
.getContentFlags()).isEqualTo(2);
440 public void getWriteBatch() {
441 try (final WriteBatch batch
= new WriteBatch()) {
442 assertThat(batch
.getWriteBatch()).isEqualTo(batch
);
446 static byte[] getContents(final WriteBatch wb
) {
447 return getContents(wb
.nativeHandle_
);
450 static String
getFromWriteBatch(final WriteBatch wb
, final String key
)
451 throws RocksDBException
{
452 final WriteBatchGetter getter
=
453 new WriteBatchGetter(key
.getBytes(UTF_8
));
455 if(getter
.getValue() != null) {
456 return new String(getter
.getValue(), UTF_8
);
462 private static native byte[] getContents(final long writeBatchHandle
);
466 * Package-private class which provides java api to access
467 * c++ WriteBatchInternal.
469 class WriteBatchTestInternalHelper
{
470 static void setSequence(final WriteBatch wb
, final long sn
) {
471 setSequence(wb
.nativeHandle_
, sn
);
474 static long sequence(final WriteBatch wb
) {
475 return sequence(wb
.nativeHandle_
);
478 static void append(final WriteBatch wb1
, final WriteBatch wb2
) {
479 append(wb1
.nativeHandle_
, wb2
.nativeHandle_
);
482 private static native void setSequence(final long writeBatchHandle
,
485 private static native long sequence(final long writeBatchHandle
);
487 private static native void append(final long writeBatchHandle1
,
488 final long writeBatchHandle2
);