You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

261 line
7.7 KiB

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