| 1 | |
| 2 | |
| 3 | |
| 4 | |
| 5 | |
| 6 | #include "table/block_prefix_index.h" |
| 7 | |
| 8 | #include <vector> |
| 9 | |
| 10 | #include "rocksdb/comparator.h" |
| 11 | #include "rocksdb/slice.h" |
| 12 | #include "rocksdb/slice_transform.h" |
| 13 | #include "util/arena.h" |
| 14 | #include "util/coding.h" |
| 15 | #include "util/hash.h" |
| 16 | |
| 17 | namespace rocksdb { |
| 18 | |
| 19 | inline uint32_t Hash(const Slice& s) { |
| 20 | return rocksdb::Hash(s.data(), s.size(), 0); |
| 21 | } |
| 22 | |
| 23 | inline uint32_t PrefixToBucket(const Slice& prefix, uint32_t num_buckets) { |
| 24 | return Hash(prefix) % num_buckets; |
| 25 | } |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | const uint32_t kNoneBlock = 0x7FFFFFFF; |
| 42 | const uint32_t kBlockArrayMask = 0x80000000; |
| 43 | |
| 44 | inline bool IsNone(uint32_t block_id) { return block_id == kNoneBlock; } |
| 45 | |
| 46 | inline bool IsBlockId(uint32_t block_id) { |
| 47 | return (block_id & kBlockArrayMask) == 0; |
| 48 | } |
| 49 | |
| 50 | inline uint32_t DecodeIndex(uint32_t block_id) { |
| 51 | uint32_t index = block_id ^ kBlockArrayMask; |
| 52 | assert(index < kBlockArrayMask)(static_cast<void> (0)); |
| 53 | return index; |
| 54 | } |
| 55 | |
| 56 | inline uint32_t EncodeIndex(uint32_t index) { |
| 57 | assert(index < kBlockArrayMask)(static_cast<void> (0)); |
| 58 | return index | kBlockArrayMask; |
| 59 | } |
| 60 | |
| 61 | |
| 62 | struct PrefixRecord { |
| 63 | Slice prefix; |
| 64 | uint32_t start_block; |
| 65 | uint32_t end_block; |
| 66 | uint32_t num_blocks; |
| 67 | PrefixRecord* next; |
| 68 | }; |
| 69 | |
| 70 | class BlockPrefixIndex::Builder { |
| 71 | public: |
| 72 | explicit Builder(const SliceTransform* internal_prefix_extractor) |
| 73 | : internal_prefix_extractor_(internal_prefix_extractor) {} |
| 74 | |
| 75 | void Add(const Slice& key_prefix, uint32_t start_block, uint32_t num_blocks) { |
| 76 | PrefixRecord* record = reinterpret_cast<PrefixRecord*>( |
| 77 | arena_.AllocateAligned(sizeof(PrefixRecord))); |
| 78 | record->prefix = key_prefix; |
| 79 | record->start_block = start_block; |
| 80 | record->end_block = start_block + num_blocks - 1; |
| 81 | record->num_blocks = num_blocks; |
| 82 | prefixes_.push_back(record); |
| 83 | } |
| 84 | |
| 85 | BlockPrefixIndex* Finish() { |
| 86 | |
| 87 | uint32_t num_buckets = static_cast<uint32_t>(prefixes_.size()) + 1; |
| 88 | |
| 89 | |
| 90 | |
| 91 | std::vector<PrefixRecord*> prefixes_per_bucket(num_buckets, nullptr); |
| 92 | std::vector<uint32_t> num_blocks_per_bucket(num_buckets, 0); |
| 93 | for (PrefixRecord* current : prefixes_) { |
| 94 | uint32_t bucket = PrefixToBucket(current->prefix, num_buckets); |
| 95 | |
| 96 | |
| 97 | PrefixRecord* prev = prefixes_per_bucket[bucket]; |
| 98 | if (prev) { |
| 99 | assert(current->start_block >= prev->end_block)(static_cast<void> (0)); |
| 100 | auto distance = current->start_block - prev->end_block; |
| 101 | if (distance <= 1) { |
| 102 | prev->end_block = current->end_block; |
| 103 | prev->num_blocks = prev->end_block - prev->start_block + 1; |
| 104 | num_blocks_per_bucket[bucket] += (current->num_blocks + distance - 1); |
| 105 | continue; |
| 106 | } |
| 107 | } |
| 108 | current->next = prev; |
| 109 | prefixes_per_bucket[bucket] = current; |
| 110 | num_blocks_per_bucket[bucket] += current->num_blocks; |
| 111 | } |
| 112 | |
| 113 | |
| 114 | uint32_t total_block_array_entries = 0; |
| 115 | for (uint32_t i = 0; i < num_buckets; i++) { |
| 17 | | Assuming 'i' is < 'num_buckets' | |
|
| 18 | | Loop condition is true. Entering loop body | |
|
| 21 | | Assuming 'i' is >= 'num_buckets' | |
|
| 22 | | Loop condition is false. Execution continues on line 123 | |
|
| 116 | uint32_t num_blocks = num_blocks_per_bucket[i]; |
| 117 | if (num_blocks > 1) { |
| 19 | | Assuming 'num_blocks' is <= 1 | |
|
| |
| 118 | total_block_array_entries += (num_blocks + 1); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | |
| 123 | uint32_t* block_array_buffer = new uint32_t[total_block_array_entries]; |
| |
| 124 | uint32_t* buckets = new uint32_t[num_buckets]; |
| 125 | uint32_t offset = 0; |
| 126 | for (uint32_t i = 0; i < num_buckets; i++) { |
| 24 | | Loop condition is true. Entering loop body | |
|
| 127 | uint32_t num_blocks = num_blocks_per_bucket[i]; |
| 128 | if (num_blocks == 0) { |
| 25 | | Assuming 'num_blocks' is not equal to 0 | |
|
| |
| 129 | assert(prefixes_per_bucket[i] == nullptr)(static_cast<void> (0)); |
| 130 | buckets[i] = kNoneBlock; |
| 131 | } else if (num_blocks == 1) { |
| 27 | | Assuming 'num_blocks' is not equal to 1 | |
|
| |
| 132 | assert(prefixes_per_bucket[i] != nullptr)(static_cast<void> (0)); |
| 133 | assert(prefixes_per_bucket[i]->next == nullptr)(static_cast<void> (0)); |
| 134 | buckets[i] = prefixes_per_bucket[i]->start_block; |
| 135 | } else { |
| 136 | assert(total_block_array_entries > 0)(static_cast<void> (0)); |
| 137 | assert(prefixes_per_bucket[i] != nullptr)(static_cast<void> (0)); |
| 138 | buckets[i] = EncodeIndex(offset); |
| 139 | block_array_buffer[offset] = num_blocks; |
| 29 | | Use of zero-allocated memory |
|
| 140 | uint32_t* last_block = &block_array_buffer[offset + num_blocks]; |
| 141 | auto current = prefixes_per_bucket[i]; |
| 142 | |
| 143 | while (current != nullptr) { |
| 144 | for (uint32_t iter = 0; iter < current->num_blocks; iter++) { |
| 145 | *last_block = current->end_block - iter; |
| 146 | last_block--; |
| 147 | } |
| 148 | current = current->next; |
| 149 | } |
| 150 | assert(last_block == &block_array_buffer[offset])(static_cast<void> (0)); |
| 151 | offset += (num_blocks + 1); |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | assert(offset == total_block_array_entries)(static_cast<void> (0)); |
| 156 | |
| 157 | return new BlockPrefixIndex(internal_prefix_extractor_, num_buckets, |
| 158 | buckets, total_block_array_entries, |
| 159 | block_array_buffer); |
| 160 | } |
| 161 | |
| 162 | private: |
| 163 | const SliceTransform* internal_prefix_extractor_; |
| 164 | |
| 165 | std::vector<PrefixRecord*> prefixes_; |
| 166 | Arena arena_; |
| 167 | }; |
| 168 | |
| 169 | Status BlockPrefixIndex::Create(const SliceTransform* internal_prefix_extractor, |
| 170 | const Slice& prefixes, const Slice& prefix_meta, |
| 171 | BlockPrefixIndex** prefix_index) { |
| 172 | uint64_t pos = 0; |
| 173 | auto meta_pos = prefix_meta; |
| 174 | Status s; |
| 175 | Builder builder(internal_prefix_extractor); |
| 176 | |
| 177 | while (!meta_pos.empty()) { |
| 1 | Loop condition is true. Entering loop body | |
|
| 4 | | Loop condition is true. Entering loop body | |
|
| 7 | | Loop condition is true. Entering loop body | |
|
| 10 | | Loop condition is true. Entering loop body | |
|
| 178 | uint32_t prefix_size = 0; |
| 179 | uint32_t entry_index = 0; |
| 180 | uint32_t num_blocks = 0; |
| 181 | if (!GetVarint32(&meta_pos, &prefix_size) || |
| |
| |
| |
| |
| 182 | !GetVarint32(&meta_pos, &entry_index) || |
| 183 | !GetVarint32(&meta_pos, &num_blocks)) { |
| 184 | s = Status::Corruption( |
| 185 | "Corrupted prefix meta block: unable to read from it."); |
| 186 | break; |
| 187 | } |
| 188 | if (pos + prefix_size > prefixes.size()) { |
| |
| |
| |
| |
| 189 | s = Status::Corruption( |
| 190 | "Corrupted prefix meta block: size inconsistency."); |
| 191 | break; |
| 13 | | Execution continues on line 199 | |
|
| 192 | } |
| 193 | Slice prefix(prefixes.data() + pos, prefix_size); |
| 194 | builder.Add(prefix, entry_index, num_blocks); |
| 195 | |
| 196 | pos += prefix_size; |
| 197 | } |
| 198 | |
| 199 | if (s.ok() && pos != prefixes.size()) { |
| |
| 200 | s = Status::Corruption("Corrupted prefix meta block"); |
| 201 | } |
| 202 | |
| 203 | if (s.ok()) { |
| |
| 204 | *prefix_index = builder.Finish(); |
| 16 | | Calling 'Builder::Finish' | |
|
| 205 | } |
| 206 | |
| 207 | return s; |
| 208 | } |
| 209 | |
| 210 | uint32_t BlockPrefixIndex::GetBlocks(const Slice& key, uint32_t** blocks) { |
| 211 | Slice prefix = internal_prefix_extractor_->Transform(key); |
| 212 | |
| 213 | uint32_t bucket = PrefixToBucket(prefix, num_buckets_); |
| 214 | uint32_t block_id = buckets_[bucket]; |
| 215 | |
| 216 | if (IsNone(block_id)) { |
| 217 | return 0; |
| 218 | } else if (IsBlockId(block_id)) { |
| 219 | *blocks = &buckets_[bucket]; |
| 220 | return 1; |
| 221 | } else { |
| 222 | uint32_t index = DecodeIndex(block_id); |
| 223 | assert(index < num_block_array_buffer_entries_)(static_cast<void> (0)); |
| 224 | *blocks = &block_array_buffer_[index + 1]; |
| 225 | uint32_t num_blocks = block_array_buffer_[index]; |
| 226 | assert(num_blocks > 1)(static_cast<void> (0)); |
| 227 | assert(index + num_blocks < num_block_array_buffer_entries_)(static_cast<void> (0)); |
| 228 | return num_blocks; |
| 229 | } |
| 230 | } |
| 231 | |
| 232 | } |