Should only decode restart points for uncompressed blocks (#3996)

Summary:
The Block object assumes contents are uncompressed. Block's constructor tries to read the number of restarts, but does not get an accurate number when its contents are compressed, which is causing issues like https://github.com/facebook/rocksdb/issues/3843.
This PR address this issue by skipping reconstruction of restart points when blocks are known to be compressed. Somehow the restart points can be read directly when Snappy is used and some tests (for example https://github.com/facebook/rocksdb/blob/master/db/db_block_cache_test.cc#L196) expects blocks to be fully constructed even when Snappy compression is used, so here we keep the restart point logic for Snappy.
Closes https://github.com/facebook/rocksdb/pull/3996

Differential Revision: D8416186

Pulled By: miasantreble

fbshipit-source-id: 002c0b62b9e5d89fb7736563d354ce0023c8cb28
This commit is contained in:
Zhongyi Xie 2018-06-15 19:24:21 -07:00 committed by Facebook Github Bot
parent c48764ba47
commit 80bc35927c
11 changed files with 72 additions and 31 deletions

View file

@ -333,21 +333,23 @@ class TestPlainTableFactory : public PlainTableFactory {
TableProperties* props = nullptr; TableProperties* props = nullptr;
auto s = auto s =
ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber, ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber,
table_reader_options.ioptions, &props); table_reader_options.ioptions, &props,
true /* compression_type_missing */);
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
if (store_index_in_file_) { if (store_index_in_file_) {
BlockHandle bloom_block_handle; BlockHandle bloom_block_handle;
s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber, s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
table_reader_options.ioptions, table_reader_options.ioptions,
BloomBlockBuilder::kBloomBlock, &bloom_block_handle); BloomBlockBuilder::kBloomBlock, &bloom_block_handle,
/* compression_type_missing */ true);
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
BlockHandle index_block_handle; BlockHandle index_block_handle;
s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber, s = FindMetaBlock(file.get(), file_size, kPlainTableMagicNumber,
table_reader_options.ioptions, table_reader_options.ioptions,
PlainTableIndexBuilder::kPlainTableIndexBlock, PlainTableIndexBuilder::kPlainTableIndexBlock,
&index_block_handle); &index_block_handle, /* compression_type_missing */ true);
EXPECT_TRUE(s.ok()); EXPECT_TRUE(s.ok());
} }

View file

@ -279,7 +279,8 @@ void TestCustomizedTablePropertiesCollector(
new test::StringSource(fwf->contents()))); new test::StringSource(fwf->contents())));
TableProperties* props; TableProperties* props;
Status s = ReadTableProperties(fake_file_reader.get(), fwf->contents().size(), Status s = ReadTableProperties(fake_file_reader.get(), fwf->contents().size(),
magic_number, ioptions, &props); magic_number, ioptions, &props,
true /* compression_type_missing */);
std::unique_ptr<TableProperties> props_guard(props); std::unique_ptr<TableProperties> props_guard(props);
ASSERT_OK(s); ASSERT_OK(s);
@ -421,7 +422,7 @@ void TestInternalKeyPropertiesCollector(
TableProperties* props; TableProperties* props;
Status s = Status s =
ReadTableProperties(reader.get(), fwf->contents().size(), magic_number, ReadTableProperties(reader.get(), fwf->contents().size(), magic_number,
ioptions, &props); ioptions, &props, true /* compression_type_missing */);
ASSERT_OK(s); ASSERT_OK(s);
std::unique_ptr<TableProperties> props_guard(props); std::unique_ptr<TableProperties> props_guard(props);

View file

@ -761,7 +761,8 @@ Status Version::GetTableProperties(std::shared_ptr<const TableProperties>* tp,
new RandomAccessFileReader(std::move(file), file_name)); new RandomAccessFileReader(std::move(file), file_name));
s = ReadTableProperties( s = ReadTableProperties(
file_reader.get(), file_meta->fd.GetFileSize(), file_reader.get(), file_meta->fd.GetFileSize(),
Footer::kInvalidTableMagicNumber /* table's magic number */, *ioptions, &raw_table_properties); Footer::kInvalidTableMagicNumber /* table's magic number */, *ioptions,
&raw_table_properties, false /* compression_type_missing */);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }

View file

@ -427,13 +427,16 @@ Block::Block(BlockContents&& contents, SequenceNumber _global_seqno,
if (size_ < sizeof(uint32_t)) { if (size_ < sizeof(uint32_t)) {
size_ = 0; // Error marker size_ = 0; // Error marker
} else { } else {
num_restarts_ = NumRestarts(); // Should only decode restart points for uncompressed blocks
restart_offset_ = if (compression_type() == kNoCompression) {
static_cast<uint32_t>(size_) - (1 + num_restarts_) * sizeof(uint32_t); num_restarts_ = NumRestarts();
if (restart_offset_ > size_ - sizeof(uint32_t)) { restart_offset_ =
// The size is too small for NumRestarts() and therefore static_cast<uint32_t>(size_) - (1 + num_restarts_) * sizeof(uint32_t);
// restart_offset_ wrapped around. if (restart_offset_ > size_ - sizeof(uint32_t)) {
size_ = 0; // The size is too small for NumRestarts() and therefore
// restart_offset_ wrapped around.
size_ = 0;
}
} }
} }
if (read_amp_bytes_per_bit != 0 && statistics && size_ != 0) { if (read_amp_bytes_per_bit != 0 && statistics && size_ != 0) {

View file

@ -806,7 +806,7 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
if (s.ok()) { if (s.ok()) {
s = ReadProperties(meta_iter->value(), rep->file.get(), s = ReadProperties(meta_iter->value(), rep->file.get(),
prefetch_buffer.get(), rep->footer, rep->ioptions, prefetch_buffer.get(), rep->footer, rep->ioptions,
&table_properties); &table_properties, false /* compression_type_missing */);
} }
if (!s.ok()) { if (!s.ok()) {

View file

@ -60,7 +60,7 @@ class CuckooBuilderTest : public testing::Test {
new RandomAccessFileReader(std::move(read_file), fname)); new RandomAccessFileReader(std::move(read_file), fname));
ASSERT_OK(ReadTableProperties(file_reader.get(), read_file_size, ASSERT_OK(ReadTableProperties(file_reader.get(), read_file_size,
kCuckooTableMagicNumber, ioptions, kCuckooTableMagicNumber, ioptions,
&props)); &props, true /* compression_type_missing */));
// Check unused bucket. // Check unused bucket.
std::string unused_key = props->user_collected_properties[ std::string unused_key = props->user_collected_properties[
CuckooTablePropertyNames::kEmptyKey]; CuckooTablePropertyNames::kEmptyKey];

View file

@ -57,7 +57,7 @@ CuckooTableReader::CuckooTableReader(
} }
TableProperties* props = nullptr; TableProperties* props = nullptr;
status_ = ReadTableProperties(file_.get(), file_size, kCuckooTableMagicNumber, status_ = ReadTableProperties(file_.get(), file_size, kCuckooTableMagicNumber,
ioptions, &props); ioptions, &props, true /* compression_type_missing */);
if (!status_.ok()) { if (!status_.ok()) {
return; return;
} }

View file

@ -169,7 +169,8 @@ bool NotifyCollectTableCollectorsOnFinish(
Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file, Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
FilePrefetchBuffer* prefetch_buffer, const Footer& footer, FilePrefetchBuffer* prefetch_buffer, const Footer& footer,
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions,
TableProperties** table_properties) { TableProperties** table_properties,
bool compression_type_missing) {
assert(table_properties); assert(table_properties);
Slice v = handle_value; Slice v = handle_value;
@ -189,6 +190,11 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
file, prefetch_buffer, footer, read_options, handle, &block_contents, file, prefetch_buffer, footer, read_options, handle, &block_contents,
ioptions, false /* decompress */, compression_dict, cache_options); ioptions, false /* decompress */, compression_dict, cache_options);
s = block_fetcher.ReadBlockContents(); s = block_fetcher.ReadBlockContents();
// override compression_type when table file is known to contain undefined
// value at compression type marker
if (compression_type_missing) {
block_contents.compression_type = kNoCompression;
}
if (!s.ok()) { if (!s.ok()) {
return s; return s;
@ -293,7 +299,8 @@ Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size, Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions &ioptions, const ImmutableCFOptions &ioptions,
TableProperties** properties) { TableProperties** properties,
bool compression_type_missing) {
// -- Read metaindex block // -- Read metaindex block
Footer footer; Footer footer;
auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size, auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size,
@ -317,6 +324,11 @@ Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
// override compression_type when table file is known to contain undefined
// value at compression type marker
if (compression_type_missing) {
metaindex_contents.compression_type = kNoCompression;
}
Block metaindex_block(std::move(metaindex_contents), Block metaindex_block(std::move(metaindex_contents),
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
std::unique_ptr<InternalIterator> meta_iter( std::unique_ptr<InternalIterator> meta_iter(
@ -332,7 +344,7 @@ Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
TableProperties table_properties; TableProperties table_properties;
if (found_properties_block == true) { if (found_properties_block == true) {
s = ReadProperties(meta_iter->value(), file, nullptr /* prefetch_buffer */, s = ReadProperties(meta_iter->value(), file, nullptr /* prefetch_buffer */,
footer, ioptions, properties); footer, ioptions, properties, compression_type_missing);
} else { } else {
s = Status::NotFound(); s = Status::NotFound();
} }
@ -357,7 +369,8 @@ Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions &ioptions, const ImmutableCFOptions &ioptions,
const std::string& meta_block_name, const std::string& meta_block_name,
BlockHandle* block_handle) { BlockHandle* block_handle,
bool compression_type_missing) {
Footer footer; Footer footer;
auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size, auto s = ReadFooterFromFile(file, nullptr /* prefetch_buffer */, file_size,
&footer, table_magic_number); &footer, table_magic_number);
@ -379,6 +392,11 @@ Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
// override compression_type when table file is known to contain undefined
// value at compression type marker
if (compression_type_missing) {
metaindex_contents.compression_type = kNoCompression;
}
Block metaindex_block(std::move(metaindex_contents), Block metaindex_block(std::move(metaindex_contents),
kDisableGlobalSequenceNumber); kDisableGlobalSequenceNumber);
@ -394,7 +412,7 @@ Status ReadMetaBlock(RandomAccessFileReader* file,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions,
const std::string& meta_block_name, const std::string& meta_block_name,
BlockContents* contents) { BlockContents* contents, bool compression_type_missing) {
Status status; Status status;
Footer footer; Footer footer;
status = ReadFooterFromFile(file, prefetch_buffer, file_size, &footer, status = ReadFooterFromFile(file, prefetch_buffer, file_size, &footer,
@ -419,6 +437,11 @@ Status ReadMetaBlock(RandomAccessFileReader* file,
if (!status.ok()) { if (!status.ok()) {
return status; return status;
} }
// override compression_type when table file is known to contain undefined
// value at compression type marker
if (compression_type_missing) {
metaindex_contents.compression_type = kNoCompression;
}
// Finding metablock // Finding metablock
Block metaindex_block(std::move(metaindex_contents), Block metaindex_block(std::move(metaindex_contents),

View file

@ -96,16 +96,22 @@ bool NotifyCollectTableCollectorsOnFinish(
Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file, Status ReadProperties(const Slice& handle_value, RandomAccessFileReader* file,
FilePrefetchBuffer* prefetch_buffer, const Footer& footer, FilePrefetchBuffer* prefetch_buffer, const Footer& footer,
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions,
TableProperties** table_properties); TableProperties** table_properties,
bool compression_type_missing = false);
// Directly read the properties from the properties block of a plain table. // Directly read the properties from the properties block of a plain table.
// @returns a status to indicate if the operation succeeded. On success, // @returns a status to indicate if the operation succeeded. On success,
// *table_properties will point to a heap-allocated TableProperties // *table_properties will point to a heap-allocated TableProperties
// object, otherwise value of `table_properties` will not be modified. // object, otherwise value of `table_properties` will not be modified.
// certain tables do not have compression_type byte setup properly for
// uncompressed blocks, caller can request to reset compression type by
// passing compression_type_missing = true, the same applies to
// `ReadProperties`, `FindMetaBlock`, and `ReadMetaBlock`
Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size, Status ReadTableProperties(RandomAccessFileReader* file, uint64_t file_size,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions &ioptions, const ImmutableCFOptions &ioptions,
TableProperties** properties); TableProperties** properties,
bool compression_type_missing = false);
// Find the meta block from the meta index block. // Find the meta block from the meta index block.
Status FindMetaBlock(InternalIterator* meta_index_iter, Status FindMetaBlock(InternalIterator* meta_index_iter,
@ -117,7 +123,8 @@ Status FindMetaBlock(RandomAccessFileReader* file, uint64_t file_size,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions &ioptions, const ImmutableCFOptions &ioptions,
const std::string& meta_block_name, const std::string& meta_block_name,
BlockHandle* block_handle); BlockHandle* block_handle,
bool compression_type_missing = false);
// Read the specified meta block with name meta_block_name // Read the specified meta block with name meta_block_name
// from `file` and initialize `contents` with contents of this block. // from `file` and initialize `contents` with contents of this block.
@ -127,6 +134,7 @@ Status ReadMetaBlock(RandomAccessFileReader* file,
uint64_t table_magic_number, uint64_t table_magic_number,
const ImmutableCFOptions& ioptions, const ImmutableCFOptions& ioptions,
const std::string& meta_block_name, const std::string& meta_block_name,
BlockContents* contents); BlockContents* contents,
bool compression_type_missing = false);
} // namespace rocksdb } // namespace rocksdb

View file

@ -128,7 +128,8 @@ Status PlainTableReader::Open(
TableProperties* props = nullptr; TableProperties* props = nullptr;
auto s = ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber, auto s = ReadTableProperties(file.get(), file_size, kPlainTableMagicNumber,
ioptions, &props); ioptions, &props,
true /* compression_type_missing */);
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
@ -293,7 +294,8 @@ Status PlainTableReader::PopulateIndex(TableProperties* props,
Status s = ReadMetaBlock(file_info_.file.get(), nullptr /* prefetch_buffer */, Status s = ReadMetaBlock(file_info_.file.get(), nullptr /* prefetch_buffer */,
file_size_, kPlainTableMagicNumber, ioptions_, file_size_, kPlainTableMagicNumber, ioptions_,
PlainTableIndexBuilder::kPlainTableIndexBlock, PlainTableIndexBuilder::kPlainTableIndexBlock,
&index_block_contents); &index_block_contents,
true /* compression_type_missing */);
bool index_in_file = s.ok(); bool index_in_file = s.ok();
@ -303,7 +305,8 @@ Status PlainTableReader::PopulateIndex(TableProperties* props,
if (index_in_file) { if (index_in_file) {
s = ReadMetaBlock(file_info_.file.get(), nullptr /* prefetch_buffer */, s = ReadMetaBlock(file_info_.file.get(), nullptr /* prefetch_buffer */,
file_size_, kPlainTableMagicNumber, ioptions_, file_size_, kPlainTableMagicNumber, ioptions_,
BloomBlockBuilder::kBloomBlock, &bloom_block_contents); BloomBlockBuilder::kBloomBlock, &bloom_block_contents,
true /* compression_type_missing */);
bloom_in_file = s.ok() && bloom_block_contents.data.size() > 0; bloom_in_file = s.ok() && bloom_block_contents.data.size() > 0;
} }

View file

@ -2575,7 +2575,7 @@ TEST_F(PlainTableTest, BasicPlainTableProperties) {
TableProperties* props = nullptr; TableProperties* props = nullptr;
auto s = ReadTableProperties(file_reader.get(), ss->contents().size(), auto s = ReadTableProperties(file_reader.get(), ss->contents().size(),
kPlainTableMagicNumber, ioptions, kPlainTableMagicNumber, ioptions,
&props); &props, true /* compression_type_missing */);
std::unique_ptr<TableProperties> props_guard(props); std::unique_ptr<TableProperties> props_guard(props);
ASSERT_OK(s); ASSERT_OK(s);
@ -3169,7 +3169,7 @@ TEST_P(BlockBasedTableTest, TableWithGlobalSeqno) {
TableProperties* props = nullptr; TableProperties* props = nullptr;
ASSERT_OK(ReadTableProperties(file_reader.get(), ss_rw.contents().size(), ASSERT_OK(ReadTableProperties(file_reader.get(), ss_rw.contents().size(),
kBlockBasedTableMagicNumber, ioptions, kBlockBasedTableMagicNumber, ioptions,
&props)); &props, true /* compression_type_missing */));
UserCollectedProperties user_props = props->user_collected_properties; UserCollectedProperties user_props = props->user_collected_properties;
version = DecodeFixed32( version = DecodeFixed32(
@ -3346,7 +3346,7 @@ TEST_P(BlockBasedTableTest, BlockAlignTest) {
TableProperties* props = nullptr; TableProperties* props = nullptr;
ASSERT_OK(ReadTableProperties(file_reader.get(), ss_rw.contents().size(), ASSERT_OK(ReadTableProperties(file_reader.get(), ss_rw.contents().size(),
kBlockBasedTableMagicNumber, ioptions, kBlockBasedTableMagicNumber, ioptions,
&props)); &props, true /* compression_type_missing */));
uint64_t data_block_size = props->data_size / props->num_data_blocks; uint64_t data_block_size = props->data_size / props->num_data_blocks;
ASSERT_EQ(data_block_size, 4096); ASSERT_EQ(data_block_size, 4096);