LCOV - code coverage report
Current view: top level - src/leveldb/table - block.cc (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 75.7 % 136 103
Test Date: 2026-02-04 04:43:42 Functions: 84.2 % 19 16
Branches: 46.2 % 104 48

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011 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                 :             : // Decodes the blocks generated by block_builder.cc.
       6                 :             : 
       7                 :             : #include "table/block.h"
       8                 :             : 
       9                 :             : #include <algorithm>
      10                 :             : #include <cstdint>
      11                 :             : #include <vector>
      12                 :             : 
      13                 :             : #include "leveldb/comparator.h"
      14                 :             : #include "table/format.h"
      15                 :             : #include "util/coding.h"
      16                 :             : #include "util/logging.h"
      17                 :             : 
      18                 :             : namespace leveldb {
      19                 :             : 
      20                 :     1360107 : inline uint32_t Block::NumRestarts() const {
      21         [ -  + ]:     1360107 :   assert(size_ >= sizeof(uint32_t));
      22                 :     1360107 :   return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
      23                 :             : }
      24                 :             : 
      25                 :        2054 : Block::Block(const BlockContents& contents)
      26         [ -  + ]:        2054 :     : data_(contents.data.data()),
      27         [ -  + ]:        2054 :       size_(contents.data.size()),
      28                 :        2054 :       owned_(contents.heap_allocated) {
      29         [ -  + ]:        2054 :   if (size_ < sizeof(uint32_t)) {
      30                 :           0 :     size_ = 0;  // Error marker
      31                 :             :   } else {
      32                 :        2054 :     size_t max_restarts_allowed = (size_ - sizeof(uint32_t)) / sizeof(uint32_t);
      33         [ -  + ]:        2054 :     if (NumRestarts() > max_restarts_allowed) {
      34                 :             :       // The size is too small for NumRestarts()
      35                 :           0 :       size_ = 0;
      36                 :             :     } else {
      37                 :        2054 :       restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
      38                 :             :     }
      39                 :             :   }
      40                 :        2054 : }
      41                 :             : 
      42                 :        2054 : Block::~Block() {
      43         [ +  + ]:        2054 :   if (owned_) {
      44         [ +  - ]:         257 :     delete[] data_;
      45                 :             :   }
      46                 :        2054 : }
      47                 :             : 
      48                 :             : // Helper routine: decode the next block entry starting at "p",
      49                 :             : // storing the number of shared key bytes, non_shared key bytes,
      50                 :             : // and the length of the value in "*shared", "*non_shared", and
      51                 :             : // "*value_length", respectively.  Will not dereference past "limit".
      52                 :             : //
      53                 :             : // If any errors are detected, returns nullptr.  Otherwise, returns a
      54                 :             : // pointer to the key delta (just past the three decoded values).
      55                 :    13651628 : static inline const char* DecodeEntry(const char* p, const char* limit,
      56                 :             :                                       uint32_t* shared, uint32_t* non_shared,
      57                 :             :                                       uint32_t* value_length) {
      58         [ +  - ]:    13651628 :   if (limit - p < 3) return nullptr;
      59                 :    13651628 :   *shared = reinterpret_cast<const uint8_t*>(p)[0];
      60                 :    13651628 :   *non_shared = reinterpret_cast<const uint8_t*>(p)[1];
      61                 :    13651628 :   *value_length = reinterpret_cast<const uint8_t*>(p)[2];
      62         [ +  + ]:    13651628 :   if ((*shared | *non_shared | *value_length) < 128) {
      63                 :             :     // Fast path: all three values are encoded in one byte each
      64                 :    13651607 :     p += 3;
      65                 :             :   } else {
      66         [ +  - ]:          21 :     if ((p = GetVarint32Ptr(p, limit, shared)) == nullptr) return nullptr;
      67         [ +  - ]:          21 :     if ((p = GetVarint32Ptr(p, limit, non_shared)) == nullptr) return nullptr;
      68         [ +  - ]:          21 :     if ((p = GetVarint32Ptr(p, limit, value_length)) == nullptr) return nullptr;
      69                 :             :   }
      70                 :             : 
      71         [ -  + ]:    13651628 :   if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
      72                 :           0 :     return nullptr;
      73                 :             :   }
      74                 :             :   return p;
      75                 :             : }
      76                 :             : 
      77                 :             : class Block::Iter : public Iterator {
      78                 :             :  private:
      79                 :             :   const Comparator* const comparator_;
      80                 :             :   const char* const data_;       // underlying block contents
      81                 :             :   uint32_t const restarts_;      // Offset of restart array (list of fixed32)
      82                 :             :   uint32_t const num_restarts_;  // Number of uint32_t entries in restart array
      83                 :             : 
      84                 :             :   // current_ is offset in data_ of current entry.  >= restarts_ if !Valid
      85                 :             :   uint32_t current_;
      86                 :             :   uint32_t restart_index_;  // Index of restart block in which current_ falls
      87                 :             :   std::string key_;
      88                 :             :   Slice value_;
      89                 :             :   Status status_;
      90                 :             : 
      91                 :    13642168 :   inline int Compare(const Slice& a, const Slice& b) const {
      92                 :    13642168 :     return comparator_->Compare(a, b);
      93                 :             :   }
      94                 :             : 
      95                 :             :   // Return the offset in data_ just past the end of the current entry.
      96                 :     3185747 :   inline uint32_t NextEntryOffset() const {
      97   [ #  #  #  # ]:           0 :     return (value_.data() + value_.size()) - data_;
      98                 :             :   }
      99                 :             : 
     100                 :    14965847 :   uint32_t GetRestartPoint(uint32_t index) {
     101         [ -  + ]:    14965847 :     assert(index < num_restarts_);
     102                 :    14965847 :     return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));
     103                 :             :   }
     104                 :             : 
     105                 :     1357870 :   void SeekToRestartPoint(uint32_t index) {
     106                 :     1357870 :     key_.clear();
     107                 :     1357870 :     restart_index_ = index;
     108                 :             :     // current_ will be fixed by ParseNextKey();
     109                 :             : 
     110                 :             :     // ParseNextKey() starts at the end of value_, so set value_ accordingly
     111                 :     1357870 :     uint32_t offset = GetRestartPoint(index);
     112                 :     1357870 :     value_ = Slice(data_ + offset, 0);
     113                 :     1357870 :   }
     114                 :             : 
     115                 :             :  public:
     116                 :     1358053 :   Iter(const Comparator* comparator, const char* data, uint32_t restarts,
     117                 :             :        uint32_t num_restarts)
     118                 :     2716106 :       : comparator_(comparator),
     119                 :     1358053 :         data_(data),
     120                 :     1358053 :         restarts_(restarts),
     121                 :     1358053 :         num_restarts_(num_restarts),
     122                 :     1358053 :         current_(restarts_),
     123         [ -  + ]:     1358053 :         restart_index_(num_restarts_) {
     124         [ -  + ]:     1358053 :     assert(num_restarts_ > 0);
     125                 :     1358053 :   }
     126                 :             : 
     127                 :     2891306 :   bool Valid() const override { return current_ < restarts_; }
     128         [ -  + ]:     1357575 :   Status status() const override { return status_; }
     129                 :       74697 :   Slice key() const override {
     130         [ -  + ]:       74697 :     assert(Valid());
     131         [ -  + ]:       74697 :     return key_;
     132                 :             :   }
     133                 :     1438610 :   Slice value() const override {
     134         [ -  + ]:     1438610 :     assert(Valid());
     135                 :     1438610 :     return value_;
     136                 :             :   }
     137                 :             : 
     138                 :        9692 :   void Next() override {
     139         [ -  + ]:        9692 :     assert(Valid());
     140                 :        9692 :     ParseNextKey();
     141                 :        9692 :   }
     142                 :             : 
     143                 :           0 :   void Prev() override {
     144         [ #  # ]:           0 :     assert(Valid());
     145                 :             : 
     146                 :             :     // Scan backwards to a restart point before current_
     147                 :           0 :     const uint32_t original = current_;
     148         [ #  # ]:           0 :     while (GetRestartPoint(restart_index_) >= original) {
     149         [ #  # ]:           0 :       if (restart_index_ == 0) {
     150                 :             :         // No more entries
     151                 :           0 :         current_ = restarts_;
     152                 :           0 :         restart_index_ = num_restarts_;
     153                 :           0 :         return;
     154                 :             :       }
     155                 :           0 :       restart_index_--;
     156                 :             :     }
     157                 :             : 
     158                 :           0 :     SeekToRestartPoint(restart_index_);
     159                 :           0 :     do {
     160                 :             :       // Loop until end of current entry hits the start of original entry
     161   [ #  #  #  #  :           0 :     } while (ParseNextKey() && NextEntryOffset() < original);
                   #  # ]
     162                 :             :   }
     163                 :             : 
     164                 :     1357592 :   void Seek(const Slice& target) override {
     165                 :             :     // Binary search in restart array to find the last restart point
     166                 :             :     // with a key < target
     167                 :     1357592 :     uint32_t left = 0;
     168                 :     1357592 :     uint32_t right = num_restarts_ - 1;
     169         [ +  + ]:    11824007 :     while (left < right) {
     170                 :    10466415 :       uint32_t mid = (left + right + 1) / 2;
     171                 :    10466415 :       uint32_t region_offset = GetRestartPoint(mid);
     172                 :    10466415 :       uint32_t shared, non_shared, value_length;
     173                 :    10466415 :       const char* key_ptr =
     174                 :    10466415 :           DecodeEntry(data_ + region_offset, data_ + restarts_, &shared,
     175                 :             :                       &non_shared, &value_length);
     176   [ +  -  -  + ]:    10466415 :       if (key_ptr == nullptr || (shared != 0)) {
     177                 :           0 :         CorruptionError();
     178                 :           0 :         return;
     179                 :             :       }
     180                 :    10466415 :       Slice mid_key(key_ptr, non_shared);
     181         [ +  + ]:    10466415 :       if (Compare(mid_key, target) < 0) {
     182                 :             :         // Key at "mid" is smaller than "target".  Therefore all
     183                 :             :         // blocks before "mid" are uninteresting.
     184                 :             :         left = mid;
     185                 :             :       } else {
     186                 :             :         // Key at "mid" is >= "target".  Therefore all blocks at or
     187                 :             :         // after "mid" are uninteresting.
     188                 :     4897743 :         right = mid - 1;
     189                 :             :       }
     190                 :             :     }
     191                 :             : 
     192                 :             :     // Linear search (within restart block) for first key >= target
     193                 :     1357592 :     SeekToRestartPoint(left);
     194                 :     3175777 :     while (true) {
     195         [ +  + ]:     3175777 :       if (!ParseNextKey()) {
     196                 :             :         return;
     197                 :             :       }
     198   [ -  +  +  + ]:     3175753 :       if (Compare(key_, target) >= 0) {
     199                 :             :         return;
     200                 :             :       }
     201                 :             :     }
     202                 :             :   }
     203                 :             : 
     204                 :         278 :   void SeekToFirst() override {
     205                 :         278 :     SeekToRestartPoint(0);
     206                 :         278 :     ParseNextKey();
     207                 :         278 :   }
     208                 :             : 
     209                 :           0 :   void SeekToLast() override {
     210                 :           0 :     SeekToRestartPoint(num_restarts_ - 1);
     211   [ #  #  #  #  :           0 :     while (ParseNextKey() && NextEntryOffset() < restarts_) {
                   #  # ]
     212                 :             :       // Keep skipping
     213                 :             :     }
     214                 :           0 :   }
     215                 :             : 
     216                 :             :  private:
     217                 :           0 :   void CorruptionError() {
     218                 :           0 :     current_ = restarts_;
     219                 :           0 :     restart_index_ = num_restarts_;
     220         [ #  # ]:           0 :     status_ = Status::Corruption("bad entry in block");
     221                 :           0 :     key_.clear();
     222                 :           0 :     value_.clear();
     223                 :           0 :   }
     224                 :             : 
     225                 :     3185747 :   bool ParseNextKey() {
     226         [ +  + ]:     3185747 :     current_ = NextEntryOffset();
     227                 :     3185747 :     const char* p = data_ + current_;
     228                 :     3185747 :     const char* limit = data_ + restarts_;  // Restarts come right after data
     229         [ +  + ]:     3185747 :     if (p >= limit) {
     230                 :             :       // No more entries to return.  Mark as invalid.
     231                 :         534 :       current_ = restarts_;
     232                 :         534 :       restart_index_ = num_restarts_;
     233                 :         534 :       return false;
     234                 :             :     }
     235                 :             : 
     236                 :             :     // Decode next entry
     237                 :     3185213 :     uint32_t shared, non_shared, value_length;
     238                 :     3185213 :     p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);
     239   [ +  -  -  +  :     3185213 :     if (p == nullptr || key_.size() < shared) {
                   -  + ]
     240                 :           0 :       CorruptionError();
     241                 :           0 :       return false;
     242                 :             :     } else {
     243                 :     3185213 :       key_.resize(shared);
     244                 :     3185213 :       key_.append(p, non_shared);
     245                 :     3185213 :       value_ = Slice(p + non_shared, value_length);
     246         [ +  + ]:     3185774 :       while (restart_index_ + 1 < num_restarts_ &&
     247         [ +  + ]:     3141562 :              GetRestartPoint(restart_index_ + 1) < current_) {
     248                 :         561 :         ++restart_index_;
     249                 :             :       }
     250                 :             :       return true;
     251                 :             :     }
     252                 :             :   }
     253                 :             : };
     254                 :             : 
     255                 :     1358053 : Iterator* Block::NewIterator(const Comparator* comparator) {
     256         [ -  + ]:     1358053 :   if (size_ < sizeof(uint32_t)) {
     257   [ #  #  #  # ]:           0 :     return NewErrorIterator(Status::Corruption("bad block contents"));
     258                 :             :   }
     259                 :     1358053 :   const uint32_t num_restarts = NumRestarts();
     260         [ -  + ]:     1358053 :   if (num_restarts == 0) {
     261                 :           0 :     return NewEmptyIterator();
     262                 :             :   } else {
     263         [ +  - ]:     1358053 :     return new Iter(comparator, data_, restart_offset_, num_restarts);
     264                 :             :   }
     265                 :             : }
     266                 :             : 
     267                 :             : }  // namespace leveldb
        

Generated by: LCOV version 2.0-1