common/binaryserializer.h (190 lines of code) (raw):

#ifndef __BINARY_SERIALIZER__ #define __BINARY_SERIALIZER__ #include "common/armhelper.h" #include "common/rediscommand.h" #include "common/table.h" #include <string> using namespace std; namespace swss { class BinarySerializer { public: static size_t serializedSize(const string &dbName, const string &tableName, const vector<KeyOpFieldsValuesTuple> &kcos) { size_t n = 0; n += dbName.size() + sizeof(size_t); n += tableName.size() + sizeof(size_t); for (const KeyOpFieldsValuesTuple &kco : kcos) { const vector<FieldValueTuple> &fvs = kfvFieldsValues(kco); n += kfvKey(kco).size() + sizeof(size_t); n += to_string(fvs.size()).size() + sizeof(size_t); for (const FieldValueTuple &fv : fvs) { n += fvField(fv).size() + sizeof(size_t); n += fvValue(fv).size() + sizeof(size_t); } } return n + sizeof(size_t); } static size_t serializeBuffer( const char* buffer, const size_t size, const std::string& dbName, const std::string& tableName, const std::vector<KeyOpFieldsValuesTuple>& kcos) { auto tmpSerializer = BinarySerializer(buffer, size); // Set the first pair as DB name and table name. tmpSerializer.setKeyAndValue( dbName.c_str(), dbName.length(), tableName.c_str(), tableName.length()); for (auto& kco : kcos) { auto& key = kfvKey(kco); auto& fvs = kfvFieldsValues(kco); std::string fvs_len = std::to_string(fvs.size()); // For each request, the first pair is the key and the number of attributes, // followed by the attribute pairs. // The operation is not set, when there is no attribute, it is a DEL request. tmpSerializer.setKeyAndValue( key.c_str(), key.length(), fvs_len.c_str(), fvs_len.length()); for (auto& fv : fvs) { auto& field = fvField(fv); auto& value = fvValue(fv); tmpSerializer.setKeyAndValue( field.c_str(), field.length(), value.c_str(), value.length()); } } return tmpSerializer.finalize(); } static void deserializeBuffer( const char* buffer, const size_t size, std::vector<swss::FieldValueTuple>& values) { WARNINGS_NO_CAST_ALIGN; auto pkvp_count = (const size_t*)buffer; WARNINGS_RESET; size_t kvp_count = *pkvp_count; auto tmp_buffer = buffer + sizeof(size_t); while (kvp_count > 0) { kvp_count--; // read key and value from buffer WARNINGS_NO_CAST_ALIGN; auto pkeylen = (const size_t*)tmp_buffer; WARNINGS_RESET; tmp_buffer += sizeof(size_t); if ((size_t)(tmp_buffer - buffer + *pkeylen) > size) { SWSS_LOG_THROW("serialized key data was truncated, key length: %zu, increase buffer size: %zu", *pkeylen, size); } auto pkey = string(tmp_buffer, *pkeylen); tmp_buffer += *pkeylen; WARNINGS_NO_CAST_ALIGN; auto pvallen = (const size_t*)tmp_buffer; WARNINGS_RESET; tmp_buffer += sizeof(size_t); if ((size_t)(tmp_buffer - buffer + *pvallen) > size) { SWSS_LOG_THROW("serialized value data was truncated,, value length: %zu increase buffer size: %zu", *pvallen, size); } auto pval = string(tmp_buffer, *pvallen); tmp_buffer += *pvallen; values.push_back(std::make_pair(pkey, pval)); } } static void deserializeBuffer( const char* buffer, const size_t size, std::string& dbName, std::string& tableName, std::vector<std::shared_ptr<KeyOpFieldsValuesTuple>>& kcos) { std::vector<FieldValueTuple> values; deserializeBuffer(buffer, size, values); int fvs_size = -1; KeyOpFieldsValuesTuple kco; auto& key = kfvKey(kco); auto& op = kfvOp(kco); auto& fvs = kfvFieldsValues(kco); for (auto& fv : values) { auto& field = fvField(fv); auto& value = fvValue(fv); // The first pair is the DB name and the table name. if (fvs_size < 0) { dbName = field; tableName = value; fvs_size = 0; continue; } // This is the beginning of a request. // The first pair is the key and the number of attributes. // If the attribute count is zero, it is a DEL request. if (fvs_size == 0) { key = field; fvs_size = std::stoi(value); op = (fvs_size == 0) ? DEL_COMMAND : SET_COMMAND; fvs.clear(); } // This is an attribut pair. else { fvs.push_back(fv); --fvs_size; } // We got the last attribut pair. This is the end of a request. if (fvs_size == 0) { kcos.push_back(std::make_shared<KeyOpFieldsValuesTuple>(kco)); } } } private: const char* m_buffer; const size_t m_buffer_size; char* m_current_position; size_t m_kvp_count; BinarySerializer(const char* buffer, const size_t size) : m_buffer(buffer), m_buffer_size(size) { resetSerializer(); } void resetSerializer() { m_current_position = const_cast<char*>(m_buffer) + sizeof(size_t); m_kvp_count = 0; } void setKeyAndValue(const char* key, size_t klen, const char* value, size_t vlen) { setData(key, klen); setData(value, vlen); m_kvp_count++; } size_t finalize() { // set key value pair count to message WARNINGS_NO_CAST_ALIGN; size_t* pkvp_count = (size_t*)const_cast<char*>(m_buffer); WARNINGS_RESET; *pkvp_count = m_kvp_count; // return size return m_current_position - m_buffer; } void setData(const char* data, size_t datalen) { if ((size_t)(m_current_position - m_buffer + datalen + sizeof(size_t)) > m_buffer_size) { SWSS_LOG_THROW("There are not enough buffer for binary serializer to serialize,\n" " key count: %zu, data length %zu, buffer size: %zu", m_kvp_count, datalen, m_buffer_size); } WARNINGS_NO_CAST_ALIGN; size_t* pdatalen = (size_t*)m_current_position; WARNINGS_RESET; *pdatalen = datalen; m_current_position += sizeof(size_t); memcpy(m_current_position, data, datalen); m_current_position += datalen; } }; } #endif