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 | } |