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 pauseContinueBackgroundWork()1088 public void pauseContinueBackgroundWork() throws RocksDBException { 1089 try (final Options options = new Options().setCreateIfMissing(true); 1090 final RocksDB db = RocksDB.open(options, 1091 dbFolder.getRoot().getAbsolutePath()) 1092 ) { 1093 db.pauseBackgroundWork(); 1094 db.continueBackgroundWork(); 1095 db.pauseBackgroundWork(); 1096 db.continueBackgroundWork(); 1097 } 1098 } 1099 1100 @Test enableDisableFileDeletions()1101 public void enableDisableFileDeletions() throws RocksDBException { 1102 try (final Options options = new Options().setCreateIfMissing(true); 1103 final RocksDB db = RocksDB.open(options, 1104 dbFolder.getRoot().getAbsolutePath()) 1105 ) { 1106 db.disableFileDeletions(); 1107 db.enableFileDeletions(false); 1108 db.disableFileDeletions(); 1109 db.enableFileDeletions(true); 1110 } 1111 } 1112 1113 @Test setOptions()1114 public void setOptions() throws RocksDBException { 1115 try (final DBOptions options = new DBOptions() 1116 .setCreateIfMissing(true) 1117 .setCreateMissingColumnFamilies(true); 1118 final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions() 1119 .setWriteBufferSize(4096)) { 1120 1121 final List<ColumnFamilyDescriptor> columnFamilyDescriptors = 1122 Arrays.asList( 1123 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY), 1124 new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)); 1125 1126 // open database 1127 final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>(); 1128 try (final RocksDB db = RocksDB.open(options, 1129 dbFolder.getRoot().getAbsolutePath(), columnFamilyDescriptors, columnFamilyHandles)) { 1130 try { 1131 final MutableColumnFamilyOptions mutableOptions = 1132 MutableColumnFamilyOptions.builder() 1133 .setWriteBufferSize(2048) 1134 .build(); 1135 1136 db.setOptions(columnFamilyHandles.get(1), mutableOptions); 1137 1138 } finally { 1139 for (final ColumnFamilyHandle handle : columnFamilyHandles) { 1140 handle.close(); 1141 } 1142 } 1143 } 1144 } 1145 } 1146 1147 @Test destroyDB()1148 public void destroyDB() throws RocksDBException { 1149 try (final Options options = new Options().setCreateIfMissing(true)) { 1150 String dbPath = dbFolder.getRoot().getAbsolutePath(); 1151 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1152 db.put("key1".getBytes(), "value".getBytes()); 1153 } 1154 assertThat(dbFolder.getRoot().exists() && dbFolder.getRoot().listFiles().length != 0) 1155 .isTrue(); 1156 RocksDB.destroyDB(dbPath, options); 1157 assertThat(dbFolder.getRoot().exists() && dbFolder.getRoot().listFiles().length != 0) 1158 .isFalse(); 1159 } 1160 } 1161 1162 @Test(expected = RocksDBException.class) destroyDBFailIfOpen()1163 public void destroyDBFailIfOpen() throws RocksDBException { 1164 try (final Options options = new Options().setCreateIfMissing(true)) { 1165 String dbPath = dbFolder.getRoot().getAbsolutePath(); 1166 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1167 // Fails as the db is open and locked. 1168 RocksDB.destroyDB(dbPath, options); 1169 } 1170 } 1171 } 1172 1173 @Ignore("This test crashes. Re-enable after fixing.") 1174 @Test getApproximateSizes()1175 public void getApproximateSizes() throws RocksDBException { 1176 final byte key1[] = "key1".getBytes(UTF_8); 1177 final byte key2[] = "key2".getBytes(UTF_8); 1178 final byte key3[] = "key3".getBytes(UTF_8); 1179 try (final Options options = new Options().setCreateIfMissing(true)) { 1180 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1181 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1182 db.put(key1, key1); 1183 db.put(key2, key2); 1184 db.put(key3, key3); 1185 1186 final long[] sizes = db.getApproximateSizes( 1187 Arrays.asList( 1188 new Range(new Slice(key1), new Slice(key2)), 1189 new Range(new Slice(key2), new Slice(key3)) 1190 ), 1191 SizeApproximationFlag.INCLUDE_FILES, 1192 SizeApproximationFlag.INCLUDE_MEMTABLES); 1193 1194 assertThat(sizes.length).isEqualTo(2); 1195 assertThat(sizes[0]).isEqualTo(0); 1196 assertThat(sizes[1]).isGreaterThanOrEqualTo(1); 1197 } 1198 } 1199 } 1200 1201 @Test getApproximateMemTableStats()1202 public void getApproximateMemTableStats() throws RocksDBException { 1203 final byte key1[] = "key1".getBytes(UTF_8); 1204 final byte key2[] = "key2".getBytes(UTF_8); 1205 final byte key3[] = "key3".getBytes(UTF_8); 1206 try (final Options options = new Options().setCreateIfMissing(true)) { 1207 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1208 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1209 db.put(key1, key1); 1210 db.put(key2, key2); 1211 db.put(key3, key3); 1212 1213 final RocksDB.CountAndSize stats = 1214 db.getApproximateMemTableStats( 1215 new Range(new Slice(key1), new Slice(key3))); 1216 1217 assertThat(stats).isNotNull(); 1218 assertThat(stats.count).isGreaterThan(1); 1219 assertThat(stats.size).isGreaterThan(1); 1220 } 1221 } 1222 } 1223 1224 @Ignore("TODO(AR) re-enable when ready!") 1225 @Test compactFiles()1226 public void compactFiles() throws RocksDBException { 1227 final int kTestKeySize = 16; 1228 final int kTestValueSize = 984; 1229 final int kEntrySize = kTestKeySize + kTestValueSize; 1230 final int kEntriesPerBuffer = 100; 1231 final int writeBufferSize = kEntrySize * kEntriesPerBuffer; 1232 final byte[] cfName = "pikachu".getBytes(UTF_8); 1233 1234 try (final Options options = new Options() 1235 .setCreateIfMissing(true) 1236 .setWriteBufferSize(writeBufferSize) 1237 .setCompactionStyle(CompactionStyle.LEVEL) 1238 .setTargetFileSizeBase(writeBufferSize) 1239 .setMaxBytesForLevelBase(writeBufferSize * 2) 1240 .setLevel0StopWritesTrigger(2) 1241 .setMaxBytesForLevelMultiplier(2) 1242 .setCompressionType(CompressionType.NO_COMPRESSION) 1243 .setMaxSubcompactions(4)) { 1244 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1245 try (final RocksDB db = RocksDB.open(options, dbPath); 1246 final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions(options)) { 1247 db.createColumnFamily(new ColumnFamilyDescriptor(cfName, 1248 cfOptions)).close(); 1249 } 1250 1251 try (final ColumnFamilyOptions cfOptions = new ColumnFamilyOptions(options)) { 1252 final List<ColumnFamilyDescriptor> cfDescriptors = Arrays.asList( 1253 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY, cfOptions), 1254 new ColumnFamilyDescriptor(cfName, cfOptions) 1255 ); 1256 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1257 try (final DBOptions dbOptions = new DBOptions(options); 1258 final RocksDB db = RocksDB.open(dbOptions, dbPath, cfDescriptors, 1259 cfHandles); 1260 ) { 1261 try (final FlushOptions flushOptions = new FlushOptions() 1262 .setWaitForFlush(true) 1263 .setAllowWriteStall(true); 1264 final CompactionOptions compactionOptions = new CompactionOptions()) { 1265 final Random rnd = new Random(301); 1266 for (int key = 64 * kEntriesPerBuffer; key >= 0; --key) { 1267 final byte[] value = new byte[kTestValueSize]; 1268 rnd.nextBytes(value); 1269 db.put(cfHandles.get(1), Integer.toString(key).getBytes(UTF_8), 1270 value); 1271 } 1272 db.flush(flushOptions, cfHandles); 1273 1274 final RocksDB.LiveFiles liveFiles = db.getLiveFiles(); 1275 final List<String> compactedFiles = 1276 db.compactFiles(compactionOptions, cfHandles.get(1), 1277 liveFiles.files, 1, -1, null); 1278 assertThat(compactedFiles).isNotEmpty(); 1279 } finally { 1280 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1281 cfHandle.close(); 1282 } 1283 } 1284 } 1285 } 1286 } 1287 } 1288 1289 @Test enableAutoCompaction()1290 public void enableAutoCompaction() throws RocksDBException { 1291 try (final DBOptions options = new DBOptions() 1292 .setCreateIfMissing(true)) { 1293 final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList( 1294 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY) 1295 ); 1296 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1297 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1298 try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) { 1299 try { 1300 db.enableAutoCompaction(cfHandles); 1301 } finally { 1302 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1303 cfHandle.close(); 1304 } 1305 } 1306 } 1307 } 1308 } 1309 1310 @Test numberLevels()1311 public void numberLevels() throws RocksDBException { 1312 try (final Options options = new Options().setCreateIfMissing(true)) { 1313 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1314 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1315 assertThat(db.numberLevels()).isEqualTo(7); 1316 } 1317 } 1318 } 1319 1320 @Test maxMemCompactionLevel()1321 public void maxMemCompactionLevel() throws RocksDBException { 1322 try (final Options options = new Options().setCreateIfMissing(true)) { 1323 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1324 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1325 assertThat(db.maxMemCompactionLevel()).isEqualTo(0); 1326 } 1327 } 1328 } 1329 1330 @Test level0StopWriteTrigger()1331 public void level0StopWriteTrigger() throws RocksDBException { 1332 try (final Options options = new Options().setCreateIfMissing(true)) { 1333 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1334 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1335 assertThat(db.level0StopWriteTrigger()).isEqualTo(36); 1336 } 1337 } 1338 } 1339 1340 @Test getName()1341 public void getName() throws RocksDBException { 1342 try (final Options options = new Options().setCreateIfMissing(true)) { 1343 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1344 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1345 assertThat(db.getName()).isEqualTo(dbPath); 1346 } 1347 } 1348 } 1349 1350 @Test getEnv()1351 public void getEnv() throws RocksDBException { 1352 try (final Options options = new Options().setCreateIfMissing(true)) { 1353 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1354 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1355 assertThat(db.getEnv()).isEqualTo(Env.getDefault()); 1356 } 1357 } 1358 } 1359 1360 @Test flush()1361 public void flush() throws RocksDBException { 1362 try (final Options options = new Options().setCreateIfMissing(true)) { 1363 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1364 try (final RocksDB db = RocksDB.open(options, dbPath); 1365 final FlushOptions flushOptions = new FlushOptions()) { 1366 db.flush(flushOptions); 1367 } 1368 } 1369 } 1370 1371 @Test flushWal()1372 public void flushWal() throws RocksDBException { 1373 try (final Options options = new Options().setCreateIfMissing(true)) { 1374 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1375 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1376 db.flushWal(true); 1377 } 1378 } 1379 } 1380 1381 @Test syncWal()1382 public void syncWal() throws RocksDBException { 1383 try (final Options options = new Options().setCreateIfMissing(true)) { 1384 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1385 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1386 db.syncWal(); 1387 } 1388 } 1389 } 1390 1391 @Test setPreserveDeletesSequenceNumber()1392 public void setPreserveDeletesSequenceNumber() throws RocksDBException { 1393 try (final Options options = new Options().setCreateIfMissing(true)) { 1394 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1395 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1396 assertThat(db.setPreserveDeletesSequenceNumber(db.getLatestSequenceNumber())) 1397 .isFalse(); 1398 } 1399 } 1400 } 1401 1402 @Test getLiveFiles()1403 public void getLiveFiles() throws RocksDBException { 1404 try (final Options options = new Options().setCreateIfMissing(true)) { 1405 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1406 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1407 final RocksDB.LiveFiles livefiles = db.getLiveFiles(true); 1408 assertThat(livefiles).isNotNull(); 1409 assertThat(livefiles.manifestFileSize).isEqualTo(13); 1410 assertThat(livefiles.files.size()).isEqualTo(3); 1411 assertThat(livefiles.files.get(0)).isEqualTo("/CURRENT"); 1412 assertThat(livefiles.files.get(1)).isEqualTo("/MANIFEST-000001"); 1413 assertThat(livefiles.files.get(2)).isEqualTo("/OPTIONS-000005"); 1414 } 1415 } 1416 } 1417 1418 @Test getSortedWalFiles()1419 public void getSortedWalFiles() throws RocksDBException { 1420 try (final Options options = new Options().setCreateIfMissing(true)) { 1421 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1422 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1423 db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1424 final List<LogFile> logFiles = db.getSortedWalFiles(); 1425 assertThat(logFiles).isNotNull(); 1426 assertThat(logFiles.size()).isEqualTo(1); 1427 assertThat(logFiles.get(0).type()) 1428 .isEqualTo(WalFileType.kAliveLogFile); 1429 } 1430 } 1431 } 1432 1433 @Test deleteFile()1434 public void deleteFile() throws RocksDBException { 1435 try (final Options options = new Options().setCreateIfMissing(true)) { 1436 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1437 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1438 db.deleteFile("unknown"); 1439 } 1440 } 1441 } 1442 1443 @Test getLiveFilesMetaData()1444 public void getLiveFilesMetaData() throws RocksDBException { 1445 try (final Options options = new Options().setCreateIfMissing(true)) { 1446 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1447 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1448 db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1449 final List<LiveFileMetaData> liveFilesMetaData 1450 = db.getLiveFilesMetaData(); 1451 assertThat(liveFilesMetaData).isEmpty(); 1452 } 1453 } 1454 } 1455 1456 @Test getColumnFamilyMetaData()1457 public void getColumnFamilyMetaData() throws RocksDBException { 1458 try (final DBOptions options = new DBOptions() 1459 .setCreateIfMissing(true)) { 1460 final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList( 1461 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY) 1462 ); 1463 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1464 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1465 try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) { 1466 db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1467 try { 1468 final ColumnFamilyMetaData cfMetadata = 1469 db.getColumnFamilyMetaData(cfHandles.get(0)); 1470 assertThat(cfMetadata).isNotNull(); 1471 assertThat(cfMetadata.name()).isEqualTo(RocksDB.DEFAULT_COLUMN_FAMILY); 1472 assertThat(cfMetadata.levels().size()).isEqualTo(7); 1473 } finally { 1474 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1475 cfHandle.close(); 1476 } 1477 } 1478 } 1479 } 1480 } 1481 1482 @Test verifyChecksum()1483 public void verifyChecksum() throws RocksDBException { 1484 try (final Options options = new Options().setCreateIfMissing(true)) { 1485 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1486 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1487 db.verifyChecksum(); 1488 } 1489 } 1490 } 1491 1492 @Test getPropertiesOfAllTables()1493 public void getPropertiesOfAllTables() throws RocksDBException { 1494 try (final DBOptions options = new DBOptions() 1495 .setCreateIfMissing(true)) { 1496 final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList( 1497 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY) 1498 ); 1499 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1500 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1501 try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) { 1502 db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1503 try { 1504 final Map<String, TableProperties> properties = 1505 db.getPropertiesOfAllTables(cfHandles.get(0)); 1506 assertThat(properties).isNotNull(); 1507 } finally { 1508 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1509 cfHandle.close(); 1510 } 1511 } 1512 } 1513 } 1514 } 1515 1516 @Test getPropertiesOfTablesInRange()1517 public void getPropertiesOfTablesInRange() throws RocksDBException { 1518 try (final DBOptions options = new DBOptions() 1519 .setCreateIfMissing(true)) { 1520 final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList( 1521 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY) 1522 ); 1523 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1524 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1525 try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) { 1526 db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1527 db.put(cfHandles.get(0), "key2".getBytes(UTF_8), "value2".getBytes(UTF_8)); 1528 db.put(cfHandles.get(0), "key3".getBytes(UTF_8), "value3".getBytes(UTF_8)); 1529 try { 1530 final Range range = new Range( 1531 new Slice("key1".getBytes(UTF_8)), 1532 new Slice("key3".getBytes(UTF_8))); 1533 final Map<String, TableProperties> properties = 1534 db.getPropertiesOfTablesInRange( 1535 cfHandles.get(0), Arrays.asList(range)); 1536 assertThat(properties).isNotNull(); 1537 } finally { 1538 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1539 cfHandle.close(); 1540 } 1541 } 1542 } 1543 } 1544 } 1545 1546 @Test suggestCompactRange()1547 public void suggestCompactRange() throws RocksDBException { 1548 try (final DBOptions options = new DBOptions() 1549 .setCreateIfMissing(true)) { 1550 final List<ColumnFamilyDescriptor> cfDescs = Arrays.asList( 1551 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY) 1552 ); 1553 final List<ColumnFamilyHandle> cfHandles = new ArrayList<>(); 1554 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1555 try (final RocksDB db = RocksDB.open(options, dbPath, cfDescs, cfHandles)) { 1556 db.put(cfHandles.get(0), "key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1557 db.put(cfHandles.get(0), "key2".getBytes(UTF_8), "value2".getBytes(UTF_8)); 1558 db.put(cfHandles.get(0), "key3".getBytes(UTF_8), "value3".getBytes(UTF_8)); 1559 try { 1560 final Range range = db.suggestCompactRange(cfHandles.get(0)); 1561 assertThat(range).isNotNull(); 1562 } finally { 1563 for (final ColumnFamilyHandle cfHandle : cfHandles) { 1564 cfHandle.close(); 1565 } 1566 } 1567 } 1568 } 1569 } 1570 1571 @Test promoteL0()1572 public void promoteL0() throws RocksDBException { 1573 try (final Options options = new Options().setCreateIfMissing(true)) { 1574 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1575 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1576 db.promoteL0(2); 1577 } 1578 } 1579 } 1580 1581 @Test startTrace()1582 public void startTrace() throws RocksDBException { 1583 try (final Options options = new Options().setCreateIfMissing(true)) { 1584 final String dbPath = dbFolder.getRoot().getAbsolutePath(); 1585 try (final RocksDB db = RocksDB.open(options, dbPath)) { 1586 final TraceOptions traceOptions = new TraceOptions(); 1587 1588 try (final InMemoryTraceWriter traceWriter = new InMemoryTraceWriter()) { 1589 db.startTrace(traceOptions, traceWriter); 1590 1591 db.put("key1".getBytes(UTF_8), "value1".getBytes(UTF_8)); 1592 1593 db.endTrace(); 1594 1595 final List<byte[]> writes = traceWriter.getWrites(); 1596 assertThat(writes.size()).isGreaterThan(0); 1597 } 1598 } 1599 } 1600 } 1601 1602 @Test setDBOptions()1603 public void setDBOptions() throws RocksDBException { 1604 try (final DBOptions options = new DBOptions() 1605 .setCreateIfMissing(true) 1606 .setCreateMissingColumnFamilies(true); 1607 final ColumnFamilyOptions new_cf_opts = new ColumnFamilyOptions() 1608 .setWriteBufferSize(4096)) { 1609 1610 final List<ColumnFamilyDescriptor> columnFamilyDescriptors = 1611 Arrays.asList( 1612 new ColumnFamilyDescriptor(RocksDB.DEFAULT_COLUMN_FAMILY), 1613 new ColumnFamilyDescriptor("new_cf".getBytes(), new_cf_opts)); 1614 1615 // open database 1616 final List<ColumnFamilyHandle> columnFamilyHandles = new ArrayList<>(); 1617 try (final RocksDB db = RocksDB.open(options, 1618 dbFolder.getRoot().getAbsolutePath(), columnFamilyDescriptors, columnFamilyHandles)) { 1619 try { 1620 final MutableDBOptions mutableOptions = 1621 MutableDBOptions.builder() 1622 .setBytesPerSync(1024 * 1027 * 7) 1623 .setAvoidFlushDuringShutdown(false) 1624 .build(); 1625 1626 db.setDBOptions(mutableOptions); 1627 } finally { 1628 for (final ColumnFamilyHandle handle : columnFamilyHandles) { 1629 handle.close(); 1630 } 1631 } 1632 } 1633 } 1634 } 1635 1636 private static class InMemoryTraceWriter extends AbstractTraceWriter { 1637 private final List<byte[]> writes = new ArrayList<>(); 1638 private volatile boolean closed = false; 1639 1640 @Override write(final Slice slice)1641 public void write(final Slice slice) { 1642 if (closed) { 1643 return; 1644 } 1645 final byte[] data = slice.data(); 1646 final byte[] dataCopy = new byte[data.length]; 1647 System.arraycopy(data, 0, dataCopy, 0, data.length); 1648 writes.add(dataCopy); 1649 } 1650 1651 @Override closeWriter()1652 public void closeWriter() { 1653 closed = true; 1654 } 1655 1656 @Override getFileSize()1657 public long getFileSize() { 1658 long size = 0; 1659 for (int i = 0; i < writes.size(); i++) { 1660 size += writes.get(i).length; 1661 } 1662 return size; 1663 } 1664 getWrites()1665 public List<byte[]> getWrites() { 1666 return writes; 1667 } 1668 } 1669 } 1670