// Copyright (c) 2011-present, Facebook, Inc. All rights reserved. // This source code is licensed under both the GPLv2 (found in the // COPYING file in the root directory) and Apache 2.0 License // (found in the LICENSE.Apache file in the root directory). // #include "table/block_based/filter_block_reader_common.h" #include "monitoring/perf_context_imp.h" #include "table/block_based/block_based_table_reader.h" #include "table/block_based/parsed_full_filter_block.h" namespace ROCKSDB_NAMESPACE { template Status FilterBlockReaderCommon::ReadFilterBlock( const BlockBasedTable* table, FilePrefetchBuffer* prefetch_buffer, const ReadOptions& read_options, bool use_cache, GetContext* get_context, BlockCacheLookupContext* lookup_context, CachableEntry* filter_block, BlockType block_type) { PERF_TIMER_GUARD(read_filter_block_nanos); assert(table); assert(filter_block); assert(filter_block->IsEmpty()); const BlockBasedTable::Rep* const rep = table->get_rep(); assert(rep); const Status s = table->RetrieveBlock(prefetch_buffer, read_options, rep->filter_handle, UncompressionDict::GetEmptyDict(), filter_block, block_type, get_context, lookup_context, /* for_compaction */ false, use_cache, /* wait_for_cache */ true, /* async_read */ false); return s; } template const SliceTransform* FilterBlockReaderCommon::table_prefix_extractor() const { assert(table_); const BlockBasedTable::Rep* const rep = table_->get_rep(); assert(rep); return rep->prefix_filtering ? rep->table_prefix_extractor.get() : nullptr; } template bool FilterBlockReaderCommon::whole_key_filtering() const { assert(table_); assert(table_->get_rep()); return table_->get_rep()->whole_key_filtering; } template bool FilterBlockReaderCommon::cache_filter_blocks() const { assert(table_); assert(table_->get_rep()); return table_->get_rep()->table_options.cache_index_and_filter_blocks; } template Status FilterBlockReaderCommon::GetOrReadFilterBlock( bool no_io, GetContext* get_context, BlockCacheLookupContext* lookup_context, CachableEntry* filter_block, BlockType block_type, Env::IOPriority rate_limiter_priority) const { assert(filter_block); if (!filter_block_.IsEmpty()) { filter_block->SetUnownedValue(filter_block_.GetValue()); return Status::OK(); } ReadOptions read_options; read_options.rate_limiter_priority = rate_limiter_priority; if (no_io) { read_options.read_tier = kBlockCacheTier; } return ReadFilterBlock(table_, nullptr /* prefetch_buffer */, read_options, cache_filter_blocks(), get_context, lookup_context, filter_block, block_type); } template size_t FilterBlockReaderCommon::ApproximateFilterBlockMemoryUsage() const { assert(!filter_block_.GetOwnValue() || filter_block_.GetValue() != nullptr); return filter_block_.GetOwnValue() ? filter_block_.GetValue()->ApproximateMemoryUsage() : 0; } template bool FilterBlockReaderCommon::RangeMayExist( const Slice* iterate_upper_bound, const Slice& user_key_without_ts, const SliceTransform* prefix_extractor, const Comparator* comparator, const Slice* const const_ikey_ptr, bool* filter_checked, bool need_upper_bound_check, bool no_io, BlockCacheLookupContext* lookup_context, Env::IOPriority rate_limiter_priority) { if (!prefix_extractor || !prefix_extractor->InDomain(user_key_without_ts)) { *filter_checked = false; return true; } Slice prefix = prefix_extractor->Transform(user_key_without_ts); if (need_upper_bound_check && !IsFilterCompatible(iterate_upper_bound, prefix, comparator)) { *filter_checked = false; return true; } else { *filter_checked = true; return PrefixMayMatch(prefix, no_io, const_ikey_ptr, /* get_context */ nullptr, lookup_context, rate_limiter_priority); } } template bool FilterBlockReaderCommon::IsFilterCompatible( const Slice* iterate_upper_bound, const Slice& prefix, const Comparator* comparator) const { // Try to reuse the bloom filter in the SST table if prefix_extractor in // mutable_cf_options has changed. If range [user_key, upper_bound) all // share the same prefix then we may still be able to use the bloom filter. const SliceTransform* const prefix_extractor = table_prefix_extractor(); if (iterate_upper_bound != nullptr && prefix_extractor) { if (!prefix_extractor->InDomain(*iterate_upper_bound)) { return false; } Slice upper_bound_xform = prefix_extractor->Transform(*iterate_upper_bound); // first check if user_key and upper_bound all share the same prefix if (comparator->CompareWithoutTimestamp(prefix, false, upper_bound_xform, false) != 0) { // second check if user_key's prefix is the immediate predecessor of // upper_bound and have the same length. If so, we know for sure all // keys in the range [user_key, upper_bound) share the same prefix. // Also need to make sure upper_bound are full length to ensure // correctness if (!full_length_enabled_ || iterate_upper_bound->size() != prefix_extractor_full_length_ || !comparator->IsSameLengthImmediateSuccessor(prefix, *iterate_upper_bound)) { return false; } } return true; } else { return false; } } // Explicitly instantiate templates for both "blocklike" types we use. // This makes it possible to keep the template definitions in the .cc file. template class FilterBlockReaderCommon; template class FilterBlockReaderCommon; } // namespace ROCKSDB_NAMESPACE