Fix MultiGet unable to query timestamp data issue (#7589)
Summary: The filter query key should not contain timestamp. The timestamp is stripped for Get(), but not MultiGet(). Pull Request resolved: https://github.com/facebook/rocksdb/pull/7589 Reviewed By: riversand963 Differential Revision: D24494661 Pulled By: jay-zhuang fbshipit-source-id: fc5ff40f9d683a89a760c6ff0ab3aed05a70c317
This commit is contained in:
parent
c992eb118b
commit
881e0dcc09
@ -10,6 +10,7 @@
|
|||||||
* Perform post-flush updates of in-memory data structures of memtable list in a callback that will be called by the thread writing to MANIFEST file before signaling other threads and releasing db mutex.
|
* Perform post-flush updates of in-memory data structures of memtable list in a callback that will be called by the thread writing to MANIFEST file before signaling other threads and releasing db mutex.
|
||||||
* Reverted a behavior change silently introduced in 6.14.2, in which the effects of the `ignore_unknown_options` flag (used in option parsing/loading functions) changed.
|
* Reverted a behavior change silently introduced in 6.14.2, in which the effects of the `ignore_unknown_options` flag (used in option parsing/loading functions) changed.
|
||||||
* Reverted a behavior change silently introduced in 6.14, in which options parsing/loading functions began returning `NotFound` instead of `InvalidArgument` for option names not available in the present version.
|
* Reverted a behavior change silently introduced in 6.14, in which options parsing/loading functions began returning `NotFound` instead of `InvalidArgument` for option names not available in the present version.
|
||||||
|
* Fixed MultiGet bugs it doesn't return valid data with user defined timestamp.
|
||||||
|
|
||||||
### Public API Change
|
### Public API Change
|
||||||
* Deprecate `BlockBasedTableOptions::pin_l0_filter_and_index_blocks_in_cache` and `BlockBasedTableOptions::pin_top_level_index_and_filter`. These options still take effect until users migrate to the replacement APIs in `BlockBasedTableOptions::metadata_cache_options`. Migration guidance can be found in the API comments on the deprecated options.
|
* Deprecate `BlockBasedTableOptions::pin_l0_filter_and_index_blocks_in_cache` and `BlockBasedTableOptions::pin_top_level_index_and_filter`. These options still take effect until users migrate to the replacement APIs in `BlockBasedTableOptions::metadata_cache_options`. Migration guidance can be found in the API comments on the deprecated options.
|
||||||
|
@ -492,6 +492,228 @@ TEST_F(DBBasicTestWithTimestamp, ReseekToNextUserKey) {
|
|||||||
Close();
|
Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(DBBasicTestWithTimestamp, MultiGetWithFastLocalBloom) {
|
||||||
|
Options options = CurrentOptions();
|
||||||
|
options.env = env_;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
BlockBasedTableOptions bbto;
|
||||||
|
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||||
|
bbto.cache_index_and_filter_blocks = true;
|
||||||
|
bbto.whole_key_filtering = true;
|
||||||
|
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||||
|
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||||
|
TestComparator test_cmp(kTimestampSize);
|
||||||
|
options.comparator = &test_cmp;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
|
||||||
|
// Write any value
|
||||||
|
WriteOptions write_opts;
|
||||||
|
std::string ts_str = Timestamp(1, 0);
|
||||||
|
Slice ts = ts_str;
|
||||||
|
write_opts.timestamp = &ts;
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(write_opts, "foo", "bar"));
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// Read with MultiGet
|
||||||
|
ReadOptions read_opts;
|
||||||
|
read_opts.timestamp = &ts;
|
||||||
|
size_t batch_size = 1;
|
||||||
|
std::vector<Slice> keys(batch_size);
|
||||||
|
std::vector<PinnableSlice> values(batch_size);
|
||||||
|
std::vector<Status> statuses(batch_size);
|
||||||
|
keys[0] = "foo";
|
||||||
|
ColumnFamilyHandle* cfh = db_->DefaultColumnFamily();
|
||||||
|
db_->MultiGet(read_opts, cfh, batch_size, keys.data(), values.data(),
|
||||||
|
statuses.data());
|
||||||
|
|
||||||
|
ASSERT_OK(statuses[0]);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DBBasicTestWithTimestamp, MultiGetWithPrefix) {
|
||||||
|
Options options = CurrentOptions();
|
||||||
|
options.env = env_;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.prefix_extractor.reset(NewCappedPrefixTransform(5));
|
||||||
|
BlockBasedTableOptions bbto;
|
||||||
|
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||||
|
bbto.cache_index_and_filter_blocks = true;
|
||||||
|
bbto.whole_key_filtering = false;
|
||||||
|
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||||
|
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||||
|
TestComparator test_cmp(kTimestampSize);
|
||||||
|
options.comparator = &test_cmp;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
|
||||||
|
// Write any value
|
||||||
|
WriteOptions write_opts;
|
||||||
|
std::string ts_str = Timestamp(1, 0);
|
||||||
|
Slice ts = ts_str;
|
||||||
|
write_opts.timestamp = &ts;
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(write_opts, "foo", "bar"));
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// Read with MultiGet
|
||||||
|
ReadOptions read_opts;
|
||||||
|
read_opts.timestamp = &ts;
|
||||||
|
size_t batch_size = 1;
|
||||||
|
std::vector<Slice> keys(batch_size);
|
||||||
|
std::vector<PinnableSlice> values(batch_size);
|
||||||
|
std::vector<Status> statuses(batch_size);
|
||||||
|
keys[0] = "foo";
|
||||||
|
ColumnFamilyHandle* cfh = db_->DefaultColumnFamily();
|
||||||
|
db_->MultiGet(read_opts, cfh, batch_size, keys.data(), values.data(),
|
||||||
|
statuses.data());
|
||||||
|
|
||||||
|
ASSERT_OK(statuses[0]);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DBBasicTestWithTimestamp, MultiGetWithMemBloomFilter) {
|
||||||
|
Options options = CurrentOptions();
|
||||||
|
options.env = env_;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.prefix_extractor.reset(NewCappedPrefixTransform(5));
|
||||||
|
BlockBasedTableOptions bbto;
|
||||||
|
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||||
|
bbto.cache_index_and_filter_blocks = true;
|
||||||
|
bbto.whole_key_filtering = false;
|
||||||
|
options.memtable_prefix_bloom_size_ratio = 0.1;
|
||||||
|
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||||
|
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||||
|
TestComparator test_cmp(kTimestampSize);
|
||||||
|
options.comparator = &test_cmp;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
|
||||||
|
// Write any value
|
||||||
|
WriteOptions write_opts;
|
||||||
|
std::string ts_str = Timestamp(1, 0);
|
||||||
|
Slice ts = ts_str;
|
||||||
|
write_opts.timestamp = &ts;
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(write_opts, "foo", "bar"));
|
||||||
|
|
||||||
|
// Read with MultiGet
|
||||||
|
ts_str = Timestamp(2, 0);
|
||||||
|
ts = ts_str;
|
||||||
|
ReadOptions read_opts;
|
||||||
|
read_opts.timestamp = &ts;
|
||||||
|
size_t batch_size = 1;
|
||||||
|
std::vector<Slice> keys(batch_size);
|
||||||
|
std::vector<PinnableSlice> values(batch_size);
|
||||||
|
std::vector<Status> statuses(batch_size);
|
||||||
|
keys[0] = "foo";
|
||||||
|
ColumnFamilyHandle* cfh = db_->DefaultColumnFamily();
|
||||||
|
db_->MultiGet(read_opts, cfh, batch_size, keys.data(), values.data(),
|
||||||
|
statuses.data());
|
||||||
|
|
||||||
|
ASSERT_OK(statuses[0]);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DBBasicTestWithTimestamp, MultiGetRangeFiltering) {
|
||||||
|
Options options = CurrentOptions();
|
||||||
|
options.env = env_;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
BlockBasedTableOptions bbto;
|
||||||
|
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||||
|
bbto.cache_index_and_filter_blocks = true;
|
||||||
|
bbto.whole_key_filtering = false;
|
||||||
|
options.memtable_prefix_bloom_size_ratio = 0.1;
|
||||||
|
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||||
|
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||||
|
TestComparator test_cmp(kTimestampSize);
|
||||||
|
options.comparator = &test_cmp;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
|
||||||
|
// Write any value
|
||||||
|
WriteOptions write_opts;
|
||||||
|
std::string ts_str = Timestamp(1, 0);
|
||||||
|
Slice ts = ts_str;
|
||||||
|
write_opts.timestamp = &ts;
|
||||||
|
|
||||||
|
// random data
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
auto key = ToString(i * 10);
|
||||||
|
auto value = ToString(i * 10);
|
||||||
|
Slice key_slice = key;
|
||||||
|
Slice value_slice = value;
|
||||||
|
ASSERT_OK(db_->Put(write_opts, key_slice, value_slice));
|
||||||
|
Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make num_levels to 2 to do key range filtering of sst files
|
||||||
|
ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(write_opts, "foo", "bar"));
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
|
||||||
|
// Read with MultiGet
|
||||||
|
ts_str = Timestamp(2, 0);
|
||||||
|
ts = ts_str;
|
||||||
|
ReadOptions read_opts;
|
||||||
|
read_opts.timestamp = &ts;
|
||||||
|
size_t batch_size = 1;
|
||||||
|
std::vector<Slice> keys(batch_size);
|
||||||
|
std::vector<PinnableSlice> values(batch_size);
|
||||||
|
std::vector<Status> statuses(batch_size);
|
||||||
|
keys[0] = "foo";
|
||||||
|
ColumnFamilyHandle* cfh = db_->DefaultColumnFamily();
|
||||||
|
db_->MultiGet(read_opts, cfh, batch_size, keys.data(), values.data(),
|
||||||
|
statuses.data());
|
||||||
|
|
||||||
|
ASSERT_OK(statuses[0]);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(DBBasicTestWithTimestamp, MultiGetPrefixFilter) {
|
||||||
|
Options options = CurrentOptions();
|
||||||
|
options.env = env_;
|
||||||
|
options.create_if_missing = true;
|
||||||
|
options.prefix_extractor.reset(NewCappedPrefixTransform(5));
|
||||||
|
BlockBasedTableOptions bbto;
|
||||||
|
bbto.filter_policy.reset(NewBloomFilterPolicy(10, false));
|
||||||
|
bbto.cache_index_and_filter_blocks = true;
|
||||||
|
bbto.whole_key_filtering = false;
|
||||||
|
options.memtable_prefix_bloom_size_ratio = 0.1;
|
||||||
|
options.table_factory.reset(NewBlockBasedTableFactory(bbto));
|
||||||
|
const size_t kTimestampSize = Timestamp(0, 0).size();
|
||||||
|
TestComparator test_cmp(kTimestampSize);
|
||||||
|
options.comparator = &test_cmp;
|
||||||
|
DestroyAndReopen(options);
|
||||||
|
|
||||||
|
WriteOptions write_opts;
|
||||||
|
std::string ts_str = Timestamp(1, 0);
|
||||||
|
Slice ts = ts_str;
|
||||||
|
write_opts.timestamp = &ts;
|
||||||
|
|
||||||
|
ASSERT_OK(db_->Put(write_opts, "foo", "bar"));
|
||||||
|
|
||||||
|
Flush();
|
||||||
|
// Read with MultiGet
|
||||||
|
ts_str = Timestamp(2, 0);
|
||||||
|
ts = ts_str;
|
||||||
|
ReadOptions read_opts;
|
||||||
|
read_opts.timestamp = &ts;
|
||||||
|
size_t batch_size = 1;
|
||||||
|
std::vector<Slice> keys(batch_size);
|
||||||
|
std::vector<std::string> values(batch_size);
|
||||||
|
std::vector<std::string> timestamps(batch_size);
|
||||||
|
keys[0] = "foo";
|
||||||
|
ColumnFamilyHandle* cfh = db_->DefaultColumnFamily();
|
||||||
|
std::vector<ColumnFamilyHandle*> cfhs(keys.size(), cfh);
|
||||||
|
std::vector<Status> statuses =
|
||||||
|
db_->MultiGet(read_opts, cfhs, keys, &values, ×tamps);
|
||||||
|
|
||||||
|
ASSERT_OK(statuses[0]);
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(DBBasicTestWithTimestamp, MaxKeysSkipped) {
|
TEST_F(DBBasicTestWithTimestamp, MaxKeysSkipped) {
|
||||||
Options options = CurrentOptions();
|
Options options = CurrentOptions();
|
||||||
options.env = env_;
|
options.env = env_;
|
||||||
|
@ -541,7 +541,8 @@ bool MemTable::Add(SequenceNumber s, ValueType type,
|
|||||||
|
|
||||||
if (bloom_filter_ && prefix_extractor_ &&
|
if (bloom_filter_ && prefix_extractor_ &&
|
||||||
prefix_extractor_->InDomain(key)) {
|
prefix_extractor_->InDomain(key)) {
|
||||||
bloom_filter_->Add(prefix_extractor_->Transform(key));
|
bloom_filter_->Add(
|
||||||
|
prefix_extractor_->Transform(StripTimestampFromUserKey(key, ts_sz)));
|
||||||
}
|
}
|
||||||
if (bloom_filter_ && moptions_.memtable_whole_key_filtering) {
|
if (bloom_filter_ && moptions_.memtable_whole_key_filtering) {
|
||||||
bloom_filter_->Add(StripTimestampFromUserKey(key, ts_sz));
|
bloom_filter_->Add(StripTimestampFromUserKey(key, ts_sz));
|
||||||
@ -908,16 +909,18 @@ void MemTable::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
|
|||||||
int num_keys = 0;
|
int num_keys = 0;
|
||||||
for (auto iter = temp_range.begin(); iter != temp_range.end(); ++iter) {
|
for (auto iter = temp_range.begin(); iter != temp_range.end(); ++iter) {
|
||||||
if (!prefix_extractor_) {
|
if (!prefix_extractor_) {
|
||||||
keys[num_keys++] = &iter->ukey;
|
keys[num_keys++] = &iter->ukey_without_ts;
|
||||||
} else if (prefix_extractor_->InDomain(iter->ukey)) {
|
} else if (prefix_extractor_->InDomain(iter->ukey_without_ts)) {
|
||||||
prefixes.emplace_back(prefix_extractor_->Transform(iter->ukey));
|
prefixes.emplace_back(
|
||||||
|
prefix_extractor_->Transform(iter->ukey_without_ts));
|
||||||
keys[num_keys++] = &prefixes.back();
|
keys[num_keys++] = &prefixes.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bloom_filter_->MayContain(num_keys, &keys[0], &may_match[0]);
|
bloom_filter_->MayContain(num_keys, &keys[0], &may_match[0]);
|
||||||
int idx = 0;
|
int idx = 0;
|
||||||
for (auto iter = temp_range.begin(); iter != temp_range.end(); ++iter) {
|
for (auto iter = temp_range.begin(); iter != temp_range.end(); ++iter) {
|
||||||
if (prefix_extractor_ && !prefix_extractor_->InDomain(iter->ukey)) {
|
if (prefix_extractor_ &&
|
||||||
|
!prefix_extractor_->InDomain(iter->ukey_without_ts)) {
|
||||||
PERF_COUNTER_ADD(bloom_memtable_hit_count, 1);
|
PERF_COUNTER_ADD(bloom_memtable_hit_count, 1);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -502,8 +502,8 @@ Status TableCache::MultiGet(const ReadOptions& options,
|
|||||||
|
|
||||||
for (auto miter = table_range.begin(); miter != table_range.end();
|
for (auto miter = table_range.begin(); miter != table_range.end();
|
||||||
++miter) {
|
++miter) {
|
||||||
const Slice& user_key = miter->ukey;
|
const Slice& user_key = miter->ukey_with_ts;
|
||||||
;
|
|
||||||
GetContext* get_context = miter->get_context;
|
GetContext* get_context = miter->get_context;
|
||||||
|
|
||||||
if (GetFromRowCache(user_key, row_cache_key, row_cache_key_prefix_size,
|
if (GetFromRowCache(user_key, row_cache_key, row_cache_key_prefix_size,
|
||||||
@ -539,9 +539,9 @@ Status TableCache::MultiGet(const ReadOptions& options,
|
|||||||
++iter) {
|
++iter) {
|
||||||
SequenceNumber* max_covering_tombstone_seq =
|
SequenceNumber* max_covering_tombstone_seq =
|
||||||
iter->get_context->max_covering_tombstone_seq();
|
iter->get_context->max_covering_tombstone_seq();
|
||||||
*max_covering_tombstone_seq =
|
*max_covering_tombstone_seq = std::max(
|
||||||
std::max(*max_covering_tombstone_seq,
|
*max_covering_tombstone_seq,
|
||||||
range_del_iter->MaxCoveringTombstoneSeqnum(iter->ukey));
|
range_del_iter->MaxCoveringTombstoneSeqnum(iter->ukey_with_ts));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -566,7 +566,7 @@ Status TableCache::MultiGet(const ReadOptions& options,
|
|||||||
for (auto miter = table_range.begin(); miter != table_range.end();
|
for (auto miter = table_range.begin(); miter != table_range.end();
|
||||||
++miter) {
|
++miter) {
|
||||||
std::string& row_cache_entry = row_cache_entries[row_idx++];
|
std::string& row_cache_entry = row_cache_entries[row_idx++];
|
||||||
const Slice& user_key = miter->ukey;
|
const Slice& user_key = miter->ukey_with_ts;
|
||||||
;
|
;
|
||||||
GetContext* get_context = miter->get_context;
|
GetContext* get_context = miter->get_context;
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ class FilePickerMultiGet {
|
|||||||
!file_hit)) {
|
!file_hit)) {
|
||||||
struct FilePickerContext& fp_ctx = fp_ctx_array_[batch_iter_.index()];
|
struct FilePickerContext& fp_ctx = fp_ctx_array_[batch_iter_.index()];
|
||||||
f = &curr_file_level_->files[fp_ctx.curr_index_in_curr_level];
|
f = &curr_file_level_->files[fp_ctx.curr_index_in_curr_level];
|
||||||
Slice& user_key = batch_iter_->ukey;
|
Slice& user_key = batch_iter_->ukey_without_ts;
|
||||||
|
|
||||||
// Do key range filtering of files or/and fractional cascading if:
|
// Do key range filtering of files or/and fractional cascading if:
|
||||||
// (1) not all the files are in level 0, or
|
// (1) not all the files are in level 0, or
|
||||||
@ -454,17 +454,17 @@ class FilePickerMultiGet {
|
|||||||
// Check if key is within a file's range. If search left bound and
|
// Check if key is within a file's range. If search left bound and
|
||||||
// right bound point to the same find, we are sure key falls in
|
// right bound point to the same find, we are sure key falls in
|
||||||
// range.
|
// range.
|
||||||
|
int cmp_smallest = user_comparator_->CompareWithoutTimestamp(
|
||||||
|
user_key, false, ExtractUserKey(f->smallest_key), true);
|
||||||
|
|
||||||
assert(curr_level_ == 0 ||
|
assert(curr_level_ == 0 ||
|
||||||
fp_ctx.curr_index_in_curr_level ==
|
fp_ctx.curr_index_in_curr_level ==
|
||||||
fp_ctx.start_index_in_curr_level ||
|
fp_ctx.start_index_in_curr_level ||
|
||||||
user_comparator_->Compare(user_key,
|
cmp_smallest <= 0);
|
||||||
ExtractUserKey(f->smallest_key)) <= 0);
|
|
||||||
|
|
||||||
int cmp_smallest = user_comparator_->Compare(
|
|
||||||
user_key, ExtractUserKey(f->smallest_key));
|
|
||||||
if (cmp_smallest >= 0) {
|
if (cmp_smallest >= 0) {
|
||||||
cmp_largest = user_comparator_->Compare(
|
cmp_largest = user_comparator_->CompareWithoutTimestamp(
|
||||||
user_key, ExtractUserKey(f->largest_key));
|
user_key, false, ExtractUserKey(f->largest_key), true);
|
||||||
} else {
|
} else {
|
||||||
cmp_largest = -1;
|
cmp_largest = -1;
|
||||||
}
|
}
|
||||||
@ -497,8 +497,9 @@ class FilePickerMultiGet {
|
|||||||
upper_key_ = batch_iter_;
|
upper_key_ = batch_iter_;
|
||||||
++upper_key_;
|
++upper_key_;
|
||||||
while (upper_key_ != current_level_range_.end() &&
|
while (upper_key_ != current_level_range_.end() &&
|
||||||
user_comparator_->Compare(batch_iter_->ukey, upper_key_->ukey) ==
|
user_comparator_->CompareWithoutTimestamp(
|
||||||
0) {
|
batch_iter_->ukey_without_ts, false,
|
||||||
|
upper_key_->ukey_without_ts, false) == 0) {
|
||||||
++upper_key_;
|
++upper_key_;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2017,11 +2018,11 @@ void Version::MultiGet(const ReadOptions& read_options, MultiGetRange* range,
|
|||||||
assert(iter->s->ok() || iter->s->IsMergeInProgress());
|
assert(iter->s->ok() || iter->s->IsMergeInProgress());
|
||||||
get_ctx.emplace_back(
|
get_ctx.emplace_back(
|
||||||
user_comparator(), merge_operator_, info_log_, db_statistics_,
|
user_comparator(), merge_operator_, info_log_, db_statistics_,
|
||||||
iter->s->ok() ? GetContext::kNotFound : GetContext::kMerge, iter->ukey,
|
iter->s->ok() ? GetContext::kNotFound : GetContext::kMerge,
|
||||||
iter->value, iter->timestamp, nullptr, &(iter->merge_context), true,
|
iter->ukey_with_ts, iter->value, iter->timestamp, nullptr,
|
||||||
&iter->max_covering_tombstone_seq, this->env_, nullptr,
|
&(iter->merge_context), true, &iter->max_covering_tombstone_seq,
|
||||||
merge_operator_ ? &pinned_iters_mgr : nullptr, callback, is_blob,
|
this->env_, nullptr, merge_operator_ ? &pinned_iters_mgr : nullptr,
|
||||||
tracing_mget_id);
|
callback, is_blob, tracing_mget_id);
|
||||||
// MergeInProgress status, if set, has been transferred to the get_context
|
// MergeInProgress status, if set, has been transferred to the get_context
|
||||||
// state, so we set status to ok here. From now on, the iter status will
|
// state, so we set status to ok here. From now on, the iter status will
|
||||||
// be used for IO errors, and get_context state will be used for any
|
// be used for IO errors, and get_context state will be used for any
|
||||||
|
@ -2208,21 +2208,20 @@ bool BlockBasedTable::FullFilterKeyMayMatch(
|
|||||||
Slice user_key = ExtractUserKey(internal_key);
|
Slice user_key = ExtractUserKey(internal_key);
|
||||||
const Slice* const const_ikey_ptr = &internal_key;
|
const Slice* const const_ikey_ptr = &internal_key;
|
||||||
bool may_match = true;
|
bool may_match = true;
|
||||||
if (rep_->whole_key_filtering) {
|
size_t ts_sz = rep_->internal_comparator.user_comparator()->timestamp_size();
|
||||||
size_t ts_sz =
|
|
||||||
rep_->internal_comparator.user_comparator()->timestamp_size();
|
|
||||||
Slice user_key_without_ts = StripTimestampFromUserKey(user_key, ts_sz);
|
Slice user_key_without_ts = StripTimestampFromUserKey(user_key, ts_sz);
|
||||||
|
if (rep_->whole_key_filtering) {
|
||||||
may_match =
|
may_match =
|
||||||
filter->KeyMayMatch(user_key_without_ts, prefix_extractor, kNotValid,
|
filter->KeyMayMatch(user_key_without_ts, prefix_extractor, kNotValid,
|
||||||
no_io, const_ikey_ptr, get_context, lookup_context);
|
no_io, const_ikey_ptr, get_context, lookup_context);
|
||||||
} else if (!read_options.total_order_seek && prefix_extractor &&
|
} else if (!read_options.total_order_seek && prefix_extractor &&
|
||||||
rep_->table_properties->prefix_extractor_name.compare(
|
rep_->table_properties->prefix_extractor_name.compare(
|
||||||
prefix_extractor->Name()) == 0 &&
|
prefix_extractor->Name()) == 0 &&
|
||||||
prefix_extractor->InDomain(user_key) &&
|
prefix_extractor->InDomain(user_key_without_ts) &&
|
||||||
!filter->PrefixMayMatch(prefix_extractor->Transform(user_key),
|
!filter->PrefixMayMatch(
|
||||||
prefix_extractor, kNotValid, no_io,
|
prefix_extractor->Transform(user_key_without_ts),
|
||||||
const_ikey_ptr, get_context,
|
prefix_extractor, kNotValid, no_io, const_ikey_ptr,
|
||||||
lookup_context)) {
|
get_context, lookup_context)) {
|
||||||
may_match = false;
|
may_match = false;
|
||||||
}
|
}
|
||||||
if (may_match) {
|
if (may_match) {
|
||||||
|
@ -108,11 +108,11 @@ class FilterBlockReader {
|
|||||||
uint64_t block_offset, const bool no_io,
|
uint64_t block_offset, const bool no_io,
|
||||||
BlockCacheLookupContext* lookup_context) {
|
BlockCacheLookupContext* lookup_context) {
|
||||||
for (auto iter = range->begin(); iter != range->end(); ++iter) {
|
for (auto iter = range->begin(); iter != range->end(); ++iter) {
|
||||||
const Slice ukey = iter->ukey;
|
const Slice ukey_without_ts = iter->ukey_without_ts;
|
||||||
const Slice ikey = iter->ikey;
|
const Slice ikey = iter->ikey;
|
||||||
GetContext* const get_context = iter->get_context;
|
GetContext* const get_context = iter->get_context;
|
||||||
if (!KeyMayMatch(ukey, prefix_extractor, block_offset, no_io, &ikey,
|
if (!KeyMayMatch(ukey_without_ts, prefix_extractor, block_offset, no_io,
|
||||||
get_context, lookup_context)) {
|
&ikey, get_context, lookup_context)) {
|
||||||
range->SkipKey(iter);
|
range->SkipKey(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,13 +133,13 @@ class FilterBlockReader {
|
|||||||
uint64_t block_offset, const bool no_io,
|
uint64_t block_offset, const bool no_io,
|
||||||
BlockCacheLookupContext* lookup_context) {
|
BlockCacheLookupContext* lookup_context) {
|
||||||
for (auto iter = range->begin(); iter != range->end(); ++iter) {
|
for (auto iter = range->begin(); iter != range->end(); ++iter) {
|
||||||
const Slice ukey = iter->ukey;
|
const Slice ukey_without_ts = iter->ukey_without_ts;
|
||||||
const Slice ikey = iter->ikey;
|
const Slice ikey = iter->ikey;
|
||||||
GetContext* const get_context = iter->get_context;
|
GetContext* const get_context = iter->get_context;
|
||||||
if (prefix_extractor->InDomain(ukey) &&
|
if (prefix_extractor->InDomain(ukey_without_ts) &&
|
||||||
!PrefixMayMatch(prefix_extractor->Transform(ukey), prefix_extractor,
|
!PrefixMayMatch(prefix_extractor->Transform(ukey_without_ts),
|
||||||
block_offset, no_io, &ikey, get_context,
|
prefix_extractor, block_offset, no_io, &ikey,
|
||||||
lookup_context)) {
|
get_context, lookup_context)) {
|
||||||
range->SkipKey(iter);
|
range->SkipKey(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -245,9 +245,9 @@ void FullFilterBlockReader::MayMatch(
|
|||||||
MultiGetRange filter_range(*range, range->begin(), range->end());
|
MultiGetRange filter_range(*range, range->begin(), range->end());
|
||||||
for (auto iter = filter_range.begin(); iter != filter_range.end(); ++iter) {
|
for (auto iter = filter_range.begin(); iter != filter_range.end(); ++iter) {
|
||||||
if (!prefix_extractor) {
|
if (!prefix_extractor) {
|
||||||
keys[num_keys++] = &iter->ukey;
|
keys[num_keys++] = &iter->ukey_without_ts;
|
||||||
} else if (prefix_extractor->InDomain(iter->ukey)) {
|
} else if (prefix_extractor->InDomain(iter->ukey_without_ts)) {
|
||||||
prefixes.emplace_back(prefix_extractor->Transform(iter->ukey));
|
prefixes.emplace_back(prefix_extractor->Transform(iter->ukey_without_ts));
|
||||||
keys[num_keys++] = &prefixes.back();
|
keys[num_keys++] = &prefixes.back();
|
||||||
} else {
|
} else {
|
||||||
filter_range.SkipKey(iter);
|
filter_range.SkipKey(iter);
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "db/dbformat.h"
|
||||||
#include "db/lookup_key.h"
|
#include "db/lookup_key.h"
|
||||||
#include "db/merge_context.h"
|
#include "db/merge_context.h"
|
||||||
#include "rocksdb/env.h"
|
#include "rocksdb/env.h"
|
||||||
@ -21,7 +23,8 @@ class GetContext;
|
|||||||
struct KeyContext {
|
struct KeyContext {
|
||||||
const Slice* key;
|
const Slice* key;
|
||||||
LookupKey* lkey;
|
LookupKey* lkey;
|
||||||
Slice ukey;
|
Slice ukey_with_ts;
|
||||||
|
Slice ukey_without_ts;
|
||||||
Slice ikey;
|
Slice ikey;
|
||||||
ColumnFamilyHandle* column_family;
|
ColumnFamilyHandle* column_family;
|
||||||
Status* s;
|
Status* s;
|
||||||
@ -110,7 +113,10 @@ class MultiGetContext {
|
|||||||
sorted_keys_[iter] = (*sorted_keys)[begin + iter];
|
sorted_keys_[iter] = (*sorted_keys)[begin + iter];
|
||||||
sorted_keys_[iter]->lkey = new (&lookup_key_ptr_[iter])
|
sorted_keys_[iter]->lkey = new (&lookup_key_ptr_[iter])
|
||||||
LookupKey(*sorted_keys_[iter]->key, snapshot, read_opts.timestamp);
|
LookupKey(*sorted_keys_[iter]->key, snapshot, read_opts.timestamp);
|
||||||
sorted_keys_[iter]->ukey = sorted_keys_[iter]->lkey->user_key();
|
sorted_keys_[iter]->ukey_with_ts = sorted_keys_[iter]->lkey->user_key();
|
||||||
|
sorted_keys_[iter]->ukey_without_ts = StripTimestampFromUserKey(
|
||||||
|
sorted_keys_[iter]->lkey->user_key(),
|
||||||
|
read_opts.timestamp == nullptr ? 0 : read_opts.timestamp->size());
|
||||||
sorted_keys_[iter]->ikey = sorted_keys_[iter]->lkey->internal_key();
|
sorted_keys_[iter]->ikey = sorted_keys_[iter]->lkey->internal_key();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user