Skip to content

Commit 98e5189

Browse files
author
anand76
committed
Fix MultiGet crash when no_block_cache is set (facebook#5991)
Summary: This PR fixes facebook#5975. In ```BlockBasedTable::RetrieveMultipleBlocks()```, we were calling ```MaybeReadBlocksAndLoadToCache()```, which is a no-op if neither uncompressed nor compressed block cache are configured. Pull Request resolved: facebook#5991 Test Plan: 1. Add unit tests that fail with the old code and pass with the new 2. make check and asan_check Cc spetrunia Differential Revision: D18272744 Pulled By: anand1976 fbshipit-source-id: e62fa6090d1a6adf84fcd51dfd6859b03c6aebfe
1 parent 3353b71 commit 98e5189

File tree

3 files changed

+61
-36
lines changed

3 files changed

+61
-36
lines changed

HISTORY.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# Rocksdb Change Log
2+
## Unreleased
3+
### Bug Fixes
4+
* Fix a assertion failure in MultiGe4t() when BlockBasedTableOptions::no_block_cache is true and there is no compressed block cache
5+
26
## 6.5.1 (10/16/2019)
37
### Bug Fixes
48
* Revert the feature "Merging iterator to avoid child iterator reseek for some cases (#5286)" since it might cause strange results when reseek happens with a different iterator upper bound.

db/db_basic_test.cc

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,8 +1566,12 @@ class DBBasicTestWithParallelIO
15661566
Options options = CurrentOptions();
15671567
Random rnd(301);
15681568
BlockBasedTableOptions table_options;
1569-
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
15701569
table_options.block_cache = uncompressed_cache_;
1570+
if (table_options.block_cache == nullptr) {
1571+
table_options.no_block_cache = true;
1572+
} else {
1573+
table_options.pin_l0_filter_and_index_blocks_in_cache = true;
1574+
}
15711575
table_options.block_cache_compressed = compressed_cache_;
15721576
table_options.flush_block_policy_factory.reset(
15731577
new MyFlushBlockPolicyFactory());
@@ -1609,6 +1613,9 @@ class DBBasicTestWithParallelIO
16091613
}
16101614

16111615
bool fill_cache() { return fill_cache_; }
1616+
bool compression_enabled() { return compression_enabled_; }
1617+
bool has_compressed_cache() { return compressed_cache_ != nullptr; }
1618+
bool has_uncompressed_cache() { return uncompressed_cache_ != nullptr; }
16121619

16131620
static void SetUpTestCase() {}
16141621
static void TearDownTestCase() {}
@@ -1793,7 +1800,16 @@ TEST_P(DBBasicTestWithParallelIO, MultiGet) {
17931800
ASSERT_TRUE(CheckValue(1, values[0].ToString()));
17941801
ASSERT_TRUE(CheckValue(51, values[1].ToString()));
17951802

1796-
int expected_reads = random_reads + (fill_cache() ? 0 : 2);
1803+
bool read_from_cache = false;
1804+
if (fill_cache()) {
1805+
if (has_uncompressed_cache()) {
1806+
read_from_cache = true;
1807+
} else if (has_compressed_cache() && compression_enabled()) {
1808+
read_from_cache = true;
1809+
}
1810+
}
1811+
1812+
int expected_reads = random_reads + (read_from_cache ? 0 : 2);
17971813
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
17981814

17991815
keys.resize(10);
@@ -1811,7 +1827,7 @@ TEST_P(DBBasicTestWithParallelIO, MultiGet) {
18111827
ASSERT_OK(statuses[i]);
18121828
ASSERT_TRUE(CheckValue(key_ints[i], values[i].ToString()));
18131829
}
1814-
expected_reads += (fill_cache() ? 2 : 4);
1830+
expected_reads += (read_from_cache ? 2 : 4);
18151831
ASSERT_EQ(env_->random_read_counter_.Read(), expected_reads);
18161832
}
18171833

@@ -1822,12 +1838,8 @@ INSTANTIATE_TEST_CASE_P(
18221838
// Param 1 - Uncompressed cache enabled
18231839
// Param 2 - Data compression enabled
18241840
// Param 3 - ReadOptions::fill_cache
1825-
::testing::Values(std::make_tuple(false, true, true, true),
1826-
std::make_tuple(true, true, true, true),
1827-
std::make_tuple(false, true, false, true),
1828-
std::make_tuple(false, true, true, false),
1829-
std::make_tuple(true, true, true, false),
1830-
std::make_tuple(false, true, false, false)));
1841+
::testing::Combine(::testing::Bool(), ::testing::Bool(),
1842+
::testing::Bool(), ::testing::Bool()));
18311843

18321844
class DBBasicTestWithTimestampWithParam
18331845
: public DBTestBase,

table/block_based/block_based_table_reader.cc

Lines changed: 36 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2368,37 +2368,46 @@ void BlockBasedTable::RetrieveMultipleBlocks(
23682368
// MaybeReadBlockAndLoadToCache will insert into the block caches if
23692369
// necessary. Since we're passing the raw block contents, it will
23702370
// avoid looking up the block cache
2371-
s = MaybeReadBlockAndLoadToCache(nullptr, options, handle,
2372-
uncompression_dict, block_entry, BlockType::kData,
2373-
mget_iter->get_context, &lookup_data_block_context,
2374-
&raw_block_contents);
2371+
s = MaybeReadBlockAndLoadToCache(
2372+
nullptr, options, handle, uncompression_dict, block_entry,
2373+
BlockType::kData, mget_iter->get_context,
2374+
&lookup_data_block_context, &raw_block_contents);
2375+
2376+
// block_entry value could be null if no block cache is present, i.e
2377+
// BlockBasedTableOptions::no_block_cache is true and no compressed
2378+
// block cache is configured. In that case, fall
2379+
// through and set up the block explicitly
2380+
if (block_entry->GetValue() != nullptr) {
2381+
continue;
2382+
}
2383+
}
2384+
2385+
CompressionType compression_type =
2386+
raw_block_contents.get_compression_type();
2387+
BlockContents contents;
2388+
if (compression_type != kNoCompression) {
2389+
UncompressionContext context(compression_type);
2390+
UncompressionInfo info(context, uncompression_dict, compression_type);
2391+
s = UncompressBlockContents(info, req.result.data(), handle.size(),
2392+
&contents, footer.version(),
2393+
rep_->ioptions, memory_allocator);
23752394
} else {
2376-
CompressionType compression_type =
2377-
raw_block_contents.get_compression_type();
2378-
BlockContents contents;
2379-
if (compression_type != kNoCompression) {
2380-
UncompressionContext context(compression_type);
2381-
UncompressionInfo info(context, uncompression_dict, compression_type);
2382-
s = UncompressBlockContents(info, req.result.data(), handle.size(),
2383-
&contents, footer.version(), rep_->ioptions,
2384-
memory_allocator);
2395+
if (scratch != nullptr) {
2396+
// If we used the scratch buffer, then the contents need to be
2397+
// copied to heap
2398+
Slice raw = Slice(req.result.data(), handle.size());
2399+
contents = BlockContents(
2400+
CopyBufferToHeap(GetMemoryAllocator(rep_->table_options), raw),
2401+
handle.size());
23852402
} else {
2386-
if (scratch != nullptr) {
2387-
// If we used the scratch buffer, then the contents need to be
2388-
// copied to heap
2389-
Slice raw = Slice(req.result.data(), handle.size());
2390-
contents = BlockContents(CopyBufferToHeap(
2391-
GetMemoryAllocator(rep_->table_options), raw),
2392-
handle.size());
2393-
} else {
2394-
contents = std::move(raw_block_contents);
2395-
}
2396-
}
2397-
if (s.ok()) {
2398-
(*results)[idx_in_batch].SetOwnedValue(new Block(std::move(contents),
2399-
global_seqno, read_amp_bytes_per_bit, ioptions.statistics));
2403+
contents = std::move(raw_block_contents);
24002404
}
24012405
}
2406+
if (s.ok()) {
2407+
(*results)[idx_in_batch].SetOwnedValue(
2408+
new Block(std::move(contents), global_seqno,
2409+
read_amp_bytes_per_bit, ioptions.statistics));
2410+
}
24022411
}
24032412
(*statuses)[idx_in_batch] = s;
24042413
}

0 commit comments

Comments
 (0)