Branch data Line data Source code
1 : : // Copyright (c) 2012 The LevelDB Authors. All rights reserved.
2 : : // Use of this source code is governed by a BSD-style license that can be
3 : : // found in the LICENSE file. See the AUTHORS file for names of contributors.
4 : :
5 : : #include "table/filter_block.h"
6 : :
7 : : #include "leveldb/filter_policy.h"
8 : : #include "util/coding.h"
9 : :
10 : : namespace leveldb {
11 : :
12 : : // See doc/table_format.md for an explanation of the filter block format.
13 : :
14 : : // Generate new filter every 2KB of data
15 : : static const size_t kFilterBaseLg = 11;
16 : : static const size_t kFilterBase = 1 << kFilterBaseLg;
17 : :
18 : 2029 : FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy)
19 : 2029 : : policy_(policy) {}
20 : :
21 : 12376 : void FilterBlockBuilder::StartBlock(uint64_t block_offset) {
22 : 12376 : uint64_t filter_index = (block_offset / kFilterBase);
23 [ - + - + ]: 12376 : assert(filter_index >= filter_offsets_.size());
24 [ - + + + ]: 29964 : while (filter_index > filter_offsets_.size()) {
25 : 17588 : GenerateFilter();
26 : : }
27 : 12376 : }
28 : :
29 : 370990 : void FilterBlockBuilder::AddKey(const Slice& key) {
30 : 370990 : Slice k = key;
31 [ - + ]: 370990 : start_.push_back(keys_.size());
32 : 370990 : keys_.append(k.data(), k.size());
33 : 370990 : }
34 : :
35 : 2028 : Slice FilterBlockBuilder::Finish() {
36 [ + + ]: 2028 : if (!start_.empty()) {
37 : 1238 : GenerateFilter();
38 : : }
39 : :
40 : : // Append array of per-filter offsets
41 [ - + ]: 2028 : const uint32_t array_offset = result_.size();
42 [ - + + + ]: 20852 : for (size_t i = 0; i < filter_offsets_.size(); i++) {
43 : 18824 : PutFixed32(&result_, filter_offsets_[i]);
44 : : }
45 : :
46 : 2028 : PutFixed32(&result_, array_offset);
47 : 2028 : result_.push_back(kFilterBaseLg); // Save encoding parameter in result
48 [ - + ]: 2028 : return Slice(result_);
49 : : }
50 : :
51 : 18826 : void FilterBlockBuilder::GenerateFilter() {
52 [ - + ]: 18826 : const size_t num_keys = start_.size();
53 [ + + ]: 18826 : if (num_keys == 0) {
54 : : // Fast path if there are no keys for this filter
55 [ - + ]: 8479 : filter_offsets_.push_back(result_.size());
56 : 8479 : return;
57 : : }
58 : :
59 : : // Make list of keys from flattened key structure
60 [ - + ]: 10347 : start_.push_back(keys_.size()); // Simplify length computation
61 : 10347 : tmp_keys_.resize(num_keys);
62 [ + + ]: 381315 : for (size_t i = 0; i < num_keys; i++) {
63 : 370968 : const char* base = keys_.data() + start_[i];
64 : 370968 : size_t length = start_[i + 1] - start_[i];
65 : 370968 : tmp_keys_[i] = Slice(base, length);
66 : : }
67 : :
68 : : // Generate filter for current set of keys and append to result_.
69 [ - + ]: 10347 : filter_offsets_.push_back(result_.size());
70 : 10347 : policy_->CreateFilter(&tmp_keys_[0], static_cast<int>(num_keys), &result_);
71 : :
72 [ + - ]: 10347 : tmp_keys_.clear();
73 [ + - ]: 10347 : keys_.clear();
74 [ + - ]: 10347 : start_.clear();
75 : : }
76 : :
77 : 4144 : FilterBlockReader::FilterBlockReader(const FilterPolicy* policy,
78 : 4144 : const Slice& contents)
79 : 4144 : : policy_(policy), data_(nullptr), offset_(nullptr), num_(0), base_lg_(0) {
80 [ + - ]: 4144 : size_t n = contents.size();
81 [ + - ]: 4144 : if (n < 5) return; // 1 byte for base_lg_ and 4 for start of offset array
82 : 4144 : base_lg_ = contents[n - 1];
83 [ + - ]: 4144 : uint32_t last_word = DecodeFixed32(contents.data() + n - 5);
84 [ + - ]: 4144 : if (last_word > n - 5) return;
85 : 4144 : data_ = contents.data();
86 : 4144 : offset_ = data_ + last_word;
87 : 4144 : num_ = (n - 5 - last_word) / 4;
88 : : }
89 : :
90 : 2216827 : bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {
91 : 2216827 : uint64_t index = block_offset >> base_lg_;
92 [ + - ]: 2216827 : if (index < num_) {
93 [ + - ]: 2216827 : uint32_t start = DecodeFixed32(offset_ + index * 4);
94 : 2216827 : uint32_t limit = DecodeFixed32(offset_ + index * 4 + 4);
95 [ + - + - ]: 2216827 : if (start <= limit && limit <= static_cast<size_t>(offset_ - data_)) {
96 : 2216827 : Slice filter = Slice(data_ + start, limit - start);
97 : 2216827 : return policy_->KeyMayMatch(key, filter);
98 [ # # ]: 0 : } else if (start == limit) {
99 : : // Empty filters do not match any keys
100 : 0 : return false;
101 : : }
102 : : }
103 : : return true; // Errors are treated as potential matches
104 : : }
105 : :
106 : : } // namespace leveldb
|