1 /*
2 Portions Copyright (c) 2016-Present, Facebook, Inc.
3 Portions Copyright (c) 2012,2013 Monty Program Ab
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17 #pragma once
18
19 #include <algorithm>
20 #include <string>
21 #include <vector>
22
23 /* MySQL header files */
24 #include "my_global.h"
25
26 /* MyRocks header files */
27 #include "./rdb_global.h"
28 #include "./rdb_utils.h"
29
30 /* RocksDB header files */
31 #include "rocksdb/slice.h"
32 #include "rocksdb/status.h"
33
34 namespace myrocks {
35
36 /*
37 Basic composition functions for a network buffer presented as a MySQL String
38 ("netstr") which stores data in Network Byte Order (Big Endian).
39 */
40
rdb_netstr_append_uint64(my_core::String * const out_netstr,const uint64 val)41 inline void rdb_netstr_append_uint64(my_core::String *const out_netstr,
42 const uint64 val) {
43 assert(out_netstr != nullptr);
44
45 // Convert from host machine byte order (usually Little Endian) to network
46 // byte order (Big Endian).
47 uint64 net_val = htobe64(val);
48 out_netstr->append(reinterpret_cast<char *>(&net_val), sizeof(net_val));
49 }
50
rdb_netstr_append_uint32(my_core::String * const out_netstr,const uint32 val)51 inline void rdb_netstr_append_uint32(my_core::String *const out_netstr,
52 const uint32 val) {
53 assert(out_netstr != nullptr);
54
55 // Convert from host machine byte order (usually Little Endian) to network
56 // byte order (Big Endian).
57 uint32 net_val = htobe32(val);
58 out_netstr->append(reinterpret_cast<char *>(&net_val), sizeof(net_val));
59 }
60
rdb_netstr_append_uint16(my_core::String * const out_netstr,const uint16 val)61 inline void rdb_netstr_append_uint16(my_core::String *const out_netstr,
62 const uint16 val) {
63 assert(out_netstr != nullptr);
64
65 // Convert from host machine byte order (usually Little Endian) to network
66 // byte order (Big Endian).
67 uint16 net_val = htobe16(val);
68 out_netstr->append(reinterpret_cast<char *>(&net_val), sizeof(net_val));
69 }
70
71 /*
72 Basic network buffer ("netbuf") write helper functions.
73 */
74
rdb_netbuf_store_uint64(uchar * const dst_netbuf,const uint64 n)75 inline void rdb_netbuf_store_uint64(uchar *const dst_netbuf, const uint64 n) {
76 assert(dst_netbuf != nullptr);
77
78 // Convert from host byte order (usually Little Endian) to network byte order
79 // (Big Endian).
80 uint64 net_val = htobe64(n);
81 memcpy(dst_netbuf, &net_val, sizeof(net_val));
82 }
83
rdb_netbuf_store_uint32(uchar * const dst_netbuf,const uint32 n)84 inline void rdb_netbuf_store_uint32(uchar *const dst_netbuf, const uint32 n) {
85 assert(dst_netbuf != nullptr);
86
87 // Convert from host byte order (usually Little Endian) to network byte order
88 // (Big Endian).
89 uint32 net_val = htobe32(n);
90 memcpy(dst_netbuf, &net_val, sizeof(net_val));
91 }
92
rdb_netbuf_store_uint16(uchar * const dst_netbuf,const uint16 n)93 inline void rdb_netbuf_store_uint16(uchar *const dst_netbuf, const uint16 n) {
94 assert(dst_netbuf != nullptr);
95
96 // Convert from host byte order (usually Little Endian) to network byte order
97 // (Big Endian).
98 uint16 net_val = htobe16(n);
99 memcpy(dst_netbuf, &net_val, sizeof(net_val));
100 }
101
rdb_netbuf_store_byte(uchar * const dst_netbuf,const uchar c)102 inline void rdb_netbuf_store_byte(uchar *const dst_netbuf, const uchar c) {
103 assert(dst_netbuf != nullptr);
104
105 *dst_netbuf = c;
106 }
107
rdb_netbuf_store_index(uchar * const dst_netbuf,const uint32 number)108 inline void rdb_netbuf_store_index(uchar *const dst_netbuf,
109 const uint32 number) {
110 assert(dst_netbuf != nullptr);
111
112 rdb_netbuf_store_uint32(dst_netbuf, number);
113 }
114
115 /*
116 Basic conversion helper functions from network byte order (Big Endian) to host
117 machine byte order (usually Little Endian).
118 */
119
rdb_netbuf_to_uint64(const uchar * const netbuf)120 inline uint64 rdb_netbuf_to_uint64(const uchar *const netbuf) {
121 assert(netbuf != nullptr);
122
123 uint64 net_val;
124 memcpy(&net_val, netbuf, sizeof(net_val));
125
126 // Convert from network byte order (Big Endian) to host machine byte order
127 // (usually Little Endian).
128 return be64toh(net_val);
129 }
130
rdb_netbuf_to_uint32(const uchar * const netbuf)131 inline uint32 rdb_netbuf_to_uint32(const uchar *const netbuf) {
132 assert(netbuf != nullptr);
133
134 uint32 net_val;
135 memcpy(&net_val, netbuf, sizeof(net_val));
136
137 // Convert from network byte order (Big Endian) to host machine byte order
138 // (usually Little Endian).
139 return be32toh(net_val);
140 }
141
rdb_netbuf_to_uint16(const uchar * const netbuf)142 inline uint16 rdb_netbuf_to_uint16(const uchar *const netbuf) {
143 assert(netbuf != nullptr);
144
145 uint16 net_val;
146 memcpy(&net_val, netbuf, sizeof(net_val));
147
148 // Convert from network byte order (Big Endian) to host machine byte order
149 // (usually Little Endian).
150 return be16toh(net_val);
151 }
152
rdb_netbuf_to_byte(const uchar * const netbuf)153 inline uchar rdb_netbuf_to_byte(const uchar *const netbuf) {
154 assert(netbuf != nullptr);
155
156 return (uchar)netbuf[0];
157 }
158
159 /*
160 Basic network buffer ("netbuf") read helper functions.
161 Network buffer stores data in Network Byte Order (Big Endian).
162 NB: The netbuf is passed as an input/output param, hence after reading,
163 the netbuf pointer gets advanced to the following byte.
164 */
165
rdb_netbuf_read_uint64(const uchar ** netbuf_ptr)166 inline uint64 rdb_netbuf_read_uint64(const uchar **netbuf_ptr) {
167 assert(netbuf_ptr != nullptr);
168
169 // Convert from network byte order (Big Endian) to host machine byte order
170 // (usually Little Endian).
171 const uint64 host_val = rdb_netbuf_to_uint64(*netbuf_ptr);
172
173 // Advance pointer.
174 *netbuf_ptr += sizeof(host_val);
175
176 return host_val;
177 }
178
rdb_netbuf_read_uint32(const uchar ** netbuf_ptr)179 inline uint32 rdb_netbuf_read_uint32(const uchar **netbuf_ptr) {
180 assert(netbuf_ptr != nullptr);
181
182 // Convert from network byte order (Big Endian) to host machine byte order
183 // (usually Little Endian).
184 const uint32 host_val = rdb_netbuf_to_uint32(*netbuf_ptr);
185
186 // Advance pointer.
187 *netbuf_ptr += sizeof(host_val);
188
189 return host_val;
190 }
191
rdb_netbuf_read_uint16(const uchar ** netbuf_ptr)192 inline uint16 rdb_netbuf_read_uint16(const uchar **netbuf_ptr) {
193 assert(netbuf_ptr != nullptr);
194
195 // Convert from network byte order (Big Endian) to host machine byte order
196 // (usually Little Endian).
197 const uint16 host_val = rdb_netbuf_to_uint16(*netbuf_ptr);
198
199 // Advance pointer.
200 *netbuf_ptr += sizeof(host_val);
201
202 return host_val;
203 }
204
rdb_netbuf_read_gl_index(const uchar ** netbuf_ptr,GL_INDEX_ID * const gl_index_id)205 inline void rdb_netbuf_read_gl_index(const uchar **netbuf_ptr,
206 GL_INDEX_ID *const gl_index_id) {
207 assert(gl_index_id != nullptr);
208 assert(netbuf_ptr != nullptr);
209
210 gl_index_id->cf_id = rdb_netbuf_read_uint32(netbuf_ptr);
211 gl_index_id->index_id = rdb_netbuf_read_uint32(netbuf_ptr);
212 }
213
214 /*
215 A simple string reader:
216 - it keeps position within the string that we read from
217 - it prevents one from reading beyond the end of the string.
218 */
219
220 class Rdb_string_reader {
221 const char *m_ptr;
222 uint m_len;
223
224 private:
225 Rdb_string_reader &operator=(const Rdb_string_reader &) = default;
226
227 public:
228 Rdb_string_reader(const Rdb_string_reader &) = default;
229 /* named constructor */
read_or_empty(const rocksdb::Slice * const slice)230 static Rdb_string_reader read_or_empty(const rocksdb::Slice *const slice) {
231 if (!slice) {
232 return Rdb_string_reader("");
233 } else {
234 return Rdb_string_reader(slice);
235 }
236 }
237
Rdb_string_reader(const std::string & str)238 explicit Rdb_string_reader(const std::string &str) {
239 m_len = str.length();
240 if (m_len) {
241 m_ptr = &str.at(0);
242 } else {
243 /*
244 One can a create a Rdb_string_reader for reading from an empty string
245 (although attempts to read anything will fail).
246 We must not access str.at(0), since len==0, we can set ptr to any
247 value.
248 */
249 m_ptr = nullptr;
250 }
251 }
252
Rdb_string_reader(const rocksdb::Slice * const slice)253 explicit Rdb_string_reader(const rocksdb::Slice *const slice) {
254 m_ptr = slice->data();
255 m_len = slice->size();
256 }
257
258 /*
259 Read the next @param size bytes. Returns pointer to the bytes read, or
260 nullptr if the remaining string doesn't have that many bytes.
261 */
read(const uint size)262 const char *read(const uint size) {
263 const char *res;
264 if (m_len < size) {
265 res = nullptr;
266 } else {
267 res = m_ptr;
268 m_ptr += size;
269 m_len -= size;
270 }
271 return res;
272 }
273
read_uint8(uint * const res)274 bool read_uint8(uint *const res) {
275 const uchar *p;
276 if (!(p = reinterpret_cast<const uchar *>(read(1)))) {
277 return true; // error
278 } else {
279 *res = *p;
280 return false; // Ok
281 }
282 }
283
read_uint16(uint * const res)284 bool read_uint16(uint *const res) {
285 const uchar *p;
286 if (!(p = reinterpret_cast<const uchar *>(read(2)))) {
287 return true; // error
288 } else {
289 *res = rdb_netbuf_to_uint16(p);
290 return false; // Ok
291 }
292 }
293
read_uint64(uint64 * const res)294 bool read_uint64(uint64 *const res) {
295 const uchar *p;
296 if (!(p = reinterpret_cast<const uchar *>(read(sizeof(uint64))))) {
297 return true; // error
298 } else {
299 *res = rdb_netbuf_to_uint64(p);
300 return false; // Ok
301 }
302 }
303
remaining_bytes()304 uint remaining_bytes() const { return m_len; }
305
306 /*
307 Return pointer to data that will be read by next read() call (if there is
308 nothing left to read, returns pointer to beyond the end of previous read()
309 call)
310 */
get_current_ptr()311 const char *get_current_ptr() const { return m_ptr; }
312 };
313
314 /*
315 @brief
316 A buffer one can write the data to.
317
318 @detail
319 Suggested usage pattern:
320
321 writer->clear();
322 writer->write_XXX(...);
323 ...
324 // Ok, writer->ptr() points to the data written so far,
325 // and writer->get_current_pos() is the length of the data
326
327 */
328
329 class Rdb_string_writer {
330 std::vector<uchar> m_data;
331
332 public:
333 Rdb_string_writer(const Rdb_string_writer &) = delete;
334 Rdb_string_writer &operator=(const Rdb_string_writer &) = delete;
335 Rdb_string_writer() = default;
336
clear()337 void clear() { m_data.clear(); }
write_uint8(const uint val)338 void write_uint8(const uint val) {
339 m_data.push_back(static_cast<uchar>(val));
340 }
341
write_uint16(const uint val)342 void write_uint16(const uint val) {
343 const auto size = m_data.size();
344 m_data.resize(size + 2);
345 rdb_netbuf_store_uint16(m_data.data() + size, val);
346 }
347
write_uint32(const uint val)348 void write_uint32(const uint val) {
349 const auto size = m_data.size();
350 m_data.resize(size + 4);
351 rdb_netbuf_store_uint32(m_data.data() + size, val);
352 }
353
write(const uchar * const new_data,const size_t len)354 void write(const uchar *const new_data, const size_t len) {
355 assert(new_data != nullptr);
356 m_data.insert(m_data.end(), new_data, new_data + len);
357 }
358
ptr()359 uchar *ptr() { return m_data.data(); }
get_current_pos()360 size_t get_current_pos() const { return m_data.size(); }
361
write_uint8_at(const size_t pos,const uint new_val)362 void write_uint8_at(const size_t pos, const uint new_val) {
363 // This function will only overwrite what was written
364 assert(pos < get_current_pos());
365 m_data.data()[pos] = new_val;
366 }
367
write_uint16_at(const size_t pos,const uint new_val)368 void write_uint16_at(const size_t pos, const uint new_val) {
369 // This function will only overwrite what was written
370 assert(pos < get_current_pos());
371 assert((pos + 1) < get_current_pos());
372 rdb_netbuf_store_uint16(m_data.data() + pos, new_val);
373 }
374
truncate(const size_t pos)375 void truncate(const size_t pos) {
376 assert(pos < m_data.size());
377 m_data.resize(pos);
378 }
379
380 void allocate(const size_t len, const uchar val = 0) {
381 assert(len > 0);
382 m_data.resize(m_data.size() + len, val);
383 }
384
385 /*
386 An awful hack to deallocate the buffer without relying on the deconstructor.
387 This is needed to suppress valgrind errors in rocksdb.partition
388 */
free()389 void free() { std::vector<uchar>().swap(m_data); }
390 };
391
392 /*
393 A helper class for writing bits into Rdb_string_writer.
394
395 The class assumes (but doesn't check) that nobody tries to write
396 anything to the Rdb_string_writer that it is writing to.
397 */
398 class Rdb_bit_writer {
399 Rdb_string_writer *m_writer;
400 uchar m_offset;
401
402 public:
403 Rdb_bit_writer(const Rdb_bit_writer &) = delete;
404 Rdb_bit_writer &operator=(const Rdb_bit_writer &) = delete;
405
Rdb_bit_writer(Rdb_string_writer * writer_arg)406 explicit Rdb_bit_writer(Rdb_string_writer *writer_arg)
407 : m_writer(writer_arg), m_offset(0) {}
408
write(uint size,const uint value)409 void write(uint size, const uint value) {
410 assert((value & ((1 << size) - 1)) == value);
411
412 while (size > 0) {
413 if (m_offset == 0) {
414 m_writer->write_uint8(0);
415 }
416 // number of bits to put in this byte
417 const uint bits = std::min(size, (uint)(8 - m_offset));
418 uchar *const last_byte =
419 m_writer->ptr() + m_writer->get_current_pos() - 1;
420 *last_byte |= (uchar)((value >> (size - bits)) & ((1 << bits) - 1))
421 << m_offset;
422 size -= bits;
423 m_offset = (m_offset + bits) & 0x7;
424 }
425 }
426 };
427
428 class Rdb_bit_reader {
429 const uchar *m_cur;
430 uchar m_offset;
431 uint m_ret;
432 Rdb_string_reader *const m_reader;
433
434 public:
435 Rdb_bit_reader(const Rdb_bit_reader &) = delete;
436 Rdb_bit_reader &operator=(const Rdb_bit_reader &) = delete;
437
Rdb_bit_reader(Rdb_string_reader * const reader)438 explicit Rdb_bit_reader(Rdb_string_reader *const reader)
439 : m_cur(nullptr), m_offset(0), m_reader(reader) {}
440
441 // Returns a pointer to an uint containing the bits read. On subsequent
442 // reads, the value being pointed to will be overwritten. Returns nullptr
443 // on failure.
read(uint size)444 uint *read(uint size) {
445 m_ret = 0;
446 assert(size <= 32);
447
448 while (size > 0) {
449 if (m_offset == 0) {
450 m_cur = (const uchar *)m_reader->read(1);
451 if (m_cur == nullptr) {
452 return nullptr;
453 }
454 }
455 // how many bits from the current byte?
456 const uint bits = std::min((uint)(8 - m_offset), size);
457 m_ret <<= bits;
458 m_ret |= (*m_cur >> m_offset) & ((1 << bits) - 1);
459 size -= bits;
460 m_offset = (m_offset + bits) & 0x7;
461 }
462
463 return &m_ret;
464 }
465 };
466
467 template <size_t buf_length>
468 class Rdb_buf_writer {
469 public:
470 Rdb_buf_writer(const Rdb_buf_writer &) = delete;
471 Rdb_buf_writer &operator=(const Rdb_buf_writer &) = delete;
Rdb_buf_writer()472 Rdb_buf_writer() { reset(); }
473
write_uint32(const uint32 n)474 void write_uint32(const uint32 n) {
475 assert(m_ptr + sizeof(n) <= m_buf.data() + buf_length);
476 rdb_netbuf_store_uint32(m_ptr, n);
477 m_ptr += sizeof(n);
478 }
479
write_uint64(const uint64 n)480 void write_uint64(const uint64 n) {
481 assert(m_ptr + sizeof(n) <= m_buf.data() + buf_length);
482 rdb_netbuf_store_uint64(m_ptr, n);
483 m_ptr += sizeof(n);
484 }
485
write_uint16(const uint16 n)486 void write_uint16(const uint16 n) {
487 assert(m_ptr + sizeof(n) <= m_buf.data() + buf_length);
488 rdb_netbuf_store_uint16(m_ptr, n);
489 m_ptr += sizeof(n);
490 }
491
write_byte(const uchar c)492 void write_byte(const uchar c) {
493 assert(m_ptr + sizeof(c) <= m_buf.data() + buf_length);
494 rdb_netbuf_store_byte(m_ptr, c);
495 m_ptr += sizeof(c);
496 }
497
write_index(const uint32 n)498 void write_index(const uint32 n) { write_uint32(n); }
499
write(const char * buf,const size_t size)500 void write(const char *buf, const size_t size) {
501 assert(m_ptr + size <= m_buf.data() + buf_length);
502 memcpy(m_ptr, buf, size);
503 m_ptr += size;
504 }
505
write(const uchar * buf,const size_t size)506 void write(const uchar *buf, const size_t size) {
507 assert(m_ptr + size <= m_buf.data() + buf_length);
508 memcpy(m_ptr, buf, size);
509 m_ptr += size;
510 }
511
reset()512 void reset() { m_ptr = m_buf.data(); }
513
data()514 const char *data() const {
515 return reinterpret_cast<const char *>(m_buf.data());
516 }
517
capacity()518 size_t capacity() { return buf_length; }
519
520 /** Returns actual size of the buffer that has data */
size()521 size_t size() { return m_ptr - m_buf.data(); }
522
to_slice()523 rocksdb::Slice to_slice() { return rocksdb::Slice(data(), size()); }
524
525 private:
526 std::array<uchar, buf_length> m_buf;
527 uchar *m_ptr;
528 };
529
530 } // namespace myrocks
531