1 /*
2    Copyright (c) 2018, Facebook, Inc.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 
17 #pragma once
18 
19 // C++ standard header files
20 #include <string>
21 #include <vector>
22 
23 // MySQL header files
24 #include "handler.h"  // handler
25 #include "ib_ut0counter.h"
26 #include "my_global.h"  // ulonglong
27 #include "sql_string.h"
28 
29 // MyRocks header files
30 #include "./ha_rocksdb.h"
31 #include "./rdb_datadic.h"
32 
33 namespace myrocks {
34 class Rdb_field_encoder;
35 
36 /**
37   Describes instructions on how to decode the field for value slice
38 */
39 struct READ_FIELD {
40   // Points to Rdb_field_encoder describing the field
41   Rdb_field_encoder *m_field_enc;
42   // if true, decode the field, otherwise skip it
43   bool m_decode;
44   // Skip this many bytes before reading (or skipping) this field
45   int m_skip;
46 };
47 
48 /**
49  Class to convert rocksdb value slice from storage format to mysql record
50  format.
51 */
52 class Rdb_convert_to_record_value_decoder {
53  public:
54   Rdb_convert_to_record_value_decoder() = delete;
55   Rdb_convert_to_record_value_decoder(
56       const Rdb_convert_to_record_value_decoder &decoder) = delete;
57   Rdb_convert_to_record_value_decoder &operator=(
58       const Rdb_convert_to_record_value_decoder &decoder) = delete;
59 
60   static int decode(uchar *const buf, TABLE *table,
61                     Rdb_field_encoder *field_dec, Rdb_string_reader *reader,
62                     bool decode, bool is_null);
63 
64  private:
65   static int decode_blob(TABLE *table, uchar *const buf,
66                          Rdb_field_encoder *field_dec,
67                          Rdb_string_reader *reader, bool decode);
68   static int decode_fixed_length_field(uchar *const buf,
69                                        Rdb_field_encoder *field_dec,
70                                        Rdb_string_reader *const reader,
71                                        bool decode);
72 
73   static int decode_varchar(uchar *const buf, Rdb_field_encoder *field_dec,
74                             Rdb_string_reader *const reader, bool decode);
75 };
76 
77 /**
78   Class to iterator fields in RocksDB value slice
79   A template class instantiation represent a way to decode the data.
80   The reason to use template class instead of normal class is to elimate
81   virtual method call.
82 */
83 template <typename value_field_decoder>
84 class Rdb_value_field_iterator {
85  private:
86   bool m_is_null;
87   std::vector<READ_FIELD>::const_iterator m_field_iter;
88   std::vector<READ_FIELD>::const_iterator m_field_end;
89   Rdb_string_reader *m_value_slice_reader;
90   // null value map
91   const char *m_null_bytes;
92   // The current open table
93   TABLE *m_table;
94   // The current field
95   Field *m_field;
96   Rdb_field_encoder *m_field_dec;
97   uchar *const m_buf;
98   uint m_offset;
99 
100  public:
101   Rdb_value_field_iterator(TABLE *table, Rdb_string_reader *value_slice_reader,
102                            const Rdb_converter *rdb_converter,
103                            uchar *const buf);
104   Rdb_value_field_iterator(const Rdb_value_field_iterator &field_iterator) =
105       delete;
106   Rdb_value_field_iterator &operator=(
107       const Rdb_value_field_iterator &field_iterator) = delete;
108 
109   /*
110     Move and decode next field
111     Run next() before accessing data
112   */
113   int next();
114   // Whether current field is the end of fields
115   bool end_of_fields() const;
116   void *get_dst() const;
117   // Whether the value of current field is null
118   bool is_null() const;
119   // get current field index
120   int get_field_index() const;
121   // get current field type
122   enum_field_types get_field_type() const;
123 };
124 
125 /**
126   Class to convert Mysql formats to rocksdb storage format, and vice versa.
127 */
128 class Rdb_converter {
129  public:
130   /*
131     Initialize converter with table data
132   */
133   Rdb_converter(const THD *thd, const Rdb_tbl_def *tbl_def, TABLE *table);
134   Rdb_converter(const Rdb_converter &decoder) = delete;
135   Rdb_converter &operator=(const Rdb_converter &decoder) = delete;
136   ~Rdb_converter();
137 
138   void setup_field_decoders(const MY_BITMAP *field_map, uint active_index,
139                             bool keyread_only, bool decode_all_fields = false);
140 
141   int decode(const std::shared_ptr<Rdb_key_def> &key_def, uchar *dst,
142              const rocksdb::Slice *key_slice, const rocksdb::Slice *value_slice,
143              bool decode_value = true);
144 
145   int encode_value_slice(const std::shared_ptr<Rdb_key_def> &pk_def,
146                          const rocksdb::Slice &pk_packed_slice,
147                          Rdb_string_writer *pk_unpack_info, bool is_update_row,
148                          bool store_row_debug_checksums, char *ttl_bytes,
149                          bool *is_ttl_bytes_updated,
150                          rocksdb::Slice *const value_slice);
151 
get_row_checksums_checked()152   my_core::ha_rows get_row_checksums_checked() const {
153     return m_row_checksums_checked;
154   }
get_verify_row_debug_checksums()155   bool get_verify_row_debug_checksums() const {
156     return m_verify_row_debug_checksums;
157   }
set_verify_row_debug_checksums(bool verify_row_debug_checksums)158   void set_verify_row_debug_checksums(bool verify_row_debug_checksums) {
159     m_verify_row_debug_checksums = verify_row_debug_checksums;
160   }
161 
get_encoder_arr()162   const Rdb_field_encoder *get_encoder_arr() const { return m_encoder_arr; }
get_null_bytes_in_record()163   int get_null_bytes_in_record() { return m_null_bytes_length_in_record; }
get_null_bytes()164   const char *get_null_bytes() const { return m_null_bytes; }
set_is_key_requested(bool key_requested)165   void set_is_key_requested(bool key_requested) {
166     m_key_requested = key_requested;
167   }
get_maybe_unpack_info()168   bool get_maybe_unpack_info() const { return m_maybe_unpack_info; }
169 
get_ttl_bytes_buffer()170   char *get_ttl_bytes_buffer() { return m_ttl_bytes; }
171 
get_decode_fields()172   const std::vector<READ_FIELD> *get_decode_fields() const {
173     return &m_decoders_vect;
174   }
175 
get_lookup_bitmap()176   const MY_BITMAP *get_lookup_bitmap() { return &m_lookup_bitmap; }
177 
178  private:
179   int decode_value_header(Rdb_string_reader *reader,
180                           const std::shared_ptr<Rdb_key_def> &pk_def,
181                           rocksdb::Slice *unpack_slice);
182 
183   void setup_field_encoders();
184 
185   void get_storage_type(Rdb_field_encoder *const encoder, const uint kp);
186 
187   int convert_record_from_storage_format(
188       const std::shared_ptr<Rdb_key_def> &pk_def,
189       const rocksdb::Slice *const key, const rocksdb::Slice *const value,
190       uchar *const buf, bool decode_value = true);
191 
192   int verify_row_debug_checksum(const std::shared_ptr<Rdb_key_def> &pk_def,
193                                 Rdb_string_reader *reader,
194                                 const rocksdb::Slice *key,
195                                 const rocksdb::Slice *value);
196 
197  private:
198   /*
199     This tells if any field which is part of the key needs to be unpacked and
200     decoded.
201   */
202   bool m_key_requested;
203   /*
204    Controls whether verifying checksums during reading, This is updated from
205   the session variable at the start of each query.
206   */
207   bool m_verify_row_debug_checksums;
208   // Thread handle
209   const THD *m_thd;
210   /* MyRocks table definition*/
211   const Rdb_tbl_def *m_tbl_def;
212   /* The current open table */
213   TABLE *m_table;
214   /*
215     Number of bytes in on-disk (storage) record format that are used for
216     storing SQL NULL flags.
217   */
218   int m_null_bytes_length_in_record;
219   /*
220     Pointer to null bytes value
221   */
222   const char *m_null_bytes;
223   /*
224    TRUE <=> Some fields in the PK may require unpack_info.
225   */
226   bool m_maybe_unpack_info;
227   /*
228     Pointer to the original TTL timestamp value (8 bytes) during UPDATE.
229   */
230   char m_ttl_bytes[ROCKSDB_SIZEOF_TTL_RECORD];
231   /*
232     Array of table->s->fields elements telling how to store fields in the
233     record.
234   */
235   Rdb_field_encoder *m_encoder_arr;
236   /*
237     Array of request fields telling how to decode data in RocksDB format
238   */
239   std::vector<READ_FIELD> m_decoders_vect;
240   /*
241     A counter of how many row checksums were checked for this table. Note that
242     this does not include checksums for secondary index entries.
243   */
244   my_core::ha_rows m_row_checksums_checked;
245   // buffer to hold data during encode_value_slice
246   String m_storage_record;
247   /*
248     For the active index, indicates which columns must be covered for the
249     current lookup to be covered. If the bitmap field is null, that means this
250     index does not cover the current lookup for any record.
251    */
252   MY_BITMAP m_lookup_bitmap;
253 };
254 }  // namespace myrocks
255