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