1 /* 2 * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. 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, version 2.0, 6 * as published by the Free Software Foundation. 7 * 8 * This program is also distributed with certain software (including 9 * but not limited to OpenSSL) that is licensed under separate terms, 10 * as designated in a particular file or component or in included license 11 * documentation. The authors of MySQL hereby grant you an additional 12 * permission to link the program and your derivative works with the 13 * separately licensed software that they have included with MySQL. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License, version 2.0, for more details. 19 * 20 * You should have received a copy of the GNU General Public License 21 * along with this program; if not, write to the Free Software 22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 23 */ 24 25 #ifndef PLUGIN_X_PROTOCOL_ENCODERS_ENCODING_PROTOBUF_H_ 26 #define PLUGIN_X_PROTOCOL_ENCODERS_ENCODING_PROTOBUF_H_ 27 28 #include <google/protobuf/wire_format_lite.h> 29 #include <cassert> 30 #include <cstdint> 31 #include <string> 32 33 #include "my_dbug.h" 34 35 #include "plugin/x/protocol/encoders/encoding_primitives.h" 36 37 namespace protocol { 38 39 class Delayed_fixed_varuint32 { 40 public: Delayed_fixed_varuint32()41 Delayed_fixed_varuint32() : m_out(nullptr) {} Delayed_fixed_varuint32(uint8_t * & out)42 explicit Delayed_fixed_varuint32(uint8_t *&out) : m_out(out) { out += 5; } 43 encode(const uint32_t value)44 void encode(const uint32_t value) const { 45 DBUG_ASSERT(m_out); 46 uint8_t *out = m_out; 47 primitives::base::Varint_length<5>::encode(out, value); 48 } 49 50 private: 51 uint8_t *m_out; 52 }; 53 54 /** 55 Class responsible for protobuf message serialization 56 57 The class is compatible with serializes supplied in libprotobuf and its 58 kept simple to be possible to run ubench on it. 59 The goal is to serialize the message payload into `Encoding_buffer class 60 with the constrain that "encode_*" method doesn't check if buffer sufficient 61 space inside it. Only following functions do that: 62 63 * encode_field_delimited_raw 64 * encode_field_string 65 66 the reason is that, those function can serialize large amount of data, and 67 other at most 20 bytes. 68 69 The user of this class should group together encode calls and check the space 70 before, for example: 71 72 ``` 73 ensure_buffer_size(100); 74 75 encode_field_bool<10>(true); 76 encode_field_bool<11>(true); 77 encode_field_var_sint32<12>(2238); 78 ... 79 ``` 80 81 User code should develop a method to check if the required size is sufficient 82 to serialize subsequent encode calls. 83 */ 84 class Protobuf_encoder : public Primitives_encoder { 85 private: 86 using Helper = primitives::base::Helper; 87 88 public: 89 /** 90 Check if output buffer has at last `size` bytes available. 91 92 If the current buffer page has less data the needed, 93 then next page should be acquired. 94 95 @tparam size required number of bytes 96 */ 97 template <uint32_t size> ensure_buffer_size()98 void ensure_buffer_size() { 99 // Static methods that check available size always must succeed 100 m_buffer->ensure_buffer_size<size>(); 101 m_page = m_buffer->m_current; 102 } 103 104 public: Protobuf_encoder(Encoding_buffer * buffer)105 explicit Protobuf_encoder(Encoding_buffer *buffer) 106 : Primitives_encoder(buffer) {} 107 108 /** 109 Function serializes a bool field. 110 111 User need to guarantee by calling `ensure_buffer_size` 112 that the buffer has at least 11 bytes (when its not checking 113 how long field entry is going to be generated by `field_id`). 114 */ 115 template <uint32_t field_id> encode_field_bool(const bool value)116 void encode_field_bool(const bool value) { 117 encode_const_var_uint<Helper::encode_field_tag( 118 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 119 encode_fixedvar8_uint8(value ? 1 : 0); 120 } 121 122 /** 123 Function serializes a varint32 field. 124 125 User need to guarantee by calling `ensure_buffer_size` 126 that the buffer has at least 15 bytes (when its not checking 127 how long field entry is going to be generated by `field_id`). 128 */ 129 template <uint32_t field_id> encode_field_var_uint32(const uint32_t value)130 void encode_field_var_uint32(const uint32_t value) { 131 encode_const_var_uint<Helper::encode_field_tag( 132 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 133 encode_var_uint32(value); 134 } 135 136 /** 137 Function serializes a varint32 field in case when `value` is not null. 138 139 User need to guarantee by calling `ensure_buffer_size` 140 that the buffer has at least 15 bytes (when its not checking 141 how long field entry is going to be generated by `field_id`). 142 */ 143 template <uint32_t field_id> encode_optional_field_var_uint32(const uint32_t * value)144 void encode_optional_field_var_uint32(const uint32_t *value) { 145 if (value) encode_field_var_uint32<field_id>(*value); 146 } 147 148 /** 149 Function serializes a varsint32 field. 150 151 User need to guarantee by calling `ensure_buffer_size` 152 that the buffer has at least 15 bytes (when its not checking 153 how long field entry is going to be generated by `field_id`). 154 */ 155 template <uint32_t field_id> encode_field_var_sint32(const int32_t value)156 void encode_field_var_sint32(const int32_t value) { 157 encode_const_var_uint<Helper::encode_field_tag( 158 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 159 encode_var_sint32(value); 160 } 161 162 /** 163 Function serializes a varsint32 field in case when `value` is not null. 164 165 User need to guarantee by calling `ensure_buffer_size` 166 that the buffer has at least 15 bytes (when its not checking 167 how long field entry is going to be generated by `field_id`). 168 */ 169 template <uint32_t field_id> encode_optiona_field_var_sint32(const int32_t * value)170 void encode_optiona_field_var_sint32(const int32_t *value) { 171 if (value) encode_field_var_sint32<field_id>(*value); 172 } 173 174 /** 175 Function serializes a varuint64 field. 176 177 User need to guarantee by calling `ensure_buffer_size` 178 that the buffer has at least 20 bytes (when its not checking 179 how long field entry is going to be generated by `field_id`). 180 */ 181 template <uint32_t field_id> encode_field_var_uint64(const uint64_t value)182 void encode_field_var_uint64(const uint64_t value) { 183 encode_const_var_uint<Helper::encode_field_tag( 184 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 185 encode_var_uint64(value); 186 } 187 188 /** 189 Function serializes a varuint64 field in case when `value` is not null. 190 191 User need to guarantee by calling `ensure_buffer_size` 192 that the buffer has at least 20 bytes (when its not checking 193 how long field entry is going to be generated by `field_id`). 194 */ 195 template <uint32_t field_id> encode_optional_field_var_uint64(const uint64_t * value)196 void encode_optional_field_var_uint64(const uint64_t *value) { 197 if (value) encode_field_var_uint64<field_id>(*value); 198 } 199 200 /** 201 Function serializes a varsint64 field. 202 203 User need to guarantee by calling `ensure_buffer_size` 204 that the buffer has at least 20 bytes (when its not checking 205 how long field entry is going to be generated by `field_id`). 206 */ 207 template <uint32_t field_id> encode_field_var_sint64(const int64_t value)208 void encode_field_var_sint64(const int64_t value) { 209 encode_const_var_uint<Helper::encode_field_tag( 210 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 211 encode_var_sint64(value); 212 } 213 214 /** 215 Function serializes a varsint64 field in case when `value` is not null. 216 217 User need to guarantee by calling `ensure_buffer_size` 218 that the buffer has at least 20 bytes (when its not checking 219 how long field entry is going to be generated by `field_id`). 220 */ 221 template <uint32_t field_id> encode_optional_field_var_sint64(const int64_t * value)222 void encode_optional_field_var_sint64(const int64_t *value) { 223 if (value) encode_field_var_sint64<field_id>(*value); 224 } 225 226 /** 227 Function serializes a varuint64 field using compile time informations. 228 229 User need to guarantee by calling `ensure_buffer_size` 230 that the buffer has at least 20 bytes (when its not checking 231 how long field entry is going to be generated by `field_id`). 232 */ 233 template <uint32_t field_id, uint64_t value> encode_field_const_var_uint()234 void encode_field_const_var_uint() { 235 encode_const_var_uint<Helper::encode_field_tag( 236 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 237 encode_const_var_uint<value>(); 238 } 239 240 /** 241 Function serializes a varsint64 field using compile time informations. 242 243 User need to guarantee by calling `ensure_buffer_size` 244 that the buffer has at least 20 bytes (when its not checking 245 how long field entry is going to be generated by `field_id`). 246 */ 247 template <uint32_t field_id, int64_t value> encode_field_const_var_int()248 void encode_field_const_var_int() { 249 encode_const_var_uint<Helper::encode_field_tag( 250 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 251 encode_const_var_sint<value>(); 252 } 253 254 /** 255 Function serializes a enum as varint32 field. 256 257 User need to guarantee by calling `ensure_buffer_size` 258 that the buffer has at least 15 bytes (when its not checking 259 how long field entry is going to be generated by `field_id`). 260 */ 261 template <uint32_t field_id> encode_field_enum(const int32_t value)262 void encode_field_enum(const int32_t value) { 263 DBUG_ASSERT(value >= 0); 264 265 encode_const_var_uint<Helper::encode_field_tag( 266 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 267 encode_var_uint32(static_cast<uint32_t>(value)); 268 } 269 270 /** 271 Function serializes a enum as varint32 field in case when `value` is not 272 null. 273 274 User need to guarantee by calling `ensure_buffer_size` 275 that the buffer has at least 15 bytes (when its not checking 276 how long field entry is going to be generated by `field_id`). 277 */ 278 template <uint32_t field_id> encode_optional_field_enum(const int32_t * value)279 void encode_optional_field_enum(const int32_t *value) { 280 if (value) encode_field_enum<field_id>(*value); 281 } 282 283 /** 284 Function serializes a enum as varsint64 field using compile time 285 informations. 286 287 User need to guarantee by calling `ensure_buffer_size` 288 that the buffer has at least 20 bytes (when its not checking 289 how long field entry is going to be generated by `field_id`). 290 */ 291 template <uint32_t field_id, int64_t value> encode_field_const_enum()292 void encode_field_const_enum() { 293 static_assert(value >= 0, 294 "This encoder doesn't support enum with negative values."); 295 encode_field_const_var_uint<field_id, value>(); 296 } 297 298 /** 299 Function serializes a field header using compile time informations. 300 301 User need to guarantee by calling `ensure_buffer_size` 302 that the buffer has at least 10 bytes (when its not checking 303 how long field entry is going to be generated by `field_id`). 304 305 This function requires that user will serialize manually the payload 306 of the field in subsequent call (with additional buffer size check). 307 */ 308 template <uint32_t field_id> encode_field_delimited_header()309 void encode_field_delimited_header() { 310 encode_const_var_uint<Helper::encode_field_tag( 311 field_id, Helper::WireType::WIRETYPE_LENGTH_DELIMITED)>(); 312 } 313 314 /** 315 Function serializes a raw data field. 316 317 Thus function is going to validated the buffer size on its own, 318 user doesn't need to call `ensure_buffer_size`. 319 */ 320 template <uint32_t field_id> encode_field_delimited_raw(const uint8_t * source,uint32_t source_size)321 void encode_field_delimited_raw(const uint8_t *source, uint32_t source_size) { 322 ensure_buffer_size<10 + 5>(); 323 encode_field_delimited_header<field_id>(); 324 encode_var_uint32(static_cast<uint32_t>(source_size)); 325 326 encode_raw(source, source_size); 327 } 328 329 /** 330 Function serializes a raw data field. 331 332 Thus function is going to validated the buffer size on its own, 333 user doesn't need to call `ensure_buffer_size`. 334 */ 335 template <uint32_t field_id> encode_field_string(const std::string & value)336 void encode_field_string(const std::string &value) { 337 encode_field_delimited_raw<field_id>( 338 reinterpret_cast<const uint8_t *>(value.c_str()), value.length()); 339 } 340 341 /** 342 Function serializes a raw data field. 343 344 Thus function is going to validated the buffer size on its own, 345 user doesn't need to call `ensure_buffer_size`. 346 */ 347 template <uint32_t field_id> encode_field_string(const char * value)348 void encode_field_string(const char *value) { 349 encode_field_delimited_raw<field_id>( 350 reinterpret_cast<const uint8_t *>(value), strlen(value)); 351 } 352 353 /** 354 Function serializes a raw data field. 355 356 Thus function is going to validated the buffer size on its own, 357 user doesn't need to call `ensure_buffer_size`. 358 */ 359 template <uint32_t field_id> encode_field_string(const char * value,const uint32_t length)360 void encode_field_string(const char *value, const uint32_t length) { 361 encode_field_delimited_raw<field_id>( 362 reinterpret_cast<const uint8_t *>(value), length); 363 } 364 365 /** 366 Function serializes that reserves space for integer varint with fixed size 367 368 Thus function is going to validated the buffer size on its own, 369 user doesn't need to call `ensure_buffer_size`. 370 */ 371 template <uint32_t field_id> encode_field_fixed_uint32()372 Delayed_fixed_varuint32 encode_field_fixed_uint32() { 373 encode_const_var_uint<Helper::encode_field_tag( 374 field_id, Helper::WireType::WIRETYPE_VARINT)>(); 375 376 return Delayed_fixed_varuint32(m_page->m_current_data); 377 } 378 }; 379 380 } // namespace protocol 381 382 #endif // PLUGIN_X_PROTOCOL_ENCODERS_ENCODING_PROTOBUF_H_ 383