github.com/cellofellow/gopkg@v0.0.0-20140722061823-eec0544a62ad/database/leveldb.chai2010/src/block.cc (about)

     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  inline uint32_t Block::NumRestarts() const {
    19    assert(size_ >= sizeof(uint32_t));
    20    return DecodeFixed32(data_ + size_ - sizeof(uint32_t));
    21  }
    22  
    23  Block::Block(const BlockContents& contents)
    24      : data_(contents.data.data()),
    25        size_(contents.data.size()),
    26        owned_(contents.heap_allocated) {
    27    if (size_ < sizeof(uint32_t)) {
    28      size_ = 0;  // Error marker
    29    } else {
    30      size_t max_restarts_allowed = (size_-sizeof(uint32_t)) / sizeof(uint32_t);
    31      if (NumRestarts() > max_restarts_allowed) {
    32        // The size is too small for NumRestarts()
    33        size_ = 0;
    34      } else {
    35        restart_offset_ = size_ - (1 + NumRestarts()) * sizeof(uint32_t);
    36      }
    37    }
    38  }
    39  
    40  Block::~Block() {
    41    if (owned_) {
    42      delete[] data_;
    43    }
    44  }
    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 derefence 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  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    if (limit - p < 3) return NULL;
    58    *shared = reinterpret_cast<const unsigned char*>(p)[0];
    59    *non_shared = reinterpret_cast<const unsigned char*>(p)[1];
    60    *value_length = reinterpret_cast<const unsigned char*>(p)[2];
    61    if ((*shared | *non_shared | *value_length) < 128) {
    62      // Fast path: all three values are encoded in one byte each
    63      p += 3;
    64    } else {
    65      if ((p = GetVarint32Ptr(p, limit, shared)) == NULL) return NULL;
    66      if ((p = GetVarint32Ptr(p, limit, non_shared)) == NULL) return NULL;
    67      if ((p = GetVarint32Ptr(p, limit, value_length)) == NULL) return NULL;
    68    }
    69  
    70    if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
    71      return NULL;
    72    }
    73    return p;
    74  }
    75  
    76  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    inline int Compare(const Slice& a, const Slice& b) const {
    91      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      return (value_.data() + value_.size()) - data_;
    97    }
    98  
    99    uint32_t GetRestartPoint(uint32_t index) {
   100      assert(index < num_restarts_);
   101      return DecodeFixed32(data_ + restarts_ + index * sizeof(uint32_t));
   102    }
   103  
   104    void SeekToRestartPoint(uint32_t index) {
   105      key_.clear();
   106      restart_index_ = index;
   107      // current_ will be fixed by ParseNextKey();
   108  
   109      // ParseNextKey() starts at the end of value_, so set value_ accordingly
   110      uint32_t offset = GetRestartPoint(index);
   111      value_ = Slice(data_ + offset, 0);
   112    }
   113  
   114   public:
   115    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          restart_index_(num_restarts_) {
   125      assert(num_restarts_ > 0);
   126    }
   127  
   128    virtual bool Valid() const { return current_ < restarts_; }
   129    virtual Status status() const { return status_; }
   130    virtual Slice key() const {
   131      assert(Valid());
   132      return key_;
   133    }
   134    virtual Slice value() const {
   135      assert(Valid());
   136      return value_;
   137    }
   138  
   139    virtual void Next() {
   140      assert(Valid());
   141      ParseNextKey();
   142    }
   143  
   144    virtual void Prev() {
   145      assert(Valid());
   146  
   147      // Scan backwards to a restart point before current_
   148      const uint32_t original = current_;
   149      while (GetRestartPoint(restart_index_) >= original) {
   150        if (restart_index_ == 0) {
   151          // No more entries
   152          current_ = restarts_;
   153          restart_index_ = num_restarts_;
   154          return;
   155        }
   156        restart_index_--;
   157      }
   158  
   159      SeekToRestartPoint(restart_index_);
   160      do {
   161        // Loop until end of current entry hits the start of original entry
   162      } while (ParseNextKey() && NextEntryOffset() < original);
   163    }
   164  
   165    virtual void Seek(const Slice& target) {
   166      // Binary search in restart array to find the last restart point
   167      // with a key < target
   168      uint32_t left = 0;
   169      uint32_t right = num_restarts_ - 1;
   170      while (left < right) {
   171        uint32_t mid = (left + right + 1) / 2;
   172        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                                          &shared, &non_shared, &value_length);
   177        if (key_ptr == NULL || (shared != 0)) {
   178          CorruptionError();
   179          return;
   180        }
   181        Slice mid_key(key_ptr, non_shared);
   182        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          right = mid - 1;
   190        }
   191      }
   192  
   193      // Linear search (within restart block) for first key >= target
   194      SeekToRestartPoint(left);
   195      while (true) {
   196        if (!ParseNextKey()) {
   197          return;
   198        }
   199        if (Compare(key_, target) >= 0) {
   200          return;
   201        }
   202      }
   203    }
   204  
   205    virtual void SeekToFirst() {
   206      SeekToRestartPoint(0);
   207      ParseNextKey();
   208    }
   209  
   210    virtual void SeekToLast() {
   211      SeekToRestartPoint(num_restarts_ - 1);
   212      while (ParseNextKey() && NextEntryOffset() < restarts_) {
   213        // Keep skipping
   214      }
   215    }
   216  
   217   private:
   218    void CorruptionError() {
   219      current_ = restarts_;
   220      restart_index_ = num_restarts_;
   221      status_ = Status::Corruption("bad entry in block");
   222      key_.clear();
   223      value_.clear();
   224    }
   225  
   226    bool ParseNextKey() {
   227      current_ = NextEntryOffset();
   228      const char* p = data_ + current_;
   229      const char* limit = data_ + restarts_;  // Restarts come right after data
   230      if (p >= limit) {
   231        // No more entries to return.  Mark as invalid.
   232        current_ = restarts_;
   233        restart_index_ = num_restarts_;
   234        return false;
   235      }
   236  
   237      // Decode next entry
   238      uint32_t shared, non_shared, value_length;
   239      p = DecodeEntry(p, limit, &shared, &non_shared, &value_length);
   240      if (p == NULL || key_.size() < shared) {
   241        CorruptionError();
   242        return false;
   243      } else {
   244        key_.resize(shared);
   245        key_.append(p, non_shared);
   246        value_ = Slice(p + non_shared, value_length);
   247        while (restart_index_ + 1 < num_restarts_ &&
   248               GetRestartPoint(restart_index_ + 1) < current_) {
   249          ++restart_index_;
   250        }
   251        return true;
   252      }
   253    }
   254  };
   255  
   256  Iterator* Block::NewIterator(const Comparator* cmp) {
   257    if (size_ < sizeof(uint32_t)) {
   258      return NewErrorIterator(Status::Corruption("bad block contents"));
   259    }
   260    const uint32_t num_restarts = NumRestarts();
   261    if (num_restarts == 0) {
   262      return NewEmptyIterator();
   263    } else {
   264      return new Iter(cmp, data_, restart_offset_, num_restarts);
   265    }
   266  }
   267  
   268  }  // namespace leveldb