Eliminate a memcpy for uncompressed blocks

Summary:
`ReadBlockFromFile` uses a stack buffer to hold small data blocks before passing them to the compression library, which outputs uncompressed data in a heap buffer. In the case of `kNoCompression` there is a `memcpy` to copy from stack buffer to heap buffer.

This PR optimizes `ReadBlockFromFile` to skip the stack buffer for files whose blocks are known to be uncompressed. We determine this using the SST file property, "compression_name", if it's available.
Closes https://github.com/facebook/rocksdb/pull/3472

Differential Revision: D6920848

Pulled By: ajkr

fbshipit-source-id: 5c753e804efc178b9229ae5dbe6a4adc32031f07
This commit is contained in:
Andrew Kryczka 2018-02-07 15:42:35 -08:00 committed by Facebook Github Bot
parent a0931b3185
commit e78715c29a
2 changed files with 17 additions and 7 deletions

View File

@ -759,7 +759,10 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
"block %s",
s.ToString().c_str());
} else {
assert(table_properties != nullptr);
rep->table_properties.reset(table_properties);
rep->blocks_maybe_compressed = rep->table_properties->compression_name !=
CompressionTypeToString(kNoCompression);
}
} else {
ROCKS_LOG_ERROR(rep->ioptions.info_log,
@ -769,7 +772,7 @@ Status BlockBasedTable::Open(const ImmutableCFOptions& ioptions,
// Read the compression dictionary meta block
bool found_compression_dict;
BlockHandle compression_dict_handle;
s = SeekToCompressionDictBlock(meta_iter.get(), &found_compression_dict,
s = SeekToCompressionDictBlock(meta_iter.get(), &found_compression_dict,
&compression_dict_handle);
if (!s.ok()) {
ROCKS_LOG_WARN(
@ -1502,11 +1505,11 @@ BlockIter* BlockBasedTable::NewDataBlockIterator(
{
StopWatch sw(rep->ioptions.env, rep->ioptions.statistics,
READ_BLOCK_GET_MICROS);
s = ReadBlockFromFile(
rep->file.get(), nullptr /* prefetch_buffer */, rep->footer, ro,
handle, &block_value, rep->ioptions, true /* compress */,
compression_dict, rep->persistent_cache_options, rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
s = ReadBlockFromFile(rep->file.get(), nullptr /* prefetch_buffer */,
rep->footer, ro, handle, &block_value, rep->ioptions,
rep->blocks_maybe_compressed, compression_dict,
rep->persistent_cache_options, rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
}
if (s.ok()) {
block.value = block_value.release();
@ -1605,7 +1608,8 @@ Status BlockBasedTable::MaybeLoadDataBlockToCache(
StopWatch sw(rep->ioptions.env, statistics, READ_BLOCK_GET_MICROS);
s = ReadBlockFromFile(
rep->file.get(), prefetch_buffer, rep->footer, ro, handle,
&raw_block, rep->ioptions, block_cache_compressed == nullptr,
&raw_block, rep->ioptions,
block_cache_compressed == nullptr && rep->blocks_maybe_compressed,
compression_dict, rep->persistent_cache_options, rep->global_seqno,
rep->table_options.read_amp_bytes_per_bit);
}

View File

@ -224,6 +224,7 @@ class BlockBasedTable : public TableReader {
Rep* rep, const ReadOptions& ro, const BlockHandle& block_hanlde,
BlockIter* input_iter = nullptr, bool is_index = false,
GetContext* get_context = nullptr, Status s = Status());
// If block cache enabled (compressed or uncompressed), looks for the block
// identified by handle in (1) uncompressed cache, (2) compressed cache, and
// then (3) file. If found, inserts into the cache(s) that were searched
@ -495,6 +496,11 @@ struct BlockBasedTable::Rep {
// A value of kDisableGlobalSequenceNumber means that this feature is disabled
// and every key have it's own seqno.
SequenceNumber global_seqno;
// If false, blocks in this file are definitely all uncompressed. Knowing this
// before reading individual blocks enables certain optimizations.
bool blocks_maybe_compressed = true;
bool closed = false;
};