LCOV - code coverage report
Current view: top level - src/leveldb/table - block.cc (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 93 126 73.8 %
Date: 2015-10-12 22:39:14 Functions: 17 23 73.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11