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).
8 import static org
.assertj
.core
.api
.Assertions
.assertThat
;
9 import static org
.junit
.Assert
.fail
;
11 import java
.nio
.charset
.StandardCharsets
;
12 import java
.nio
.file
.Files
;
13 import java
.nio
.file
.Path
;
14 import java
.nio
.file
.Paths
;
15 import java
.util
.stream
.Stream
;
16 import org
.junit
.ClassRule
;
17 import org
.junit
.Ignore
;
18 import org
.junit
.Rule
;
19 import org
.junit
.Test
;
20 import org
.junit
.rules
.TemporaryFolder
;
22 public class BlockBasedTableConfigTest
{
25 public static final RocksNativeLibraryResource ROCKS_NATIVE_LIBRARY_RESOURCE
=
26 new RocksNativeLibraryResource();
28 @Rule public TemporaryFolder dbFolder
= new TemporaryFolder();
31 public void cacheIndexAndFilterBlocks() {
32 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
33 blockBasedTableConfig
.setCacheIndexAndFilterBlocks(true);
34 assertThat(blockBasedTableConfig
.cacheIndexAndFilterBlocks()).
39 public void cacheIndexAndFilterBlocksWithHighPriority() {
40 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
41 assertThat(blockBasedTableConfig
.cacheIndexAndFilterBlocksWithHighPriority()).
43 blockBasedTableConfig
.setCacheIndexAndFilterBlocksWithHighPriority(false);
44 assertThat(blockBasedTableConfig
.cacheIndexAndFilterBlocksWithHighPriority()).isFalse();
48 public void pinL0FilterAndIndexBlocksInCache() {
49 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
50 blockBasedTableConfig
.setPinL0FilterAndIndexBlocksInCache(true);
51 assertThat(blockBasedTableConfig
.pinL0FilterAndIndexBlocksInCache()).
56 public void pinTopLevelIndexAndFilter() {
57 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
58 blockBasedTableConfig
.setPinTopLevelIndexAndFilter(false);
59 assertThat(blockBasedTableConfig
.pinTopLevelIndexAndFilter()).
64 public void indexType() {
65 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
66 assertThat(IndexType
.values().length
).isEqualTo(4);
67 blockBasedTableConfig
.setIndexType(IndexType
.kHashSearch
);
68 assertThat(blockBasedTableConfig
.indexType()).isEqualTo(IndexType
.kHashSearch
);
69 assertThat(IndexType
.valueOf("kBinarySearch")).isNotNull();
70 blockBasedTableConfig
.setIndexType(IndexType
.valueOf("kBinarySearch"));
71 assertThat(blockBasedTableConfig
.indexType()).isEqualTo(IndexType
.kBinarySearch
);
75 public void dataBlockIndexType() {
76 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
77 blockBasedTableConfig
.setDataBlockIndexType(DataBlockIndexType
.kDataBlockBinaryAndHash
);
78 assertThat(blockBasedTableConfig
.dataBlockIndexType())
79 .isEqualTo(DataBlockIndexType
.kDataBlockBinaryAndHash
);
80 blockBasedTableConfig
.setDataBlockIndexType(DataBlockIndexType
.kDataBlockBinarySearch
);
81 assertThat(blockBasedTableConfig
.dataBlockIndexType())
82 .isEqualTo(DataBlockIndexType
.kDataBlockBinarySearch
);
86 public void checksumType() {
87 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
88 assertThat(ChecksumType
.values().length
).isEqualTo(5);
89 assertThat(ChecksumType
.valueOf("kxxHash")).
90 isEqualTo(ChecksumType
.kxxHash
);
91 blockBasedTableConfig
.setChecksumType(ChecksumType
.kNoChecksum
);
92 assertThat(blockBasedTableConfig
.checksumType()).isEqualTo(ChecksumType
.kNoChecksum
);
93 blockBasedTableConfig
.setChecksumType(ChecksumType
.kxxHash
);
94 assertThat(blockBasedTableConfig
.checksumType()).isEqualTo(ChecksumType
.kxxHash
);
95 blockBasedTableConfig
.setChecksumType(ChecksumType
.kxxHash64
);
96 assertThat(blockBasedTableConfig
.checksumType()).isEqualTo(ChecksumType
.kxxHash64
);
97 blockBasedTableConfig
.setChecksumType(ChecksumType
.kXXH3
);
98 assertThat(blockBasedTableConfig
.checksumType()).isEqualTo(ChecksumType
.kXXH3
);
102 public void jniPortal() throws Exception
{
103 // Verifies that the JNI layer is correctly translating options.
104 // Since introspecting the options requires creating a database, the checks
105 // cover multiple options at the same time.
107 final BlockBasedTableConfig tableConfig
= new BlockBasedTableConfig();
109 tableConfig
.setIndexType(IndexType
.kBinarySearch
);
110 tableConfig
.setDataBlockIndexType(DataBlockIndexType
.kDataBlockBinarySearch
);
111 tableConfig
.setChecksumType(ChecksumType
.kNoChecksum
);
112 try (final Options options
= new Options().setTableFormatConfig(tableConfig
)) {
113 String opts
= getOptionAsString(options
);
114 assertThat(opts
).contains("index_type=kBinarySearch");
115 assertThat(opts
).contains("data_block_index_type=kDataBlockBinarySearch");
116 assertThat(opts
).contains("checksum=kNoChecksum");
119 tableConfig
.setIndexType(IndexType
.kHashSearch
);
120 tableConfig
.setDataBlockIndexType(DataBlockIndexType
.kDataBlockBinaryAndHash
);
121 tableConfig
.setChecksumType(ChecksumType
.kCRC32c
);
122 try (final Options options
= new Options().setTableFormatConfig(tableConfig
)) {
123 options
.useCappedPrefixExtractor(1); // Needed to use kHashSearch
124 String opts
= getOptionAsString(options
);
125 assertThat(opts
).contains("index_type=kHashSearch");
126 assertThat(opts
).contains("data_block_index_type=kDataBlockBinaryAndHash");
127 assertThat(opts
).contains("checksum=kCRC32c");
130 tableConfig
.setIndexType(IndexType
.kTwoLevelIndexSearch
);
131 tableConfig
.setChecksumType(ChecksumType
.kxxHash
);
132 try (final Options options
= new Options().setTableFormatConfig(tableConfig
)) {
133 String opts
= getOptionAsString(options
);
134 assertThat(opts
).contains("index_type=kTwoLevelIndexSearch");
135 assertThat(opts
).contains("checksum=kxxHash");
138 tableConfig
.setIndexType(IndexType
.kBinarySearchWithFirstKey
);
139 tableConfig
.setChecksumType(ChecksumType
.kxxHash64
);
140 try (final Options options
= new Options().setTableFormatConfig(tableConfig
)) {
141 String opts
= getOptionAsString(options
);
142 assertThat(opts
).contains("index_type=kBinarySearchWithFirstKey");
143 assertThat(opts
).contains("checksum=kxxHash64");
146 tableConfig
.setChecksumType(ChecksumType
.kXXH3
);
147 try (final Options options
= new Options().setTableFormatConfig(tableConfig
)) {
148 String opts
= getOptionAsString(options
);
149 assertThat(opts
).contains("checksum=kXXH3");
153 private String
getOptionAsString(Options options
) throws Exception
{
154 options
.setCreateIfMissing(true);
155 String dbPath
= dbFolder
.getRoot().getAbsolutePath();
157 try (final RocksDB db
= RocksDB
.open(options
, dbPath
);
158 final Stream
<Path
> pathStream
= Files
.walk(Paths
.get(dbPath
))) {
161 .filter(p
-> p
.getFileName().toString().startsWith("OPTIONS"))
163 .orElseThrow(() -> new AssertionError("Missing options file"));
164 byte[] optionsData
= Files
.readAllBytes(optionsPath
);
165 result
= new String(optionsData
, StandardCharsets
.UTF_8
);
167 RocksDB
.destroyDB(dbPath
, options
);
172 public void noBlockCache() {
173 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
174 blockBasedTableConfig
.setNoBlockCache(true);
175 assertThat(blockBasedTableConfig
.noBlockCache()).isTrue();
179 public void blockCache() {
181 final Cache cache
= new LRUCache(17 * 1024 * 1024);
182 final Options options
= new Options().setTableFormatConfig(
183 new BlockBasedTableConfig().setBlockCache(cache
))) {
184 assertThat(options
.tableFactoryName()).isEqualTo("BlockBasedTable");
189 public void blockCacheIntegration() throws RocksDBException
{
190 try (final Cache cache
= new LRUCache(8 * 1024 * 1024);
191 final Statistics statistics
= new Statistics()) {
192 for (int shard
= 0; shard
< 8; shard
++) {
193 try (final Options options
=
195 .setCreateIfMissing(true)
196 .setStatistics(statistics
)
197 .setTableFormatConfig(new BlockBasedTableConfig().setBlockCache(cache
));
199 RocksDB
.open(options
, dbFolder
.getRoot().getAbsolutePath() + "/" + shard
)) {
200 final byte[] key
= "some-key".getBytes(StandardCharsets
.UTF_8
);
201 final byte[] value
= "some-value".getBytes(StandardCharsets
.UTF_8
);
204 db
.flush(new FlushOptions());
207 assertThat(statistics
.getTickerCount(TickerType
.BLOCK_CACHE_ADD
)).isEqualTo(shard
+ 1);
214 public void persistentCache() throws RocksDBException
{
215 try (final DBOptions dbOptions
= new DBOptions().
216 setInfoLogLevel(InfoLogLevel
.INFO_LEVEL
).
217 setCreateIfMissing(true);
218 final Logger logger
= new Logger(dbOptions
) {
220 protected void log(final InfoLogLevel infoLogLevel
, final String logMsg
) {
221 System
.out
.println(infoLogLevel
.name() + ": " + logMsg
);
224 try (final PersistentCache persistentCache
=
225 new PersistentCache(Env
.getDefault(), dbFolder
.getRoot().getPath(), 1024 * 1024 * 100, logger
, false);
226 final Options options
= new Options().setTableFormatConfig(
227 new BlockBasedTableConfig().setPersistentCache(persistentCache
))) {
228 assertThat(options
.tableFactoryName()).isEqualTo("BlockBasedTable");
234 public void blockCacheCompressed() {
235 try (final Cache cache
= new LRUCache(17 * 1024 * 1024);
236 final Options options
= new Options().setTableFormatConfig(
237 new BlockBasedTableConfig().setBlockCacheCompressed(cache
))) {
238 assertThat(options
.tableFactoryName()).isEqualTo("BlockBasedTable");
242 @Ignore("See issue: https://github.com/facebook/rocksdb/issues/4822")
244 public void blockCacheCompressedIntegration() throws RocksDBException
{
245 final byte[] key1
= "some-key1".getBytes(StandardCharsets
.UTF_8
);
246 final byte[] key2
= "some-key1".getBytes(StandardCharsets
.UTF_8
);
247 final byte[] key3
= "some-key1".getBytes(StandardCharsets
.UTF_8
);
248 final byte[] key4
= "some-key1".getBytes(StandardCharsets
.UTF_8
);
249 final byte[] value
= "some-value".getBytes(StandardCharsets
.UTF_8
);
251 try (final Cache compressedCache
= new LRUCache(8 * 1024 * 1024);
252 final Statistics statistics
= new Statistics()) {
254 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig()
255 .setNoBlockCache(true)
257 .setBlockCacheCompressed(compressedCache
)
258 .setFormatVersion(4);
260 try (final Options options
= new Options()
261 .setCreateIfMissing(true)
262 .setStatistics(statistics
)
263 .setTableFormatConfig(blockBasedTableConfig
)) {
265 for (int shard
= 0; shard
< 8; shard
++) {
266 try (final FlushOptions flushOptions
= new FlushOptions();
267 final WriteOptions writeOptions
= new WriteOptions();
268 final ReadOptions readOptions
= new ReadOptions();
270 RocksDB
.open(options
, dbFolder
.getRoot().getAbsolutePath() + "/" + shard
)) {
272 db
.put(writeOptions
, key1
, value
);
273 db
.put(writeOptions
, key2
, value
);
274 db
.put(writeOptions
, key3
, value
);
275 db
.put(writeOptions
, key4
, value
);
276 db
.flush(flushOptions
);
278 db
.get(readOptions
, key1
);
279 db
.get(readOptions
, key2
);
280 db
.get(readOptions
, key3
);
281 db
.get(readOptions
, key4
);
283 assertThat(statistics
.getTickerCount(TickerType
.BLOCK_CACHE_COMPRESSED_ADD
)).isEqualTo(shard
+ 1);
291 public void blockSize() {
292 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
293 blockBasedTableConfig
.setBlockSize(10);
294 assertThat(blockBasedTableConfig
.blockSize()).isEqualTo(10);
298 public void blockSizeDeviation() {
299 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
300 blockBasedTableConfig
.setBlockSizeDeviation(12);
301 assertThat(blockBasedTableConfig
.blockSizeDeviation()).
306 public void blockRestartInterval() {
307 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
308 blockBasedTableConfig
.setBlockRestartInterval(15);
309 assertThat(blockBasedTableConfig
.blockRestartInterval()).
314 public void indexBlockRestartInterval() {
315 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
316 blockBasedTableConfig
.setIndexBlockRestartInterval(15);
317 assertThat(blockBasedTableConfig
.indexBlockRestartInterval()).
322 public void metadataBlockSize() {
323 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
324 blockBasedTableConfig
.setMetadataBlockSize(1024);
325 assertThat(blockBasedTableConfig
.metadataBlockSize()).
330 public void partitionFilters() {
331 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
332 blockBasedTableConfig
.setPartitionFilters(true);
333 assertThat(blockBasedTableConfig
.partitionFilters()).
338 public void optimizeFiltersForMemory() {
339 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
340 blockBasedTableConfig
.setOptimizeFiltersForMemory(true);
341 assertThat(blockBasedTableConfig
.optimizeFiltersForMemory()).isTrue();
345 public void useDeltaEncoding() {
346 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
347 blockBasedTableConfig
.setUseDeltaEncoding(false);
348 assertThat(blockBasedTableConfig
.useDeltaEncoding()).
353 public void blockBasedTableWithFilterPolicy() {
354 try(final Options options
= new Options()
355 .setTableFormatConfig(new BlockBasedTableConfig()
356 .setFilterPolicy(new BloomFilter(10)))) {
357 assertThat(options
.tableFactoryName()).
358 isEqualTo("BlockBasedTable");
363 public void blockBasedTableWithoutFilterPolicy() {
364 try(final Options options
= new Options().setTableFormatConfig(
365 new BlockBasedTableConfig().setFilterPolicy(null))) {
366 assertThat(options
.tableFactoryName()).
367 isEqualTo("BlockBasedTable");
372 public void wholeKeyFiltering() {
373 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
374 blockBasedTableConfig
.setWholeKeyFiltering(false);
375 assertThat(blockBasedTableConfig
.wholeKeyFiltering()).
380 public void verifyCompression() {
381 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
382 assertThat(blockBasedTableConfig
.verifyCompression()).isFalse();
383 blockBasedTableConfig
.setVerifyCompression(true);
384 assertThat(blockBasedTableConfig
.verifyCompression()).
389 public void readAmpBytesPerBit() {
390 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
391 blockBasedTableConfig
.setReadAmpBytesPerBit(2);
392 assertThat(blockBasedTableConfig
.readAmpBytesPerBit()).
397 public void formatVersion() {
398 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
399 for (int version
= 0; version
<= 5; version
++) {
400 blockBasedTableConfig
.setFormatVersion(version
);
401 assertThat(blockBasedTableConfig
.formatVersion()).isEqualTo(version
);
405 @Test(expected
= AssertionError
.class)
406 public void formatVersionFailNegative() {
407 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
408 blockBasedTableConfig
.setFormatVersion(-1);
411 @Test(expected
= RocksDBException
.class)
412 public void invalidFormatVersion() throws RocksDBException
{
413 final BlockBasedTableConfig blockBasedTableConfig
=
414 new BlockBasedTableConfig().setFormatVersion(99999);
416 try (final Options options
= new Options().setTableFormatConfig(blockBasedTableConfig
);
417 final RocksDB db
= RocksDB
.open(options
, dbFolder
.getRoot().getAbsolutePath())) {
418 fail("Opening the database with an invalid format_version should have raised an exception");
423 public void enableIndexCompression() {
424 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
425 blockBasedTableConfig
.setEnableIndexCompression(false);
426 assertThat(blockBasedTableConfig
.enableIndexCompression()).
431 public void blockAlign() {
432 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
433 blockBasedTableConfig
.setBlockAlign(true);
434 assertThat(blockBasedTableConfig
.blockAlign()).
439 public void indexShortening() {
440 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
441 blockBasedTableConfig
.setIndexShortening(IndexShorteningMode
.kShortenSeparatorsAndSuccessor
);
442 assertThat(blockBasedTableConfig
.indexShortening())
443 .isEqualTo(IndexShorteningMode
.kShortenSeparatorsAndSuccessor
);
448 public void hashIndexAllowCollision() {
449 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
450 blockBasedTableConfig
.setHashIndexAllowCollision(false);
451 assertThat(blockBasedTableConfig
.hashIndexAllowCollision()).
452 isTrue(); // NOTE: setHashIndexAllowCollision should do nothing!
457 public void blockCacheSize() {
458 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
459 blockBasedTableConfig
.setBlockCacheSize(8 * 1024);
460 assertThat(blockBasedTableConfig
.blockCacheSize()).
466 public void blockCacheNumShardBits() {
467 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
468 blockBasedTableConfig
.setCacheNumShardBits(5);
469 assertThat(blockBasedTableConfig
.cacheNumShardBits()).
475 public void blockCacheCompressedSize() {
476 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
477 blockBasedTableConfig
.setBlockCacheCompressedSize(40);
478 assertThat(blockBasedTableConfig
.blockCacheCompressedSize()).
484 public void blockCacheCompressedNumShardBits() {
485 final BlockBasedTableConfig blockBasedTableConfig
= new BlockBasedTableConfig();
486 blockBasedTableConfig
.setBlockCacheCompressedNumShardBits(4);
487 assertThat(blockBasedTableConfig
.blockCacheCompressedNumShardBits()).