/src/rocksdb/table/plain/plain_table_key_coding.cc
Line | Count | Source |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | |
6 | | #include "table/plain/plain_table_key_coding.h" |
7 | | |
8 | | #include <algorithm> |
9 | | #include <string> |
10 | | |
11 | | #include "db/dbformat.h" |
12 | | #include "file/writable_file_writer.h" |
13 | | #include "table/plain/plain_table_factory.h" |
14 | | #include "table/plain/plain_table_reader.h" |
15 | | |
16 | | namespace ROCKSDB_NAMESPACE { |
17 | | |
18 | | enum PlainTableEntryType : unsigned char { |
19 | | kFullKey = 0, |
20 | | kPrefixFromPreviousKey = 1, |
21 | | kKeySuffix = 2, |
22 | | }; |
23 | | |
24 | | namespace { |
25 | | |
26 | | // Control byte: |
27 | | // First two bits indicate type of entry |
28 | | // Other bytes are inlined sizes. If all bits are 1 (0x03F), overflow bytes |
29 | | // are used. key_size-0x3F will be encoded as a variint32 after this bytes. |
30 | | |
31 | | const unsigned char kSizeInlineLimit = 0x3F; |
32 | | |
33 | | // Return 0 for error |
34 | | size_t EncodeSize(PlainTableEntryType type, uint32_t key_size, |
35 | 0 | char* out_buffer) { |
36 | 0 | out_buffer[0] = type << 6; |
37 | |
|
38 | 0 | if (key_size < static_cast<uint32_t>(kSizeInlineLimit)) { |
39 | | // size inlined |
40 | 0 | out_buffer[0] |= static_cast<char>(key_size); |
41 | 0 | return 1; |
42 | 0 | } else { |
43 | 0 | out_buffer[0] |= kSizeInlineLimit; |
44 | 0 | char* ptr = EncodeVarint32(out_buffer + 1, key_size - kSizeInlineLimit); |
45 | 0 | return ptr - out_buffer; |
46 | 0 | } |
47 | 0 | } |
48 | | } // namespace |
49 | | |
50 | | // Fill bytes_read with number of bytes read. |
51 | | inline Status PlainTableKeyDecoder::DecodeSize(uint32_t start_offset, |
52 | | PlainTableEntryType* entry_type, |
53 | | uint32_t* key_size, |
54 | 0 | uint32_t* bytes_read) { |
55 | 0 | Slice next_byte_slice; |
56 | 0 | bool success = file_reader_.Read(start_offset, 1, &next_byte_slice); |
57 | 0 | if (!success) { |
58 | 0 | return file_reader_.status(); |
59 | 0 | } |
60 | 0 | *entry_type = static_cast<PlainTableEntryType>( |
61 | 0 | (static_cast<unsigned char>(next_byte_slice[0]) & ~kSizeInlineLimit) >> |
62 | 0 | 6); |
63 | 0 | char inline_key_size = next_byte_slice[0] & kSizeInlineLimit; |
64 | 0 | if (inline_key_size < kSizeInlineLimit) { |
65 | 0 | *key_size = inline_key_size; |
66 | 0 | *bytes_read = 1; |
67 | 0 | return Status::OK(); |
68 | 0 | } else { |
69 | 0 | uint32_t extra_size; |
70 | 0 | uint32_t tmp_bytes_read; |
71 | 0 | success = file_reader_.ReadVarint32(start_offset + 1, &extra_size, |
72 | 0 | &tmp_bytes_read); |
73 | 0 | if (!success) { |
74 | 0 | return file_reader_.status(); |
75 | 0 | } |
76 | 0 | assert(tmp_bytes_read > 0); |
77 | 0 | *key_size = kSizeInlineLimit + extra_size; |
78 | 0 | *bytes_read = tmp_bytes_read + 1; |
79 | 0 | return Status::OK(); |
80 | 0 | } |
81 | 0 | } |
82 | | |
83 | | IOStatus PlainTableKeyEncoder::AppendKey(const Slice& key, |
84 | | WritableFileWriter* file, |
85 | | uint64_t* offset, char* meta_bytes_buf, |
86 | 0 | size_t* meta_bytes_buf_size) { |
87 | 0 | ParsedInternalKey parsed_key; |
88 | 0 | Status pik_status = |
89 | 0 | ParseInternalKey(key, &parsed_key, false /* log_err_key */); // TODO |
90 | 0 | if (!pik_status.ok()) { |
91 | 0 | return IOStatus::Corruption(pik_status.getState()); |
92 | 0 | } |
93 | | |
94 | 0 | Slice key_to_write = key; // Portion of internal key to write out. |
95 | |
|
96 | 0 | uint32_t user_key_size = static_cast<uint32_t>(key.size() - 8); |
97 | 0 | const IOOptions opts; |
98 | |
|
99 | 0 | if (encoding_type_ == kPlain) { |
100 | 0 | if (fixed_user_key_len_ == kPlainTableVariableLength) { |
101 | | // Write key length |
102 | 0 | char key_size_buf[5]; // tmp buffer for key size as varint32 |
103 | 0 | char* ptr = EncodeVarint32(key_size_buf, user_key_size); |
104 | 0 | assert(ptr <= key_size_buf + sizeof(key_size_buf)); |
105 | 0 | auto len = ptr - key_size_buf; |
106 | 0 | IOStatus io_s = file->Append(opts, Slice(key_size_buf, len)); |
107 | 0 | if (!io_s.ok()) { |
108 | 0 | return io_s; |
109 | 0 | } |
110 | 0 | *offset += len; |
111 | 0 | } |
112 | 0 | } else { |
113 | 0 | assert(encoding_type_ == kPrefix); |
114 | 0 | char size_bytes[12]; |
115 | 0 | size_t size_bytes_pos = 0; |
116 | |
|
117 | 0 | Slice prefix = |
118 | 0 | prefix_extractor_->Transform(Slice(key.data(), user_key_size)); |
119 | 0 | if (key_count_for_prefix_ == 0 || prefix != pre_prefix_.GetUserKey() || |
120 | 0 | key_count_for_prefix_ % index_sparseness_ == 0) { |
121 | 0 | key_count_for_prefix_ = 1; |
122 | 0 | pre_prefix_.SetUserKey(prefix); |
123 | 0 | size_bytes_pos += EncodeSize(kFullKey, user_key_size, size_bytes); |
124 | 0 | IOStatus io_s = file->Append(opts, Slice(size_bytes, size_bytes_pos)); |
125 | 0 | if (!io_s.ok()) { |
126 | 0 | return io_s; |
127 | 0 | } |
128 | 0 | *offset += size_bytes_pos; |
129 | 0 | } else { |
130 | 0 | key_count_for_prefix_++; |
131 | 0 | if (key_count_for_prefix_ == 2) { |
132 | | // For second key within a prefix, need to encode prefix length |
133 | 0 | size_bytes_pos += |
134 | 0 | EncodeSize(kPrefixFromPreviousKey, |
135 | 0 | static_cast<uint32_t>(pre_prefix_.GetUserKey().size()), |
136 | 0 | size_bytes + size_bytes_pos); |
137 | 0 | } |
138 | 0 | uint32_t prefix_len = |
139 | 0 | static_cast<uint32_t>(pre_prefix_.GetUserKey().size()); |
140 | 0 | size_bytes_pos += EncodeSize(kKeySuffix, user_key_size - prefix_len, |
141 | 0 | size_bytes + size_bytes_pos); |
142 | 0 | IOStatus io_s = file->Append(opts, Slice(size_bytes, size_bytes_pos)); |
143 | 0 | if (!io_s.ok()) { |
144 | 0 | return io_s; |
145 | 0 | } |
146 | 0 | *offset += size_bytes_pos; |
147 | 0 | key_to_write = Slice(key.data() + prefix_len, key.size() - prefix_len); |
148 | 0 | } |
149 | 0 | } |
150 | | |
151 | | // Encode full key |
152 | | // For value size as varint32 (up to 5 bytes). |
153 | | // If the row is of value type with seqId 0, flush the special flag together |
154 | | // in this buffer to safe one file append call, which takes 1 byte. |
155 | 0 | if (parsed_key.sequence == 0 && parsed_key.type == kTypeValue) { |
156 | 0 | IOStatus io_s = |
157 | 0 | file->Append(opts, Slice(key_to_write.data(), key_to_write.size() - 8)); |
158 | 0 | if (!io_s.ok()) { |
159 | 0 | return io_s; |
160 | 0 | } |
161 | 0 | *offset += key_to_write.size() - 8; |
162 | 0 | meta_bytes_buf[*meta_bytes_buf_size] = PlainTableFactory::kValueTypeSeqId0; |
163 | 0 | *meta_bytes_buf_size += 1; |
164 | 0 | } else { |
165 | 0 | IOStatus io_s = file->Append(opts, key_to_write); |
166 | 0 | if (!io_s.ok()) { |
167 | 0 | return io_s; |
168 | 0 | } |
169 | 0 | *offset += key_to_write.size(); |
170 | 0 | } |
171 | | |
172 | 0 | return IOStatus::OK(); |
173 | 0 | } |
174 | | |
175 | | Slice PlainTableFileReader::GetFromBuffer(Buffer* buffer, uint32_t file_offset, |
176 | 0 | uint32_t len) { |
177 | 0 | assert(file_offset + len <= file_info_->data_end_offset); |
178 | 0 | return Slice(buffer->buf.get() + (file_offset - buffer->buf_start_offset), |
179 | 0 | len); |
180 | 0 | } |
181 | | |
182 | | bool PlainTableFileReader::ReadNonMmap(uint32_t file_offset, uint32_t len, |
183 | 0 | Slice* out) { |
184 | 0 | const uint32_t kPrefetchSize = 256u; |
185 | | |
186 | | // Try to read from buffers. |
187 | 0 | for (uint32_t i = 0; i < num_buf_; i++) { |
188 | 0 | Buffer* buffer = buffers_[num_buf_ - 1 - i].get(); |
189 | 0 | if (file_offset >= buffer->buf_start_offset && |
190 | 0 | file_offset + len <= buffer->buf_start_offset + buffer->buf_len) { |
191 | 0 | *out = GetFromBuffer(buffer, file_offset, len); |
192 | 0 | return true; |
193 | 0 | } |
194 | 0 | } |
195 | | |
196 | 0 | Buffer* new_buffer; |
197 | | // Data needed is not in any of the buffer. Allocate a new buffer. |
198 | 0 | if (num_buf_ < buffers_.size()) { |
199 | | // Add a new buffer |
200 | 0 | new_buffer = new Buffer(); |
201 | 0 | buffers_[num_buf_++].reset(new_buffer); |
202 | 0 | } else { |
203 | | // Now simply replace the last buffer. Can improve the placement policy |
204 | | // if needed. |
205 | 0 | new_buffer = buffers_[num_buf_ - 1].get(); |
206 | 0 | } |
207 | |
|
208 | 0 | assert(file_offset + len <= file_info_->data_end_offset); |
209 | 0 | uint32_t size_to_read = std::min(file_info_->data_end_offset - file_offset, |
210 | 0 | std::max(kPrefetchSize, len)); |
211 | 0 | if (size_to_read > new_buffer->buf_capacity) { |
212 | 0 | new_buffer->buf.reset(new char[size_to_read]); |
213 | 0 | new_buffer->buf_capacity = size_to_read; |
214 | 0 | new_buffer->buf_len = 0; |
215 | 0 | } |
216 | 0 | Slice read_result; |
217 | | // TODO: rate limit plain table reads. |
218 | 0 | Status s = |
219 | 0 | file_info_->file->Read(IOOptions(), file_offset, size_to_read, |
220 | 0 | &read_result, new_buffer->buf.get(), nullptr); |
221 | 0 | if (!s.ok()) { |
222 | 0 | status_ = s; |
223 | 0 | return false; |
224 | 0 | } |
225 | 0 | new_buffer->buf_start_offset = file_offset; |
226 | 0 | new_buffer->buf_len = size_to_read; |
227 | 0 | *out = GetFromBuffer(new_buffer, file_offset, len); |
228 | 0 | return true; |
229 | 0 | } |
230 | | |
231 | | inline bool PlainTableFileReader::ReadVarint32(uint32_t offset, uint32_t* out, |
232 | 0 | uint32_t* bytes_read) { |
233 | 0 | if (file_info_->is_mmap_mode) { |
234 | 0 | const char* start = file_info_->file_data.data() + offset; |
235 | 0 | const char* limit = |
236 | 0 | file_info_->file_data.data() + file_info_->data_end_offset; |
237 | 0 | const char* key_ptr = GetVarint32Ptr(start, limit, out); |
238 | 0 | assert(key_ptr != nullptr); |
239 | 0 | *bytes_read = static_cast<uint32_t>(key_ptr - start); |
240 | 0 | return true; |
241 | 0 | } else { |
242 | 0 | return ReadVarint32NonMmap(offset, out, bytes_read); |
243 | 0 | } |
244 | 0 | } |
245 | | |
246 | | bool PlainTableFileReader::ReadVarint32NonMmap(uint32_t offset, uint32_t* out, |
247 | 0 | uint32_t* bytes_read) { |
248 | 0 | const char* start; |
249 | 0 | const char* limit; |
250 | 0 | const uint32_t kMaxVarInt32Size = 6u; |
251 | 0 | uint32_t bytes_to_read = |
252 | 0 | std::min(file_info_->data_end_offset - offset, kMaxVarInt32Size); |
253 | 0 | Slice bytes; |
254 | 0 | if (!Read(offset, bytes_to_read, &bytes)) { |
255 | 0 | return false; |
256 | 0 | } |
257 | 0 | start = bytes.data(); |
258 | 0 | limit = bytes.data() + bytes.size(); |
259 | |
|
260 | 0 | const char* key_ptr = GetVarint32Ptr(start, limit, out); |
261 | 0 | *bytes_read = |
262 | 0 | (key_ptr != nullptr) ? static_cast<uint32_t>(key_ptr - start) : 0; |
263 | 0 | return true; |
264 | 0 | } |
265 | | |
266 | | Status PlainTableKeyDecoder::ReadInternalKey( |
267 | | uint32_t file_offset, uint32_t user_key_size, ParsedInternalKey* parsed_key, |
268 | 0 | uint32_t* bytes_read, bool* internal_key_valid, Slice* internal_key) { |
269 | 0 | Slice tmp_slice; |
270 | 0 | bool success = file_reader_.Read(file_offset, user_key_size + 1, &tmp_slice); |
271 | 0 | if (!success) { |
272 | 0 | return file_reader_.status(); |
273 | 0 | } |
274 | 0 | if (tmp_slice[user_key_size] == PlainTableFactory::kValueTypeSeqId0) { |
275 | | // Special encoding for the row with seqID=0 |
276 | 0 | parsed_key->user_key = Slice(tmp_slice.data(), user_key_size); |
277 | 0 | parsed_key->sequence = 0; |
278 | 0 | parsed_key->type = kTypeValue; |
279 | 0 | *bytes_read += user_key_size + 1; |
280 | 0 | *internal_key_valid = false; |
281 | 0 | } else { |
282 | 0 | success = file_reader_.Read(file_offset, user_key_size + 8, internal_key); |
283 | 0 | if (!success) { |
284 | 0 | return file_reader_.status(); |
285 | 0 | } |
286 | 0 | *internal_key_valid = true; |
287 | 0 | Status pik_status = ParseInternalKey(*internal_key, parsed_key, |
288 | 0 | false /* log_err_key */); // TODO |
289 | 0 | if (!pik_status.ok()) { |
290 | 0 | return Status::Corruption( |
291 | 0 | Slice("Corrupted key found during next key read. "), |
292 | 0 | pik_status.getState()); |
293 | 0 | } |
294 | 0 | *bytes_read += user_key_size + 8; |
295 | 0 | } |
296 | 0 | return Status::OK(); |
297 | 0 | } |
298 | | |
299 | | Status PlainTableKeyDecoder::NextPlainEncodingKey(uint32_t start_offset, |
300 | | ParsedInternalKey* parsed_key, |
301 | | Slice* internal_key, |
302 | | uint32_t* bytes_read, |
303 | 0 | bool* /*seekable*/) { |
304 | 0 | uint32_t user_key_size = 0; |
305 | 0 | Status s; |
306 | 0 | if (fixed_user_key_len_ != kPlainTableVariableLength) { |
307 | 0 | user_key_size = fixed_user_key_len_; |
308 | 0 | } else { |
309 | 0 | uint32_t tmp_size = 0; |
310 | 0 | uint32_t tmp_read; |
311 | 0 | bool success = |
312 | 0 | file_reader_.ReadVarint32(start_offset, &tmp_size, &tmp_read); |
313 | 0 | if (!success) { |
314 | 0 | return file_reader_.status(); |
315 | 0 | } |
316 | 0 | assert(tmp_read > 0); |
317 | 0 | user_key_size = tmp_size; |
318 | 0 | *bytes_read = tmp_read; |
319 | 0 | } |
320 | | // dummy initial value to avoid compiler complain |
321 | 0 | bool decoded_internal_key_valid = true; |
322 | 0 | Slice decoded_internal_key; |
323 | 0 | s = ReadInternalKey(start_offset + *bytes_read, user_key_size, parsed_key, |
324 | 0 | bytes_read, &decoded_internal_key_valid, |
325 | 0 | &decoded_internal_key); |
326 | 0 | if (!s.ok()) { |
327 | 0 | return s; |
328 | 0 | } |
329 | 0 | if (!file_reader_.file_info()->is_mmap_mode) { |
330 | 0 | cur_key_.SetInternalKey(*parsed_key); |
331 | 0 | parsed_key->user_key = |
332 | 0 | Slice(cur_key_.GetInternalKey().data(), user_key_size); |
333 | 0 | if (internal_key != nullptr) { |
334 | 0 | *internal_key = cur_key_.GetInternalKey(); |
335 | 0 | } |
336 | 0 | } else if (internal_key != nullptr) { |
337 | 0 | if (decoded_internal_key_valid) { |
338 | 0 | *internal_key = decoded_internal_key; |
339 | 0 | } else { |
340 | | // Need to copy out the internal key |
341 | 0 | cur_key_.SetInternalKey(*parsed_key); |
342 | 0 | *internal_key = cur_key_.GetInternalKey(); |
343 | 0 | } |
344 | 0 | } |
345 | 0 | return Status::OK(); |
346 | 0 | } |
347 | | |
348 | | Status PlainTableKeyDecoder::NextPrefixEncodingKey( |
349 | | uint32_t start_offset, ParsedInternalKey* parsed_key, Slice* internal_key, |
350 | 0 | uint32_t* bytes_read, bool* seekable) { |
351 | 0 | PlainTableEntryType entry_type; |
352 | |
|
353 | 0 | bool expect_suffix = false; |
354 | 0 | Status s; |
355 | 0 | do { |
356 | 0 | uint32_t size = 0; |
357 | | // dummy initial value to avoid compiler complain |
358 | 0 | bool decoded_internal_key_valid = true; |
359 | 0 | uint32_t my_bytes_read = 0; |
360 | 0 | s = DecodeSize(start_offset + *bytes_read, &entry_type, &size, |
361 | 0 | &my_bytes_read); |
362 | 0 | if (!s.ok()) { |
363 | 0 | return s; |
364 | 0 | } |
365 | 0 | if (my_bytes_read == 0) { |
366 | 0 | return Status::Corruption("Unexpected EOF when reading size of the key"); |
367 | 0 | } |
368 | 0 | *bytes_read += my_bytes_read; |
369 | |
|
370 | 0 | switch (entry_type) { |
371 | 0 | case kFullKey: { |
372 | 0 | expect_suffix = false; |
373 | 0 | Slice decoded_internal_key; |
374 | 0 | s = ReadInternalKey(start_offset + *bytes_read, size, parsed_key, |
375 | 0 | bytes_read, &decoded_internal_key_valid, |
376 | 0 | &decoded_internal_key); |
377 | 0 | if (!s.ok()) { |
378 | 0 | return s; |
379 | 0 | } |
380 | 0 | if (!file_reader_.file_info()->is_mmap_mode || |
381 | 0 | (internal_key != nullptr && !decoded_internal_key_valid)) { |
382 | | // In non-mmap mode, always need to make a copy of keys returned to |
383 | | // users, because after reading value for the key, the key might |
384 | | // be invalid. |
385 | 0 | cur_key_.SetInternalKey(*parsed_key); |
386 | 0 | saved_user_key_ = cur_key_.GetUserKey(); |
387 | 0 | if (!file_reader_.file_info()->is_mmap_mode) { |
388 | 0 | parsed_key->user_key = |
389 | 0 | Slice(cur_key_.GetInternalKey().data(), size); |
390 | 0 | } |
391 | 0 | if (internal_key != nullptr) { |
392 | 0 | *internal_key = cur_key_.GetInternalKey(); |
393 | 0 | } |
394 | 0 | } else { |
395 | 0 | if (internal_key != nullptr) { |
396 | 0 | *internal_key = decoded_internal_key; |
397 | 0 | } |
398 | 0 | saved_user_key_ = parsed_key->user_key; |
399 | 0 | } |
400 | 0 | break; |
401 | 0 | } |
402 | 0 | case kPrefixFromPreviousKey: { |
403 | 0 | if (seekable != nullptr) { |
404 | 0 | *seekable = false; |
405 | 0 | } |
406 | 0 | prefix_len_ = size; |
407 | 0 | assert(prefix_extractor_ == nullptr || |
408 | 0 | prefix_extractor_->Transform(saved_user_key_).size() == |
409 | 0 | prefix_len_); |
410 | | // Need read another size flag for suffix |
411 | 0 | expect_suffix = true; |
412 | 0 | break; |
413 | 0 | } |
414 | 0 | case kKeySuffix: { |
415 | 0 | expect_suffix = false; |
416 | 0 | if (seekable != nullptr) { |
417 | 0 | *seekable = false; |
418 | 0 | } |
419 | |
|
420 | 0 | Slice tmp_slice; |
421 | 0 | s = ReadInternalKey(start_offset + *bytes_read, size, parsed_key, |
422 | 0 | bytes_read, &decoded_internal_key_valid, |
423 | 0 | &tmp_slice); |
424 | 0 | if (!s.ok()) { |
425 | 0 | return s; |
426 | 0 | } |
427 | 0 | if (!file_reader_.file_info()->is_mmap_mode) { |
428 | | // In non-mmap mode, we need to make a copy of keys returned to |
429 | | // users, because after reading value for the key, the key might |
430 | | // be invalid. |
431 | | // saved_user_key_ points to cur_key_. We are making a copy of |
432 | | // the prefix part to another string, and construct the current |
433 | | // key from the prefix part and the suffix part back to cur_key_. |
434 | 0 | std::string tmp = |
435 | 0 | Slice(saved_user_key_.data(), prefix_len_).ToString(); |
436 | 0 | cur_key_.Reserve(prefix_len_ + size); |
437 | 0 | cur_key_.SetInternalKey(tmp, *parsed_key); |
438 | 0 | parsed_key->user_key = |
439 | 0 | Slice(cur_key_.GetInternalKey().data(), prefix_len_ + size); |
440 | 0 | saved_user_key_ = cur_key_.GetUserKey(); |
441 | 0 | } else { |
442 | 0 | cur_key_.Reserve(prefix_len_ + size); |
443 | 0 | cur_key_.SetInternalKey(Slice(saved_user_key_.data(), prefix_len_), |
444 | 0 | *parsed_key); |
445 | 0 | } |
446 | 0 | parsed_key->user_key = cur_key_.GetUserKey(); |
447 | 0 | if (internal_key != nullptr) { |
448 | 0 | *internal_key = cur_key_.GetInternalKey(); |
449 | 0 | } |
450 | 0 | break; |
451 | 0 | } |
452 | 0 | default: |
453 | 0 | return Status::Corruption("Un-identified size flag."); |
454 | 0 | } |
455 | 0 | } while (expect_suffix); // Another round if suffix is expected. |
456 | 0 | return Status::OK(); |
457 | 0 | } |
458 | | |
459 | | Status PlainTableKeyDecoder::NextKey(uint32_t start_offset, |
460 | | ParsedInternalKey* parsed_key, |
461 | | Slice* internal_key, Slice* value, |
462 | 0 | uint32_t* bytes_read, bool* seekable) { |
463 | 0 | assert(value != nullptr); |
464 | 0 | Status s = NextKeyNoValue(start_offset, parsed_key, internal_key, bytes_read, |
465 | 0 | seekable); |
466 | 0 | if (s.ok()) { |
467 | 0 | assert(bytes_read != nullptr); |
468 | 0 | uint32_t value_size; |
469 | 0 | uint32_t value_size_bytes; |
470 | 0 | bool success = file_reader_.ReadVarint32(start_offset + *bytes_read, |
471 | 0 | &value_size, &value_size_bytes); |
472 | 0 | if (!success) { |
473 | 0 | return file_reader_.status(); |
474 | 0 | } |
475 | 0 | if (value_size_bytes == 0) { |
476 | 0 | return Status::Corruption( |
477 | 0 | "Unexpected EOF when reading the next value's size."); |
478 | 0 | } |
479 | 0 | *bytes_read += value_size_bytes; |
480 | 0 | success = file_reader_.Read(start_offset + *bytes_read, value_size, value); |
481 | 0 | if (!success) { |
482 | 0 | return file_reader_.status(); |
483 | 0 | } |
484 | 0 | *bytes_read += value_size; |
485 | 0 | } |
486 | 0 | return s; |
487 | 0 | } |
488 | | |
489 | | Status PlainTableKeyDecoder::NextKeyNoValue(uint32_t start_offset, |
490 | | ParsedInternalKey* parsed_key, |
491 | | Slice* internal_key, |
492 | | uint32_t* bytes_read, |
493 | 0 | bool* seekable) { |
494 | 0 | *bytes_read = 0; |
495 | 0 | if (seekable != nullptr) { |
496 | 0 | *seekable = true; |
497 | 0 | } |
498 | 0 | if (encoding_type_ == kPlain) { |
499 | 0 | return NextPlainEncodingKey(start_offset, parsed_key, internal_key, |
500 | 0 | bytes_read, seekable); |
501 | 0 | } else { |
502 | | assert(encoding_type_ == kPrefix); |
503 | 0 | return NextPrefixEncodingKey(start_offset, parsed_key, internal_key, |
504 | 0 | bytes_read, seekable); |
505 | 0 | } |
506 | 0 | } |
507 | | |
508 | | } // namespace ROCKSDB_NAMESPACE |