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