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