LCOV - code coverage report
Current view: top level - src/leveldb/table - filter_block.cc (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 96.6 % 59 57
Test Date: 2026-02-04 04:43:42 Functions: 100.0 % 7 7
Branches: 57.1 % 56 32

             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                 :          74 : FilterBlockBuilder::FilterBlockBuilder(const FilterPolicy* policy)
      19                 :          74 :     : policy_(policy) {}
      20                 :             : 
      21                 :         492 : void FilterBlockBuilder::StartBlock(uint64_t block_offset) {
      22                 :         492 :   uint64_t filter_index = (block_offset / kFilterBase);
      23   [ -  +  -  + ]:         492 :   assert(filter_index >= filter_offsets_.size());
      24   [ -  +  +  + ]:        1194 :   while (filter_index > filter_offsets_.size()) {
      25                 :         702 :     GenerateFilter();
      26                 :             :   }
      27                 :         492 : }
      28                 :             : 
      29                 :       28387 : void FilterBlockBuilder::AddKey(const Slice& key) {
      30                 :       28387 :   Slice k = key;
      31         [ -  + ]:       28387 :   start_.push_back(keys_.size());
      32                 :       28387 :   keys_.append(k.data(), k.size());
      33                 :       28387 : }
      34                 :             : 
      35                 :          73 : Slice FilterBlockBuilder::Finish() {
      36         [ +  + ]:          73 :   if (!start_.empty()) {
      37                 :          66 :     GenerateFilter();
      38                 :             :   }
      39                 :             : 
      40                 :             :   // Append array of per-filter offsets
      41         [ -  + ]:          73 :   const uint32_t array_offset = result_.size();
      42   [ -  +  +  + ]:         839 :   for (size_t i = 0; i < filter_offsets_.size(); i++) {
      43                 :         766 :     PutFixed32(&result_, filter_offsets_[i]);
      44                 :             :   }
      45                 :             : 
      46                 :          73 :   PutFixed32(&result_, array_offset);
      47                 :          73 :   result_.push_back(kFilterBaseLg);  // Save encoding parameter in result
      48         [ -  + ]:          73 :   return Slice(result_);
      49                 :             : }
      50                 :             : 
      51                 :         768 : void FilterBlockBuilder::GenerateFilter() {
      52         [ -  + ]:         768 :   const size_t num_keys = start_.size();
      53         [ +  + ]:         768 :   if (num_keys == 0) {
      54                 :             :     // Fast path if there are no keys for this filter
      55         [ -  + ]:         350 :     filter_offsets_.push_back(result_.size());
      56                 :         350 :     return;
      57                 :             :   }
      58                 :             : 
      59                 :             :   // Make list of keys from flattened key structure
      60         [ -  + ]:         418 :   start_.push_back(keys_.size());  // Simplify length computation
      61                 :         418 :   tmp_keys_.resize(num_keys);
      62         [ +  + ]:       28783 :   for (size_t i = 0; i < num_keys; i++) {
      63                 :       28365 :     const char* base = keys_.data() + start_[i];
      64                 :       28365 :     size_t length = start_[i + 1] - start_[i];
      65                 :       28365 :     tmp_keys_[i] = Slice(base, length);
      66                 :             :   }
      67                 :             : 
      68                 :             :   // Generate filter for current set of keys and append to result_.
      69         [ -  + ]:         418 :   filter_offsets_.push_back(result_.size());
      70                 :         418 :   policy_->CreateFilter(&tmp_keys_[0], static_cast<int>(num_keys), &result_);
      71                 :             : 
      72         [ +  - ]:         418 :   tmp_keys_.clear();
      73         [ +  - ]:         418 :   keys_.clear();
      74         [ +  - ]:         418 :   start_.clear();
      75                 :             : }
      76                 :             : 
      77                 :         155 : FilterBlockReader::FilterBlockReader(const FilterPolicy* policy,
      78                 :         155 :                                      const Slice& contents)
      79                 :         155 :     : policy_(policy), data_(nullptr), offset_(nullptr), num_(0), base_lg_(0) {
      80         [ +  - ]:         155 :   size_t n = contents.size();
      81         [ +  - ]:         155 :   if (n < 5) return;  // 1 byte for base_lg_ and 4 for start of offset array
      82                 :         155 :   base_lg_ = contents[n - 1];
      83         [ +  - ]:         155 :   uint32_t last_word = DecodeFixed32(contents.data() + n - 5);
      84         [ +  - ]:         155 :   if (last_word > n - 5) return;
      85                 :         155 :   data_ = contents.data();
      86                 :         155 :   offset_ = data_ + last_word;
      87                 :         155 :   num_ = (n - 5 - last_word) / 4;
      88                 :             : }
      89                 :             : 
      90                 :     1292221 : bool FilterBlockReader::KeyMayMatch(uint64_t block_offset, const Slice& key) {
      91                 :     1292221 :   uint64_t index = block_offset >> base_lg_;
      92         [ +  - ]:     1292221 :   if (index < num_) {
      93         [ +  - ]:     1292221 :     uint32_t start = DecodeFixed32(offset_ + index * 4);
      94                 :     1292221 :     uint32_t limit = DecodeFixed32(offset_ + index * 4 + 4);
      95   [ +  -  +  - ]:     1292221 :     if (start <= limit && limit <= static_cast<size_t>(offset_ - data_)) {
      96                 :     1292221 :       Slice filter = Slice(data_ + start, limit - start);
      97                 :     1292221 :       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
        

Generated by: LCOV version 2.0-1