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