From a78db9ee0508a93b0b011c046eb6ea2bf8f09fbb Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 26 Dec 2022 17:33:09 +0300 Subject: [PATCH 01/15] Compact schema distribution on write is implemented. hazelcast-enterprise-VERSION-tests.jar is downloaded from private-test-artifacts repo. Enterprise tests are added to CLASSPATH rc-bat corrected. --- examples/serialization/CMakeLists.txt | 1 + examples/serialization/compact/CMakeLists.txt | 16 + examples/serialization/compact/main.cpp | 86 + .../client/protocol/codec/codecs.cpp | 27 + .../hazelcast/client/protocol/codec/codecs.h | 12 + .../impl/hazelcast_client_instance_impl.h | 2 + .../hazelcast/client/protocol/ClientMessage.h | 49 + .../client/serialization/field_kind.h | 76 + .../pimpl/{ => compact}/compact.h | 160 +- .../{compact.i.h => compact/compact_impl.h} | 123 +- .../pimpl/compact/default_schema_service.h | 79 + .../pimpl/compact/field_descriptor.h | 73 + .../serialization/pimpl/compact/schema.h | 65 + .../client/serialization/pimpl/data.h | 9 +- .../client/serialization/serialization.h | 19 +- .../hazelcast/client/spi/ClientContext.h | 3 + .../client/spi/impl/ClientInvocation.h | 6 + .../src/hazelcast/client/client_impl.cpp | 4 +- hazelcast/src/hazelcast/client/compact.cpp | 723 ++++++--- hazelcast/src/hazelcast/client/protocol.cpp | 6 + .../src/hazelcast/client/serialization.cpp | 15 +- hazelcast/src/hazelcast/client/spi.cpp | 88 +- hazelcast/test/resources/compact.xml | 5 + hazelcast/test/src/ClientTest.cpp | 11 +- hazelcast/test/src/ClientTest.h | 1 - hazelcast/test/src/HazelcastTests2.cpp | 78 +- hazelcast/test/src/HazelcastTests8.cpp | 3 +- hazelcast/test/src/TestHelperFunctions.h | 24 + hazelcast/test/src/compact/compact_helper.h | 62 + ...nullable_primitive_interoperability_test.h | 184 +++ .../compact/compact_rabin_fingerprint_test.h | 119 ++ ...compact_schema_replication_on_write_test.h | 59 + .../compact_schema_replication_stress_test.h | 140 ++ .../test/src/compact/compact_schema_test.h | 271 ++++ .../compact/compact_schema_validation_test.h | 154 ++ .../src/compact/compact_serialization_test.h | 156 ++ .../test/src/compact/compact_test_base.h | 121 ++ .../test/src/compact/serialization/a_type.h | 65 + .../test/src/compact/serialization/bits_dto.h | 97 ++ .../src/compact/serialization/employee_dto.h | 72 + .../compact/serialization/empty_main_dto.h | 57 + .../src/compact/serialization/inner_dto.h | 241 +++ .../test/src/compact/serialization/main_dto.h | 191 +++ .../src/compact/serialization/named_dto.h | 66 + .../src/compact/serialization/nested_type.h | 61 + .../test/src/compact/serialization/node_dto.h | 75 + .../serialization/nullable_primitive_object.h | 106 ++ .../compact/serialization/primitive_object.h | 98 ++ .../src/compact/serialization/stress_type.h | 56 + .../compact/serialization/type_mismatch_obj.h | 59 + .../serialization/wrong_field_name_read_obj.h | 60 + hazelcast/test/src/compact_test.cpp | 1432 +---------------- scripts/start-rc.bat | 18 +- scripts/start-rc.sh | 23 +- 54 files changed, 3874 insertions(+), 1933 deletions(-) create mode 100644 examples/serialization/compact/CMakeLists.txt create mode 100644 examples/serialization/compact/main.cpp create mode 100644 hazelcast/include/hazelcast/client/serialization/field_kind.h rename hazelcast/include/hazelcast/client/serialization/pimpl/{ => compact}/compact.h (92%) rename hazelcast/include/hazelcast/client/serialization/pimpl/{compact.i.h => compact/compact_impl.h} (86%) create mode 100644 hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h create mode 100644 hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h create mode 100644 hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h create mode 100644 hazelcast/test/resources/compact.xml create mode 100644 hazelcast/test/src/compact/compact_helper.h create mode 100644 hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h create mode 100644 hazelcast/test/src/compact/compact_rabin_fingerprint_test.h create mode 100644 hazelcast/test/src/compact/compact_schema_replication_on_write_test.h create mode 100644 hazelcast/test/src/compact/compact_schema_replication_stress_test.h create mode 100644 hazelcast/test/src/compact/compact_schema_test.h create mode 100644 hazelcast/test/src/compact/compact_schema_validation_test.h create mode 100644 hazelcast/test/src/compact/compact_serialization_test.h create mode 100644 hazelcast/test/src/compact/compact_test_base.h create mode 100644 hazelcast/test/src/compact/serialization/a_type.h create mode 100644 hazelcast/test/src/compact/serialization/bits_dto.h create mode 100644 hazelcast/test/src/compact/serialization/employee_dto.h create mode 100644 hazelcast/test/src/compact/serialization/empty_main_dto.h create mode 100644 hazelcast/test/src/compact/serialization/inner_dto.h create mode 100644 hazelcast/test/src/compact/serialization/main_dto.h create mode 100644 hazelcast/test/src/compact/serialization/named_dto.h create mode 100644 hazelcast/test/src/compact/serialization/nested_type.h create mode 100644 hazelcast/test/src/compact/serialization/node_dto.h create mode 100644 hazelcast/test/src/compact/serialization/nullable_primitive_object.h create mode 100644 hazelcast/test/src/compact/serialization/primitive_object.h create mode 100644 hazelcast/test/src/compact/serialization/stress_type.h create mode 100644 hazelcast/test/src/compact/serialization/type_mismatch_obj.h create mode 100644 hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h diff --git a/examples/serialization/CMakeLists.txt b/examples/serialization/CMakeLists.txt index 51797ce89b..c3bd6be2e2 100644 --- a/examples/serialization/CMakeLists.txt +++ b/examples/serialization/CMakeLists.txt @@ -19,3 +19,4 @@ add_subdirectory(custom) add_subdirectory(globalserializer) add_subdirectory(json) add_subdirectory(mixed-type-collection) +add_subdirectory(compact) diff --git a/examples/serialization/compact/CMakeLists.txt b/examples/serialization/compact/CMakeLists.txt new file mode 100644 index 0000000000..dfed0e4349 --- /dev/null +++ b/examples/serialization/compact/CMakeLists.txt @@ -0,0 +1,16 @@ +# +# Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +add_executable(compact ./main.cpp) \ No newline at end of file diff --git a/examples/serialization/compact/main.cpp b/examples/serialization/compact/main.cpp new file mode 100644 index 0000000000..9e0051d59b --- /dev/null +++ b/examples/serialization/compact/main.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include +#include +#include + +struct PersonDTO +{ + std::string name; + std::string surname; + int32_t age; +}; + +std::ostream& +operator<<(std::ostream& os, const PersonDTO& person) +{ + os << "name: " << person.name << " surname: " << person.surname + << " age: " << person.age; + + return os; +} + +namespace hazelcast { +namespace client { +namespace serialization { + +template<> +struct hz_serializer : compact_serializer +{ + static void write(const PersonDTO& object, compact_writer& out) + { + out.write_int32("age", object.age); + out.write_string("name", object.name); + out.write_string("surname", object.surname); + } + + static PersonDTO read(compact_reader& in) + { + PersonDTO person; + + person.age = in.read_int32("age"); + person.name = *in.read_string("name"); + person.surname = *in.read_string("surname"); + + return person; + } + + static std::string type_name() { return "person"; } +}; + +} // namespace serialization +} // namespace client +} // namespace hazelcast + +/** + * This example demonstrates how to use a type with compact serialization. +*/ +int +main() +{ + auto hz = hazelcast::new_client().get(); + auto map = hz.get_map("map").get(); + + map->put("Peter", PersonDTO{ "Peter", "Stone", 45 }).get(); + auto person = + map->get(std::string{ "Peter" }).get(); + + std::cout << person << std::endl; + + std::cout << "Finished" << std::endl; + + return 0; +} \ No newline at end of file diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp index 353f04c871..706111de39 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp @@ -16,6 +16,7 @@ #include #include "hazelcast/client/member.h" +#include "hazelcast/client/serialization/pimpl/compact/schema.h" #include "hazelcast/logger.h" #include "codecs.h" @@ -5787,6 +5788,32 @@ sql_fetch_encode(const sql::impl::query_id& query_id, return msg; } +ClientMessage +send_schema_request_encode(const serialization::pimpl::schema& sch) +{ + static constexpr int32_t MESSAGE_TYPE = 4864; // 0x001300 + static constexpr size_t INITIAL_FRAME_SIZE = + ClientMessage::REQUEST_HEADER_LEN; + + ClientMessage msg{ INITIAL_FRAME_SIZE }; + msg.set_retryable(true); + msg.set_operation_name("Client.SendSchema"); + + msg.set_message_type(MESSAGE_TYPE); + msg.set_partition_id(-1); + + msg.set(sch, true); + + return msg; +} + +std::vector +send_schema_response_decode(ClientMessage& m) +{ + m.skip_frame(); + return m.get>(); +} + } // namespace codec } // namespace protocol } // namespace client diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h index 46318cd630..c0be339204 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h @@ -3079,6 +3079,18 @@ ClientMessage HAZELCAST_API sql_fetch_encode(const sql::impl::query_id& query_id, int32_t cursor_buffer_size); +/** + * Replicates schema on cluster + */ +ClientMessage HAZELCAST_API +send_schema_request_encode(const serialization::pimpl::schema& sch); + +/** + * Decodes response of send schema request + */ +std::vector HAZELCAST_API +send_schema_response_decode(ClientMessage&); + } // namespace codec } // namespace protocol } // namespace client diff --git a/hazelcast/include/hazelcast/client/impl/hazelcast_client_instance_impl.h b/hazelcast/include/hazelcast/client/impl/hazelcast_client_instance_impl.h index e7907bd066..acdff08842 100644 --- a/hazelcast/include/hazelcast/client/impl/hazelcast_client_instance_impl.h +++ b/hazelcast/include/hazelcast/client/impl/hazelcast_client_instance_impl.h @@ -56,6 +56,7 @@ #include "hazelcast/cp/cp_impl.h" #include "hazelcast/logger.h" #include "hazelcast/client/sql/sql_service.h" +#include "hazelcast/client/serialization/pimpl/compact/compact.h" #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(push) @@ -225,6 +226,7 @@ class HAZELCAST_API hazelcast_client_instance_impl client_config client_config_; client_properties client_properties_; spi::ClientContext client_context_; + serialization::pimpl::default_schema_service schema_service_; serialization::pimpl::SerializationService serialization_service_; std::shared_ptr connection_manager_; diff --git a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h index 462ea85b06..e000d592f0 100644 --- a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h +++ b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include @@ -47,6 +49,8 @@ #include "hazelcast/client/sql/impl/sql_error.h" #include "hazelcast/client/sql/sql_column_type.h" #include "hazelcast/client/protocol/codec/builtin/custom_type_factory.h" +#include "hazelcast/client/serialization/pimpl/compact/schema.h" +#include "hazelcast/client/serialization/pimpl/compact/field_descriptor.h" namespace hazelcast { namespace util { @@ -1207,6 +1211,10 @@ class HAZELCAST_API ClientMessage header->flags = is_final ? IS_FINAL_FLAG : DEFAULT_FLAGS; std::memcpy( fp + SIZE_OF_FRAME_LENGTH_AND_FLAGS, &bytes[0], bytes.size()); + + copy(begin(value.schemas_will_be_replicated()), + end(value.schemas_will_be_replicated()), + back_inserter(schemas_will_be_replicated_)); } inline void set(const serialization::pimpl::data* value, @@ -1284,6 +1292,44 @@ class HAZELCAST_API ClientMessage add_end_frame(is_final); } + void set(const serialization::pimpl::field_descriptor& descriptor, + const std::string& field_name, + bool is_final = false) + { + add_begin_frame(); + + set(frame_header_type{ SIZE_OF_FRAME_LENGTH_AND_FLAGS + INT32_SIZE, + DEFAULT_FLAGS }); + set(int32_t(descriptor.kind)); + set(field_name); + + add_end_frame(is_final); + } + + void set(const serialization::pimpl::schema& s, bool is_final = false) + { + add_begin_frame(); + + set(s.type_name()); + + { // Fields list + add_begin_frame(); + + for (const auto& p : s.fields()) { + const std::string& field_name{ p.first }; + const serialization::pimpl::field_descriptor& descriptor{ + p.second + }; + + set(descriptor, field_name, false); + } + + add_end_frame(false); + } + + add_end_frame(is_final); + } + //----- Setter methods end --------------------- //----- utility methods ------------------- @@ -1342,6 +1388,8 @@ class HAZELCAST_API ClientMessage } void fast_forward_to_end_frame(); + const std::vector& + schemas_will_be_replicated() const; static const frame_header_type& null_frame(); static const frame_header_type& begin_frame(); @@ -1446,6 +1494,7 @@ class HAZELCAST_API ClientMessage std::vector> data_buffer_; size_t buffer_index_{ 0 }; size_t offset_{ 0 }; + std::vector schemas_will_be_replicated_; }; template<> diff --git a/hazelcast/include/hazelcast/client/serialization/field_kind.h b/hazelcast/include/hazelcast/client/serialization/field_kind.h new file mode 100644 index 0000000000..3232d7d890 --- /dev/null +++ b/hazelcast/include/hazelcast/client/serialization/field_kind.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace hazelcast { +namespace client { +namespace serialization { + +enum class HAZELCAST_API field_kind +{ + BOOLEAN = 1, + ARRAY_OF_BOOLEAN = 2, + INT8 = 3, + ARRAY_OF_INT8 = 4, + INT16 = 7, + ARRAY_OF_INT16 = 8, + INT32 = 9, + ARRAY_OF_INT32 = 10, + INT64 = 11, + ARRAY_OF_INT64 = 12, + FLOAT32 = 13, + ARRAY_OF_FLOAT32 = 14, + FLOAT64 = 15, + ARRAY_OF_FLOAT64 = 16, + STRING = 17, + ARRAY_OF_STRING = 18, + DECIMAL = 19, + ARRAY_OF_DECIMAL = 20, + TIME = 21, + ARRAY_OF_TIME = 22, + DATE = 23, + ARRAY_OF_DATE = 24, + TIMESTAMP = 25, + ARRAY_OF_TIMESTAMP = 26, + TIMESTAMP_WITH_TIMEZONE = 27, + ARRAY_OF_TIMESTAMP_WITH_TIMEZONE = 28, + COMPACT = 29, + ARRAY_OF_COMPACT = 30, + NULLABLE_BOOLEAN = 33, + ARRAY_OF_NULLABLE_BOOLEAN = 34, + NULLABLE_INT8 = 35, + ARRAY_OF_NULLABLE_INT8 = 36, + NULLABLE_INT16 = 37, + ARRAY_OF_NULLABLE_INT16 = 38, + NULLABLE_INT32 = 39, + ARRAY_OF_NULLABLE_INT32 = 40, + NULLABLE_INT64 = 41, + ARRAY_OF_NULLABLE_INT64 = 42, + NULLABLE_FLOAT32 = 43, + ARRAY_OF_NULLABLE_FLOAT32 = 44, + NULLABLE_FLOAT64 = 45, + ARRAY_OF_NULLABLE_FLOAT64 = 46 +}; + +std::ostream HAZELCAST_API & +operator<<(std::ostream&, field_kind); + +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h similarity index 92% rename from hazelcast/include/hazelcast/client/serialization/pimpl/compact.h rename to hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h index b4502d5b3c..df2749c197 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h @@ -24,6 +24,8 @@ #include "hazelcast/util/export.h" #include "hazelcast/client/serialization/serialization.h" #include "hazelcast/util/SynchronizedMap.h" +#include "hazelcast/client/serialization/field_kind.h" +#include "hazelcast/client/serialization/pimpl/compact/default_schema_service.h" #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(push) @@ -32,6 +34,10 @@ namespace hazelcast { namespace client { +namespace spi { +class ClientContext; +} + namespace serialization { class compact_reader; class compact_writer; @@ -49,53 +55,6 @@ create_compact_reader( object_data_input& object_data_input, const pimpl::schema& schema); struct field_descriptor; -enum HAZELCAST_API field_kind -{ - BOOLEAN = 0, - ARRAY_OF_BOOLEAN = 1, - INT8 = 2, - ARRAY_OF_INT8 = 3, - INT16 = 6, - ARRAY_OF_INT16 = 7, - INT32 = 8, - ARRAY_OF_INT32 = 9, - INT64 = 10, - ARRAY_OF_INT64 = 11, - FLOAT32 = 12, - ARRAY_OF_FLOAT32 = 13, - FLOAT64 = 14, - ARRAY_OF_FLOAT64 = 15, - STRING = 16, - ARRAY_OF_STRING = 17, - DECIMAL = 18, - ARRAY_OF_DECIMAL = 19, - TIME = 20, - ARRAY_OF_TIME = 21, - DATE = 22, - ARRAY_OF_DATE = 23, - TIMESTAMP = 24, - ARRAY_OF_TIMESTAMP = 25, - TIMESTAMP_WITH_TIMEZONE = 26, - ARRAY_OF_TIMESTAMP_WITH_TIMEZONE = 27, - COMPACT = 28, - ARRAY_OF_COMPACT = 29, - NULLABLE_BOOLEAN = 32, - ARRAY_OF_NULLABLE_BOOLEAN = 33, - NULLABLE_INT8 = 34, - ARRAY_OF_NULLABLE_INT8 = 35, - NULLABLE_INT16 = 36, - ARRAY_OF_NULLABLE_INT16 = 37, - NULLABLE_INT32 = 38, - ARRAY_OF_NULLABLE_INT32 = 39, - NULLABLE_INT64 = 40, - ARRAY_OF_NULLABLE_INT64 = 41, - NULLABLE_FLOAT32 = 42, - ARRAY_OF_NULLABLE_FLOAT32 = 43, - NULLABLE_FLOAT64 = 44, - ARRAY_OF_NULLABLE_FLOAT64 = 45, -}; -static const int NUMBER_OF_FIELD_KINDS = ARRAY_OF_NULLABLE_FLOAT64 + 1; - } // namespace pimpl /** @@ -633,24 +592,23 @@ class HAZELCAST_API compact_reader const pimpl::schema& schema); template T read_primitive(const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind, + field_kind kind, + field_kind nullable_kind, const std::string& method_suffix); template T read_primitive(const pimpl::field_descriptor& field_descriptor); - bool is_field_exists(const std::string& field_name, - enum pimpl::field_kind kind) const; + bool is_field_exists(const std::string& field_name, field_kind kind) const; const pimpl::field_descriptor& get_field_descriptor( const std::string& field_name) const; const pimpl::field_descriptor& get_field_descriptor( const std::string& field_name, - enum pimpl::field_kind field_kind) const; + field_kind field_kind) const; template boost::optional read_variable_size( const pimpl::field_descriptor& field_descriptor); template boost::optional read_variable_size(const std::string& field_name, - enum pimpl::field_kind field_kind); + field_kind field_kind); template T read_variable_size_as_non_null( const pimpl::field_descriptor& field_descriptor, @@ -711,8 +669,8 @@ class HAZELCAST_API compact_reader template boost::optional read_array_of_primitive( const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind, + field_kind kind, + field_kind nullable_kind, const std::string& method_suffix); template boost::optional>> @@ -729,15 +687,14 @@ class HAZELCAST_API compact_reader static const offset_func SHORT_OFFSET_READER; static const offset_func INT_OFFSET_READER; template - boost::optional read_nullable_primitive( - const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind); + boost::optional read_nullable_primitive(const std::string& field_name, + field_kind kind, + field_kind nullable_kind); template boost::optional>> read_array_of_nullable( const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind); + field_kind kind, + field_kind nullable_kind); template boost::optional>> read_primitive_array_as_nullable_array( @@ -751,7 +708,7 @@ class HAZELCAST_API compact_reader exception::hazelcast_serialization unknown_field( const std::string& field_name) const; exception::hazelcast_serialization unexpected_field_kind( - enum pimpl::field_kind field_kind, + field_kind kind, const std::string& field_name) const; static exception::hazelcast_serialization unexpected_null_value( const std::string& field_name, @@ -1405,55 +1362,6 @@ class HAZELCAST_API default_compact_writer std::vector field_offsets; }; -struct HAZELCAST_API field_descriptor -{ - field_descriptor(enum field_kind f = static_cast(-1), - int32_t i = -1, - int32_t o = -1, - int8_t b = -1); - - enum field_kind field_kind; - /** - * Index of the offset of the non-primitive field. For others, it is -1 - */ - int32_t index; - /** - * Applicable only for primitive fields. For others, it is -1 - */ - int32_t offset; - /** - * Applicable only for boolean field. For others, it is -1 - */ - int8_t bit_offset; -}; - -std::ostream& -operator<<(std::ostream& os, const field_descriptor& field_descriptor); - -class HAZELCAST_API schema -{ -public: - schema() = default; - schema( - std::string type_name, - std::unordered_map&& field_definition_map); - int64_t schema_id() const; - size_t number_of_var_size_fields() const; - size_t fixed_size_fields_length() const; - const std::string& type_name() const; - const std::unordered_map& fields() const; - -private: - std::string type_name_; - std::unordered_map field_definition_map_; - size_t number_of_var_size_fields_{}; - size_t fixed_size_fields_length_{}; - int64_t schema_id_{}; -}; - -std::ostream& -operator<<(std::ostream& os, const schema& schema); - } // namespace pimpl namespace pimpl { @@ -1469,33 +1377,11 @@ class HAZELCAST_API schema_writer std::string type_name; }; -/** - * Service to put and get metadata to cluster. - */ -class HAZELCAST_API default_schema_service -{ -public: - /** - * Gets the schema with the given id either by - *
    - *
  • returning it directly from the local registry, if it exists.
  • - *
  • searching the cluster.
  • - *
- */ - schema get(int64_t schemaId); - - /** - * Puts the schema with the given id to the cluster. - */ - void put(const schema& schema); - -private: - util::SynchronizedMap schemas; -}; - class HAZELCAST_API compact_stream_serializer { public: + compact_stream_serializer(default_schema_service&); + template T read(object_data_input& in); @@ -1503,9 +1389,7 @@ class HAZELCAST_API compact_stream_serializer void write(const T& object, object_data_output& out); private: - void put_to_schema_service(const schema& schema); - - default_schema_service schema_service; + default_schema_service& schema_service; }; struct HAZELCAST_API field_kind_based_operations diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact.i.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h similarity index 86% rename from hazelcast/include/hazelcast/client/serialization/pimpl/compact.i.h rename to hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h index e513ecd085..e1dc23a71e 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact.i.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h @@ -15,7 +15,7 @@ */ #pragma once -#include "hazelcast/client/serialization/pimpl/compact.h" +#include "hazelcast/client/serialization/pimpl/compact/compact.h" #include "hazelcast/util/finally.h" #include "hazelcast/util/IOUtil.h" #include @@ -57,15 +57,15 @@ get_offset(serialization::object_data_input& in, template T compact_reader::read_primitive(const std::string& field_name, - enum pimpl::field_kind primitive_field_kind, - enum pimpl::field_kind nullable_field_kind, + field_kind primitive, + field_kind nullable, const std::string& method_suffix) { const auto& fd = get_field_descriptor(field_name); - const auto& field_kind = fd.field_kind; - if (field_kind == primitive_field_kind) { + const auto& field_kind = fd.kind; + if (field_kind == primitive) { return read_primitive(fd); - } else if (field_kind == nullable_field_kind) { + } else if (field_kind == nullable) { return read_variable_size_as_non_null(fd, field_name, method_suffix); } else { BOOST_THROW_EXCEPTION(unexpected_field_kind(field_kind, field_name)); @@ -111,9 +111,9 @@ compact_reader::read_variable_size( template boost::optional compact_reader::read_variable_size(const std::string& field_name, - enum pimpl::field_kind field_kind) + field_kind kind) { - auto field_descriptor = get_field_descriptor(field_name, field_kind); + auto field_descriptor = get_field_descriptor(field_name, kind); return read_variable_size(field_descriptor); } @@ -237,20 +237,19 @@ compact_reader::read() template boost::optional -compact_reader::read_array_of_primitive( - const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind, - const std::string& method_suffix) +compact_reader::read_array_of_primitive(const std::string& field_name, + field_kind kind, + field_kind nullable_kind, + const std::string& method_suffix) { auto& field_descriptor = get_field_descriptor(field_name); - if (field_descriptor.field_kind == field_kind) { + if (field_descriptor.kind == kind) { return read_variable_size(field_descriptor); - } else if (field_descriptor.field_kind == nullable_field_kind) { + } else if (field_descriptor.kind == nullable_kind) { return read_nullable_array_as_primitive_array( field_descriptor, field_name, method_suffix); } - throw unexpected_field_kind(field_descriptor.field_kind, field_name); + throw unexpected_field_kind(field_descriptor.kind, field_name); } template @@ -317,34 +316,32 @@ compact_reader::read_nullable_array_as_primitive_array( template boost::optional -compact_reader::read_nullable_primitive( - const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind) +compact_reader::read_nullable_primitive(const std::string& field_name, + field_kind kind, + field_kind nullable_kind) { auto& field_descriptor = get_field_descriptor(field_name); - if (field_descriptor.field_kind == field_kind) { + if (field_descriptor.kind == kind) { return boost::make_optional(read_primitive(field_descriptor)); - } else if (field_descriptor.field_kind == nullable_field_kind) { + } else if (field_descriptor.kind == nullable_kind) { return read_variable_size(field_descriptor); } - throw unexpected_field_kind(field_descriptor.field_kind, field_name); + throw unexpected_field_kind(field_descriptor.kind, field_name); } template boost::optional>> -compact_reader::read_array_of_nullable( - const std::string& field_name, - enum pimpl::field_kind field_kind, - enum pimpl::field_kind nullable_field_kind) +compact_reader::read_array_of_nullable(const std::string& field_name, + field_kind kind, + field_kind nullable_kind) { auto& field_descriptor = get_field_descriptor(field_name); - if (field_descriptor.field_kind == field_kind) { + if (field_descriptor.kind == kind) { return read_primitive_array_as_nullable_array(field_descriptor); - } else if (field_descriptor.field_kind == nullable_field_kind) { + } else if (field_descriptor.kind == nullable_kind) { return read_array_of_variable_size(field_descriptor); } - throw unexpected_field_kind(field_descriptor.field_kind, field_name); + throw unexpected_field_kind(field_descriptor.kind, field_name); } template @@ -383,7 +380,7 @@ template boost::optional compact_reader::read_compact(const std::string& field_name) { - return read_variable_size(field_name, pimpl::field_kind::COMPACT); + return read_variable_size(field_name, field_kind::COMPACT); } template @@ -391,7 +388,7 @@ boost::optional>> compact_reader::read_array_of_compact(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_COMPACT); + get_field_descriptor(field_name, field_kind::ARRAY_OF_COMPACT); return read_array_of_variable_size(descriptor); } @@ -403,7 +400,7 @@ compact_writer::write_compact(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_compact(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::COMPACT); + schema_writer->add_field(field_name, field_kind::COMPACT); } } @@ -416,8 +413,7 @@ compact_writer::write_array_of_compact( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_compact(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_COMPACT); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_COMPACT); } } namespace pimpl { @@ -574,6 +570,47 @@ struct schema_of template const schema schema_of::schema_v = schema_of::build_schema(); +template +schema build_schema(const T& object) +{ + schema_writer schema_writer(hz_serializer::type_name()); + serialization::compact_writer writer = + create_compact_writer(&schema_writer); + serialization::hz_serializer::write(object, writer); + return std::move(schema_writer).build(); +} + +template +class class_to_schema +{ +public: + + static const boost::optional& get() + { + std::lock_guard guard{ mtx_ }; + + return value_; + } + + static void set(const boost::optional& schema) + { + std::lock_guard guard { mtx_ }; + + value_ = schema; + } + +private: + + static std::mutex mtx_; + static boost::optional value_; +}; + +template +boost::optional class_to_schema::value_ = boost::none; + +template +std::mutex class_to_schema::mtx_; + template T inline compact_stream_serializer::read(object_data_input& in) { @@ -604,10 +641,18 @@ template void inline compact_stream_serializer::write(const T& object, object_data_output& out) { - const auto& schema_v = schema_of::schema_v; - put_to_schema_service(schema_v); - out.write(schema_v.schema_id()); - default_compact_writer default_writer(*this, out, schema_v); + const boost::optional& schema_v = class_to_schema::get(); + + if (!schema_v.has_value()) { + class_to_schema::set(build_schema(object)); + } + + if (!schema_service.is_schema_replicated(*schema_v)) { + out.schemas_will_be_replicated_.push_back(*schema_v); + } + + out.write(schema_v->schema_id()); + default_compact_writer default_writer(*this, out, *schema_v); compact_writer writer = create_compact_writer(&default_writer); hz_serializer::write(object, writer); default_writer.end(); diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h new file mode 100644 index 0000000000..5bf2b52dbc --- /dev/null +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "hazelcast/util/export.h" +#include "hazelcast/util/SynchronizedMap.h" +#include "hazelcast/client/serialization/pimpl/compact/schema.h" + +namespace hazelcast { +namespace client { + +namespace spi { +class ClientContext; +} + +namespace serialization { +namespace pimpl { + +/** + * Service to put and get metadata to cluster. + */ +class HAZELCAST_API default_schema_service +{ +public: + static constexpr const char* SERVICE_NAME = "schema-service"; + /** + * Maximum number of attempts for schema replication process. + */ + static constexpr const char* MAX_PUT_RETRY_COUNT = + "hazelcast.client.schema.max.put.retry.count"; + static constexpr const char* MAX_PUT_RETRY_COUNT_DEFAULT = "100"; + + default_schema_service(spi::ClientContext&); + + /** + * Gets the schema with the given id either by + *
    + *
  • returning it directly from the local registry, if it exists.
  • + *
  • searching the cluster.
  • + *
+ */ + schema get(int64_t schemaId); + + /** + * Replicates schema on the cluster + */ + boost::future replicate_schema(schema); + + bool is_schema_replicated(const schema&); + +private: + boost::future replicate_schema_attempt(schema, int attempts = 0); + + int retry_pause_millis_; + int max_put_retry_count_; + spi::ClientContext& context_; + util::SynchronizedMap replicateds_; +}; + +} // namespace pimpl +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h new file mode 100644 index 0000000000..cbab0812f8 --- /dev/null +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/util/export.h" +#include "hazelcast/client/serialization/field_kind.h" + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#pragma warning(push) +#pragma warning(disable : 4251) // for dll export +#endif + +namespace hazelcast { +namespace client { +namespace serialization { +namespace pimpl { + +struct HAZELCAST_API field_descriptor +{ + field_descriptor(field_kind k = field_kind(-1), + int32_t i = -1, + int32_t o = -1, + int8_t b = -1); + + /** + * Kind of the field + */ + field_kind kind; + + /** + * Index of the offset of the non-primitive field. For others, it is -1 + */ + int32_t index; + + /** + * Applicable only for primitive fields. For others, it is -1 + */ + int32_t offset; + + /** + * Applicable only for boolean field. For others, it is -1 + */ + int8_t bit_offset; +}; + +bool HAZELCAST_API +operator==(const field_descriptor& x, const field_descriptor& y); + +std::ostream HAZELCAST_API & +operator<<(std::ostream& os, const field_descriptor&); + +} // namespace pimpl +} // namespace serialization +} // namespace client +} // namespace hazelcast + +#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) +#pragma warning(pop) +#endif diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h new file mode 100644 index 0000000000..34fdd1c908 --- /dev/null +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h @@ -0,0 +1,65 @@ + +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include "hazelcast/util/export.h" +#include "hazelcast/client/serialization/pimpl/compact/field_descriptor.h" + +namespace hazelcast { +namespace client { +namespace serialization { +namespace pimpl { + +class HAZELCAST_API schema +{ +public: + schema() = default; + schema( + std::string type_name, + std::unordered_map&& field_definition_map); + int64_t schema_id() const; + size_t number_of_var_size_fields() const; + size_t fixed_size_fields_length() const; + const std::string& type_name() const; + const std::unordered_map& fields() const; + +private: + std::string type_name_; + std::unordered_map field_definition_map_; + size_t number_of_var_size_fields_{}; + size_t fixed_size_fields_length_{}; + int64_t schema_id_{}; +}; + +bool HAZELCAST_API +operator==(const schema& x, const schema& y); + +bool HAZELCAST_API +operator!=(const schema& x, const schema& y); + +std::ostream HAZELCAST_API & +operator<<(std::ostream& os, const schema& schema); + +} // namespace pimpl +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/data.h b/hazelcast/include/hazelcast/client/serialization/pimpl/data.h index 1bfe6c6041..0c0fba8868 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/data.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/data.h @@ -22,6 +22,7 @@ #include #include "hazelcast/util/export.h" +#include "hazelcast/client/serialization/pimpl/compact/schema.h" #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(push) @@ -35,6 +36,8 @@ namespace pimpl { class HAZELCAST_API data { public: + using schemas_t = std::vector; + // type and partition_hash are always written with BIG_ENDIAN byte-order static unsigned int PARTITION_HASH_OFFSET; @@ -46,7 +49,8 @@ class HAZELCAST_API data data(); - data(std::vector buffer); + data(std::vector buffer, + schemas_t will_be_replicated_schemas = schemas_t{}); size_t data_size() const; @@ -66,6 +70,8 @@ class HAZELCAST_API data int32_t get_type() const; + const schemas_t& schemas_will_be_replicated() const; + bool operator<(const data& rhs) const; friend bool HAZELCAST_API operator==(const data& lhs, const data& rhs); @@ -73,6 +79,7 @@ class HAZELCAST_API data private: std::vector data_; int cached_hash_value_; + schemas_t schemas_will_be_replicated_; inline int calculate_hash() const; }; diff --git a/hazelcast/include/hazelcast/client/serialization/serialization.h b/hazelcast/include/hazelcast/client/serialization/serialization.h index 1018b087d9..9efbd69fd9 100644 --- a/hazelcast/include/hazelcast/client/serialization/serialization.h +++ b/hazelcast/include/hazelcast/client/serialization/serialization.h @@ -924,6 +924,12 @@ class HAZELCAST_API object_data_output : public pimpl::data_output } private: + using schemas_t = std::vector; + + friend class pimpl::compact_stream_serializer; + friend class pimpl::SerializationService; + + schemas_t schemas_will_be_replicated_; pimpl::PortableSerializer* portable_serializer_; pimpl::compact_stream_serializer* compact_serializer_; std::shared_ptr global_serializer_; @@ -1799,7 +1805,7 @@ class HAZELCAST_API DefaultPortableWriter } // namespace client } // namespace hazelcast -#include "hazelcast/client/serialization/pimpl/compact.h" +#include "hazelcast/client/serialization/pimpl/compact/compact.h" namespace hazelcast { namespace client { @@ -1808,7 +1814,8 @@ namespace pimpl { class HAZELCAST_API SerializationService : public util::Disposable { public: - SerializationService(const serialization_config& config); + SerializationService(const serialization_config& config, + default_schema_service&); PortableSerializer& get_portable_serializer(); @@ -1830,7 +1837,8 @@ class HAZELCAST_API SerializationService : public util::Disposable output.write_object(object); - return { std::move(output).to_byte_array() }; + return { std::move(output).to_byte_array(), + move(output.schemas_will_be_replicated_) }; } template @@ -1847,7 +1855,8 @@ class HAZELCAST_API SerializationService : public util::Disposable output.write_object(object); - return { std::move(output).to_byte_array() }; + return { std::move(output).to_byte_array(), + move(output.schemas_will_be_replicated_) }; } template @@ -2856,7 +2865,7 @@ typed_data::get() const } // namespace client } // namespace hazelcast -#include "hazelcast/client/serialization/pimpl/compact.i.h" +#include "hazelcast/client/serialization/pimpl/compact/compact_impl.h" #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(pop) diff --git a/hazelcast/include/hazelcast/client/spi/ClientContext.h b/hazelcast/include/hazelcast/client/spi/ClientContext.h index 12600c0017..2968d9b286 100644 --- a/hazelcast/include/hazelcast/client/spi/ClientContext.h +++ b/hazelcast/include/hazelcast/client/spi/ClientContext.h @@ -45,6 +45,7 @@ class client_properties; namespace serialization { namespace pimpl { class SerializationService; +class default_schema_service; } } // namespace serialization @@ -154,6 +155,8 @@ class HAZELCAST_API ClientContext cp::internal::session::proxy_session_manager& get_proxy_session_manager(); + serialization::pimpl::default_schema_service& get_schema_service(); + private: client::impl::hazelcast_client_instance_impl& hazelcast_client_; }; diff --git a/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h b/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h index ab27332430..0f81649747 100644 --- a/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h +++ b/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h @@ -32,6 +32,8 @@ #include "hazelcast/client/spi/EventHandler.h" #include "hazelcast/client/protocol/ClientMessage.h" +#include "hazelcast/client/serialization/pimpl/compact/default_schema_service.h" + #if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) #pragma warning(push) #pragma warning(disable : 4251) // for dll export @@ -152,10 +154,14 @@ class HAZELCAST_API ClientInvocation static constexpr int MAX_FAST_INVOCATION_COUNT = 5; static constexpr int UNASSIGNED_PARTITION = -1; + boost::future>> replicate_schemas( + const std::vector& schemas); + logger& logger_; lifecycle_service& lifecycle_service_; ClientInvocationServiceImpl& invocation_service_; std::shared_ptr execution_service_; + serialization::pimpl::default_schema_service& schema_service_; boost::atomic_shared_ptr> client_message_; std::shared_ptr call_id_sequence_; diff --git a/hazelcast/src/hazelcast/client/client_impl.cpp b/hazelcast/src/hazelcast/client/client_impl.cpp index cae5f16bec..998fffa86b 100644 --- a/hazelcast/src/hazelcast/client/client_impl.cpp +++ b/hazelcast/src/hazelcast/client/client_impl.cpp @@ -161,7 +161,9 @@ hazelcast_client_instance_impl::hazelcast_client_instance_impl( : client_config_(std::move(config)) , client_properties_(client_config_.get_properties()) , client_context_(*this) - , serialization_service_(client_config_.get_serialization_config()) + , schema_service_{ client_context_ } + , serialization_service_(client_config_.get_serialization_config(), + schema_service_) , cluster_service_(client_context_) , transaction_manager_(client_context_) , cluster_(cluster_service_) diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index e64e0818e4..8b8b936aec 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -15,8 +15,198 @@ */ #include + +#include +#include + #include "hazelcast/client/serialization/serialization.h" +#include "hazelcast/client/serialization/field_kind.h" +#include "hazelcast/client/serialization/pimpl/compact/schema.h" +#include "hazelcast/client/protocol/codec/codecs.h" +#include "hazelcast/client/spi/impl/ClientInvocation.h" +#include "hazelcast/client/spi/ClientContext.h" +#include "hazelcast/client/cluster.h" #include "hazelcast/util/Bits.h" +#include "hazelcast/client/client_properties.h" + +namespace hazelcast { +namespace client { +namespace serialization { +namespace pimpl { + +field_descriptor::field_descriptor(field_kind k, int32_t i, int32_t o, int8_t b) + : kind{ k } + , index{ i } + , offset{ o } + , bit_offset{ b } +{ +} + +bool +operator==(const field_descriptor& x, const field_descriptor& y) +{ + return x.kind == y.kind; +} + +std::ostream& +operator<<(std::ostream& os, const field_descriptor& fd) +{ + return os << "FieldDescriptor{" + << "kind=" << fd.kind + << ", index=" << fd.index + << ", offset=" << fd.offset + << ", bitOffset=" << fd.bit_offset + << '}'; +} + +} // namespace pimpl +} // namespace serialization +} // namespace client +} // namespace hazelcast + +namespace hazelcast { +namespace client { +namespace serialization { + +std::ostream& +operator<<(std::ostream& os, field_kind kind) +{ + switch (kind) { + case field_kind::BOOLEAN: + os << "BOOLEAN"; + break; + case field_kind::ARRAY_OF_BOOLEAN: + os << "ARRAY_OF_BOOLEAN"; + break; + case field_kind::INT8: + os << "INT8"; + break; + case field_kind::ARRAY_OF_INT8: + os << "ARRAY_OF_INT8"; + break; + case field_kind::INT16: + os << "INT16"; + break; + case field_kind::ARRAY_OF_INT16: + os << "ARRAY_OF_INT16"; + break; + case field_kind::INT32: + os << "INT32"; + break; + case field_kind::ARRAY_OF_INT32: + os << "ARRAY_OF_INT32"; + break; + case field_kind::INT64: + os << "INT64"; + break; + case field_kind::ARRAY_OF_INT64: + os << "ARRAY_OF_INT16"; + break; + case field_kind::FLOAT32: + os << "FLOAT32"; + break; + case field_kind::ARRAY_OF_FLOAT32: + os << "ARRAY_OF_FLOAT32"; + break; + case field_kind::FLOAT64: + os << "FLOAT64"; + break; + case field_kind::ARRAY_OF_FLOAT64: + os << "ARRAY_OF_FLOAT64"; + break; + case field_kind::STRING: + os << "STRING"; + break; + case field_kind::ARRAY_OF_STRING: + os << "ARRAY_OF_STRING"; + break; + case field_kind::DECIMAL: + os << "DECIMAL"; + break; + case field_kind::ARRAY_OF_DECIMAL: + os << "ARRAY_OF_DECIMAL"; + break; + case field_kind::TIME: + os << "TIME"; + break; + case field_kind::ARRAY_OF_TIME: + os << "ARRAY_OF_TIME"; + break; + case field_kind::DATE: + os << "DATE"; + break; + case field_kind::ARRAY_OF_DATE: + os << "ARRAY_OF_DATE"; + break; + case field_kind::TIMESTAMP: + os << "TIMESTAMP"; + break; + case field_kind::ARRAY_OF_TIMESTAMP: + os << "ARRAY_OF_TIMESTAMP"; + break; + case field_kind::TIMESTAMP_WITH_TIMEZONE: + os << "TIMESTAMP_WITH_TIMEZONE"; + break; + case field_kind::ARRAY_OF_TIMESTAMP_WITH_TIMEZONE: + os << "ARRAY_OF_TIMESTAMP_WITH_TIMEZONE"; + break; + case field_kind::COMPACT: + os << "COMPACT"; + break; + case field_kind::ARRAY_OF_COMPACT: + os << "ARRAY_OF_COMPACT"; + break; + case field_kind::NULLABLE_BOOLEAN: + os << "NULLABLE_BOOLEAN"; + break; + case field_kind::ARRAY_OF_NULLABLE_BOOLEAN: + os << "ARRAY_OF_NULLABLE_BOOLEAN"; + break; + case field_kind::NULLABLE_INT8: + os << "NULLABLE_INT8"; + break; + case field_kind::ARRAY_OF_NULLABLE_INT8: + os << "ARRAY_OF_NULLABLE_INT8"; + break; + case field_kind::NULLABLE_INT16: + os << "NULLABLE_INT16"; + break; + case field_kind::ARRAY_OF_NULLABLE_INT16: + os << "ARRAY_OF_NULLABLE_INT16"; + break; + case field_kind::NULLABLE_INT32: + os << "NULLABLE_INT32"; + break; + case field_kind::ARRAY_OF_NULLABLE_INT32: + os << "ARRAY_OF_NULLABLE_INT32"; + break; + case field_kind::NULLABLE_INT64: + os << "NULLABLE_INT64"; + break; + case field_kind::ARRAY_OF_NULLABLE_INT64: + os << "ARRAY_OF_NULLABLE_INT64"; + break; + case field_kind::NULLABLE_FLOAT32: + os << "NULLABLE_FLOAT32"; + break; + case field_kind::ARRAY_OF_NULLABLE_FLOAT32: + os << "ARRAY_OF_NULLABLE_FLOAT32"; + break; + case field_kind::NULLABLE_FLOAT64: + os << "NULLABLE_FLOAT64"; + break; + case field_kind::ARRAY_OF_NULLABLE_FLOAT64: + os << "ARRAY_OF_NULLABLE_FLOAT64"; + break; + } + + return os; +} + +} // namespace serialization +} // namespace client +} // namespace hazelcast + namespace hazelcast { namespace client { namespace serialization { @@ -26,6 +216,7 @@ compact_writer::compact_writer( : default_compact_writer(default_compact_writer) , schema_writer(nullptr) {} + compact_writer::compact_writer(pimpl::schema_writer* schema_writer) : default_compact_writer(nullptr) , schema_writer(schema_writer) @@ -37,7 +228,7 @@ compact_writer::write_boolean(const std::string& field_name, bool value) if (default_compact_writer) { default_compact_writer->write_boolean(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::BOOLEAN); + schema_writer->add_field(field_name, field_kind::BOOLEAN); } } void @@ -46,7 +237,7 @@ compact_writer::write_int8(const std::string& field_name, int8_t value) if (default_compact_writer) { default_compact_writer->write_int8(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::INT8); + schema_writer->add_field(field_name, field_kind::INT8); } } @@ -56,7 +247,7 @@ compact_writer::write_int16(const std::string& field_name, int16_t value) if (default_compact_writer) { default_compact_writer->write_int16(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::INT16); + schema_writer->add_field(field_name, field_kind::INT16); } } @@ -66,7 +257,7 @@ compact_writer::write_int32(const std::string& field_name, int32_t value) if (default_compact_writer != nullptr) { default_compact_writer->write_int32(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::INT32); + schema_writer->add_field(field_name, field_kind::INT32); } } @@ -76,7 +267,7 @@ compact_writer::write_int64(const std::string& field_name, int64_t value) if (default_compact_writer != nullptr) { default_compact_writer->write_int64(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::INT64); + schema_writer->add_field(field_name, field_kind::INT64); } } @@ -86,7 +277,7 @@ compact_writer::write_float32(const std::string& field_name, float value) if (default_compact_writer != nullptr) { default_compact_writer->write_float32(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::FLOAT32); + schema_writer->add_field(field_name, field_kind::FLOAT32); } } @@ -96,7 +287,7 @@ compact_writer::write_float64(const std::string& field_name, double value) if (default_compact_writer != nullptr) { default_compact_writer->write_float64(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::FLOAT64); + schema_writer->add_field(field_name, field_kind::FLOAT64); } } @@ -107,7 +298,7 @@ compact_writer::write_string(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_string(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::STRING); + schema_writer->add_field(field_name, field_kind::STRING); } } @@ -118,7 +309,7 @@ compact_writer::write_decimal(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_decimal(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::DECIMAL); + schema_writer->add_field(field_name, field_kind::DECIMAL); } } @@ -130,7 +321,7 @@ compact_writer::write_time( if (default_compact_writer != nullptr) { default_compact_writer->write_time(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::TIME); + schema_writer->add_field(field_name, field_kind::TIME); } } @@ -142,7 +333,7 @@ compact_writer::write_date( if (default_compact_writer != nullptr) { default_compact_writer->write_date(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::DATE); + schema_writer->add_field(field_name, field_kind::DATE); } } @@ -154,7 +345,7 @@ compact_writer::write_timestamp( if (default_compact_writer != nullptr) { default_compact_writer->write_timestamp(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::TIMESTAMP); + schema_writer->add_field(field_name, field_kind::TIMESTAMP); } } @@ -168,7 +359,7 @@ compact_writer::write_timestamp_with_timezone( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::TIMESTAMP_WITH_TIMEZONE); + field_kind::TIMESTAMP_WITH_TIMEZONE); } } @@ -180,8 +371,7 @@ compact_writer::write_array_of_boolean( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_boolean(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_BOOLEAN); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_BOOLEAN); } } @@ -193,7 +383,7 @@ compact_writer::write_array_of_int8( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_int8(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_INT8); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_INT8); } } @@ -205,7 +395,7 @@ compact_writer::write_array_of_int16( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_int16(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_INT16); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_INT16); } } @@ -217,7 +407,7 @@ compact_writer::write_array_of_int32( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_int32(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_INT32); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_INT32); } } @@ -229,7 +419,7 @@ compact_writer::write_array_of_int64( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_int64(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_INT64); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_INT64); } } @@ -241,8 +431,7 @@ compact_writer::write_array_of_float32( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_float32(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_FLOAT32); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_FLOAT32); } } @@ -254,8 +443,7 @@ compact_writer::write_array_of_float64( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_float64(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_FLOAT64); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_FLOAT64); } } @@ -267,8 +455,7 @@ compact_writer::write_array_of_string( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_string(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_STRING); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_STRING); } } @@ -280,8 +467,7 @@ compact_writer::write_array_of_decimal( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_decimal(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_DECIMAL); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_DECIMAL); } } @@ -293,7 +479,7 @@ compact_writer::write_array_of_time( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_time(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_TIME); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_TIME); } } @@ -305,7 +491,7 @@ compact_writer::write_array_of_date( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_date(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::ARRAY_OF_DATE); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_DATE); } } @@ -317,8 +503,7 @@ compact_writer::write_array_of_timestamp( if (default_compact_writer != nullptr) { default_compact_writer->write_array_of_timestamp(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_TIMESTAMP); + schema_writer->add_field(field_name, field_kind::ARRAY_OF_TIMESTAMP); } } @@ -331,8 +516,8 @@ compact_writer::write_array_of_timestamp_with_timezone( default_compact_writer->write_array_of_timestamp_with_timezone( field_name, value); } else { - schema_writer->add_field( - field_name, pimpl::field_kind::ARRAY_OF_TIMESTAMP_WITH_TIMEZONE); + schema_writer->add_field(field_name, + field_kind::ARRAY_OF_TIMESTAMP_WITH_TIMEZONE); } } @@ -343,8 +528,7 @@ compact_writer::write_nullable_boolean(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_boolean(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::NULLABLE_BOOLEAN); + schema_writer->add_field(field_name, field_kind::NULLABLE_BOOLEAN); } } @@ -355,7 +539,7 @@ compact_writer::write_nullable_int8(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_int8(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::NULLABLE_INT8); + schema_writer->add_field(field_name, field_kind::NULLABLE_INT8); } } @@ -366,7 +550,7 @@ compact_writer::write_nullable_int16(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_int16(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::NULLABLE_INT16); + schema_writer->add_field(field_name, field_kind::NULLABLE_INT16); } } @@ -377,7 +561,7 @@ compact_writer::write_nullable_int32(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_int32(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::NULLABLE_INT32); + schema_writer->add_field(field_name, field_kind::NULLABLE_INT32); } } @@ -388,7 +572,7 @@ compact_writer::write_nullable_int64(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_int64(field_name, value); } else { - schema_writer->add_field(field_name, pimpl::field_kind::NULLABLE_INT64); + schema_writer->add_field(field_name, field_kind::NULLABLE_INT64); } } @@ -399,8 +583,7 @@ compact_writer::write_nullable_float32(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_float32(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::NULLABLE_FLOAT32); + schema_writer->add_field(field_name, field_kind::NULLABLE_FLOAT32); } } @@ -411,8 +594,7 @@ compact_writer::write_nullable_float64(const std::string& field_name, if (default_compact_writer != nullptr) { default_compact_writer->write_nullable_float64(field_name, value); } else { - schema_writer->add_field(field_name, - pimpl::field_kind::NULLABLE_FLOAT64); + schema_writer->add_field(field_name, field_kind::NULLABLE_FLOAT64); } } @@ -426,7 +608,7 @@ compact_writer::write_array_of_nullable_boolean( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_BOOLEAN); + field_kind::ARRAY_OF_NULLABLE_BOOLEAN); } } @@ -439,7 +621,7 @@ compact_writer::write_array_of_nullable_int8( default_compact_writer->write_array_of_nullable_int8(field_name, value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_INT8); + field_kind::ARRAY_OF_NULLABLE_INT8); } } @@ -453,7 +635,7 @@ compact_writer::write_array_of_nullable_int16( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_INT16); + field_kind::ARRAY_OF_NULLABLE_INT16); } } @@ -467,7 +649,7 @@ compact_writer::write_array_of_nullable_int32( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_INT32); + field_kind::ARRAY_OF_NULLABLE_INT32); } } @@ -481,7 +663,7 @@ compact_writer::write_array_of_nullable_int64( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_INT64); + field_kind::ARRAY_OF_NULLABLE_INT64); } } @@ -495,7 +677,7 @@ compact_writer::write_array_of_nullable_float32( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_FLOAT32); + field_kind::ARRAY_OF_NULLABLE_FLOAT32); } } @@ -509,11 +691,12 @@ compact_writer::write_array_of_nullable_float64( value); } else { schema_writer->add_field(field_name, - pimpl::field_kind::ARRAY_OF_NULLABLE_FLOAT64); + field_kind::ARRAY_OF_NULLABLE_FLOAT64); } } namespace pimpl { + compact_reader create_compact_reader( pimpl::compact_stream_serializer& compact_stream_serializer, @@ -524,6 +707,7 @@ create_compact_reader( object_data_input, schema }; } + } // namespace pimpl const compact_reader::offset_func compact_reader::BYTE_OFFSET_READER = @@ -577,14 +761,14 @@ compact_reader::compact_reader( bool compact_reader::is_field_exists(const std::string& field_name, - enum pimpl::field_kind kind) const + field_kind kind) const { const auto& fields = schema.fields(); const auto& field_descriptor = fields.find(field_name); if (field_descriptor == fields.end()) { return false; } - return field_descriptor->second.field_kind == kind; + return field_descriptor->second.kind == kind; } const pimpl::field_descriptor& @@ -600,12 +784,12 @@ compact_reader::get_field_descriptor(const std::string& field_name) const const pimpl::field_descriptor& compact_reader::get_field_descriptor(const std::string& field_name, - enum pimpl::field_kind kind) const + field_kind kind) const { const auto& field_descriptor = get_field_descriptor(field_name); - if (field_descriptor.field_kind != kind) { + if (field_descriptor.kind != kind) { BOOST_THROW_EXCEPTION( - unexpected_field_kind(field_descriptor.field_kind, field_name)); + unexpected_field_kind(field_descriptor.kind, field_name)); } return field_descriptor; } @@ -646,12 +830,12 @@ compact_reader::unknown_field(const std::string& field_name) const } exception::hazelcast_serialization -compact_reader::unexpected_field_kind(enum pimpl::field_kind field_kind, +compact_reader::unexpected_field_kind(field_kind kind, const std::string& field_name) const { return { "compact_reader", - (boost::format("Unexpected fieldKind %1% for %2% on %3%") % - field_kind % field_name % schema) + (boost::format("Unexpected fieldKind %1% for %2% on %3%") % kind % + field_name % schema) .str() }; } @@ -690,106 +874,90 @@ compact_reader::read_var_size_position( bool compact_reader::read_boolean(const std::string& fieldName) { - return read_primitive(fieldName, - pimpl::field_kind::BOOLEAN, - pimpl::field_kind::NULLABLE_BOOLEAN, - "boolean"); + return read_primitive( + fieldName, field_kind::BOOLEAN, field_kind::NULLABLE_BOOLEAN, "boolean"); } int8_t compact_reader::read_int8(const std::string& fieldName) { - return read_primitive(fieldName, - pimpl::field_kind::INT8, - pimpl::field_kind::NULLABLE_INT8, - "int8"); + return read_primitive( + fieldName, field_kind::INT8, field_kind::NULLABLE_INT8, "int8"); } int16_t compact_reader::read_int16(const std::string& field_name) { - return read_primitive(field_name, - pimpl::field_kind::INT16, - pimpl::field_kind::NULLABLE_INT16, - "int16"); + return read_primitive( + field_name, field_kind::INT16, field_kind::NULLABLE_INT16, "int16"); } int32_t compact_reader::read_int32(const std::string& field_name) { - return read_primitive(field_name, - pimpl::field_kind::INT32, - pimpl::field_kind::NULLABLE_INT32, - "int32"); + return read_primitive( + field_name, field_kind::INT32, field_kind::NULLABLE_INT32, "int32"); } int64_t compact_reader::read_int64(const std::string& field_name) { - return read_primitive(field_name, - pimpl::field_kind::INT64, - pimpl::field_kind::NULLABLE_INT64, - "int64"); + return read_primitive( + field_name, field_kind::INT64, field_kind::NULLABLE_INT64, "int64"); } float compact_reader::read_float32(const std::string& field_name) { - return read_primitive(field_name, - pimpl::field_kind::FLOAT32, - pimpl::field_kind::NULLABLE_FLOAT32, - "float32"); + return read_primitive( + field_name, field_kind::FLOAT32, field_kind::NULLABLE_FLOAT32, "float32"); } double compact_reader::read_float64(const std::string& field_name) { - return read_primitive(field_name, - pimpl::field_kind::FLOAT64, - pimpl::field_kind::NULLABLE_FLOAT64, - "float64"); + return read_primitive( + field_name, field_kind::FLOAT64, field_kind::NULLABLE_FLOAT64, "float64"); } boost::optional compact_reader::read_string(const std::string& field_name) { - return read_variable_size(field_name, - pimpl::field_kind::STRING); + return read_variable_size(field_name, field_kind::STRING); } boost::optional compact_reader::read_decimal(const std::string& field_name) { - return read_variable_size(field_name, - pimpl::field_kind::DECIMAL); + return read_variable_size(field_name, field_kind::DECIMAL); } boost::optional compact_reader::read_time(const std::string& field_name) { - return read_variable_size( - field_name, pimpl::field_kind::TIME); + return read_variable_size(field_name, + field_kind::TIME); } boost::optional compact_reader::read_date(const std::string& field_name) { - return read_variable_size( - field_name, pimpl::field_kind::DATE); + return read_variable_size(field_name, + field_kind::DATE); } boost::optional compact_reader::read_timestamp(const std::string& field_name) { return read_variable_size( - field_name, pimpl::field_kind::TIMESTAMP); + field_name, field_kind::TIMESTAMP); } boost::optional compact_reader::read_timestamp_with_timezone(const std::string& field_name) { return read_variable_size( - field_name, pimpl::field_kind::TIMESTAMP_WITH_TIMEZONE); + field_name, field_kind::TIMESTAMP_WITH_TIMEZONE); } boost::optional> @@ -797,8 +965,8 @@ compact_reader::read_array_of_boolean(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_BOOLEAN, - pimpl::ARRAY_OF_NULLABLE_BOOLEAN, + field_kind::ARRAY_OF_BOOLEAN, + field_kind::ARRAY_OF_NULLABLE_BOOLEAN, "boolean"); } @@ -807,8 +975,8 @@ compact_reader::read_array_of_int8(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_INT8, - pimpl::ARRAY_OF_NULLABLE_INT8, + field_kind::ARRAY_OF_INT8, + field_kind::ARRAY_OF_NULLABLE_INT8, "int8"); } @@ -817,8 +985,8 @@ compact_reader::read_array_of_int16(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_INT16, - pimpl::ARRAY_OF_NULLABLE_INT16, + field_kind::ARRAY_OF_INT16, + field_kind::ARRAY_OF_NULLABLE_INT16, "int16"); } @@ -827,8 +995,8 @@ compact_reader::read_array_of_int32(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_INT32, - pimpl::ARRAY_OF_NULLABLE_INT32, + field_kind::ARRAY_OF_INT32, + field_kind::ARRAY_OF_NULLABLE_INT32, "int32"); } boost::optional> @@ -836,8 +1004,8 @@ compact_reader::read_array_of_int64(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_INT64, - pimpl::ARRAY_OF_NULLABLE_INT64, + field_kind::ARRAY_OF_INT64, + field_kind::ARRAY_OF_NULLABLE_INT64, "int64"); } @@ -846,8 +1014,8 @@ compact_reader::read_array_of_float32(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_FLOAT32, - pimpl::ARRAY_OF_NULLABLE_FLOAT32, + field_kind::ARRAY_OF_FLOAT32, + field_kind::ARRAY_OF_NULLABLE_FLOAT32, "float32"); } @@ -856,8 +1024,8 @@ compact_reader::read_array_of_float64(const std::string& field_name) { return read_array_of_primitive>( field_name, - pimpl::field_kind::ARRAY_OF_FLOAT64, - pimpl::ARRAY_OF_NULLABLE_FLOAT64, + field_kind::ARRAY_OF_FLOAT64, + field_kind::ARRAY_OF_NULLABLE_FLOAT64, "float64"); } @@ -865,7 +1033,7 @@ boost::optional>> compact_reader::read_array_of_string(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_STRING); + get_field_descriptor(field_name, field_kind::ARRAY_OF_STRING); return read_array_of_variable_size(descriptor); } @@ -873,7 +1041,7 @@ boost::optional>> compact_reader::read_array_of_decimal(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_DECIMAL); + get_field_descriptor(field_name, field_kind::ARRAY_OF_DECIMAL); return read_array_of_variable_size(descriptor); } @@ -881,7 +1049,7 @@ boost::optional>> compact_reader::read_array_of_time(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_TIME); + get_field_descriptor(field_name, field_kind::ARRAY_OF_TIME); return read_array_of_variable_size(descriptor); } @@ -889,7 +1057,7 @@ boost::optional>> compact_reader::read_array_of_date(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_DATE); + get_field_descriptor(field_name, field_kind::ARRAY_OF_DATE); return read_array_of_variable_size(descriptor); } @@ -897,7 +1065,7 @@ boost::optional>> compact_reader::read_array_of_timestamp(const std::string& field_name) { const auto& descriptor = - get_field_descriptor(field_name, pimpl::field_kind::ARRAY_OF_TIMESTAMP); + get_field_descriptor(field_name, field_kind::ARRAY_OF_TIMESTAMP); return read_array_of_variable_size(descriptor); } @@ -906,116 +1074,114 @@ compact_reader::read_array_of_timestamp_with_timezone( const std::string& field_name) { const auto& descriptor = get_field_descriptor( - field_name, pimpl::field_kind::ARRAY_OF_TIMESTAMP_WITH_TIMEZONE); + field_name, field_kind::ARRAY_OF_TIMESTAMP_WITH_TIMEZONE); return read_array_of_variable_size(descriptor); } boost::optional compact_reader::read_nullable_boolean(const std::string& field_name) { - return read_nullable_primitive(field_name, - pimpl::field_kind::BOOLEAN, - pimpl::field_kind::NULLABLE_BOOLEAN); + return read_nullable_primitive( + field_name, field_kind::BOOLEAN, field_kind::NULLABLE_BOOLEAN); } boost::optional compact_reader::read_nullable_int8(const std::string& field_name) { return read_nullable_primitive( - field_name, pimpl::field_kind::INT8, pimpl::field_kind::NULLABLE_INT8); + field_name, field_kind::INT8, field_kind::NULLABLE_INT8); } boost::optional compact_reader::read_nullable_int16(const std::string& field_name) { return read_nullable_primitive( - field_name, pimpl::field_kind::INT16, pimpl::field_kind::NULLABLE_INT16); + field_name, field_kind::INT16, field_kind::NULLABLE_INT16); } boost::optional compact_reader::read_nullable_int32(const std::string& field_name) { return read_nullable_primitive( - field_name, pimpl::field_kind::INT32, pimpl::field_kind::NULLABLE_INT32); + field_name, field_kind::INT32, field_kind::NULLABLE_INT32); } boost::optional compact_reader::read_nullable_int64(const std::string& field_name) { return read_nullable_primitive( - field_name, pimpl::field_kind::INT64, pimpl::field_kind::NULLABLE_INT64); + field_name, field_kind::INT64, field_kind::NULLABLE_INT64); } boost::optional compact_reader::read_nullable_float32(const std::string& field_name) { - return read_nullable_primitive(field_name, - pimpl::field_kind::FLOAT32, - pimpl::field_kind::NULLABLE_FLOAT32); + return read_nullable_primitive( + field_name, field_kind::FLOAT32, field_kind::NULLABLE_FLOAT32); } boost::optional compact_reader::read_nullable_float64(const std::string& field_name) { - return read_nullable_primitive(field_name, - pimpl::field_kind::FLOAT64, - pimpl::field_kind::NULLABLE_FLOAT64); + return read_nullable_primitive( + field_name, field_kind::FLOAT64, field_kind::NULLABLE_FLOAT64); } boost::optional>> compact_reader::read_array_of_nullable_boolean(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_BOOLEAN, - pimpl::ARRAY_OF_NULLABLE_BOOLEAN); + field_kind::ARRAY_OF_BOOLEAN, + field_kind::ARRAY_OF_NULLABLE_BOOLEAN); } boost::optional>> compact_reader::read_array_of_nullable_int8(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_INT8, - pimpl::ARRAY_OF_NULLABLE_INT8); + field_kind::ARRAY_OF_INT8, + field_kind::ARRAY_OF_NULLABLE_INT8); } boost::optional>> compact_reader::read_array_of_nullable_int16(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_INT16, - pimpl::ARRAY_OF_NULLABLE_INT16); + field_kind::ARRAY_OF_INT16, + field_kind::ARRAY_OF_NULLABLE_INT16); } boost::optional>> compact_reader::read_array_of_nullable_int32(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_INT32, - pimpl::ARRAY_OF_NULLABLE_INT32); + field_kind::ARRAY_OF_INT32, + field_kind::ARRAY_OF_NULLABLE_INT32); } boost::optional>> compact_reader::read_array_of_nullable_int64(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_INT64, - pimpl::ARRAY_OF_NULLABLE_INT64); + field_kind::ARRAY_OF_INT64, + field_kind::ARRAY_OF_NULLABLE_INT64); } boost::optional>> compact_reader::read_array_of_nullable_float32(const std::string& field_name) { return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_FLOAT32, - pimpl::ARRAY_OF_NULLABLE_FLOAT32); + field_kind::ARRAY_OF_FLOAT32, + field_kind::ARRAY_OF_NULLABLE_FLOAT32); } boost::optional>> compact_reader::read_array_of_nullable_float64(const std::string& field_name) { - return read_array_of_nullable(field_name, - pimpl::field_kind::ARRAY_OF_FLOAT64, - pimpl::ARRAY_OF_NULLABLE_FLOAT64); + return read_array_of_nullable( + field_name, + field_kind::ARRAY_OF_FLOAT64, + field_kind::ARRAY_OF_NULLABLE_FLOAT64); } namespace pimpl { @@ -1025,6 +1191,7 @@ create_compact_writer(pimpl::default_compact_writer* default_compact_writer) { return compact_writer{ default_compact_writer }; } + compact_writer create_compact_writer(pimpl::schema_writer* schema_writer) { @@ -1414,7 +1581,7 @@ default_compact_writer::get_fixed_size_field_position( const field_descriptor& default_compact_writer::check_field_definition(const std::string& field_name, - enum field_kind field_kind) const + field_kind kind) const { auto iterator = schema_.fields().find(field_name); if (iterator == schema_.fields().end()) { @@ -1424,7 +1591,7 @@ default_compact_writer::check_field_definition(const std::string& field_name, schema_) .str())); } - if (iterator->second.field_kind != field_kind) { + if (iterator->second.kind != kind) { BOOST_THROW_EXCEPTION(exception::hazelcast_serialization( "default_compact_writer", (boost::format("Invalid field type %1% for %2%") % field_name % @@ -1475,17 +1642,6 @@ default_compact_writer::set_position_as_null(const std::string& field_name, field_offsets[index] = -1; } -field_descriptor::field_descriptor(enum field_kind f, - int32_t i, - int32_t o, - int8_t b) - : field_kind{ f } - , index{ i } - , offset{ o } - , bit_offset{ b } -{ -} - std::array init_fp_table() { @@ -1542,7 +1698,7 @@ rabin_finger_print::fingerprint64( for (const auto& entry : fields) { const field_descriptor& descriptor = entry.second; fingerPrint = fingerprint64(fingerPrint, entry.first); - fingerPrint = fingerprint64(fingerPrint, (int)descriptor.field_kind); + fingerPrint = fingerprint64(fingerPrint, (int)descriptor.kind); } int64_t signed_fp{}; @@ -1554,10 +1710,8 @@ rabin_finger_print::fingerprint64( bool kind_size_comparator(const field_descriptor* i, const field_descriptor* j) { - auto i_kind_size = - field_operations::get(i->field_kind).kind_size_in_byte_func(); - auto j_kind_size = - field_operations::get(j->field_kind).kind_size_in_byte_func(); + auto i_kind_size = field_operations::get(i->kind).kind_size_in_byte_func(); + auto j_kind_size = field_operations::get(j->kind).kind_size_in_byte_func(); return i_kind_size > j_kind_size; } @@ -1575,7 +1729,7 @@ schema::schema( field_definition_map_.begin(), field_definition_map_.end()); for (auto& item : sorted_fields) { field_descriptor& descriptor = item.second; - field_kind kind = descriptor.field_kind; + field_kind kind = descriptor.kind; if (field_operations::get(kind).kind_size_in_byte_func() == field_kind_based_operations::VARIABLE_SIZE) { variable_size_fields.push_back(&descriptor); @@ -1592,8 +1746,8 @@ schema::schema( int offset = 0; for (auto descriptor : fixed_size_fields) { descriptor->offset = offset; - offset += field_operations::get(descriptor->field_kind) - .kind_size_in_byte_func(); + offset += + field_operations::get(descriptor->kind).kind_size_in_byte_func(); } int8_t bit_offset = 0; @@ -1656,12 +1810,28 @@ schema::fields() const return field_definition_map_; } +bool +operator==(const schema& x, const schema& y) +{ + return x.number_of_var_size_fields() == y.number_of_var_size_fields() && + x.fixed_size_fields_length() == y.fixed_size_fields_length() && + x.schema_id() == y.schema_id() && x.type_name() == y.type_name() && + x.fields() == y.fields(); +} + +bool +operator!=(const schema& x, const schema& y) +{ + return !(x == y); +} + std::ostream& operator<<(std::ostream& os, const schema& schema) { - os << "type name " << schema.type_name() << ",number of var size fields " - << schema.number_of_var_size_fields() << ",fixed size fields length " - << schema.fixed_size_fields_length() << ",fields {"; + os << "Schema { className = " << schema.type_name() + << ", numberOfComplextFields = " << schema.number_of_var_size_fields() + << ",primitivesLength = " << schema.fixed_size_fields_length() + << ",fields {"; for (const auto& item : schema.fields()) { os << item.first << " " << item.second << ","; } @@ -1669,19 +1839,14 @@ operator<<(std::ostream& os, const schema& schema) return os; } -std::ostream& -operator<<(std::ostream& os, const field_descriptor& field_descriptor) -{ - os << field_descriptor.field_kind; - return os; -} - } // namespace pimpl namespace pimpl { + schema_writer::schema_writer(std::string type_name) : type_name(std::move(type_name)) {} + void schema_writer::add_field(std::string field_name, enum field_kind kind) { @@ -1694,28 +1859,122 @@ schema_writer::build() && return schema{ type_name, std::move(field_definition_map) }; } +default_schema_service::default_schema_service(spi::ClientContext& context) + : retry_pause_millis_{ context.get_client_properties().get_integer( + context.get_client_properties().get_invocation_retry_pause_millis()) } + , max_put_retry_count_{ context.get_client_properties().get_integer( + client_property{ MAX_PUT_RETRY_COUNT, MAX_PUT_RETRY_COUNT_DEFAULT }) } + , context_{ context } +{ +} + schema default_schema_service::get(int64_t schemaId) { - auto ptr = schemas.get(schemaId); - if (ptr == nullptr) { - // TODO sancar throw schema_does_not_exist; + auto ptr = replicateds_.get(schemaId); + + if (!ptr) { + throw exception::illegal_state{ "default_schema_service::get", + "Schema doesn't exist for this type" }; } + return *ptr; } -void -default_schema_service::put(const schema& schema_v) + +boost::future +default_schema_service::replicate_schema(schema s) +{ + return replicate_schema_attempt(std::move(s)); +} + +boost::future +default_schema_service::replicate_schema_attempt(schema s, int attempts) +{ + using hazelcast::client::protocol::ClientMessage; + using namespace protocol::codec; + + auto max_retry_count{ max_put_retry_count_ }; + auto message = send_schema_request_encode(s); + + auto invocation = + spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); + + return invocation->invoke().then( + boost::launch::sync, + [this, max_retry_count, attempts, s]( + boost::future future) { + auto msg = future.get(); + + auto replicated_member_uuids = send_schema_response_decode(msg); + auto members = context_.get_cluster().get_members(); + + for (const member& searchee : members) { + auto contains = + any_of(begin(replicated_member_uuids), + end(replicated_member_uuids), + [&searchee](const boost::uuids::uuid member_id) { + return searchee.get_uuid() == member_id; + }); + + if (!contains) { + if (attempts >= max_retry_count) { + throw exception::illegal_state{ + "default_schema_service::replicate_schema_attempt", + (boost::format("The schema %1% cannot be " + "replicated in the cluster, after " + "%2% retries. It might be the case " + "that the client is experiencing a " + "split-brain, and continue putting " + "the data associated with that " + "schema might result in data loss. " + "It might be possible to replicate " + "the schema after some time, when " + "the cluster is healed.") % + s % max_retry_count) + .str() + }; + } else { + std::this_thread::sleep_for( + std::chrono::milliseconds{ retry_pause_millis_ }); + + replicate_schema_attempt(std::move(s), attempts + 1) + .get(); + + return; + } + } + } + + auto s_p = std::make_shared(std::move(s)); + auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); + + if (!existing) { + return; + } + + if (*s_p != *existing) { + throw exception::illegal_state{ + "default_schema_service::replicate_schema_attempt", + (boost::format("Schema with schemaId %1% " + "already exists. Existing " + "schema %2%, new schema %3%") % + s.schema_id() % *existing % s) + .str() + }; + } + }); +} + +bool +default_schema_service::is_schema_replicated(const schema& s) { - if (schemas.contains_key(schema_v.schema_id())) { - return; - } - schemas.put(schema_v.schema_id(), std::make_shared(schema_v)); + return bool(replicateds_.get(s.schema_id())); } -void -compact_stream_serializer::put_to_schema_service(const schema& schema) +compact_stream_serializer::compact_stream_serializer( + default_schema_service& service) + : schema_service{ service } { - schema_service.put(schema); } field_kind_based_operations::field_kind_based_operations() @@ -1727,62 +1986,40 @@ field_kind_based_operations::field_kind_based_operations( : kind_size_in_byte_func(std::move(kind_size_in_byte_func)) {} field_kind_based_operations -field_operations::get(enum field_kind field_kind) -{ - static const field_kind_based_operations ALL[NUMBER_OF_FIELD_KINDS] = { - field_kind_based_operations{ []() { return 0; } }, - field_kind_based_operations{}, - field_kind_based_operations{ []() { return 1; } }, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{ - []() { return util::Bits::SHORT_SIZE_IN_BYTES; } }, - field_kind_based_operations{}, - field_kind_based_operations( - []() { return util::Bits::INT_SIZE_IN_BYTES; }), - field_kind_based_operations{}, - field_kind_based_operations{ - []() { return util::Bits::LONG_SIZE_IN_BYTES; } }, - field_kind_based_operations{}, - field_kind_based_operations{ - []() { return util::Bits::FLOAT_SIZE_IN_BYTES; } }, - field_kind_based_operations{}, - field_kind_based_operations{ - []() { return util::Bits::DOUBLE_SIZE_IN_BYTES; } }, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{}, - field_kind_based_operations{} - }; - return ALL[field_kind]; +field_operations::get(field_kind kind) +{ + using util::Bits; + + switch (kind) { + case field_kind::BOOLEAN: + return field_kind_based_operations{ []() { return 0; } }; + case field_kind::INT8: + return field_kind_based_operations{ []() { return 1; } }; + case field_kind::INT16: + return field_kind_based_operations{ []() { + return Bits::SHORT_SIZE_IN_BYTES; + } }; + case field_kind::INT32: + return field_kind_based_operations{ []() { + return Bits::INT_SIZE_IN_BYTES; + } }; + case field_kind::INT64: + return field_kind_based_operations{ []() { + return Bits::LONG_SIZE_IN_BYTES; + } }; + case field_kind::FLOAT32: + return field_kind_based_operations{ []() { + return Bits::FLOAT_SIZE_IN_BYTES; + } }; + case field_kind::FLOAT64: + return field_kind_based_operations{ []() { + return Bits::DOUBLE_SIZE_IN_BYTES; + } }; + default: + return field_kind_based_operations{}; + } + + return field_kind_based_operations{}; } } // namespace pimpl } // namespace serialization diff --git a/hazelcast/src/hazelcast/client/protocol.cpp b/hazelcast/src/hazelcast/client/protocol.cpp index ff68ae3905..1541365df3 100644 --- a/hazelcast/src/hazelcast/client/protocol.cpp +++ b/hazelcast/src/hazelcast/client/protocol.cpp @@ -399,6 +399,12 @@ ClientMessage::fast_forward_to_end_frame() } } +const std::vector& +ClientMessage::schemas_will_be_replicated() const +{ + return schemas_will_be_replicated_; +} + const ClientMessage::frame_header_type& ClientMessage::null_frame() { diff --git a/hazelcast/src/hazelcast/client/serialization.cpp b/hazelcast/src/hazelcast/client/serialization.cpp index 9b7ceb7e98..12568001e3 100644 --- a/hazelcast/src/hazelcast/client/serialization.cpp +++ b/hazelcast/src/hazelcast/client/serialization.cpp @@ -970,11 +970,13 @@ PortableContext::get_serialization_config() const return serialization_config_; } -SerializationService::SerializationService(const serialization_config& config) +SerializationService::SerializationService( + const serialization_config& config, + default_schema_service& schema_service) : serialization_config_(config) , portable_context_(serialization_config_) , portable_serializer_(portable_context_) - , compact_serializer_() + , compact_serializer_(schema_service) {} DefaultPortableWriter::DefaultPortableWriter( @@ -1186,9 +1188,10 @@ data::data() : cached_hash_value_(-1) {} -data::data(std::vector buffer) +data::data(std::vector buffer, schemas_t s) : data_(std::move(buffer)) , cached_hash_value_(-1) + , schemas_will_be_replicated_{ move(s) } { size_t size = data_.size(); if (size > 0 && size < data::DATA_OVERHEAD) { @@ -1248,6 +1251,12 @@ data::get_type() const &data_[data::TYPE_OFFSET]); } +const data::schemas_t& +data::schemas_will_be_replicated() const +{ + return schemas_will_be_replicated_; +} + int data::hash() const { diff --git a/hazelcast/src/hazelcast/client/spi.cpp b/hazelcast/src/hazelcast/client/spi.cpp index 131eb087f9..086810f248 100644 --- a/hazelcast/src/hazelcast/client/spi.cpp +++ b/hazelcast/src/hazelcast/client/spi.cpp @@ -325,6 +325,12 @@ ClientContext::get_proxy_session_manager() return hazelcast_client_.proxy_session_manager_; } +serialization::pimpl::default_schema_service& +ClientContext::get_schema_service() +{ + return hazelcast_client_.schema_service_; +} + lifecycle_service::lifecycle_service( ClientContext& client_context, const std::vector& listeners) @@ -1357,6 +1363,7 @@ ClientInvocation::ClientInvocation( , invocation_service_(client_context.get_invocation_service()) , execution_service_( client_context.get_client_execution_service().shared_from_this()) + , schema_service_(client_context.get_schema_service()) , call_id_sequence_(client_context.get_call_id_sequence()) , uuid_(uuid) , partition_id_(partition) @@ -1381,20 +1388,44 @@ boost::future ClientInvocation::invoke() { assert(client_message_.load()); - // for back pressure - call_id_sequence_->next(); - invoke_on_selection(); - if (!lifecycle_service_.is_running()) { + + auto actual_work = [this]() { + // for back pressure + call_id_sequence_->next(); + invoke_on_selection(); + if (!lifecycle_service_.is_running()) { + return invocation_promise_.get_future().then( + [](boost::future f) { return f.get(); }); + } + auto id_seq = call_id_sequence_; return invocation_promise_.get_future().then( - [](boost::future f) { return f.get(); }); + execution_service_->get_user_executor(), + [=](boost::future f) { + id_seq->complete(); + return f.get(); + }); + }; + + const auto& schemas = + (*(client_message_.load()))->schemas_will_be_replicated(); + + if (!schemas.empty()) { + auto self = shared_from_this(); + + return replicate_schemas(schemas) + .then( + boost::launch::sync, + [this, actual_work, self]( + boost::future>> replications) { + for (auto& replication : replications.get()) + replication.get(); + + return actual_work(); + }) + .unwrap(); } - auto id_seq = call_id_sequence_; - return invocation_promise_.get_future().then( - execution_service_->get_user_executor(), - [=](boost::future f) { - id_seq->complete(); - return f.get(); - }); + + return actual_work(); } boost::future @@ -1402,20 +1433,41 @@ ClientInvocation::invoke_urgent() { assert(client_message_.load()); urgent_ = true; + // for back pressure call_id_sequence_->force_next(); invoke_on_selection(); if (!lifecycle_service_.is_running()) { return invocation_promise_.get_future().then( - [](boost::future f) { return f.get(); }); + [](boost::future f) { return f.get(); }); } auto id_seq = call_id_sequence_; return invocation_promise_.get_future().then( - execution_service_->get_user_executor(), - [=](boost::future f) { - id_seq->complete(); - return f.get(); - }); + execution_service_->get_user_executor(), + [=](boost::future f) { + id_seq->complete(); + return f.get(); + }); +} + +boost::future>> +ClientInvocation::replicate_schemas( + const std::vector& schemas) +{ + std::vector> replications; + + replications.reserve(schemas.size()); + + transform(begin(schemas), + end(schemas), + back_inserter(replications), + [this](const serialization::pimpl::schema& s) { + return schema_service_.replicate_schema(s); + }); + + auto self = shared_from_this(); + + return boost::when_all(begin(replications), end(replications)); } void diff --git a/hazelcast/test/resources/compact.xml b/hazelcast/test/resources/compact.xml new file mode 100644 index 0000000000..4d118259c5 --- /dev/null +++ b/hazelcast/test/resources/compact.xml @@ -0,0 +1,5 @@ + + + compact-dev + + \ No newline at end of file diff --git a/hazelcast/test/src/ClientTest.cpp b/hazelcast/test/src/ClientTest.cpp index 66e24c9372..ee436746ef 100644 --- a/hazelcast/test/src/ClientTest.cpp +++ b/hazelcast/test/src/ClientTest.cpp @@ -29,6 +29,7 @@ #include "HazelcastServerFactory.h" #include "remote_controller_client.h" +#include "TestHelperFunctions.h" namespace hazelcast { namespace client { @@ -107,16 +108,6 @@ ClientTest::random_map_name() return "test_" + boost::replace_all_copy(random_string(), "-", "_"); } -std::string -ClientTest::random_string() -{ - // performance is not important, hence we can use random_device for the - // tests - std::random_device rand{}; - return boost::uuids::to_string( - boost::uuids::basic_random_generator{ rand }()); -} - boost::uuids::uuid ClientTest::generate_key_owned_by(spi::ClientContext& context, const member& member) diff --git a/hazelcast/test/src/ClientTest.h b/hazelcast/test/src/ClientTest.h index 80a3160dfc..5c88f981e7 100644 --- a/hazelcast/test/src/ClientTest.h +++ b/hazelcast/test/src/ClientTest.h @@ -54,7 +54,6 @@ class ClientTest : public ::testing::Test static std::string get_test_name(); static std::string get_ca_file_path(); static std::string random_map_name(); - static std::string random_string(); static boost::uuids::uuid generate_key_owned_by(spi::ClientContext& context, const member& member); static client_config get_config(bool ssl_enabled = false, diff --git a/hazelcast/test/src/HazelcastTests2.cpp b/hazelcast/test/src/HazelcastTests2.cpp index 79f2e233d1..44cca2fd1e 100644 --- a/hazelcast/test/src/HazelcastTests2.cpp +++ b/hazelcast/test/src/HazelcastTests2.cpp @@ -834,11 +834,13 @@ class PortableVersionTest : public ::testing::Test TEST_F(PortableVersionTest, test_nestedPortable_versionedSerializer) { serialization_config serializationConfig; - serialization::pimpl::SerializationService ss1(serializationConfig); + serialization::pimpl::SerializationService ss1(serializationConfig, + null_schema_service()); serialization_config serializationConfig2; serializationConfig2.set_portable_version(6); - serialization::pimpl::SerializationService ss2(serializationConfig2); + serialization::pimpl::SerializationService ss2(serializationConfig2, + null_schema_service()); // make sure ss2 cached class definition of Child { @@ -932,7 +934,7 @@ TEST_F(PartitionAwareTest, testSimplePartitionAwareObjectSerialisation) { serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); SimplePartitionAwareObject obj; serialization::pimpl::data data = @@ -950,7 +952,7 @@ TEST_F(PartitionAwareTest, testNonPartitionAwareObjectSerialisation) { serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); int obj = 7; serialization::pimpl::data data = serializationService.to_data(&obj); @@ -989,7 +991,7 @@ class JsonValueSerializationTest : public ::testing::Test { public: JsonValueSerializationTest() - : serialization_service_(config_) + : serialization_service_(config_, null_schema_service()) {} protected: @@ -1082,7 +1084,7 @@ TEST_F(ClientSerializationTest, testCustomSerialization) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestCustomXSerializable a{ 131321 }; serialization::pimpl::data data = @@ -1104,7 +1106,7 @@ TEST_F(ClientSerializationTest, testRawData) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); char charA[] = "test chars"; std::vector chars(charA, charA + 10); std::vector bytes; @@ -1125,7 +1127,7 @@ TEST_F(ClientSerializationTest, testIdentifiedDataSerializable) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization::pimpl::data data; TestDataSerializable np{ 4, 'k' }; data = serializationService.to_data(&np); @@ -1146,7 +1148,7 @@ TEST_F(ClientSerializationTest, testRawDataWithoutRegistering) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); char charA[] = "test chars"; std::vector chars(charA, charA + 10); std::vector bytes; @@ -1167,7 +1169,7 @@ TEST_F(ClientSerializationTest, testInvalidWrite) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestInvalidWritePortable p{ 2131, 123, "q4edfd" }; ASSERT_THROW(serializationService.to_data(&p), exception::hazelcast_serialization); @@ -1178,7 +1180,7 @@ TEST_F(ClientSerializationTest, testInvalidRead) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestInvalidReadPortable p{ 2131, 123, "q4edfd" }; serialization::pimpl::data data = serializationService.to_data(&p); @@ -1191,12 +1193,12 @@ TEST_F(ClientSerializationTest, testDifferentVersions) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization_config serializationConfig2; serializationConfig2.set_portable_version(2); serialization::pimpl::SerializationService serializationService2( - serializationConfig2); + serializationConfig2, null_schema_service()); serialization::pimpl::data data = serializationService.to_data( @@ -1223,7 +1225,7 @@ TEST_F(ClientSerializationTest, testBasicFunctionality) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization::pimpl::data data; int x = 3; @@ -1279,7 +1281,8 @@ TEST_F(ClientSerializationTest, testStringLiterals) { auto literal = R"delimeter(My example string literal)delimeter"; serialization_config config; - serialization::pimpl::SerializationService serializationService(config); + serialization::pimpl::SerializationService serializationService( + config, null_schema_service()); auto data = serializationService.to_data(literal); auto obj = serializationService.to_object(data); ASSERT_TRUE(obj); @@ -1291,7 +1294,7 @@ TEST_F(ClientSerializationTest, testBasicFunctionalityWithLargeData) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization::pimpl::data data; std::vector bb(LARGE_ARRAY_SIZE); @@ -1327,12 +1330,12 @@ TEST_F(ClientSerializationTest, testBasicFunctionalityWithDifferentVersions) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization_config serializationConfig2; serializationConfig2.set_portable_version(2); serialization::pimpl::SerializationService serializationService2( - serializationConfig2); + serializationConfig2, null_schema_service()); serialization::pimpl::data data; int32_t x = 3; @@ -1389,7 +1392,7 @@ TEST_F(ClientSerializationTest, testDataHash) { serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); std::string serializable = "key1"; serialization::pimpl::data data = serializationService.to_data(&serializable); @@ -1402,7 +1405,7 @@ TEST_F(ClientSerializationTest, testPrimitives) { serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); byte by = 2; bool boolean = true; char c = 'c'; @@ -1431,7 +1434,7 @@ TEST_F(ClientSerializationTest, testPrimitiveArrays) { serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); char charArray[] = { 'c', 'h', 'a', 'r' }; std::vector cc(charArray, charArray + 4); @@ -1489,7 +1492,8 @@ TEST_F(ClientSerializationTest, testPrimitiveArrays) TEST_F(ClientSerializationTest, testWriteObjectWithPortable) { serialization_config serializationConfig; - serialization::pimpl::SerializationService ss(serializationConfig); + serialization::pimpl::SerializationService ss(serializationConfig, + null_schema_service()); ObjectCarryingPortable objectCarryingPortable{ TestNamedPortable{ "name", 2 } @@ -1504,7 +1508,8 @@ TEST_F(ClientSerializationTest, testWriteObjectWithPortable) TEST_F(ClientSerializationTest, testWriteObjectWithIdentifiedDataSerializable) { serialization_config serializationConfig; - serialization::pimpl::SerializationService ss(serializationConfig); + serialization::pimpl::SerializationService ss(serializationConfig, + null_schema_service()); ObjectCarryingPortable objectCarryingPortable{ TestDataSerializable{ 2, 'c' } @@ -1519,7 +1524,8 @@ TEST_F(ClientSerializationTest, testWriteObjectWithIdentifiedDataSerializable) TEST_F(ClientSerializationTest, testWriteObjectWithCustomXSerializable) { serialization_config serializationConfig; - serialization::pimpl::SerializationService ss(serializationConfig); + serialization::pimpl::SerializationService ss(serializationConfig, + null_schema_service()); ObjectCarryingPortable objectCarryingPortable{ TestCustomXSerializable{ 131321 } }; @@ -1534,7 +1540,8 @@ TEST_F(ClientSerializationTest, testWriteObjectWithCustomXSerializable) TEST_F(ClientSerializationTest, testWriteObjectWithCustomPersonSerializable) { serialization_config serializationConfig; - serialization::pimpl::SerializationService ss(serializationConfig); + serialization::pimpl::SerializationService ss(serializationConfig, + null_schema_service()); ObjectCarryingPortable objectCarryingPortable{ TestCustomPerson{ "TestCustomPerson" } @@ -1550,7 +1557,8 @@ TEST_F(ClientSerializationTest, testNullData) { serialization::pimpl::data data; serialization_config serializationConfig; - serialization::pimpl::SerializationService ss(serializationConfig); + serialization::pimpl::SerializationService ss(serializationConfig, + null_schema_service()); auto ptr = ss.to_object(data); ASSERT_FALSE(ptr.has_value()); } @@ -1560,7 +1568,7 @@ TEST_F(ClientSerializationTest, testMorphingPortableV1ToV2Conversion) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestNamedPortable p{ "portable-v1", 123 }; serialization::pimpl::data data = @@ -1578,7 +1586,7 @@ TEST_F(ClientSerializationTest, testMorphingPortableV2ToV1Conversion) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestNamedPortableV2 p2{ "portable-v2", 123, 9999 }; serialization::pimpl::data data = @@ -1595,7 +1603,7 @@ TEST_F(ClientSerializationTest, testMorphingPortableV1ToV3Conversion) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); TestNamedPortable p{ "portable-v1", 123 }; serialization::pimpl::data data = @@ -1611,12 +1619,12 @@ TEST_F(ClientSerializationTest, serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization_config serializationConfig2; serializationConfig.set_portable_version(5); serialization::pimpl::SerializationService serializationService2( - serializationConfig2); + serializationConfig2, null_schema_service()); TestNamedPortableV2 p2{ "portable-v2", 123, 7 }; serialization::pimpl::data data2 = @@ -1633,7 +1641,7 @@ TEST_F(ClientSerializationTest, object_data_input_output) serialization_config serializationConfig; serializationConfig.set_portable_version(1); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization::object_data_output out(boost::endian::order::big); @@ -1749,7 +1757,7 @@ TEST_F(ClientSerializationTest, testExtendedAscii) serialization_config serializationConfig; serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); serialization::pimpl::data data = serializationService.to_data(&utfStr); @@ -1764,7 +1772,7 @@ TEST_F(ClientSerializationTest, testGlobalSerializer) serializationConfig.set_global_serializer( std::make_shared()); serialization::pimpl::SerializationService serializationService( - serializationConfig); + serializationConfig, null_schema_service()); NonSerializableObject obj{ "My class with no serializer" }; @@ -2151,7 +2159,7 @@ class NearCacheRecordStoreTest { ss_ = std::unique_ptr( new serialization::pimpl::SerializationService( - serialization_config_)); + serialization_config_, null_schema_service())); } protected: diff --git a/hazelcast/test/src/HazelcastTests8.cpp b/hazelcast/test/src/HazelcastTests8.cpp index d4b601074a..434d2cf417 100644 --- a/hazelcast/test/src/HazelcastTests8.cpp +++ b/hazelcast/test/src/HazelcastTests8.cpp @@ -2046,7 +2046,8 @@ TEST(ClientMessageTest, testFragmentedMessageHandling) ASSERT_EQ(10, datas.size()); serialization_config serializationConfig; - serialization::pimpl::SerializationService ss{ serializationConfig }; + serialization::pimpl::SerializationService ss{ serializationConfig, + null_schema_service() }; for (int32_t i = 0; i < 10; ++i) { ASSERT_EQ(i, ss.to_object(&datas[i].first)); ASSERT_EQ(i, ss.to_object(&datas[i].second)); diff --git a/hazelcast/test/src/TestHelperFunctions.h b/hazelcast/test/src/TestHelperFunctions.h index 42266d9f3e..551be3dc8b 100644 --- a/hazelcast/test/src/TestHelperFunctions.h +++ b/hazelcast/test/src/TestHelperFunctions.h @@ -16,6 +16,30 @@ #pragma once +#include +#include +#include +#include + +#include "hazelcast/client/spi/ClientContext.h" + +inline hazelcast::client::serialization::pimpl::default_schema_service& +null_schema_service() +{ + return *static_cast< + hazelcast::client::serialization::pimpl::default_schema_service*>( + nullptr); +} + +inline std::string +random_string() +{ + std::random_device rand{}; + + return boost::uuids::to_string( + boost::uuids::basic_random_generator{ rand }()); +} + #define ASSERT_EQ_EVENTUALLY_WITH_TIMEOUT_MSG( \ message, expected, actual, timeoutSeconds) \ do { \ diff --git a/hazelcast/test/src/compact/compact_helper.h b/hazelcast/test/src/compact/compact_helper.h new file mode 100644 index 0000000000..5aaf66542e --- /dev/null +++ b/hazelcast/test/src/compact/compact_helper.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +inline hazelcast::client::local_time +current_time() +{ + std::time_t t = std::time(nullptr); // get time now + std::tm* now = std::localtime(&t); + return hazelcast::client::local_time{ static_cast(now->tm_hour), + static_cast(now->tm_min), + static_cast(now->tm_sec), + 0 }; +} + +inline hazelcast::client::local_date +current_date() +{ + std::time_t t = std::time(nullptr); // get time now + std::tm* now = std::localtime(&t); + return hazelcast::client::local_date{ now->tm_year + 1900, + static_cast(now->tm_mon), + static_cast(now->tm_mday) }; +} + +inline hazelcast::client::local_date_time +current_timestamp() +{ + return hazelcast::client::local_date_time{ current_date(), current_time() }; +} + +inline hazelcast::client::offset_date_time +current_timestamp_with_timezone() +{ + return hazelcast::client::offset_date_time{ current_timestamp(), 3600 }; +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h b/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h new file mode 100644 index 0000000000..8c2a12b99f --- /dev/null +++ b/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "compact_test_base.h" +#include "serialization/primitive_object.h" +#include "serialization/nullable_primitive_object.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +template +void +ASSERT_SAME_CONTENT( + const boost::optional>>& expected, + const boost::optional>& actual) +{ + ASSERT_EQ(expected->size(), actual->size()); + for (size_t i = 0; i < expected->size(); ++i) { + ASSERT_EQ(expected->at(i).value(), actual->at(i)); + } +} + +template +void +ASSERT_SAME_CONTENT( + const boost::optional>& expected, + const boost::optional>>& actual) +{ + ASSERT_EQ(expected->size(), actual->size()); + for (size_t i = 0; i < expected->size(); ++i) { + ASSERT_EQ(expected->at(i), actual->at(i).value()); + } +} + +class CompactNullablePrimitiveInteroperabilityTest : public compact_test_base +{ + protected: + SerializationService& serialization_service(){ + return spi::ClientContext{ client }.get_serialization_service(); + } +}; + +TEST_F(CompactNullablePrimitiveInteroperabilityTest, + testWritePrimitiveReadNullable) +{ + primitive_object expected{ + true, + 2, + 4, + 8, + 4444, + 8321.321F, + 41231.32, + boost::make_optional(std::vector{ true, false }), + boost::make_optional(std::vector{ 1, 2 }), + boost::make_optional(std::vector{ 1, 4 }), + boost::make_optional(std::vector{ 1, 8 }), + boost::make_optional(std::vector{ 1, 4444 }), + boost::make_optional(std::vector{ 1.0F, 8321.321F }), + boost::make_optional(std::vector{ 41231.32, 2 }) + }; + + replicate_schema(); + replicate_schema(); + + SerializationService& ss = serialization_service(); + + const data& data = ss.to_data(expected); + auto actual = ss.to_object(data).value(); + ASSERT_EQ(expected.boolean_, actual.nullableBoolean.value()); + ASSERT_EQ(expected.byte_, actual.nullableByte.value()); + ASSERT_EQ(expected.short_, actual.nullableShort.value()); + ASSERT_EQ(expected.int_, actual.nullableInt.value()); + ASSERT_EQ(expected.long_, actual.nullableLong.value()); + ASSERT_EQ(expected.float_, actual.nullableFloat.value()); + ASSERT_EQ(expected.double_, actual.nullableDouble.value()); + ASSERT_SAME_CONTENT(expected.booleans, actual.nullableBooleans); + ASSERT_SAME_CONTENT(expected.bytes, actual.nullableBytes); + ASSERT_SAME_CONTENT(expected.shorts, actual.nullableShorts); + ASSERT_SAME_CONTENT(expected.ints, actual.nullableInts); + ASSERT_SAME_CONTENT(expected.longs, actual.nullableLongs); + ASSERT_SAME_CONTENT(expected.floats, actual.nullableFloats); + ASSERT_SAME_CONTENT(expected.doubles, actual.nullableDoubles); +} + +TEST_F(CompactNullablePrimitiveInteroperabilityTest, + testWriteNullableReadPrimitive) +{ + nullable_primitive_object expected{ + boost::make_optional(true), + boost::make_optional(4), + boost::make_optional(6), + boost::make_optional(8), + boost::make_optional(4444), + boost::make_optional(8321.321F), + boost::make_optional(41231.32), + boost::make_optional>>( + std::vector>{ + boost::make_optional(true), + boost::make_optional(false) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(1), boost::make_optional(2) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(1), + boost::make_optional(4) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(1), + boost::make_optional(8) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(1), + boost::make_optional(4444) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(1.0F), + boost::make_optional(8321.321F) }), + boost::make_optional>>( + std::vector>{ + boost::make_optional(41231.32), + boost::make_optional(2) }) + }; + + replicate_schema(); + replicate_schema(); + + SerializationService& ss = serialization_service(); + + const data& data = ss.to_data(expected); + auto actual = ss.to_object(data).value(); + ASSERT_EQ(expected.nullableBoolean.value(), actual.boolean_); + ASSERT_EQ(expected.nullableByte.value(), actual.byte_); + ASSERT_EQ(expected.nullableShort.value(), actual.short_); + ASSERT_EQ(expected.nullableInt.value(), actual.int_); + ASSERT_EQ(expected.nullableLong.value(), actual.long_); + ASSERT_EQ(expected.nullableFloat.value(), actual.float_); + ASSERT_EQ(expected.nullableDouble.value(), actual.double_); + ASSERT_SAME_CONTENT(expected.nullableBooleans, actual.booleans); + ASSERT_SAME_CONTENT(expected.nullableBytes, actual.bytes); + ASSERT_SAME_CONTENT(expected.nullableShorts, actual.shorts); + ASSERT_SAME_CONTENT(expected.nullableInts, actual.ints); + ASSERT_SAME_CONTENT(expected.nullableLongs, actual.longs); + ASSERT_SAME_CONTENT(expected.nullableFloats, actual.floats); + ASSERT_SAME_CONTENT(expected.nullableDoubles, actual.doubles); +} + +TEST_F(CompactNullablePrimitiveInteroperabilityTest, + testWriteNullReadPrimitiveThrowsException) +{ + nullable_primitive_object expected; + + replicate_schema(); + replicate_schema(); + + SerializationService& ss = serialization_service(); + + const data& data = ss.to_data(expected); + ASSERT_THROW(ss.to_object(data), + exception::hazelcast_serialization); +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h b/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h new file mode 100644 index 0000000000..ccc93d324a --- /dev/null +++ b/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct CompactRabinFingerprintTest : public ::testing::Test +{ + template + using entry_t = std::tuple; + + static constexpr int int32_min = std::numeric_limits::min(); + static constexpr int64_t int64_min = std::numeric_limits::min(); + + template + void check_each(std::vector> entries) + { + for (const entry_t& e : entries) { + using namespace hazelcast::client::serialization::pimpl; + + auto fp_before = std::get<0>(e); + auto value = std::get<1>(e); + auto expected = std::get<2>(e); + auto fp_after = rabin_finger_print::fingerprint64(fp_before, value); + + EXPECT_EQ(fp_after, expected); + } + } +}; + +TEST_F(CompactRabinFingerprintTest, test_i8_fingerprint) +{ + check_each(std::vector>{ + // Before Val After(Expected) + { 100, -5, -6165936963810616235 }, + { int64_min, 0, 36028797018963968 }, + { 9223372036854775807, 113, -3588673659009074035 }, + { -13, -13, 72057594037927935 }, + { 42, 42, 0 }, + { 42, -42, -1212835703325587522 }, + { 0, 0, 0 }, + { -123456789, 0, 7049212178818848951 }, + { 123456789, 127, -8322440716502314713 }, + { 127, -128, -7333697815154264656 }, + }); +} + +TEST_F(CompactRabinFingerprintTest, test_i32_fingerprint) +{ + check_each(std::vector>{ + // Before Val After(Expected) + { int64_min, 2147483647, 6066553457199370002 }, + { 9223372036854775807, int32_min, 6066553459773452525 }, + { 9223372036854707, 42, -961937498224213201 }, + { -42, -42, 4294967295 }, + { 42, 42, 0 }, + { 42, -442, 7797744281030715531 }, + { 0, 0, 0 }, + { -123456789, 0, -565582369564281851 }, + { 123456786669, 42127, 7157681543413310373 }, + { 2147483647, int32_min, -7679311364898232185 } }); +} + +TEST_F(CompactRabinFingerprintTest, test_str_fingerprint) +{ + check_each(std::vector>{ + { 0, "hazelcast", 8164249978089638648 }, + { -31231241235, "üğişçö", 6128923854942458838 }, + { 41231542121235, "😀 😃 😄", -6875080751809013377 }, + { rabin_finger_print::INIT, "STUdent", 1896492170246289820 }, + { rabin_finger_print::INIT, "aü😄", -2084249746924383631 }, + { rabin_finger_print::INIT, "", -2316162475121075004 }, + { -123321, "xyz", 2601391163390439688 }, + { 132132123132132, " ç", -7699875372487088773 }, + { 42, "42", 7764866287864698590 }, + { -42, "-42", -3434092993477103253 } }); +} + +// hazelcast.internal.serialization.impl.compact.RabinFingerPrintTest::testRabinFingerprint() +TEST_F(CompactRabinFingerprintTest, test_schema) +{ + using hazelcast::client::serialization::pimpl::schema_writer; + + schema_writer s_writer{ "SomeType" }; + auto writer = + hazelcast::client::serialization::pimpl::create_compact_writer(&s_writer); + + writer.write_int32("id", 0); + writer.write_string("name", boost::none); + writer.write_int8("age", 0); + writer.write_array_of_timestamp("times", boost::none); + + auto schema_id = std::move(s_writer).build().schema_id(); + ASSERT_EQ(3662264393229655598, schema_id); +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_replication_on_write_test.h b/hazelcast/test/src/compact/compact_schema_replication_on_write_test.h new file mode 100644 index 0000000000..2b257b6c69 --- /dev/null +++ b/hazelcast/test/src/compact/compact_schema_replication_on_write_test.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include "hazelcast/client/hazelcast_client.h" +#include "../HazelcastServerFactory.h" +#include "../HazelcastServer.h" +#include "../remote_controller_client.h" +#include "../TestHelperFunctions.h" + +#include "compact_test_base.h" +#include "serialization/a_type.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +class CompactSchemaReplicationOnWrite : public compact_test_base +{}; + +TEST_F(CompactSchemaReplicationOnWrite, imap_put) +{ + auto schema_parent = get_schema(); + auto schema_child = get_schema(); + + ASSERT_EQ(check_schema_on_backend(schema_parent), false); + ASSERT_EQ(check_schema_on_backend(schema_child), false); + + auto map = client.get_map(random_string()).get(); + + map->put(random_string(), a_type{}).get(); + + ASSERT_EQ(check_schema_on_backend(schema_parent), true); + ASSERT_EQ(check_schema_on_backend(schema_child), true); +} + +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_replication_stress_test.h b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h new file mode 100644 index 0000000000..c47204d031 --- /dev/null +++ b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "hazelcast/client/serialization/pimpl/compact/schema.h" +#include "hazelcast/client/spi/ClientContext.h" +#include "compact_test_base.h" +#include "serialization/stress_type.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +class CompactSchemaReplicationStress : public compact_test_base +{}; + +template +struct schema_replicator; + +template +struct schema_replicator +{ + schema_replicator(std::shared_ptr m, std::vector&) + {} +}; + +template +struct schema_replicator : schema_replicator +{ + schema_replicator(std::shared_ptr m, std::vector& schemas) + : schema_replicator(m, schemas) + { + stress_type instance{}; + auto schema = serialization::pimpl::build_schema(instance); + schemas.push_back(std::move(schema)); + m->put(Current, instance).get(); + } +}; + +template +std::vector replicate_schemas(std::shared_ptr map) +{ + std::vector schemas; + schema_replicator{map, schemas}; + return schemas; +} + +TEST_F(CompactSchemaReplicationStress, test) +{ + using replication_work_t = boost::future>; + auto map = client.get_map(random_string()).get(); + + replication_work_t replication_works[] = + { + boost::async( + boost::launch::async, + replicate_schemas<0,10>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<10,20>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<20,30>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<30,40>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<40,50>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<50,60>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<60,70>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<70,80>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<80,90>, + map + ), + boost::async( + boost::launch::async, + replicate_schemas<90,100>, + map + ) + }; + + std::vector replicated_schemas; + + auto append = [&replicated_schemas](std::vector schemas){ + replicated_schemas.insert(end(replicated_schemas),begin(schemas),end(schemas)); + }; + + for (replication_work_t& work : replication_works) + EXPECT_NO_THROW(append(work.get())); + + for (const serialization::pimpl::schema& s : replicated_schemas) + EXPECT_TRUE(check_schema_on_backend(s)); +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_test.h b/hazelcast/test/src/compact/compact_schema_test.h new file mode 100644 index 0000000000..1daa2824f9 --- /dev/null +++ b/hazelcast/test/src/compact/compact_schema_test.h @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include "hazelcast/client/serialization/pimpl/schema.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +class CompactSchemaTest : public ::testing::Test +{}; + +TEST_F(CompactSchemaTest, test_constructor) +{ + using hazelcast::client::serialization::pimpl::field_descriptor; + using hazelcast::client::serialization::pimpl::field_kind; + using hazelcast::client::serialization::pimpl::schema; + + schema all_types_schema{ + std::string{ "something" }, + std::unordered_map{ + { "boolean-0", BOOLEAN }, + { "boolean-1", BOOLEAN }, + { "boolean-2", BOOLEAN }, + { "boolean-3", BOOLEAN }, + { "boolean-4", BOOLEAN }, + { "boolean-5", BOOLEAN }, + { "boolean-6", BOOLEAN }, + { "boolean-7", BOOLEAN }, + { "boolean-8", BOOLEAN }, + { "boolean-9", BOOLEAN }, + { "boolean[]", ARRAY_OF_BOOLEAN }, + { "int8", INT8 }, + { "int8[]", ARRAY_OF_INT8 }, + { "int16", INT16 }, + { "int16[]", ARRAY_OF_INT16 }, + { "int32", INT32 }, + { "int32[]", ARRAY_OF_INT32 }, + { "int64", INT64 }, + { "int64[]", ARRAY_OF_INT64 }, + { "float32", FLOAT32 }, + { "float32[]", ARRAY_OF_FLOAT32 }, + { "float64", FLOAT64 }, + { "float64[]", ARRAY_OF_FLOAT64 }, + { "string", STRING }, + { "string[]", ARRAY_OF_STRING }, + { "decimal", DECIMAL }, + { "decimal[]", ARRAY_OF_DECIMAL }, + { "time", TIME }, + { "time[]", ARRAY_OF_TIME }, + { "date", DATE }, + { "date[]", ARRAY_OF_DATE }, + { "timestamp", TIMESTAMP }, + { "timestamp[]", ARRAY_OF_TIMESTAMP }, + { "timestamp_with_timezone", TIMESTAMP_WITH_TIMEZONE }, + { "timestamp_with_timezone[]", ARRAY_OF_TIMESTAMP_WITH_TIMEZONE }, + { "compact", COMPACT }, + { "compact[]", ARRAY_OF_COMPACT }, + { "nullable", NULLABLE_BOOLEAN }, + { "nullable[]", ARRAY_OF_NULLABLE_BOOLEAN }, + { "nullable", NULLABLE_INT8 }, + { "nullable[]", ARRAY_OF_NULLABLE_INT8 }, + { "nullable", NULLABLE_INT16 }, + { "nullable[]", ARRAY_OF_NULLABLE_INT16 }, + { "nullable", NULLABLE_INT32 }, + { "nullable[]", ARRAY_OF_NULLABLE_INT32 }, + { "nullable", NULLABLE_INT64 }, + { "nullable[]", ARRAY_OF_NULLABLE_INT64 }, + { "nullable", NULLABLE_FLOAT32 }, + { "nullable[]", ARRAY_OF_NULLABLE_INT64 }, + { "nullable", NULLABLE_FLOAT64 }, + { "nullable[]", ARRAY_OF_NULLABLE_FLOAT64 } } + }; + + auto result = all_types_schema.fields(); + + // Assert num of fields + ASSERT_EQ(all_types_schema.fixed_size_fields_length(), 29); + ASSERT_EQ(all_types_schema.number_of_var_size_fields(), 35); + + // Assert fix-sized fields + ASSERT_EQ(result["float64"].offset, 0); + ASSERT_EQ(result["float64"].index, -1); + ASSERT_EQ(result["float64"].bit_offset, -1); + ASSERT_EQ(result["int64"].offset, 8); + ASSERT_EQ(result["int64"].index, -1); + ASSERT_EQ(result["int64"].bit_offset, -1); + ASSERT_EQ(result["float32"].offset, 16); + ASSERT_EQ(result["float32"].index, -1); + ASSERT_EQ(result["float32"].bit_offset, -1); + ASSERT_EQ(result["int32"].offset, 20); + ASSERT_EQ(result["int32"].index, -1); + ASSERT_EQ(result["int32"].bit_offset, -1); + ASSERT_EQ(result["int16"].offset, 24); + ASSERT_EQ(result["int16"].index, -1); + ASSERT_EQ(result["int16"].bit_offset, -1); + ASSERT_EQ(result["int8"].offset, 26); + ASSERT_EQ(result["int8"].index, -1); + ASSERT_EQ(result["int8"].bit_offset, -1); + ASSERT_EQ(result["boolean-0"].offset, 27); + ASSERT_EQ(result["boolean-0"].index, -1); + ASSERT_EQ(result["boolean-0"].bit_offset, 0); + ASSERT_EQ(result["boolean-1"].offset, 27); + ASSERT_EQ(result["boolean-1"].index, -1); + ASSERT_EQ(result["boolean-1"].bit_offset, 1); + ASSERT_EQ(result["boolean-2"].offset, 27); + ASSERT_EQ(result["boolean-2"].index, -1); + ASSERT_EQ(result["boolean-2"].bit_offset, 2); + ASSERT_EQ(result["boolean-3"].offset, 27); + ASSERT_EQ(result["boolean-3"].index, -1); + ASSERT_EQ(result["boolean-3"].bit_offset, 3); + ASSERT_EQ(result["boolean-4"].offset, 27); + ASSERT_EQ(result["boolean-4"].index, -1); + ASSERT_EQ(result["boolean-4"].bit_offset, 4); + ASSERT_EQ(result["boolean-5"].offset, 27); + ASSERT_EQ(result["boolean-5"].index, -1); + ASSERT_EQ(result["boolean-5"].bit_offset, 5); + ASSERT_EQ(result["boolean-6"].offset, 27); + ASSERT_EQ(result["boolean-6"].index, -1); + ASSERT_EQ(result["boolean-6"].bit_offset, 6); + ASSERT_EQ(result["boolean-7"].offset, 27); + ASSERT_EQ(result["boolean-7"].index, -1); + ASSERT_EQ(result["boolean-7"].bit_offset, 7); + ASSERT_EQ(result["boolean-8"].offset, 28); + ASSERT_EQ(result["boolean-8"].index, -1); + ASSERT_EQ(result["boolean-8"].bit_offset, 0); + ASSERT_EQ(result["boolean-9"].offset, 28); + ASSERT_EQ(result["boolean-9"].index, -1); + ASSERT_EQ(result["boolean-9"].bit_offset, 1); + + // Assert variable sized fields + ASSERT_EQ(result["boolean[]"].offset, -1); + ASSERT_EQ(result["boolean[]"].index, 0); + ASSERT_EQ(result["boolean[]"].bit_offset, -1); + ASSERT_EQ(result["compact"].offset, -1); + ASSERT_EQ(result["compact"].index, 1); + ASSERT_EQ(result["compact"].bit_offset, -1); + ASSERT_EQ(result["compact[]"].offset, -1); + ASSERT_EQ(result["compact[]"].index, 2); + ASSERT_EQ(result["compact[]"].bit_offset, -1); + ASSERT_EQ(result["date"].offset, -1); + ASSERT_EQ(result["date"].index, 3); + ASSERT_EQ(result["date"].bit_offset, -1); + ASSERT_EQ(result["date[]"].offset, -1); + ASSERT_EQ(result["date[]"].index, 4); + ASSERT_EQ(result["date[]"].bit_offset, -1); + ASSERT_EQ(result["decimal"].offset, -1); + ASSERT_EQ(result["decimal"].index, 5); + ASSERT_EQ(result["decimal"].bit_offset, -1); + ASSERT_EQ(result["decimal[]"].offset, -1); + ASSERT_EQ(result["decimal[]"].index, 6); + ASSERT_EQ(result["decimal[]"].bit_offset, -1); + ASSERT_EQ(result["float32[]"].offset, -1); + ASSERT_EQ(result["float32[]"].index, 7); + ASSERT_EQ(result["float32[]"].bit_offset, -1); + ASSERT_EQ(result["float64[]"].offset, -1); + ASSERT_EQ(result["float64[]"].index, 8); + ASSERT_EQ(result["float64[]"].bit_offset, -1); + ASSERT_EQ(result["int16[]"].offset, -1); + ASSERT_EQ(result["int16[]"].index, 9); + ASSERT_EQ(result["int16[]"].bit_offset, -1); + ASSERT_EQ(result["int32[]"].offset, -1); + ASSERT_EQ(result["int32[]"].index, 10); + ASSERT_EQ(result["int32[]"].bit_offset, -1); + ASSERT_EQ(result["int64[]"].offset, -1); + ASSERT_EQ(result["int64[]"].index, 11); + ASSERT_EQ(result["int64[]"].bit_offset, -1); + ASSERT_EQ(result["int8[]"].offset, -1); + ASSERT_EQ(result["int8[]"].index, 12); + ASSERT_EQ(result["int8[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 13); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 14); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 15); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 16); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 17); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 18); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 19); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 20); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 21); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 22); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 23); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 24); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["nullable"].offset, -1); + ASSERT_EQ(result["nullable"].index, 25); + ASSERT_EQ(result["nullable"].bit_offset, -1); + ASSERT_EQ(result["nullable[]"].offset, -1); + ASSERT_EQ(result["nullable[]"].index, 26); + ASSERT_EQ(result["nullable[]"].bit_offset, -1); + ASSERT_EQ(result["string"].offset, -1); + ASSERT_EQ(result["string"].index, 27); + ASSERT_EQ(result["string"].bit_offset, -1); + ASSERT_EQ(result["string[]"].offset, -1); + ASSERT_EQ(result["string[]"].index, 28); + ASSERT_EQ(result["string[]"].bit_offset, -1); + ASSERT_EQ(result["time"].offset, -1); + ASSERT_EQ(result["time"].index, 29); + ASSERT_EQ(result["time"].bit_offset, -1); + ASSERT_EQ(result["time[]"].offset, -1); + ASSERT_EQ(result["time[]"].index, 30); + ASSERT_EQ(result["time[]"].bit_offset, -1); + ASSERT_EQ(result["timestamp"].offset, -1); + ASSERT_EQ(result["timestamp"].index, 31); + ASSERT_EQ(result["timestamp"].bit_offset, -1); + ASSERT_EQ(result["timestamp[]"].offset, -1); + ASSERT_EQ(result["timestamp[]"].index, 32); + ASSERT_EQ(result["timestamp[]"].bit_offset, -1); + ASSERT_EQ(result["timestamp_with_timezone"].offset, -1); + ASSERT_EQ(result["timestamp_with_timezone"].index, 33); + ASSERT_EQ(result["timestamp_with_timezone"].bit_offset, -1); + ASSERT_EQ(result["timestamp_with_timezone[]"].offset, -1); + ASSERT_EQ(result["timestamp_with_timezone[]"].index, 34); + ASSERT_EQ(result["timestamp_with_timezone[]"].bit_offset, -1); +} + +TEST_F(CompactSchemaTest, test_with_no_fields) +{ + schema no_fields_schema{ + std::string{ "something" }, + std::unordered_map{} + }; + + ASSERT_EQ(no_fields_schema.fields().size(), 0); + ASSERT_EQ(no_fields_schema.fixed_size_fields_length(), 0); + ASSERT_EQ(no_fields_schema.number_of_var_size_fields(), 0); +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_validation_test.h b/hazelcast/test/src/compact/compact_schema_validation_test.h new file mode 100644 index 0000000000..b4d0c04719 --- /dev/null +++ b/hazelcast/test/src/compact/compact_schema_validation_test.h @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +#include "hazelcast/client/serialization/pimpl/compact/schema.h" +#include "hazelcast/client/spi/ClientContext.h" +#include "compact_test_base.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +class CompactSchemaValidation : public compact_test_base +{ +protected: + + using schema_t = hazelcast::client::serialization::pimpl::schema; + using field_descriptor_t = hazelcast::client::serialization::pimpl::field_descriptor; + + struct schema_proxy + { + std::string type_name; + std::vector descriptors; + }; + + schema_proxy read_schema_from_server(const schema_t& schema) + { + Response response; + + remote_controller_client().executeOnController( + response, + factory_.get_cluster_id(), + ( + boost::format( + R"( + var schemas = instance_0.getOriginal().node.getSchemaService().getAllSchemas(); + var iterator = schemas.iterator(); + + var schema; + while(iterator.hasNext()){ + var schema = iterator.next(); + + if (schema.getSchemaId() == "%1%") + break; + } + + var schema_obj = {}; + + schema_obj.type_name = schema.getTypeName(); + schema_obj.fields = []; + + iterator = schema.getFields().iterator(); + + while(iterator.hasNext()){ + var descriptor = iterator.next(); + + schema_obj.fields.push( + { + kind: descriptor.getKind().getId(), + field_name: descriptor.getFieldName(), + index: descriptor.getIndex(), + offset: descriptor.getOffset(), + bitOffset: descriptor.getBitOffset() + } + ); + } + + result = "" + JSON.stringify(schema_obj); + )") % schema.schema_id() + ).str(), + Lang::JAVASCRIPT + ); + + return json_to_proxy(response.result); + } + +private: + + schema_proxy json_to_proxy(const std::string& text) + { + using namespace boost::property_tree; + + std::stringstream input; + + input << text; + + ptree root; + read_json(input,root); + + schema_proxy proxy; + proxy.type_name = root.get("type_name"); + + for (ptree::value_type& field : root.get_child("fields")){ + proxy.descriptors.push_back( + { + serialization::field_kind(field.second.get("kind")), + field.second.get("index") , + field.second.get("offset"), + field.second.get("bitOffset") + } + ); + } + + return proxy; + } +}; + +TEST_F(CompactSchemaValidation, validate) +{ + auto schema = get_schema(); + + replicate_schema(); + + auto actual = read_schema_from_server(schema); + + EXPECT_EQ(schema.type_name(), actual.type_name); + + for(const auto& pair : schema.fields()){ + field_descriptor_t descriptor = pair.second; + + bool found = find( + begin(actual.descriptors), + end(actual.descriptors), + descriptor + ) != end(actual.descriptors); + + EXPECT_TRUE(found); + } +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_serialization_test.h b/hazelcast/test/src/compact/compact_serialization_test.h new file mode 100644 index 0000000000..d0256e54fd --- /dev/null +++ b/hazelcast/test/src/compact/compact_serialization_test.h @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +#include "../TestHelperFunctions.h" + +#include "compact_test_base.h" +#include "serialization/main_dto.h" +#include "serialization/node_dto.h" +#include "serialization/bits_dto.h" +#include "serialization/employee_dto.h" +#include "serialization/wrong_field_name_read_obj.h" +#include "serialization/type_mismatch_obj.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +using namespace serialization::pimpl; + +class CompactSerializationTest : public compact_test_base +{ +public: + + SerializationService& serialization_service(){ + return spi::ClientContext{ client }.get_serialization_service(); + } + + template + T to_data_and_back_to_object(SerializationService& ss, T& value) + { + data data = ss.to_data(value); + return *(ss.to_object(data)); + } +}; + +TEST_F(CompactSerializationTest, testAllTypes) +{ + auto expected = create_main_dto(); + auto actual = to_data_and_back_to_object(serialization_service(), expected); + ASSERT_EQ(expected, actual); +} + +TEST_F(CompactSerializationTest, testRecursive) +{ + auto n2 = std::make_shared(node_dto{ 2, nullptr }); + auto n1 = std::make_shared(node_dto{ 1, n2 }); + node_dto expected{ 0, n1 }; + auto actual = to_data_and_back_to_object(serialization_service(), expected); + ASSERT_EQ(expected, actual); +} + +TEST_F(CompactSerializationTest, testBits) +{ + auto& ss = serialization_service(); + + bits_dto expected; + expected.a = true; + expected.b = true; + expected.i = true; + expected.id = 121; + expected.booleans = boost::make_optional>( + { true, false, false, false, true, false, false, false }); + + const data& data = ss.to_data(expected); + // hash(4) + typeid(4) + schemaId(8) + (4 byte length) + (2 bytes for 9 + // bits) + (4 bytes for int) (4 byte length of byte array) + (1 byte for + // booleans array of 8 bits) + (1 byte offset bytes) + ASSERT_EQ(32, data.total_size()); + + bits_dto actual = *(ss.to_object(data)); + ASSERT_EQ(expected, actual); +} + +void +check_schema_field(const schema& schema, + const std::string& field_name, + int offset, + int index, + int bit_offset) +{ + ASSERT_EQ(offset, schema.fields().at(field_name).offset); + ASSERT_EQ(index, schema.fields().at(field_name).index); + ASSERT_EQ(bit_offset, schema.fields().at(field_name).bit_offset); +} + +TEST_F(CompactSerializationTest, test_field_order_fixed_size) +{ + schema_writer schema_writer("typeName"); + auto writer = serialization::pimpl::create_compact_writer(&schema_writer); + serialization::hz_serializer::write(employee_dto{}, writer); + auto schema = std::move(schema_writer).build(); + + check_schema_field(schema, "id", 0, -1, -1); + check_schema_field(schema, "age", 8, -1, -1); + check_schema_field(schema, "rank", 12, -1, -1); + check_schema_field(schema, "isFired", 16, -1, 0); + check_schema_field(schema, "isHired", 16, -1, 1); +} + +TEST_F(CompactSerializationTest, test_schema_writer_counts) +{ + using serialization::field_kind; + + schema_writer schema_writer("typename"); + schema_writer.add_field("int1", field_kind::INT32); + schema_writer.add_field("int2", field_kind::INT32); + schema_writer.add_field("string1", field_kind::STRING); + auto schema = std::move(schema_writer).build(); + + ASSERT_EQ(8, schema.fixed_size_fields_length()); + ASSERT_EQ(1, schema.number_of_var_size_fields()); +} + +TEST_F(CompactSerializationTest, test_read_when_field_does_not_exist) +{ + auto& ss = serialization_service(); + + wrong_field_name_read_obj obj; + + auto data = ss.to_data(obj); + ASSERT_THROW(ss.to_object(data), + exception::hazelcast_serialization); +} + +TEST_F(CompactSerializationTest, test_read_with_type_mismatch) +{ + auto& ss = serialization_service(); + type_mistmatch_obj obj; + + auto data = ss.to_data(obj); + ASSERT_THROW(ss.to_object(data), + exception::hazelcast_serialization); +} + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_test_base.h b/hazelcast/test/src/compact/compact_test_base.h new file mode 100644 index 0000000000..0204e1e8e2 --- /dev/null +++ b/hazelcast/test/src/compact/compact_test_base.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "hazelcast/client/hazelcast_client.h" +#include "../HazelcastServerFactory.h" +#include "../HazelcastServer.h" +#include "../remote_controller_client.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +class compact_test_base : public testing::Test +{ +public: + using schema_t = serialization::pimpl::schema; + + compact_test_base() + : factory_{ "hazelcast/test/resources/compact.xml" } + , member_{ factory_ } + , client{ new_client(config()).get() } + { + remote_controller_client().ping(); + } + +protected: + + void SetUp() override { + auto version = client.get_cluster() + .get_members() + .front() + .get_version(); + + if (version < member::version {5,2,0}) + GTEST_SKIP(); + } + + template + void replicate_schema() + { + auto schema = get_schema(); + + spi::ClientContext context {client}; + + ASSERT_NO_THROW(context.get_schema_service().replicate_schema(schema).get()); + } + + bool check_schema_on_backend(const schema_t& schema) + { + Response response; + + remote_controller_client().executeOnController( + response, + factory_.get_cluster_id(), + (boost::format( + R"( + var schemas = instance_0.getOriginal().node.getSchemaService().getAllSchemas(); + var iterator = schemas.iterator(); + + var exist = false; + while(iterator.hasNext()){ + var schema = iterator.next(); + + if (schema.getSchemaId() == "%1%") + exist = true; + } + + result = "" + exist; + )") % + schema.schema_id()) + .str(), + Lang::JAVASCRIPT); + + return response.result == "true"; + } + + template + schema_t get_schema() + { + T instance; + return serialization::pimpl::build_schema(instance); + } + + HazelcastServerFactory factory_; + HazelcastServer member_; + hazelcast_client client; + +private: + + static client_config config() + { + client_config cfg; + + cfg.set_cluster_name("compact-dev"); + + return cfg; + } +}; + +} +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/a_type.h b/hazelcast/test/src/compact/serialization/a_type.h new file mode 100644 index 0000000000..bf406129e0 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/a_type.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" +#include "nested_type.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct a_type +{ + int x; + nested_type nested; +}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer : compact_serializer +{ + static void write(const test::compact::a_type& object, + compact_writer& writer) + { + writer.write_boolean("x", object.x); + writer.write_compact("nested", + object.nested); + } + + static test::compact::a_type read(compact_reader& reader) + { + test::compact::a_type object; + + object.x = reader.read_int32("x"); + object.nested = + *reader.read_compact("nested"); + + return object; + } + + static std::string type_name() { return "a_type"; } +}; + +} // namespace serialization +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/bits_dto.h b/hazelcast/test/src/compact/serialization/bits_dto.h new file mode 100644 index 0000000000..56ab5608b0 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/bits_dto.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct bits_dto +{ + bool a = false; + bool b = false; + bool c = false; + bool d = false; + bool e = false; + bool f = false; + bool g = false; + bool h = false; + bool i = false; + int id = 0; + boost::optional> booleans; +}; + +bool +operator==(const bits_dto& lhs, const bits_dto& rhs) +{ + return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c && + lhs.d == rhs.d && lhs.e == rhs.e && lhs.f == rhs.f && + lhs.g == rhs.g && lhs.h == rhs.h && lhs.i == rhs.i && + lhs.id == rhs.id && lhs.booleans == rhs.booleans; +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::bits_dto& dto, + compact_writer& writer) + { + writer.write_boolean("a", dto.a); + writer.write_boolean("b", dto.b); + writer.write_boolean("c", dto.c); + writer.write_boolean("d", dto.d); + writer.write_boolean("e", dto.e); + writer.write_boolean("f", dto.f); + writer.write_boolean("g", dto.g); + writer.write_boolean("h", dto.h); + writer.write_boolean("i", dto.i); + writer.write_int32("id", dto.id); + writer.write_array_of_boolean("booleans", dto.booleans); + } + + static test::compact::bits_dto read(compact_reader& reader) + { + test::compact::bits_dto dto; + dto.a = reader.read_boolean("a"); + dto.b = reader.read_boolean("b"); + dto.c = reader.read_boolean("c"); + dto.d = reader.read_boolean("d"); + dto.e = reader.read_boolean("e"); + dto.f = reader.read_boolean("f"); + dto.g = reader.read_boolean("g"); + dto.h = reader.read_boolean("h"); + dto.i = reader.read_boolean("i"); + dto.id = reader.read_int32("id"); + dto.booleans = reader.read_array_of_boolean("booleans"); + return dto; + } + + static std::string type_name() { return "bits_dto"; } +}; + +} + +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/employee_dto.h b/hazelcast/test/src/compact/serialization/employee_dto.h new file mode 100644 index 0000000000..4261b19782 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/employee_dto.h @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct employee_dto +{ + int32_t age; + int32_t rank; + int64_t id; + bool isHired; + bool isFired; +}; + +bool +operator==(const employee_dto& lhs, const employee_dto& rhs) +{ + return lhs.age == rhs.age && lhs.rank == rhs.rank && lhs.id == rhs.id && + lhs.isHired == rhs.isHired && lhs.isFired == rhs.isFired; +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::employee_dto& object, + compact_writer& writer) + { + writer.write_int32("age", object.age); + writer.write_int32("rank", object.rank); + writer.write_int64("id", object.id); + writer.write_boolean("isHired", object.isHired); + writer.write_boolean("isFired", object.isFired); + } + + static test::compact::employee_dto read(compact_reader& reader) + { + auto age = reader.read_int32("age"); + auto rank = reader.read_int32("rank"); + auto id = reader.read_int64("id"); + auto isHired = reader.read_boolean("isHired"); + auto isFired = reader.read_boolean("isFired"); + + return test::compact::employee_dto{ age, rank, id, isHired, isFired }; + } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/empty_main_dto.h b/hazelcast/test/src/compact/serialization/empty_main_dto.h new file mode 100644 index 0000000000..f6a8cacbe0 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/empty_main_dto.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +/** + * This class is to simulate versioning. + * We will provide this struct with serializer returning type name of the + * original main dto. This way we can use the serialized data of this class + * to test to_object of the original main_dto. + */ +struct empty_main_dto +{}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const compact::test::empty_main_dto& object, + compact_writer& writer) + {} + + static compact::test::empty_main_dto read(compact_reader& reader) + { + return compact::test::empty_main_dto{}; + } + + static std::string type_name() { return "main"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/inner_dto.h b/hazelcast/test/src/compact/serialization/inner_dto.h new file mode 100644 index 0000000000..3705c09e15 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/inner_dto.h @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +#include "named_dto.h" +#include "../compact_helper.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct inner_dto +{ + boost::optional> bools; + boost::optional> bytes; + boost::optional> shorts; + boost::optional> ints; + boost::optional> longs; + boost::optional> floats; + boost::optional> doubles; + boost::optional>> strings; + boost::optional>> nn; + boost::optional>> bigDecimals; + boost::optional>> localTimes; + boost::optional>> localDates; + boost::optional>> + localDateTimes; + boost::optional>> + offsetDateTimes; + boost::optional>> nullableBools; + boost::optional>> nullableBytes; + boost::optional>> nullableShorts; + boost::optional>> nullableInts; + boost::optional>> nullableLongs; + boost::optional>> nullableFloats; + boost::optional>> nullableDoubles; +}; + +bool +operator==(const inner_dto& lhs, const inner_dto& rhs) +{ + return lhs.bools == rhs.bools && lhs.bytes == rhs.bytes && + lhs.shorts == rhs.shorts && lhs.ints == rhs.ints && + lhs.longs == rhs.longs && lhs.floats == rhs.floats && + lhs.doubles == rhs.doubles && lhs.strings == rhs.strings && + lhs.nn == rhs.nn && lhs.bigDecimals == rhs.bigDecimals && + lhs.localTimes == rhs.localTimes && + lhs.localDates == rhs.localDates && + lhs.localDateTimes == rhs.localDateTimes && + lhs.offsetDateTimes == rhs.offsetDateTimes && + lhs.nullableBools == rhs.nullableBools && + lhs.nullableBytes == rhs.nullableBytes && + lhs.nullableShorts == rhs.nullableShorts && + lhs.nullableInts == rhs.nullableInts && + lhs.nullableLongs == rhs.nullableLongs && + lhs.nullableFloats == rhs.nullableFloats && + lhs.nullableDoubles == rhs.nullableDoubles; +} + +inner_dto +create_inner_dto() +{ + return inner_dto{ + boost::make_optional>({ true, false }), + boost::make_optional>({ 0, 1, 2 }), + boost::make_optional>({ 3, 4, 5 }), + boost::make_optional>({ 9, 8, 7, 6 }), + boost::make_optional>({ 0, 1, 5, 7, 9, 11 }), + boost::make_optional>({ 0.6543f, -3.56f, 45.67f }), + boost::make_optional>( + { 456.456, 789.789, 321.321 }), + boost::make_optional>>( + { boost::make_optional("test"), boost::none }), + boost::make_optional>>( + { boost::make_optional( + named_dto{ boost::make_optional("test"), 1 }), + boost::none }), + boost::make_optional< + std::vector>>( + { boost::make_optional(hazelcast::client::big_decimal{ + boost::multiprecision::cpp_int{ "12345" }, 0 }), + boost::make_optional(hazelcast::client::big_decimal{ + boost::multiprecision::cpp_int{ "123456" }, 0 }) }), + boost::make_optional< + std::vector>>( + { boost::make_optional(current_time()), + boost::none, + boost::make_optional(current_time()) }), + boost::make_optional< + std::vector>>( + { boost::make_optional(current_date()), + boost::none, + boost::make_optional(current_date()) }), + boost::make_optional< + std::vector>>( + { boost::make_optional(current_timestamp()), boost::none }), + boost::make_optional< + std::vector>>( + { boost::make_optional(current_timestamp_with_timezone()) }), + boost::make_optional>>( + { boost::make_optional(true), + boost::make_optional(false), + boost::none }), + boost::make_optional>>( + { boost::make_optional(0), + boost::make_optional(1), + boost::make_optional(2), + boost::none }), + boost::make_optional>>( + { boost::make_optional(3), + boost::make_optional(4), + boost::make_optional(5), + boost::none }), + boost::make_optional>>( + { boost::make_optional(9), + boost::make_optional(8), + boost::make_optional(7), + boost::make_optional(6), + boost::none }), + boost::make_optional>>( + { boost::make_optional(0), + boost::make_optional(1), + boost::make_optional(5), + boost::make_optional(7), + boost::none }), + boost::make_optional>>( + { boost::make_optional(0.6543f), + boost::make_optional(-3.56f), + boost::make_optional(45.67f), + boost::none }), + boost::make_optional>>( + { boost::make_optional(456.456), + boost::make_optional(789.789), + boost::make_optional(321.321), + boost::none }), + }; +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::inner_dto& object, + compact_writer& writer) + { + writer.write_array_of_boolean("bools", object.bools); + writer.write_array_of_int8("bytes", object.bytes); + writer.write_array_of_int16("shorts", object.shorts); + writer.write_array_of_int32("ints", object.ints); + writer.write_array_of_int64("longs", object.longs); + writer.write_array_of_float32("floats", object.floats); + writer.write_array_of_float64("doubles", object.doubles); + writer.write_array_of_string("strings", object.strings); + writer.write_array_of_decimal("bigDecimals", object.bigDecimals); + writer.write_array_of_time("localTimes", object.localTimes); + writer.write_array_of_date("localDates", object.localDates); + writer.write_array_of_timestamp("localDateTimes", + object.localDateTimes); + writer.write_array_of_timestamp_with_timezone("offsetDateTimes", + object.offsetDateTimes); + writer.write_array_of_compact("nn", object.nn); + writer.write_array_of_nullable_boolean("nullableBools", + object.nullableBools); + writer.write_array_of_nullable_int8("nullableBytes", + object.nullableBytes); + writer.write_array_of_nullable_int16("nullableShorts", + object.nullableShorts); + writer.write_array_of_nullable_int32("nullableInts", + object.nullableInts); + writer.write_array_of_nullable_int64("nullableLongs", + object.nullableLongs); + writer.write_array_of_nullable_float32("nullableFloats", + object.nullableFloats); + writer.write_array_of_nullable_float64("nullableDoubles", + object.nullableDoubles); + } + + static test::compact::inner_dto read(compact_reader& reader) + { + test::compact::inner_dto object; + object.bools = reader.read_array_of_boolean("bools"); + object.bytes = reader.read_array_of_int8("bytes"); + object.shorts = reader.read_array_of_int16("shorts"); + object.ints = reader.read_array_of_int32("ints"); + object.longs = reader.read_array_of_int64("longs"); + object.floats = reader.read_array_of_float32("floats"); + object.doubles = reader.read_array_of_float64("doubles"); + object.strings = reader.read_array_of_string("strings"); + object.bigDecimals = reader.read_array_of_decimal("bigDecimals"); + object.localTimes = reader.read_array_of_time("localTimes"); + object.localDates = reader.read_array_of_date("localDates"); + object.localDateTimes = + reader.read_array_of_timestamp("localDateTimes"); + object.offsetDateTimes = + reader.read_array_of_timestamp_with_timezone("offsetDateTimes"); + object.nn = + reader.read_array_of_compact("nn"); + object.nullableBools = + reader.read_array_of_nullable_boolean("nullableBools"); + object.nullableBytes = + reader.read_array_of_nullable_int8("nullableBytes"); + object.nullableShorts = + reader.read_array_of_nullable_int16("nullableShorts"); + object.nullableInts = + reader.read_array_of_nullable_int32("nullableInts"); + object.nullableLongs = + reader.read_array_of_nullable_int64("nullableLongs"); + object.nullableFloats = + reader.read_array_of_nullable_float32("nullableFloats"); + object.nullableDoubles = + reader.read_array_of_nullable_float64("nullableDoubles"); + return object; + } + + static std::string type_name() { return "inner"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/main_dto.h b/hazelcast/test/src/compact/serialization/main_dto.h new file mode 100644 index 0000000000..ca2c03d352 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/main_dto.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" +#include "inner_dto.h" + +namespace hazelcast{ +namespace client { +namespace test { +namespace compact { + +struct main_dto +{ + bool boolean; + int8_t b; + int16_t s; + int32_t i; + int64_t l; + float f; + double d; + std::string str; + boost::optional p; + boost::optional bigDecimal; + boost::optional localTime; + boost::optional localDate; + boost::optional localDateTime; + boost::optional offsetDateTime; + boost::optional nullableBool; + boost::optional nullableB; + boost::optional nullableS; + boost::optional nullableI; + boost::optional nullableL; + boost::optional nullableF; + boost::optional nullableD; +}; + +bool +operator==(const main_dto& lhs, const main_dto& rhs) +{ + return lhs.boolean == rhs.boolean && lhs.b == rhs.b && lhs.s == rhs.s && + lhs.i == rhs.i && lhs.l == rhs.l && lhs.f == rhs.f && + lhs.d == rhs.d && lhs.str == rhs.str && lhs.p == rhs.p && + lhs.bigDecimal == rhs.bigDecimal && lhs.localTime == rhs.localTime && + lhs.localDate == rhs.localDate && + lhs.localDateTime == rhs.localDateTime && + lhs.offsetDateTime == rhs.offsetDateTime && + lhs.nullableBool == rhs.nullableBool && + lhs.nullableB == rhs.nullableB && lhs.nullableS == rhs.nullableS && + lhs.nullableI == rhs.nullableI && lhs.nullableL == rhs.nullableL && + lhs.nullableF == rhs.nullableF && lhs.nullableD == rhs.nullableD; +} + +main_dto +create_main_dto() +{ + inner_dto p = create_inner_dto(); + + return main_dto{ true, + 113, + -500, + 56789, + -50992225L, + 900.5678f, + -897543.3678909, + "this is main object created for testing!", + p, + hazelcast::client::big_decimal{ + boost::multiprecision::cpp_int{ "12312313" }, 0 }, + hazelcast::client::local_time{ 1, 2, 3, 4 }, + hazelcast::client::local_date{ 2015, 12, 31 }, + hazelcast::client::local_date_time{ + hazelcast::client::local_date{ 2015, 12, 31 }, + hazelcast::client::local_time{ 1, 2, 3, 4 } }, + hazelcast::client::offset_date_time{ + hazelcast::client::local_date_time{ + hazelcast::client::local_date{ 2015, 12, 31 }, + hazelcast::client::local_time{ 1, 2, 3, 4 } }, + 100 }, + true, + 113, + (short)-500, + 56789, + -50992225L, + 900.5678f, + -897543.3678909 }; +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::main_dto& object, + compact_writer& writer) + { + writer.write_boolean("bool", object.boolean); + writer.write_int8("b", object.b); + writer.write_int16("s", object.s); + writer.write_int32("i", object.i); + writer.write_int64("l", object.l); + writer.write_float32("f", object.f); + writer.write_float64("d", object.d); + writer.write_string("str", object.str); + writer.write_decimal("bigDecimal", object.bigDecimal); + writer.write_time("localTime", object.localTime); + writer.write_date("localDate", object.localDate); + writer.write_timestamp("localDateTime", object.localDateTime); + writer.write_timestamp_with_timezone("offsetDateTime", + object.offsetDateTime); + writer.write_compact("p", object.p); + writer.write_nullable_boolean("nullableBool", object.nullableBool); + writer.write_nullable_int8("nullableB", object.nullableB); + writer.write_nullable_int16("nullableS", object.nullableS); + writer.write_nullable_int32("nullableI", object.nullableI); + writer.write_nullable_int64("nullableL", object.nullableL); + writer.write_nullable_float32("nullableF", object.nullableF); + writer.write_nullable_float64("nullableD", object.nullableD); + } + + static test::compact::main_dto read(compact_reader& reader) + { + auto boolean = reader.read_boolean("bool"); + auto b = reader.read_int8("b"); + auto s = reader.read_int16("s"); + auto i = reader.read_int32("i"); + auto l = reader.read_int64("l"); + auto f = reader.read_float32("f"); + auto d = reader.read_float64("d"); + auto str = reader.read_string("str"); + auto bigDecimal = reader.read_decimal("bigDecimal"); + auto localTime = reader.read_time("localTime"); + auto localDate = reader.read_date("localDate"); + auto localDateTime = reader.read_timestamp("localDateTime"); + auto offsetDateTime = + reader.read_timestamp_with_timezone("offsetDateTime"); + auto p = reader.read_compact("p"); + auto nullableBool = reader.read_nullable_boolean("nullableBool"); + auto nullableB = reader.read_nullable_int8("nullableB"); + auto nullableS = reader.read_nullable_int16("nullableS"); + auto nullableI = reader.read_nullable_int32("nullableI"); + auto nullableL = reader.read_nullable_int64("nullableL"); + auto nullableF = reader.read_nullable_float32("nullableF"); + auto nullableD = reader.read_nullable_float64("nullableD"); + + return test::compact::main_dto{ boolean, + b, + s, + i, + l, + f, + d, + *str, + p, + bigDecimal, + localTime, + localDate, + localDateTime, + offsetDateTime, + nullableBool, + nullableB, + nullableS, + nullableI, + nullableL, + nullableF, + nullableD }; + } + + static std::string type_name() { return "main"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/named_dto.h b/hazelcast/test/src/compact/serialization/named_dto.h new file mode 100644 index 0000000000..1546676a3c --- /dev/null +++ b/hazelcast/test/src/compact/serialization/named_dto.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct named_dto +{ + boost::optional name; + int my_int; +}; + +bool +operator==(const named_dto& lhs, const named_dto& rhs) +{ + return lhs.name == rhs.name && lhs.my_int == rhs.my_int; +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::named_dto& dto, + compact_writer& writer) + { + writer.write_string("name", dto.name); + writer.write_int32("my_int", dto.my_int); + } + + static test::compact::named_dto read(compact_reader& reader) + { + test::compact::named_dto dto; + dto.name = reader.read_string("name"); + dto.my_int = reader.read_int32("my_int"); + return dto; + } + + static std::string type_name() { return "named_dto"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/nested_type.h b/hazelcast/test/src/compact/serialization/nested_type.h new file mode 100644 index 0000000000..b986e4adff --- /dev/null +++ b/hazelcast/test/src/compact/serialization/nested_type.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct nested_type +{ + int y; +}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer : compact_serializer +{ + static void write(const test::compact::nested_type& object, + compact_writer& writer) + { + writer.write_int32("x", object.y); + } + + static test::compact::nested_type read(compact_reader& reader) + { + test::compact::nested_type object; + + object.y = reader.read_int32("y"); + + return object; + } + + static std::string type_name() { return "nested_type"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/node_dto.h b/hazelcast/test/src/compact/serialization/node_dto.h new file mode 100644 index 0000000000..e41b56c094 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/node_dto.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct node_dto +{ + int id; + std::shared_ptr child; +}; + +bool +operator==(const node_dto& lhs, const node_dto& rhs) +{ + return lhs.id == rhs.id && + (lhs.child == rhs.child || + (lhs.child && rhs.child && *lhs.child == *rhs.child)); +} + +} +} + +namespace serialization { + +template<> +struct hz_serializer : public compact_serializer +{ + static void write(const test::compact::node_dto& object, + compact_writer& writer) + { + writer.write_int32("id", object.id); + writer.write_compact( + "child", + object.child == nullptr ? boost::none + : boost::make_optional(*object.child)); + } + + static test::compact::node_dto read(compact_reader& reader) + { + auto id = reader.read_int32("id"); + auto&& child = reader.read_compact("child"); + return test::compact::node_dto{ + id, + child.has_value() + ? std::make_shared(child.value()) + : nullptr + }; + } + + static std::string type_name() { return "node"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/nullable_primitive_object.h b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h new file mode 100644 index 0000000000..283d312dbb --- /dev/null +++ b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct nullable_primitive_object +{ + boost::optional nullableBoolean; + boost::optional nullableByte; + boost::optional nullableShort; + boost::optional nullableInt; + boost::optional nullableLong; + boost::optional nullableFloat; + boost::optional nullableDouble; + boost::optional>> nullableBooleans; + boost::optional>> nullableBytes; + boost::optional>> nullableShorts; + boost::optional>> nullableInts; + boost::optional>> nullableLongs; + boost::optional>> nullableFloats; + boost::optional>> nullableDoubles; +}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer + : public compact_serializer +{ + static void write(const test::compact::nullable_primitive_object& object, + compact_writer& writer) + { + writer.write_nullable_boolean("boolean", object.nullableBoolean); + writer.write_nullable_int8("byte", object.nullableByte); + writer.write_nullable_int16("short", object.nullableShort); + writer.write_nullable_int32("int", object.nullableInt); + writer.write_nullable_int64("long", object.nullableLong); + writer.write_nullable_float32("float", object.nullableFloat); + writer.write_nullable_float64("double", object.nullableDouble); + writer.write_array_of_nullable_boolean("booleans", + object.nullableBooleans); + writer.write_array_of_nullable_int8("bytes", object.nullableBytes); + writer.write_array_of_nullable_int16("shorts", object.nullableShorts); + writer.write_array_of_nullable_int32("ints", object.nullableInts); + writer.write_array_of_nullable_int64("longs", object.nullableLongs); + writer.write_array_of_nullable_float32("floats", object.nullableFloats); + writer.write_array_of_nullable_float64("doubles", + object.nullableDoubles); + } + + static test::compact::nullable_primitive_object read(compact_reader& reader) + { + test::compact::nullable_primitive_object object; + + object.nullableBoolean = reader.read_nullable_boolean("boolean"); + object.nullableByte = reader.read_nullable_int8("byte"); + object.nullableShort = reader.read_nullable_int16("short"); + object.nullableInt = reader.read_nullable_int32("int"); + object.nullableLong = reader.read_nullable_int64("long"); + object.nullableFloat = reader.read_nullable_float32("float"); + object.nullableDouble = reader.read_nullable_float64("double"); + object.nullableBooleans = + reader.read_array_of_nullable_boolean("booleans"); + object.nullableBytes = reader.read_array_of_nullable_int8("bytes"); + object.nullableShorts = reader.read_array_of_nullable_int16("shorts"); + object.nullableInts = reader.read_array_of_nullable_int32("ints"); + object.nullableLongs = reader.read_array_of_nullable_int64("longs"); + object.nullableFloats = reader.read_array_of_nullable_float32("floats"); + object.nullableDoubles = + reader.read_array_of_nullable_float64("doubles"); + + return object; + } + + // typename is same as the primitive_object on purpose. + // This is to simulate two different applications implementing the same + // class with different serializers. + static std::string type_name() { return "primitive_object"; } +}; +} + +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/primitive_object.h b/hazelcast/test/src/compact/serialization/primitive_object.h new file mode 100644 index 0000000000..d14360b49e --- /dev/null +++ b/hazelcast/test/src/compact/serialization/primitive_object.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast{ +namespace client { +namespace test { +namespace compact { + +struct primitive_object +{ + bool boolean_; + int8_t byte_; + int16_t short_; + int32_t int_; + int64_t long_; + float float_; + double double_; + boost::optional> booleans; + boost::optional> bytes; + boost::optional> shorts; + boost::optional> ints; + boost::optional> longs; + boost::optional> floats; + boost::optional> doubles; +}; + +} +} + +namespace serialization { +template<> +struct hz_serializer + : public compact_serializer +{ + static void write(const test::compact::primitive_object& object, + compact_writer& writer) + { + writer.write_boolean("boolean", object.boolean_); + writer.write_int8("byte", object.byte_); + writer.write_int16("short", object.short_); + writer.write_int32("int", object.int_); + writer.write_int64("long", object.long_); + writer.write_float32("float", object.float_); + writer.write_float64("double", object.double_); + writer.write_array_of_boolean("booleans", object.booleans); + writer.write_array_of_int8("bytes", object.bytes); + writer.write_array_of_int16("shorts", object.shorts); + writer.write_array_of_int32("ints", object.ints); + writer.write_array_of_int64("longs", object.longs); + writer.write_array_of_float32("floats", object.floats); + writer.write_array_of_float64("doubles", object.doubles); + } + + static test::compact::primitive_object read(compact_reader& reader) + { + test::compact::primitive_object object; + + object.boolean_ = reader.read_boolean("boolean"); + object.byte_ = reader.read_int8("byte"); + object.short_ = reader.read_int16("short"); + object.int_ = reader.read_int32("int"); + object.long_ = reader.read_int64("long"); + object.float_ = reader.read_float32("float"); + object.double_ = reader.read_float64("double"); + object.booleans = reader.read_array_of_boolean("booleans"); + object.bytes = reader.read_array_of_int8("bytes"); + object.shorts = reader.read_array_of_int16("shorts"); + object.ints = reader.read_array_of_int32("ints"); + object.longs = reader.read_array_of_int64("longs"); + object.floats = reader.read_array_of_float32("floats"); + object.doubles = reader.read_array_of_float64("doubles"); + + return object; + } + + static std::string type_name() { return "primitive_object"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/stress_type.h b/hazelcast/test/src/compact/serialization/stress_type.h new file mode 100644 index 0000000000..9009f12fc9 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/stress_type.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +template +struct stress_type +{}; + +} +} +} +} + +namespace hazelcast { +namespace client { +namespace serialization { + +template +struct hz_serializer> : compact_serializer +{ + static std::string type_name() { return "stress_type_" + std::to_string(Idx); } + + static void write(const test::compact::stress_type&, + compact_writer& writer) + { + writer.write_int32("field_" + std::to_string(Idx), Idx); + } + + static test::compact::stress_type read(compact_reader& reader) + { + return test::compact::stress_type{}; + } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/type_mismatch_obj.h b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h new file mode 100644 index 0000000000..a08ef378cb --- /dev/null +++ b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct type_mistmatch_obj +{ + int value; +}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer : compact_serializer +{ + static void write(const test::compact::type_mistmatch_obj& obj, + compact_writer& writer) + { + writer.write_int32("field_1", obj.value); + } + + static test::compact::type_mistmatch_obj read(compact_reader& reader) + { + test::compact::type_mistmatch_obj obj; + + obj.value = static_cast(reader.read_float32("field_1")); + + return obj; + } + + static std::string type_name() { return "type_mistmatch_obj"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h new file mode 100644 index 0000000000..341d56ec59 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct wrong_field_name_read_obj +{ + int value; +}; + +} +} + +namespace serialization { + +template<> +struct hz_serializer + : compact_serializer +{ + static void write(const test::compact::wrong_field_name_read_obj& obj, + compact_writer& writer) + { + writer.write_int32("field_1", obj.value); + } + + static test::compact::wrong_field_name_read_obj read(compact_reader& reader) + { + test::compact::wrong_field_name_read_obj obj; + + obj.value = reader.read_int32("wrong_field"); + + return obj; + } + + static std::string type_name() { return "wrong_field_name_read_obj"; } +}; + +} +} +} \ No newline at end of file diff --git a/hazelcast/test/src/compact_test.cpp b/hazelcast/test/src/compact_test.cpp index f97ff44054..12845c4a88 100644 --- a/hazelcast/test/src/compact_test.cpp +++ b/hazelcast/test/src/compact_test.cpp @@ -13,1430 +13,10 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include -#include -#include -#include -#include -#include -#include - -#ifdef HZ_BUILD_WITH_SSL -#include -#endif - -#include - -#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64) -#pragma warning(push) -#pragma warning(disable : 4996) // for unsafe getenv -#endif -using namespace hazelcast::client::serialization::pimpl; -namespace hazelcast { -namespace client { -namespace compact { -namespace test { - -/** - * It contains 9 boolean fields. - * So it will occupy to 9 bits when it is serialized. - * 9 bits mean 2 bytes - * So 'i' was added for this reason to accomodate more than a byte - * to enlarge to scope of the test. -*/ -struct bits_dto -{ - bool a = false; - bool b = false; - bool c = false; - bool d = false; - bool e = false; - bool f = false; - bool g = false; - bool h = false; - bool i = false; - int id = 0; - boost::optional> booleans; -}; - -bool -operator==(const bits_dto& lhs, const bits_dto& rhs) -{ - return lhs.a == rhs.a && lhs.b == rhs.b && lhs.c == rhs.c && - lhs.d == rhs.d && lhs.e == rhs.e && lhs.f == rhs.f && - lhs.g == rhs.g && lhs.h == rhs.h && lhs.i == rhs.i && - lhs.id == rhs.id && lhs.booleans == rhs.booleans; -} - -struct node_dto -{ - int id; - std::shared_ptr child; -}; - -bool -operator==(const node_dto& lhs, const node_dto& rhs) -{ - return lhs.id == rhs.id && - (lhs.child == rhs.child || - (lhs.child && rhs.child && *lhs.child == *rhs.child)); -} - -struct named_dto -{ - boost::optional name; - int my_int; -}; - -bool -operator==(const named_dto& lhs, const named_dto& rhs) -{ - return lhs.name == rhs.name && lhs.my_int == rhs.my_int; -} - -struct inner_dto -{ - boost::optional> bools; - boost::optional> bytes; - boost::optional> shorts; - boost::optional> ints; - boost::optional> longs; - boost::optional> floats; - boost::optional> doubles; - boost::optional>> strings; - boost::optional>> nn; - boost::optional>> bigDecimals; - boost::optional>> localTimes; - boost::optional>> localDates; - boost::optional>> - localDateTimes; - boost::optional>> - offsetDateTimes; - boost::optional>> nullableBools; - boost::optional>> nullableBytes; - boost::optional>> nullableShorts; - boost::optional>> nullableInts; - boost::optional>> nullableLongs; - boost::optional>> nullableFloats; - boost::optional>> nullableDoubles; -}; -bool -operator==(const inner_dto& lhs, const inner_dto& rhs) -{ - return lhs.bools == rhs.bools && lhs.bytes == rhs.bytes && - lhs.shorts == rhs.shorts && lhs.ints == rhs.ints && - lhs.longs == rhs.longs && lhs.floats == rhs.floats && - lhs.doubles == rhs.doubles && lhs.strings == rhs.strings && - lhs.nn == rhs.nn && lhs.bigDecimals == rhs.bigDecimals && - lhs.localTimes == rhs.localTimes && - lhs.localDates == rhs.localDates && - lhs.localDateTimes == rhs.localDateTimes && - lhs.offsetDateTimes == rhs.offsetDateTimes && - lhs.nullableBools == rhs.nullableBools && - lhs.nullableBytes == rhs.nullableBytes && - lhs.nullableShorts == rhs.nullableShorts && - lhs.nullableInts == rhs.nullableInts && - lhs.nullableLongs == rhs.nullableLongs && - lhs.nullableFloats == rhs.nullableFloats && - lhs.nullableDoubles == rhs.nullableDoubles; -} - -struct main_dto -{ - bool boolean; - int8_t b; - int16_t s; - int32_t i; - int64_t l; - float f; - double d; - std::string str; - boost::optional p; - boost::optional bigDecimal; - boost::optional localTime; - boost::optional localDate; - boost::optional localDateTime; - boost::optional offsetDateTime; - boost::optional nullableBool; - boost::optional nullableB; - boost::optional nullableS; - boost::optional nullableI; - boost::optional nullableL; - boost::optional nullableF; - boost::optional nullableD; -}; - -bool -operator==(const main_dto& lhs, const main_dto& rhs) -{ - return lhs.boolean == rhs.boolean && lhs.b == rhs.b && lhs.s == rhs.s && - lhs.i == rhs.i && lhs.l == rhs.l && lhs.f == rhs.f && - lhs.d == rhs.d && lhs.str == rhs.str && lhs.p == rhs.p && - lhs.bigDecimal == rhs.bigDecimal && lhs.localTime == rhs.localTime && - lhs.localDate == rhs.localDate && - lhs.localDateTime == rhs.localDateTime && - lhs.offsetDateTime == rhs.offsetDateTime && - lhs.nullableBool == rhs.nullableBool && - lhs.nullableB == rhs.nullableB && lhs.nullableS == rhs.nullableS && - lhs.nullableI == rhs.nullableI && lhs.nullableL == rhs.nullableL && - lhs.nullableF == rhs.nullableF && lhs.nullableD == rhs.nullableD; -} - -struct wrong_field_name_read_obj -{ - int value; -}; - -struct type_mistmatch_obj -{ - int value; -}; - -hazelcast::client::local_time -current_time() -{ - std::time_t t = std::time(nullptr); // get time now - std::tm* now = std::localtime(&t); - return hazelcast::client::local_time{ static_cast(now->tm_hour), - static_cast(now->tm_min), - static_cast(now->tm_sec), - 0 }; -} - -hazelcast::client::local_date -current_date() -{ - std::time_t t = std::time(nullptr); // get time now - std::tm* now = std::localtime(&t); - return hazelcast::client::local_date{ now->tm_year + 1900, - static_cast(now->tm_mon), - static_cast(now->tm_mday) }; -} - -hazelcast::client::local_date_time -current_timestamp() -{ - return hazelcast::client::local_date_time{ current_date(), current_time() }; -} - -hazelcast::client::offset_date_time -current_timestamp_with_timezone() -{ - return hazelcast::client::offset_date_time{ current_timestamp(), 3600 }; -} - -inner_dto -create_inner_dto() -{ - return inner_dto{ - boost::make_optional>({ true, false }), - boost::make_optional>({ 0, 1, 2 }), - boost::make_optional>({ 3, 4, 5 }), - boost::make_optional>({ 9, 8, 7, 6 }), - boost::make_optional>({ 0, 1, 5, 7, 9, 11 }), - boost::make_optional>({ 0.6543f, -3.56f, 45.67f }), - boost::make_optional>( - { 456.456, 789.789, 321.321 }), - boost::make_optional>>( - { boost::make_optional("test"), boost::none }), - boost::make_optional>>( - { boost::make_optional( - named_dto{ boost::make_optional("test"), 1 }), - boost::none }), - boost::make_optional< - std::vector>>( - { boost::make_optional(hazelcast::client::big_decimal{ - boost::multiprecision::cpp_int{ "12345" }, 0 }), - boost::make_optional(hazelcast::client::big_decimal{ - boost::multiprecision::cpp_int{ "123456" }, 0 }) }), - boost::make_optional< - std::vector>>( - { boost::make_optional(current_time()), - boost::none, - boost::make_optional(current_time()) }), - boost::make_optional< - std::vector>>( - { boost::make_optional(current_date()), - boost::none, - boost::make_optional(current_date()) }), - boost::make_optional< - std::vector>>( - { boost::make_optional(current_timestamp()), boost::none }), - boost::make_optional< - std::vector>>( - { boost::make_optional(current_timestamp_with_timezone()) }), - boost::make_optional>>( - { boost::make_optional(true), - boost::make_optional(false), - boost::none }), - boost::make_optional>>( - { boost::make_optional(0), - boost::make_optional(1), - boost::make_optional(2), - boost::none }), - boost::make_optional>>( - { boost::make_optional(3), - boost::make_optional(4), - boost::make_optional(5), - boost::none }), - boost::make_optional>>( - { boost::make_optional(9), - boost::make_optional(8), - boost::make_optional(7), - boost::make_optional(6), - boost::none }), - boost::make_optional>>( - { boost::make_optional(0), - boost::make_optional(1), - boost::make_optional(5), - boost::make_optional(7), - boost::none }), - boost::make_optional>>( - { boost::make_optional(0.6543f), - boost::make_optional(-3.56f), - boost::make_optional(45.67f), - boost::none }), - boost::make_optional>>( - { boost::make_optional(456.456), - boost::make_optional(789.789), - boost::make_optional(321.321), - boost::none }), - }; -} -main_dto -create_main_dto() -{ - inner_dto p = create_inner_dto(); - return main_dto{ true, - 113, - -500, - 56789, - -50992225L, - 900.5678f, - -897543.3678909, - "this is main object created for testing!", - p, - hazelcast::client::big_decimal{ - boost::multiprecision::cpp_int{ "12312313" }, 0 }, - hazelcast::client::local_time{ 1, 2, 3, 4 }, - hazelcast::client::local_date{ 2015, 12, 31 }, - hazelcast::client::local_date_time{ - hazelcast::client::local_date{ 2015, 12, 31 }, - hazelcast::client::local_time{ 1, 2, 3, 4 } }, - hazelcast::client::offset_date_time{ - hazelcast::client::local_date_time{ - hazelcast::client::local_date{ 2015, 12, 31 }, - hazelcast::client::local_time{ 1, 2, 3, 4 } }, - 100 }, - true, - 113, - (short)-500, - 56789, - -50992225L, - 900.5678f, - -897543.3678909 }; -} - -/** - * This class is to simulate versioning. - * We will provide this struct with serializer returning type name of the - * original main dto. This way we can use the serialized data of this class - * to test to_object of the original main_dto. - */ -struct empty_main_dto -{}; - -struct employee_dto -{ - int32_t age; - int32_t rank; - int64_t id; - bool isHired; - bool isFired; -}; - -bool -operator==(const employee_dto& lhs, const employee_dto& rhs) -{ - return lhs.age == rhs.age && lhs.rank == rhs.rank && lhs.id == rhs.id && - lhs.isHired == rhs.isHired && lhs.isFired == rhs.isFired; -} - -} // namespace test -} // namespace compact - -namespace serialization { - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::bits_dto& dto, - compact_writer& writer) - { - writer.write_boolean("a", dto.a); - writer.write_boolean("b", dto.b); - writer.write_boolean("c", dto.c); - writer.write_boolean("d", dto.d); - writer.write_boolean("e", dto.e); - writer.write_boolean("f", dto.f); - writer.write_boolean("g", dto.g); - writer.write_boolean("h", dto.h); - writer.write_boolean("i", dto.i); - writer.write_int32("id", dto.id); - writer.write_array_of_boolean("booleans", dto.booleans); - } - - static compact::test::bits_dto read(compact_reader& reader) - { - compact::test::bits_dto dto; - dto.a = reader.read_boolean("a"); - dto.b = reader.read_boolean("b"); - dto.c = reader.read_boolean("c"); - dto.d = reader.read_boolean("d"); - dto.e = reader.read_boolean("e"); - dto.f = reader.read_boolean("f"); - dto.g = reader.read_boolean("g"); - dto.h = reader.read_boolean("h"); - dto.i = reader.read_boolean("i"); - dto.id = reader.read_int32("id"); - dto.booleans = reader.read_array_of_boolean("booleans"); - return dto; - } - - static std::string type_name() { return "bits_dto"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::named_dto& dto, - compact_writer& writer) - { - writer.write_string("name", dto.name); - writer.write_int32("my_int", dto.my_int); - } - - static compact::test::named_dto read(compact_reader& reader) - { - compact::test::named_dto dto; - dto.name = reader.read_string("name"); - dto.my_int = reader.read_int32("my_int"); - return dto; - } - - static std::string type_name() { return "named_dto"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::inner_dto& object, - compact_writer& writer) - { - writer.write_array_of_boolean("bools", object.bools); - writer.write_array_of_int8("bytes", object.bytes); - writer.write_array_of_int16("shorts", object.shorts); - writer.write_array_of_int32("ints", object.ints); - writer.write_array_of_int64("longs", object.longs); - writer.write_array_of_float32("floats", object.floats); - writer.write_array_of_float64("doubles", object.doubles); - writer.write_array_of_string("strings", object.strings); - writer.write_array_of_decimal("bigDecimals", object.bigDecimals); - writer.write_array_of_time("localTimes", object.localTimes); - writer.write_array_of_date("localDates", object.localDates); - writer.write_array_of_timestamp("localDateTimes", - object.localDateTimes); - writer.write_array_of_timestamp_with_timezone("offsetDateTimes", - object.offsetDateTimes); - writer.write_array_of_compact("nn", object.nn); - writer.write_array_of_nullable_boolean("nullableBools", - object.nullableBools); - writer.write_array_of_nullable_int8("nullableBytes", - object.nullableBytes); - writer.write_array_of_nullable_int16("nullableShorts", - object.nullableShorts); - writer.write_array_of_nullable_int32("nullableInts", - object.nullableInts); - writer.write_array_of_nullable_int64("nullableLongs", - object.nullableLongs); - writer.write_array_of_nullable_float32("nullableFloats", - object.nullableFloats); - writer.write_array_of_nullable_float64("nullableDoubles", - object.nullableDoubles); - } - - static compact::test::inner_dto read(compact_reader& reader) - { - compact::test::inner_dto object; - object.bools = reader.read_array_of_boolean("bools"); - object.bytes = reader.read_array_of_int8("bytes"); - object.shorts = reader.read_array_of_int16("shorts"); - object.ints = reader.read_array_of_int32("ints"); - object.longs = reader.read_array_of_int64("longs"); - object.floats = reader.read_array_of_float32("floats"); - object.doubles = reader.read_array_of_float64("doubles"); - object.strings = reader.read_array_of_string("strings"); - object.bigDecimals = reader.read_array_of_decimal("bigDecimals"); - object.localTimes = reader.read_array_of_time("localTimes"); - object.localDates = reader.read_array_of_date("localDates"); - object.localDateTimes = - reader.read_array_of_timestamp("localDateTimes"); - object.offsetDateTimes = - reader.read_array_of_timestamp_with_timezone("offsetDateTimes"); - object.nn = - reader.read_array_of_compact("nn"); - object.nullableBools = - reader.read_array_of_nullable_boolean("nullableBools"); - object.nullableBytes = - reader.read_array_of_nullable_int8("nullableBytes"); - object.nullableShorts = - reader.read_array_of_nullable_int16("nullableShorts"); - object.nullableInts = - reader.read_array_of_nullable_int32("nullableInts"); - object.nullableLongs = - reader.read_array_of_nullable_int64("nullableLongs"); - object.nullableFloats = - reader.read_array_of_nullable_float32("nullableFloats"); - object.nullableDoubles = - reader.read_array_of_nullable_float64("nullableDoubles"); - return object; - } - - static std::string type_name() { return "inner"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::main_dto& object, - compact_writer& writer) - { - writer.write_boolean("bool", object.boolean); - writer.write_int8("b", object.b); - writer.write_int16("s", object.s); - writer.write_int32("i", object.i); - writer.write_int64("l", object.l); - writer.write_float32("f", object.f); - writer.write_float64("d", object.d); - writer.write_string("str", object.str); - writer.write_decimal("bigDecimal", object.bigDecimal); - writer.write_time("localTime", object.localTime); - writer.write_date("localDate", object.localDate); - writer.write_timestamp("localDateTime", object.localDateTime); - writer.write_timestamp_with_timezone("offsetDateTime", - object.offsetDateTime); - writer.write_compact("p", object.p); - writer.write_nullable_boolean("nullableBool", object.nullableBool); - writer.write_nullable_int8("nullableB", object.nullableB); - writer.write_nullable_int16("nullableS", object.nullableS); - writer.write_nullable_int32("nullableI", object.nullableI); - writer.write_nullable_int64("nullableL", object.nullableL); - writer.write_nullable_float32("nullableF", object.nullableF); - writer.write_nullable_float64("nullableD", object.nullableD); - } - - static compact::test::main_dto read(compact_reader& reader) - { - auto boolean = reader.read_boolean("bool"); - auto b = reader.read_int8("b"); - auto s = reader.read_int16("s"); - auto i = reader.read_int32("i"); - auto l = reader.read_int64("l"); - auto f = reader.read_float32("f"); - auto d = reader.read_float64("d"); - auto str = reader.read_string("str"); - auto bigDecimal = reader.read_decimal("bigDecimal"); - auto localTime = reader.read_time("localTime"); - auto localDate = reader.read_date("localDate"); - auto localDateTime = reader.read_timestamp("localDateTime"); - auto offsetDateTime = - reader.read_timestamp_with_timezone("offsetDateTime"); - auto p = reader.read_compact("p"); - auto nullableBool = reader.read_nullable_boolean("nullableBool"); - auto nullableB = reader.read_nullable_int8("nullableB"); - auto nullableS = reader.read_nullable_int16("nullableS"); - auto nullableI = reader.read_nullable_int32("nullableI"); - auto nullableL = reader.read_nullable_int64("nullableL"); - auto nullableF = reader.read_nullable_float32("nullableF"); - auto nullableD = reader.read_nullable_float64("nullableD"); - return compact::test::main_dto{ boolean, - b, - s, - i, - l, - f, - d, - *str, - p, - bigDecimal, - localTime, - localDate, - localDateTime, - offsetDateTime, - nullableBool, - nullableB, - nullableS, - nullableI, - nullableL, - nullableF, - nullableD }; - } - - static std::string type_name() { return "main"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::node_dto& object, - compact_writer& writer) - { - writer.write_int32("id", object.id); - writer.write_compact( - "child", - object.child == nullptr ? boost::none - : boost::make_optional(*object.child)); - } - - static compact::test::node_dto read(compact_reader& reader) - { - auto id = reader.read_int32("id"); - auto&& child = reader.read_compact("child"); - return compact::test::node_dto{ - id, - child.has_value() - ? std::make_shared(child.value()) - : nullptr - }; - } - - static std::string type_name() { return "node"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::empty_main_dto& object, - compact_writer& writer) - {} - - static compact::test::empty_main_dto read(compact_reader& reader) - { - return compact::test::empty_main_dto{}; - } - - static std::string type_name() { return "main"; } -}; - -template<> -struct hz_serializer : public compact_serializer -{ - static void write(const compact::test::employee_dto& object, - compact_writer& writer) - { - writer.write_int32("age", object.age); - writer.write_int32("rank", object.rank); - writer.write_int64("id", object.id); - writer.write_boolean("isHired", object.isHired); - writer.write_boolean("isFired", object.isFired); - } - - static compact::test::employee_dto read(compact_reader& reader) - { - auto age = reader.read_int32("age"); - auto rank = reader.read_int32("rank"); - auto id = reader.read_int64("id"); - auto isHired = reader.read_boolean("isHired"); - auto isFired = reader.read_boolean("isFired"); - return compact::test::employee_dto{ age, rank, id, isHired, isFired }; - } -}; - -} // namespace serialization - -namespace compact { -namespace test { -struct CompactRabinFingerprintTest : public ::testing::Test -{ - template - using entry_t = std::tuple; - - template - void check_each(std::vector> entries) - { - for (const entry_t& e : entries) { - using namespace hazelcast::client::serialization::pimpl; - - auto fp_before = std::get<0>(e); - auto value = std::get<1>(e); - auto expected = std::get<2>(e); - auto fp_after = rabin_finger_print::fingerprint64(fp_before, value); - - EXPECT_EQ(fp_after, expected); - } - } -}; - -TEST_F(CompactRabinFingerprintTest, test_i8_fingerprint) -{ - check_each(std::vector>{ - // Before Val After(Expected) - { 100, -5, -6165936963810616235 }, - { INT64_MIN, 0, 36028797018963968 }, - { 9223372036854775807, 113, -3588673659009074035 }, - { -13, -13, 72057594037927935 }, - { 42, 42, 0 }, - { 42, -42, -1212835703325587522 }, - { 0, 0, 0 }, - { -123456789, 0, 7049212178818848951 }, - { 123456789, 127, -8322440716502314713 }, - { 127, -128, -7333697815154264656 }, - }); -} - -TEST_F(CompactRabinFingerprintTest, test_i32_fingerprint) -{ - check_each(std::vector>{ - // Before Val After(Expected) - { INT64_MIN, 2147483647, 6066553457199370002 }, - { 9223372036854775807, INT32_MIN, 6066553459773452525 }, - { 9223372036854707, 42, -961937498224213201 }, - { -42, -42, 4294967295 }, - { 42, 42, 0 }, - { 42, -442, 7797744281030715531 }, - { 0, 0, 0 }, - { -123456789, 0, -565582369564281851 }, - { 123456786669, 42127, 7157681543413310373 }, - { 2147483647, INT32_MIN, -7679311364898232185 } }); -} - -TEST_F(CompactRabinFingerprintTest, test_str_fingerprint) -{ - check_each(std::vector>{ - { 0, "hazelcast", 8164249978089638648 }, - { -31231241235, "üğişçö", 6128923854942458838 }, - { 41231542121235, "😀 😃 😄", -6875080751809013377 }, - { rabin_finger_print::INIT, "STUdent", 1896492170246289820 }, - { rabin_finger_print::INIT, "aü😄", -2084249746924383631 }, - { rabin_finger_print::INIT, "", -2316162475121075004 }, - { -123321, "xyz", 2601391163390439688 }, - { 132132123132132, " ç", -7699875372487088773 }, - { 42, "42", 7764866287864698590 }, - { -42, "-42", -3434092993477103253 } }); -} - -// hazelcast.internal.serialization.impl.compact.RabinFingerPrintTest::testRabinFingerprint() -TEST_F(CompactRabinFingerprintTest, test_schema) -{ - using hazelcast::client::serialization::compact_writer; - using hazelcast::client::serialization::pimpl::field_kind; - using hazelcast::client::serialization::pimpl::schema_writer; - - schema_writer s_writer{ "SomeType" }; - auto writer = - hazelcast::client::serialization::pimpl::create_compact_writer(&s_writer); - - writer.write_int32("id", 0); - writer.write_string("name", boost::none); - writer.write_int8("age", 0); - writer.write_array_of_timestamp("times", boost::none); - - auto schema_id = std::move(s_writer).build().schema_id(); - ASSERT_EQ(-5445839760245891300, schema_id); -} - -class CompactSchemaTest : public ::testing::Test -{}; - -TEST_F(CompactSchemaTest, test_constructor) -{ - using hazelcast::client::serialization::pimpl::field_descriptor; - using hazelcast::client::serialization::pimpl::field_kind; - using hazelcast::client::serialization::pimpl::schema; - - schema all_types_schema{ - std::string{ "something" }, - std::unordered_map{ - { "boolean-0", BOOLEAN }, - { "boolean-1", BOOLEAN }, - { "boolean-2", BOOLEAN }, - { "boolean-3", BOOLEAN }, - { "boolean-4", BOOLEAN }, - { "boolean-5", BOOLEAN }, - { "boolean-6", BOOLEAN }, - { "boolean-7", BOOLEAN }, - { "boolean-8", BOOLEAN }, - { "boolean-9", BOOLEAN }, - { "boolean[]", ARRAY_OF_BOOLEAN }, - { "int8", INT8 }, - { "int8[]", ARRAY_OF_INT8 }, - { "int16", INT16 }, - { "int16[]", ARRAY_OF_INT16 }, - { "int32", INT32 }, - { "int32[]", ARRAY_OF_INT32 }, - { "int64", INT64 }, - { "int64[]", ARRAY_OF_INT64 }, - { "float32", FLOAT32 }, - { "float32[]", ARRAY_OF_FLOAT32 }, - { "float64", FLOAT64 }, - { "float64[]", ARRAY_OF_FLOAT64 }, - { "string", STRING }, - { "string[]", ARRAY_OF_STRING }, - { "decimal", DECIMAL }, - { "decimal[]", ARRAY_OF_DECIMAL }, - { "time", TIME }, - { "time[]", ARRAY_OF_TIME }, - { "date", DATE }, - { "date[]", ARRAY_OF_DATE }, - { "timestamp", TIMESTAMP }, - { "timestamp[]", ARRAY_OF_TIMESTAMP }, - { "timestamp_with_timezone", TIMESTAMP_WITH_TIMEZONE }, - { "timestamp_with_timezone[]", ARRAY_OF_TIMESTAMP_WITH_TIMEZONE }, - { "compact", COMPACT }, - { "compact[]", ARRAY_OF_COMPACT }, - { "nullable", NULLABLE_BOOLEAN }, - { "nullable[]", ARRAY_OF_NULLABLE_BOOLEAN }, - { "nullable", NULLABLE_INT8 }, - { "nullable[]", ARRAY_OF_NULLABLE_INT8 }, - { "nullable", NULLABLE_INT16 }, - { "nullable[]", ARRAY_OF_NULLABLE_INT16 }, - { "nullable", NULLABLE_INT32 }, - { "nullable[]", ARRAY_OF_NULLABLE_INT32 }, - { "nullable", NULLABLE_INT64 }, - { "nullable[]", ARRAY_OF_NULLABLE_INT64 }, - { "nullable", NULLABLE_FLOAT32 }, - { "nullable[]", ARRAY_OF_NULLABLE_INT64 }, - { "nullable", NULLABLE_FLOAT64 }, - { "nullable[]", ARRAY_OF_NULLABLE_FLOAT64 } } - }; - - auto result = all_types_schema.fields(); - - // Assert num of fields - ASSERT_EQ(all_types_schema.fixed_size_fields_length(), 29); - ASSERT_EQ(all_types_schema.number_of_var_size_fields(), 35); - - // Assert fix-sized fields - ASSERT_EQ(result["float64"].offset, 0); - ASSERT_EQ(result["float64"].index, -1); - ASSERT_EQ(result["float64"].bit_offset, -1); - ASSERT_EQ(result["int64"].offset, 8); - ASSERT_EQ(result["int64"].index, -1); - ASSERT_EQ(result["int64"].bit_offset, -1); - ASSERT_EQ(result["float32"].offset, 16); - ASSERT_EQ(result["float32"].index, -1); - ASSERT_EQ(result["float32"].bit_offset, -1); - ASSERT_EQ(result["int32"].offset, 20); - ASSERT_EQ(result["int32"].index, -1); - ASSERT_EQ(result["int32"].bit_offset, -1); - ASSERT_EQ(result["int16"].offset, 24); - ASSERT_EQ(result["int16"].index, -1); - ASSERT_EQ(result["int16"].bit_offset, -1); - ASSERT_EQ(result["int8"].offset, 26); - ASSERT_EQ(result["int8"].index, -1); - ASSERT_EQ(result["int8"].bit_offset, -1); - ASSERT_EQ(result["boolean-0"].offset, 27); - ASSERT_EQ(result["boolean-0"].index, -1); - ASSERT_EQ(result["boolean-0"].bit_offset, 0); - ASSERT_EQ(result["boolean-1"].offset, 27); - ASSERT_EQ(result["boolean-1"].index, -1); - ASSERT_EQ(result["boolean-1"].bit_offset, 1); - ASSERT_EQ(result["boolean-2"].offset, 27); - ASSERT_EQ(result["boolean-2"].index, -1); - ASSERT_EQ(result["boolean-2"].bit_offset, 2); - ASSERT_EQ(result["boolean-3"].offset, 27); - ASSERT_EQ(result["boolean-3"].index, -1); - ASSERT_EQ(result["boolean-3"].bit_offset, 3); - ASSERT_EQ(result["boolean-4"].offset, 27); - ASSERT_EQ(result["boolean-4"].index, -1); - ASSERT_EQ(result["boolean-4"].bit_offset, 4); - ASSERT_EQ(result["boolean-5"].offset, 27); - ASSERT_EQ(result["boolean-5"].index, -1); - ASSERT_EQ(result["boolean-5"].bit_offset, 5); - ASSERT_EQ(result["boolean-6"].offset, 27); - ASSERT_EQ(result["boolean-6"].index, -1); - ASSERT_EQ(result["boolean-6"].bit_offset, 6); - ASSERT_EQ(result["boolean-7"].offset, 27); - ASSERT_EQ(result["boolean-7"].index, -1); - ASSERT_EQ(result["boolean-7"].bit_offset, 7); - ASSERT_EQ(result["boolean-8"].offset, 28); - ASSERT_EQ(result["boolean-8"].index, -1); - ASSERT_EQ(result["boolean-8"].bit_offset, 0); - ASSERT_EQ(result["boolean-9"].offset, 28); - ASSERT_EQ(result["boolean-9"].index, -1); - ASSERT_EQ(result["boolean-9"].bit_offset, 1); - - // Assert variable sized fields - ASSERT_EQ(result["boolean[]"].offset, -1); - ASSERT_EQ(result["boolean[]"].index, 0); - ASSERT_EQ(result["boolean[]"].bit_offset, -1); - ASSERT_EQ(result["compact"].offset, -1); - ASSERT_EQ(result["compact"].index, 1); - ASSERT_EQ(result["compact"].bit_offset, -1); - ASSERT_EQ(result["compact[]"].offset, -1); - ASSERT_EQ(result["compact[]"].index, 2); - ASSERT_EQ(result["compact[]"].bit_offset, -1); - ASSERT_EQ(result["date"].offset, -1); - ASSERT_EQ(result["date"].index, 3); - ASSERT_EQ(result["date"].bit_offset, -1); - ASSERT_EQ(result["date[]"].offset, -1); - ASSERT_EQ(result["date[]"].index, 4); - ASSERT_EQ(result["date[]"].bit_offset, -1); - ASSERT_EQ(result["decimal"].offset, -1); - ASSERT_EQ(result["decimal"].index, 5); - ASSERT_EQ(result["decimal"].bit_offset, -1); - ASSERT_EQ(result["decimal[]"].offset, -1); - ASSERT_EQ(result["decimal[]"].index, 6); - ASSERT_EQ(result["decimal[]"].bit_offset, -1); - ASSERT_EQ(result["float32[]"].offset, -1); - ASSERT_EQ(result["float32[]"].index, 7); - ASSERT_EQ(result["float32[]"].bit_offset, -1); - ASSERT_EQ(result["float64[]"].offset, -1); - ASSERT_EQ(result["float64[]"].index, 8); - ASSERT_EQ(result["float64[]"].bit_offset, -1); - ASSERT_EQ(result["int16[]"].offset, -1); - ASSERT_EQ(result["int16[]"].index, 9); - ASSERT_EQ(result["int16[]"].bit_offset, -1); - ASSERT_EQ(result["int32[]"].offset, -1); - ASSERT_EQ(result["int32[]"].index, 10); - ASSERT_EQ(result["int32[]"].bit_offset, -1); - ASSERT_EQ(result["int64[]"].offset, -1); - ASSERT_EQ(result["int64[]"].index, 11); - ASSERT_EQ(result["int64[]"].bit_offset, -1); - ASSERT_EQ(result["int8[]"].offset, -1); - ASSERT_EQ(result["int8[]"].index, 12); - ASSERT_EQ(result["int8[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 13); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 14); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 15); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 16); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 17); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 18); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 19); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 20); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 21); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 22); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 23); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 24); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["nullable"].offset, -1); - ASSERT_EQ(result["nullable"].index, 25); - ASSERT_EQ(result["nullable"].bit_offset, -1); - ASSERT_EQ(result["nullable[]"].offset, -1); - ASSERT_EQ(result["nullable[]"].index, 26); - ASSERT_EQ(result["nullable[]"].bit_offset, -1); - ASSERT_EQ(result["string"].offset, -1); - ASSERT_EQ(result["string"].index, 27); - ASSERT_EQ(result["string"].bit_offset, -1); - ASSERT_EQ(result["string[]"].offset, -1); - ASSERT_EQ(result["string[]"].index, 28); - ASSERT_EQ(result["string[]"].bit_offset, -1); - ASSERT_EQ(result["time"].offset, -1); - ASSERT_EQ(result["time"].index, 29); - ASSERT_EQ(result["time"].bit_offset, -1); - ASSERT_EQ(result["time[]"].offset, -1); - ASSERT_EQ(result["time[]"].index, 30); - ASSERT_EQ(result["time[]"].bit_offset, -1); - ASSERT_EQ(result["timestamp"].offset, -1); - ASSERT_EQ(result["timestamp"].index, 31); - ASSERT_EQ(result["timestamp"].bit_offset, -1); - ASSERT_EQ(result["timestamp[]"].offset, -1); - ASSERT_EQ(result["timestamp[]"].index, 32); - ASSERT_EQ(result["timestamp[]"].bit_offset, -1); - ASSERT_EQ(result["timestamp_with_timezone"].offset, -1); - ASSERT_EQ(result["timestamp_with_timezone"].index, 33); - ASSERT_EQ(result["timestamp_with_timezone"].bit_offset, -1); - ASSERT_EQ(result["timestamp_with_timezone[]"].offset, -1); - ASSERT_EQ(result["timestamp_with_timezone[]"].index, 34); - ASSERT_EQ(result["timestamp_with_timezone[]"].bit_offset, -1); -} - -TEST_F(CompactSchemaTest, test_with_no_fields) -{ - schema no_fields_schema{ - std::string{ "something" }, - std::unordered_map{} - }; - - ASSERT_EQ(no_fields_schema.fields().size(), 0); - ASSERT_EQ(no_fields_schema.fixed_size_fields_length(), 0); - ASSERT_EQ(no_fields_schema.number_of_var_size_fields(), 0); -} - -class CompactSerializationTest : public ::testing::Test -{ -public: - template - T to_data_and_back_to_object(SerializationService& ss, T& value) - { - data data = ss.to_data(value); - return *(ss.to_object(data)); - } -}; - -TEST_F(CompactSerializationTest, testAllTypes) -{ - serialization_config config; - SerializationService ss(config); - - auto expected = create_main_dto(); - auto actual = to_data_and_back_to_object(ss, expected); - ASSERT_EQ(expected, actual); -} - -TEST_F(CompactSerializationTest, testRecursive) -{ - serialization_config config; - SerializationService ss(config); - - auto n2 = std::make_shared(node_dto{ 2, nullptr }); - auto n1 = std::make_shared(node_dto{ 1, n2 }); - node_dto expected{ 0, n1 }; - auto actual = to_data_and_back_to_object(ss, expected); - ASSERT_EQ(expected, actual); -} - -TEST_F(CompactSerializationTest, testBits) -{ - serialization_config config; - SerializationService ss(config); - - bits_dto expected; - expected.a = true; - expected.b = true; - expected.i = true; - expected.id = 121; - expected.booleans = boost::make_optional>( - { true, false, false, false, true, false, false, false }); - - const data& data = ss.to_data(expected); - // hash(4) + typeid(4) + schemaId(8) + (4 byte length) + (2 bytes for 9 - // bits) + (4 bytes for int) (4 byte length of byte array) + (1 byte for - // booleans array of 8 bits) + (1 byte offset bytes) - ASSERT_EQ(32, data.total_size()); - - bits_dto actual = *(ss.to_object(data)); - ASSERT_EQ(expected, actual); -} - -void -check_schema_field(const schema& schema, - const std::string& field_name, - int offset, - int index, - int bit_offset) -{ - ASSERT_EQ(offset, schema.fields().at(field_name).offset); - ASSERT_EQ(index, schema.fields().at(field_name).index); - ASSERT_EQ(bit_offset, schema.fields().at(field_name).bit_offset); -} - -TEST_F(CompactSerializationTest, test_field_order_fixed_size) -{ - schema_writer schema_writer("typeName"); - auto writer = serialization::pimpl::create_compact_writer(&schema_writer); - serialization::hz_serializer::write(employee_dto{}, writer); - auto schema = std::move(schema_writer).build(); - - check_schema_field(schema, "id", 0, -1, -1); - check_schema_field(schema, "age", 8, -1, -1); - check_schema_field(schema, "rank", 12, -1, -1); - check_schema_field(schema, "isFired", 16, -1, 0); - check_schema_field(schema, "isHired", 16, -1, 1); -} - -TEST_F(CompactSerializationTest, test_schema_writer_counts) -{ - schema_writer schema_writer("typename"); - schema_writer.add_field("int1", field_kind::INT32); - schema_writer.add_field("int2", field_kind::INT32); - schema_writer.add_field("string1", field_kind::STRING); - auto schema = std::move(schema_writer).build(); - - ASSERT_EQ(8, schema.fixed_size_fields_length()); - ASSERT_EQ(1, schema.number_of_var_size_fields()); -} - -TEST_F(CompactSerializationTest, test_rabin_fingerprint_consistent_with_server) -{ - const auto& schema = schema_of::schema_v; - // This magic number is generated via Java code for exact same class. - ASSERT_EQ(814479248787788739L, schema.schema_id()); -} - -TEST_F(CompactSerializationTest, test_read_when_field_does_not_exist) -{ - using hazelcast::client::compact::test::wrong_field_name_read_obj; - - serialization_config config; - SerializationService ss(config); - - wrong_field_name_read_obj obj; - - auto data = ss.to_data(obj); - ASSERT_THROW(ss.to_object(data), - exception::hazelcast_serialization); -} - -TEST_F(CompactSerializationTest, test_read_with_type_mismatch) -{ - using hazelcast::client::compact::test::type_mistmatch_obj; - - serialization_config config; - SerializationService ss(config); - type_mistmatch_obj obj; - - auto data = ss.to_data(obj); - ASSERT_THROW(ss.to_object(data), - exception::hazelcast_serialization); -} - -struct primitive_object -{ - bool boolean_; - int8_t byte_; - int16_t short_; - int32_t int_; - int64_t long_; - float float_; - double double_; - boost::optional> booleans; - boost::optional> bytes; - boost::optional> shorts; - boost::optional> ints; - boost::optional> longs; - boost::optional> floats; - boost::optional> doubles; -}; - -struct nullable_primitive_object -{ - boost::optional nullableBoolean; - boost::optional nullableByte; - boost::optional nullableShort; - boost::optional nullableInt; - boost::optional nullableLong; - boost::optional nullableFloat; - boost::optional nullableDouble; - boost::optional>> nullableBooleans; - boost::optional>> nullableBytes; - boost::optional>> nullableShorts; - boost::optional>> nullableInts; - boost::optional>> nullableLongs; - boost::optional>> nullableFloats; - boost::optional>> nullableDoubles; -}; - -} // namespace test -} // namespace compact - -namespace serialization { -template<> -struct hz_serializer : compact_serializer -{ - static void write(const compact::test::primitive_object& object, - compact_writer& writer) - { - writer.write_boolean("boolean", object.boolean_); - writer.write_int8("byte", object.byte_); - writer.write_int16("short", object.short_); - writer.write_int32("int", object.int_); - writer.write_int64("long", object.long_); - writer.write_float32("float", object.float_); - writer.write_float64("double", object.double_); - writer.write_array_of_boolean("booleans", object.booleans); - writer.write_array_of_int8("bytes", object.bytes); - writer.write_array_of_int16("shorts", object.shorts); - writer.write_array_of_int32("ints", object.ints); - writer.write_array_of_int64("longs", object.longs); - writer.write_array_of_float32("floats", object.floats); - writer.write_array_of_float64("doubles", object.doubles); - } - - static compact::test::primitive_object read(compact_reader& reader) - { - compact::test::primitive_object object; - object.boolean_ = reader.read_boolean("boolean"); - object.byte_ = reader.read_int8("byte"); - object.short_ = reader.read_int16("short"); - object.int_ = reader.read_int32("int"); - object.long_ = reader.read_int64("long"); - object.float_ = reader.read_float32("float"); - object.double_ = reader.read_float64("double"); - object.booleans = reader.read_array_of_boolean("booleans"); - object.bytes = reader.read_array_of_int8("bytes"); - object.shorts = reader.read_array_of_int16("shorts"); - object.ints = reader.read_array_of_int32("ints"); - object.longs = reader.read_array_of_int64("longs"); - object.floats = reader.read_array_of_float32("floats"); - object.doubles = reader.read_array_of_float64("doubles"); - return object; - } - - static std::string type_name() { return "primitive_object"; } -}; - -template<> -struct hz_serializer - : compact_serializer -{ - static void write(const compact::test::nullable_primitive_object& object, - compact_writer& writer) - { - writer.write_nullable_boolean("boolean", object.nullableBoolean); - writer.write_nullable_int8("byte", object.nullableByte); - writer.write_nullable_int16("short", object.nullableShort); - writer.write_nullable_int32("int", object.nullableInt); - writer.write_nullable_int64("long", object.nullableLong); - writer.write_nullable_float32("float", object.nullableFloat); - writer.write_nullable_float64("double", object.nullableDouble); - writer.write_array_of_nullable_boolean("booleans", - object.nullableBooleans); - writer.write_array_of_nullable_int8("bytes", object.nullableBytes); - writer.write_array_of_nullable_int16("shorts", object.nullableShorts); - writer.write_array_of_nullable_int32("ints", object.nullableInts); - writer.write_array_of_nullable_int64("longs", object.nullableLongs); - writer.write_array_of_nullable_float32("floats", object.nullableFloats); - writer.write_array_of_nullable_float64("doubles", - object.nullableDoubles); - } - - static compact::test::nullable_primitive_object read(compact_reader& reader) - { - compact::test::nullable_primitive_object object; - object.nullableBoolean = reader.read_nullable_boolean("boolean"); - object.nullableByte = reader.read_nullable_int8("byte"); - object.nullableShort = reader.read_nullable_int16("short"); - object.nullableInt = reader.read_nullable_int32("int"); - object.nullableLong = reader.read_nullable_int64("long"); - object.nullableFloat = reader.read_nullable_float32("float"); - object.nullableDouble = reader.read_nullable_float64("double"); - object.nullableBooleans = - reader.read_array_of_nullable_boolean("booleans"); - object.nullableBytes = reader.read_array_of_nullable_int8("bytes"); - object.nullableShorts = reader.read_array_of_nullable_int16("shorts"); - object.nullableInts = reader.read_array_of_nullable_int32("ints"); - object.nullableLongs = reader.read_array_of_nullable_int64("longs"); - object.nullableFloats = reader.read_array_of_nullable_float32("floats"); - object.nullableDoubles = - reader.read_array_of_nullable_float64("doubles"); - return object; - } - - // typename is same as the primitive_object on purpose. - // This is to simulate two different applications implementing the same - // class with different serializers. - static std::string type_name() { return "primitive_object"; } -}; - -template<> -struct hz_serializer - : compact_serializer -{ - static void write(const compact::test::wrong_field_name_read_obj& obj, - compact_writer& writer) - { - writer.write_int32("field_1", obj.value); - } - - static compact::test::wrong_field_name_read_obj read(compact_reader& reader) - { - compact::test::wrong_field_name_read_obj obj; - - obj.value = reader.read_int32("wrong_field"); - - return obj; - } - - static std::string type_name() { return "wrong_field_name_read_obj"; } -}; - -template<> -struct hz_serializer : compact_serializer -{ - static void write(const compact::test::type_mistmatch_obj& obj, - compact_writer& writer) - { - writer.write_int32("field_1", obj.value); - } - - static compact::test::type_mistmatch_obj read(compact_reader& reader) - { - compact::test::type_mistmatch_obj obj; - - obj.value = static_cast(reader.read_float32("field_1")); - - return obj; - } - - static std::string type_name() { return "type_mistmatch_obj"; } -}; -} // namespace serialization -namespace compact { -namespace test { -class CompactNullablePrimitiveInteroperabilityTest : public ::testing::Test -{}; - -template -void -ASSERT_SAME_CONTENT( - const boost::optional>>& expected, - const boost::optional>& actual) -{ - ASSERT_EQ(expected->size(), actual->size()); - for (size_t i = 0; i < expected->size(); ++i) { - ASSERT_EQ(expected->at(i).value(), actual->at(i)); - } -} - -template -void -ASSERT_SAME_CONTENT( - const boost::optional>& expected, - const boost::optional>>& actual) -{ - ASSERT_EQ(expected->size(), actual->size()); - for (size_t i = 0; i < expected->size(); ++i) { - ASSERT_EQ(expected->at(i), actual->at(i).value()); - } -} - -TEST_F(CompactNullablePrimitiveInteroperabilityTest, - testWritePrimitiveReadNullable) -{ - primitive_object expected{ - true, - 2, - 4, - 8, - 4444, - 8321.321F, - 41231.32, - boost::make_optional(std::vector{ true, false }), - boost::make_optional(std::vector{ 1, 2 }), - boost::make_optional(std::vector{ 1, 4 }), - boost::make_optional(std::vector{ 1, 8 }), - boost::make_optional(std::vector{ 1, 4444 }), - boost::make_optional(std::vector{ 1.0F, 8321.321F }), - boost::make_optional(std::vector{ 41231.32, 2 }) - }; - serialization_config config; - SerializationService ss(config); - - const data& data = ss.to_data(expected); - auto actual = ss.to_object(data).value(); - ASSERT_EQ(expected.boolean_, actual.nullableBoolean.value()); - ASSERT_EQ(expected.byte_, actual.nullableByte.value()); - ASSERT_EQ(expected.short_, actual.nullableShort.value()); - ASSERT_EQ(expected.int_, actual.nullableInt.value()); - ASSERT_EQ(expected.long_, actual.nullableLong.value()); - ASSERT_EQ(expected.float_, actual.nullableFloat.value()); - ASSERT_EQ(expected.double_, actual.nullableDouble.value()); - ASSERT_SAME_CONTENT(expected.booleans, actual.nullableBooleans); - ASSERT_SAME_CONTENT(expected.bytes, actual.nullableBytes); - ASSERT_SAME_CONTENT(expected.shorts, actual.nullableShorts); - ASSERT_SAME_CONTENT(expected.ints, actual.nullableInts); - ASSERT_SAME_CONTENT(expected.longs, actual.nullableLongs); - ASSERT_SAME_CONTENT(expected.floats, actual.nullableFloats); - ASSERT_SAME_CONTENT(expected.doubles, actual.nullableDoubles); -} - -TEST_F(CompactNullablePrimitiveInteroperabilityTest, - testWriteNullableReadPrimitive) -{ - nullable_primitive_object expected{ - boost::make_optional(true), - boost::make_optional(4), - boost::make_optional(6), - boost::make_optional(8), - boost::make_optional(4444), - boost::make_optional(8321.321F), - boost::make_optional(41231.32), - boost::make_optional>>( - std::vector>{ - boost::make_optional(true), - boost::make_optional(false) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(1), boost::make_optional(2) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(1), - boost::make_optional(4) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(1), - boost::make_optional(8) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(1), - boost::make_optional(4444) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(1.0F), - boost::make_optional(8321.321F) }), - boost::make_optional>>( - std::vector>{ - boost::make_optional(41231.32), - boost::make_optional(2) }) - }; - serialization_config config; - SerializationService ss(config); - - const data& data = ss.to_data(expected); - auto actual = ss.to_object(data).value(); - ASSERT_EQ(expected.nullableBoolean.value(), actual.boolean_); - ASSERT_EQ(expected.nullableByte.value(), actual.byte_); - ASSERT_EQ(expected.nullableShort.value(), actual.short_); - ASSERT_EQ(expected.nullableInt.value(), actual.int_); - ASSERT_EQ(expected.nullableLong.value(), actual.long_); - ASSERT_EQ(expected.nullableFloat.value(), actual.float_); - ASSERT_EQ(expected.nullableDouble.value(), actual.double_); - ASSERT_SAME_CONTENT(expected.nullableBooleans, actual.booleans); - ASSERT_SAME_CONTENT(expected.nullableBytes, actual.bytes); - ASSERT_SAME_CONTENT(expected.nullableShorts, actual.shorts); - ASSERT_SAME_CONTENT(expected.nullableInts, actual.ints); - ASSERT_SAME_CONTENT(expected.nullableLongs, actual.longs); - ASSERT_SAME_CONTENT(expected.nullableFloats, actual.floats); - ASSERT_SAME_CONTENT(expected.nullableDoubles, actual.doubles); -} - -TEST_F(CompactNullablePrimitiveInteroperabilityTest, - testWriteNullReadPrimitiveThrowsException) -{ - nullable_primitive_object expected; - serialization_config config; - SerializationService ss(config); - - const data& data = ss.to_data(expected); - ASSERT_THROW(ss.to_object(data), - exception::hazelcast_serialization); -} -} // namespace test -} // namespace compact -} // namespace client -} // namespace hazelcast \ No newline at end of file +#include "compact/compact_serialization_test.h" +#include "compact/compact_rabin_fingerprint_test.h" +#include "compact/compact_nullable_primitive_interoperability_test.h" +#include "compact/compact_schema_replication_on_write_test.h" +#include "compact/compact_schema_validation_test.h" +#include "compact/compact_schema_replication_stress_test.h" \ No newline at end of file diff --git a/scripts/start-rc.bat b/scripts/start-rc.bat index 65fe184dd2..93be50911b 100755 --- a/scripts/start-rc.bat +++ b/scripts/start-rc.bat @@ -2,7 +2,7 @@ setlocal EnableDelayedExpansion if "%HZ_VERSION%"=="" ( - set HZ_VERSION=5.1.3 + set HZ_VERSION=5.2.0 ) set HAZELCAST_TEST_VERSION=%HZ_VERSION% set HAZELCAST_ENTERPRISE_VERSION=%HZ_VERSION% @@ -66,13 +66,19 @@ if exist "hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar" ( echo "hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar already exists, not downloading from maven." ) else ( echo "Downloading: hazelcast enterprise test jar com.hazelcast:hazelcast-enterprise:%HAZELCAST_ENTERPRISE_VERSION%:jar:tests" - call mvn -q dependency:get -Dtransitive=false -DrepoUrl=%ENTERPRISE_REPO% -Dartifact=com.hazelcast:hazelcast-enterprise:%HAZELCAST_ENTERPRISE_VERSION%:jar:tests -Ddest=hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar || ( - echo "Failed download hazelcast enterprise test jar com.hazelcast:hazelcast-enterprise:%HAZELCAST_ENTERPRISE_VERSION%:jar:tests" - exit /b 1 - ) + + git.exe clone git@github.com:hazelcast/private-test-artifacts.git + + cd private-test-artifacts + git.exe checkout data + copy certs.jar ..\hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar + cd .. + del /s /q private-test-artifacts + rmdir /s /q private-test-artifacts ) -set CLASSPATH="hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar;hazelcast-sql-%HZ_VERSION%.jar;hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%.jar;hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar;hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar" + +set CLASSPATH="hazelcast-remote-controller-%HAZELCAST_RC_VERSION%.jar;hazelcast-sql-%HZ_VERSION%.jar;hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%.jar;hazelcast-%HAZELCAST_TEST_VERSION%-tests.jar;hazelcast-enterprise-%HAZELCAST_ENTERPRISE_VERSION%-tests.jar" echo "Starting Remote Controller ... enterprise ...Using classpath: %CLASSPATH%" echo "Starting hazelcast-remote-controller" diff --git a/scripts/start-rc.sh b/scripts/start-rc.sh index 26f61018f6..d5cbb17517 100755 --- a/scripts/start-rc.sh +++ b/scripts/start-rc.sh @@ -20,7 +20,7 @@ set +x trap cleanup EXIT -HZ_VERSION=${HZ_VERSION:-5.1.3} +HZ_VERSION=${HZ_VERSION:-5.2.0} HAZELCAST_TEST_VERSION=${HZ_VERSION} HAZELCAST_ENTERPRISE_VERSION=${HZ_VERSION} HAZELCAST_RC_VERSION=0.8-SNAPSHOT @@ -91,13 +91,24 @@ else exit 1 fi fi + if [ -f "hazelcast-enterprise-${HAZELCAST_ENTERPRISE_VERSION}-tests.jar" ]; then -echo "hazelcast-enterprise-tests.jar already exists, not downloading from maven." +echo "hazelcast-enterprise-tests.jar already exists, not downloading." else - echo "Downloading: hazelcast enterprise test jar com.hazelcast:hazelcast-enterprise:${HAZELCAST_ENTERPRISE_VERSION}:jar:tests" - mvn -q dependency:get -Dtransitive=false -DrepoUrl=${ENTERPRISE_REPO} -Dartifact=com.hazelcast:hazelcast-enterprise:${HAZELCAST_ENTERPRISE_VERSION}:jar:tests -Ddest=hazelcast-enterprise-${HAZELCAST_ENTERPRISE_VERSION}-tests.jar - if [ $? -ne 0 ]; then - echo "Failed download hazelcast enterprise test jar com.hazelcast:hazelcast-enterprise:${HAZELCAST_ENTERPRISE_VERSION}:jar:tests" + echo "Downloading: hazelcast enterprise test jar ${HAZELCAST_ENTERPRISE_VERSION}" + git clone git@github.com:hazelcast/private-test-artifacts.git + + if [ $? -eq 0 ]; then + cd private-test-artifacts + git checkout data + cp certs.jar ../hazelcast-enterprise-${HAZELCAST_ENTERPRISE_VERSION}-tests.jar + cd .. + rm -rf private-test-artifacts + else + echo "Failed download hazelcast enterprise test jar hazelcast-enterprise-${HAZELCAST_ENTERPRISE_VERSION}-tests.jar" + echo "Make sure you have access permission to 'github.com/hazelcast/private-test-artifacts repo'" + echo "Make sure that you added you ssh-key to your github account." + exit 1 fi fi From 5d683ea68a109f7d17f55c10b0d9bf093634f027 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 20 Jan 2023 15:37:18 +0300 Subject: [PATCH 02/15] Optional value is checked. Unnecessary include is removed. --- examples/serialization/compact/main.cpp | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/examples/serialization/compact/main.cpp b/examples/serialization/compact/main.cpp index 9e0051d59b..605459a4ae 100644 --- a/examples/serialization/compact/main.cpp +++ b/examples/serialization/compact/main.cpp @@ -15,7 +15,6 @@ */ #include #include -#include struct PersonDTO { @@ -52,8 +51,17 @@ struct hz_serializer : compact_serializer PersonDTO person; person.age = in.read_int32("age"); - person.name = *in.read_string("name"); - person.surname = *in.read_string("surname"); + boost::optional name = in.read_string("name"); + + if (name){ + person.name = *name; + } + + boost::optional surname = in.read_string("surname"); + + if (surname) { + person.surname = *surname; + } return person; } From d904fd2e627025f690ea028274cb4e58e6732428 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 20 Jan 2023 15:38:44 +0300 Subject: [PATCH 03/15] Refactor --- hazelcast/include/hazelcast/client/protocol/ClientMessage.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h index e000d592f0..24995b9040 100644 --- a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h +++ b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h @@ -1212,8 +1212,10 @@ class HAZELCAST_API ClientMessage std::memcpy( fp + SIZE_OF_FRAME_LENGTH_AND_FLAGS, &bytes[0], bytes.size()); - copy(begin(value.schemas_will_be_replicated()), - end(value.schemas_will_be_replicated()), + const auto& replicated_schemas = value.schemas_will_be_replicated(); + + copy(begin(replicated_schemas), + end(replicated_schemas), back_inserter(schemas_will_be_replicated_)); } From 67ee237695e306246fc171c5d4cd60969e92aeb8 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 20 Jan 2023 15:44:12 +0300 Subject: [PATCH 04/15] class_to_schema is refactored to prevent race condition. Also it doesn't lock/unlock for every call --- examples/serialization/compact/main.cpp | 4 +- .../pimpl/compact/compact_impl.h | 47 +++++----- .../pimpl/compact/field_descriptor.h | 2 +- hazelcast/src/hazelcast/client/compact.cpp | 14 +-- hazelcast/src/hazelcast/client/spi.cpp | 30 +++--- hazelcast/test/src/compact/compact_helper.h | 8 +- ...nullable_primitive_interoperability_test.h | 17 ++-- .../compact/compact_rabin_fingerprint_test.h | 8 +- .../compact_schema_replication_stress_test.h | 92 ++++++------------- .../test/src/compact/compact_schema_test.h | 8 +- .../compact/compact_schema_validation_test.h | 55 +++++------ .../src/compact/compact_serialization_test.h | 12 +-- .../test/src/compact/compact_test_base.h | 25 +++-- .../test/src/compact/serialization/a_type.h | 8 +- .../test/src/compact/serialization/bits_dto.h | 10 +- .../src/compact/serialization/employee_dto.h | 10 +- .../compact/serialization/empty_main_dto.h | 13 +-- .../src/compact/serialization/inner_dto.h | 10 +- .../test/src/compact/serialization/main_dto.h | 12 +-- .../src/compact/serialization/named_dto.h | 10 +- .../src/compact/serialization/nested_type.h | 10 +- .../test/src/compact/serialization/node_dto.h | 10 +- .../serialization/nullable_primitive_object.h | 10 +- .../compact/serialization/primitive_object.h | 12 +-- .../src/compact/serialization/stress_type.h | 24 +++-- .../compact/serialization/type_mismatch_obj.h | 10 +- .../serialization/wrong_field_name_read_obj.h | 10 +- hazelcast/test/src/compact_test.cpp | 2 +- 28 files changed, 221 insertions(+), 262 deletions(-) diff --git a/examples/serialization/compact/main.cpp b/examples/serialization/compact/main.cpp index 605459a4ae..ff87f3f17e 100644 --- a/examples/serialization/compact/main.cpp +++ b/examples/serialization/compact/main.cpp @@ -53,7 +53,7 @@ struct hz_serializer : compact_serializer person.age = in.read_int32("age"); boost::optional name = in.read_string("name"); - if (name){ + if (name) { person.name = *name; } @@ -75,7 +75,7 @@ struct hz_serializer : compact_serializer /** * This example demonstrates how to use a type with compact serialization. -*/ + */ int main() { diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h index e1dc23a71e..55174571b3 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h @@ -19,6 +19,8 @@ #include "hazelcast/util/finally.h" #include "hazelcast/util/IOUtil.h" #include +#include +#include namespace hazelcast { namespace client { @@ -571,11 +573,12 @@ template const schema schema_of::schema_v = schema_of::build_schema(); template -schema build_schema(const T& object) +schema +build_schema(const T& object) { schema_writer schema_writer(hz_serializer::type_name()); serialization::compact_writer writer = - create_compact_writer(&schema_writer); + create_compact_writer(&schema_writer); serialization::hz_serializer::write(object, writer); return std::move(schema_writer).build(); } @@ -584,24 +587,19 @@ template class class_to_schema { public: + static std::atomic is_initialized; + static std::mutex mtx; - static const boost::optional& get() - { - std::lock_guard guard{ mtx_ }; - - return value_; - } + static const schema& get() { return *value_; } - static void set(const boost::optional& schema) + static void set(const schema& schema) { - std::lock_guard guard { mtx_ }; - value_ = schema; + + is_initialized = true; } private: - - static std::mutex mtx_; static boost::optional value_; }; @@ -609,7 +607,10 @@ template boost::optional class_to_schema::value_ = boost::none; template -std::mutex class_to_schema::mtx_; +std::atomic class_to_schema::is_initialized{ false }; + +template +std::mutex class_to_schema::mtx; template T inline compact_stream_serializer::read(object_data_input& in) @@ -641,18 +642,22 @@ template void inline compact_stream_serializer::write(const T& object, object_data_output& out) { - const boost::optional& schema_v = class_to_schema::get(); + if (!class_to_schema::is_initialized) { + std::lock_guard lck{ class_to_schema::mtx }; - if (!schema_v.has_value()) { - class_to_schema::set(build_schema(object)); + if (!class_to_schema::is_initialized) { + class_to_schema::set(build_schema(object)); + } } - if (!schema_service.is_schema_replicated(*schema_v)) { - out.schemas_will_be_replicated_.push_back(*schema_v); + const schema& schema_v = class_to_schema::get(); + + if (!schema_service.is_schema_replicated(schema_v)) { + out.schemas_will_be_replicated_.push_back(schema_v); } - out.write(schema_v->schema_id()); - default_compact_writer default_writer(*this, out, *schema_v); + out.write(schema_v.schema_id()); + default_compact_writer default_writer(*this, out, schema_v); compact_writer writer = create_compact_writer(&default_writer); hz_serializer::write(object, writer); default_writer.end(); diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h index cbab0812f8..b684b681b5 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h @@ -31,7 +31,7 @@ namespace pimpl { struct HAZELCAST_API field_descriptor { - field_descriptor(field_kind k = field_kind(-1), + field_descriptor(field_kind k = field_kind(0), int32_t i = -1, int32_t o = -1, int8_t b = -1); diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 8b8b936aec..513003aa77 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -52,10 +52,8 @@ std::ostream& operator<<(std::ostream& os, const field_descriptor& fd) { return os << "FieldDescriptor{" - << "kind=" << fd.kind - << ", index=" << fd.index - << ", offset=" << fd.offset - << ", bitOffset=" << fd.bit_offset + << "kind=" << fd.kind << ", index=" << fd.index + << ", offset=" << fd.offset << ", bitOffset=" << fd.bit_offset << '}'; } @@ -1893,7 +1891,6 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) using hazelcast::client::protocol::ClientMessage; using namespace protocol::codec; - auto max_retry_count{ max_put_retry_count_ }; auto message = send_schema_request_encode(s); auto invocation = @@ -1901,8 +1898,7 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) return invocation->invoke().then( boost::launch::sync, - [this, max_retry_count, attempts, s]( - boost::future future) { + [this, attempts, s](boost::future future) { auto msg = future.get(); auto replicated_member_uuids = send_schema_response_decode(msg); @@ -1917,7 +1913,7 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) }); if (!contains) { - if (attempts >= max_retry_count) { + if (attempts >= max_put_retry_count_) { throw exception::illegal_state{ "default_schema_service::replicate_schema_attempt", (boost::format("The schema %1% cannot be " @@ -1930,7 +1926,7 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) "It might be possible to replicate " "the schema after some time, when " "the cluster is healed.") % - s % max_retry_count) + s % max_put_retry_count_) .str() }; } else { diff --git a/hazelcast/src/hazelcast/client/spi.cpp b/hazelcast/src/hazelcast/client/spi.cpp index 086810f248..3bc7a0ba5f 100644 --- a/hazelcast/src/hazelcast/client/spi.cpp +++ b/hazelcast/src/hazelcast/client/spi.cpp @@ -1413,15 +1413,15 @@ ClientInvocation::invoke() auto self = shared_from_this(); return replicate_schemas(schemas) - .then( - boost::launch::sync, - [this, actual_work, self]( - boost::future>> replications) { - for (auto& replication : replications.get()) - replication.get(); - - return actual_work(); - }) + .then(boost::launch::sync, + [this, actual_work, self]( + boost::future>> + replications) { + for (auto& replication : replications.get()) + replication.get(); + + return actual_work(); + }) .unwrap(); } @@ -1439,15 +1439,15 @@ ClientInvocation::invoke_urgent() invoke_on_selection(); if (!lifecycle_service_.is_running()) { return invocation_promise_.get_future().then( - [](boost::future f) { return f.get(); }); + [](boost::future f) { return f.get(); }); } auto id_seq = call_id_sequence_; return invocation_promise_.get_future().then( - execution_service_->get_user_executor(), - [=](boost::future f) { - id_seq->complete(); - return f.get(); - }); + execution_service_->get_user_executor(), + [=](boost::future f) { + id_seq->complete(); + return f.get(); + }); } boost::future>> diff --git a/hazelcast/test/src/compact/compact_helper.h b/hazelcast/test/src/compact/compact_helper.h index 5aaf66542e..8d4b09c76d 100644 --- a/hazelcast/test/src/compact/compact_helper.h +++ b/hazelcast/test/src/compact/compact_helper.h @@ -56,7 +56,7 @@ current_timestamp_with_timezone() return hazelcast::client::offset_date_time{ current_timestamp(), 3600 }; } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h b/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h index 8c2a12b99f..1c6ed69ace 100644 --- a/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h +++ b/hazelcast/test/src/compact/compact_nullable_primitive_interoperability_test.h @@ -51,10 +51,11 @@ ASSERT_SAME_CONTENT( class CompactNullablePrimitiveInteroperabilityTest : public compact_test_base { - protected: - SerializationService& serialization_service(){ - return spi::ClientContext{ client }.get_serialization_service(); - } +protected: + SerializationService& serialization_service() + { + return spi::ClientContext{ client }.get_serialization_service(); + } }; TEST_F(CompactNullablePrimitiveInteroperabilityTest, @@ -178,7 +179,7 @@ TEST_F(CompactNullablePrimitiveInteroperabilityTest, exception::hazelcast_serialization); } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h b/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h index ccc93d324a..0b78e4f943 100644 --- a/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h +++ b/hazelcast/test/src/compact/compact_rabin_fingerprint_test.h @@ -113,7 +113,7 @@ TEST_F(CompactRabinFingerprintTest, test_schema) ASSERT_EQ(3662264393229655598, schema_id); } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_replication_stress_test.h b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h index c47204d031..5bd16ab37a 100644 --- a/hazelcast/test/src/compact/compact_schema_replication_stress_test.h +++ b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h @@ -37,15 +37,14 @@ struct schema_replicator; template struct schema_replicator { - schema_replicator(std::shared_ptr m, std::vector&) - {} + schema_replicator(std::shared_ptr m, std::vector&) {} }; template struct schema_replicator : schema_replicator { schema_replicator(std::shared_ptr m, std::vector& schemas) - : schema_replicator(m, schemas) + : schema_replicator(m, schemas) { stress_type instance{}; auto schema = serialization::pimpl::build_schema(instance); @@ -55,77 +54,40 @@ struct schema_replicator : schema_replicator }; template -std::vector replicate_schemas(std::shared_ptr map) +std::vector +replicate_schemas(std::shared_ptr map) { std::vector schemas; - schema_replicator{map, schemas}; + schema_replicator{ map, schemas }; return schemas; } TEST_F(CompactSchemaReplicationStress, test) { - using replication_work_t = boost::future>; + using replication_work_t = + boost::future>; auto map = client.get_map(random_string()).get(); - replication_work_t replication_works[] = - { - boost::async( - boost::launch::async, - replicate_schemas<0,10>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<10,20>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<20,30>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<30,40>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<40,50>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<50,60>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<60,70>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<70,80>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<80,90>, - map - ), - boost::async( - boost::launch::async, - replicate_schemas<90,100>, - map - ) + replication_work_t replication_works[] = { + boost::async(boost::launch::async, replicate_schemas<0, 10>, map), + boost::async(boost::launch::async, replicate_schemas<10, 20>, map), + boost::async(boost::launch::async, replicate_schemas<20, 30>, map), + boost::async(boost::launch::async, replicate_schemas<30, 40>, map), + boost::async(boost::launch::async, replicate_schemas<40, 50>, map), + boost::async(boost::launch::async, replicate_schemas<50, 60>, map), + boost::async(boost::launch::async, replicate_schemas<60, 70>, map), + boost::async(boost::launch::async, replicate_schemas<70, 80>, map), + boost::async(boost::launch::async, replicate_schemas<80, 90>, map), + boost::async(boost::launch::async, replicate_schemas<90, 100>, map) }; std::vector replicated_schemas; - auto append = [&replicated_schemas](std::vector schemas){ - replicated_schemas.insert(end(replicated_schemas),begin(schemas),end(schemas)); - }; + auto append = + [&replicated_schemas](std::vector schemas) { + replicated_schemas.insert( + end(replicated_schemas), begin(schemas), end(schemas)); + }; for (replication_work_t& work : replication_works) EXPECT_NO_THROW(append(work.get())); @@ -134,7 +96,7 @@ TEST_F(CompactSchemaReplicationStress, test) EXPECT_TRUE(check_schema_on_backend(s)); } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_test.h b/hazelcast/test/src/compact/compact_schema_test.h index 1daa2824f9..dddb32d81a 100644 --- a/hazelcast/test/src/compact/compact_schema_test.h +++ b/hazelcast/test/src/compact/compact_schema_test.h @@ -265,7 +265,7 @@ TEST_F(CompactSchemaTest, test_with_no_fields) ASSERT_EQ(no_fields_schema.number_of_var_size_fields(), 0); } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_schema_validation_test.h b/hazelcast/test/src/compact/compact_schema_validation_test.h index b4d0c04719..24556103aa 100644 --- a/hazelcast/test/src/compact/compact_schema_validation_test.h +++ b/hazelcast/test/src/compact/compact_schema_validation_test.h @@ -33,9 +33,9 @@ namespace compact { class CompactSchemaValidation : public compact_test_base { protected: - using schema_t = hazelcast::client::serialization::pimpl::schema; - using field_descriptor_t = hazelcast::client::serialization::pimpl::field_descriptor; + using field_descriptor_t = + hazelcast::client::serialization::pimpl::field_descriptor; struct schema_proxy { @@ -48,11 +48,10 @@ class CompactSchemaValidation : public compact_test_base Response response; remote_controller_client().executeOnController( - response, - factory_.get_cluster_id(), - ( - boost::format( - R"( + response, + factory_.get_cluster_id(), + (boost::format( + R"( var schemas = instance_0.getOriginal().node.getSchemaService().getAllSchemas(); var iterator = schemas.iterator(); @@ -86,16 +85,15 @@ class CompactSchemaValidation : public compact_test_base } result = "" + JSON.stringify(schema_obj); - )") % schema.schema_id() - ).str(), - Lang::JAVASCRIPT - ); + )") % + schema.schema_id()) + .str(), + Lang::JAVASCRIPT); return json_to_proxy(response.result); } private: - schema_proxy json_to_proxy(const std::string& text) { using namespace boost::property_tree; @@ -105,20 +103,17 @@ class CompactSchemaValidation : public compact_test_base input << text; ptree root; - read_json(input,root); + read_json(input, root); schema_proxy proxy; proxy.type_name = root.get("type_name"); - for (ptree::value_type& field : root.get_child("fields")){ + for (ptree::value_type& field : root.get_child("fields")) { proxy.descriptors.push_back( - { - serialization::field_kind(field.second.get("kind")), - field.second.get("index") , - field.second.get("offset"), - field.second.get("bitOffset") - } - ); + { serialization::field_kind(field.second.get("kind")), + field.second.get("index"), + field.second.get("offset"), + field.second.get("bitOffset") }); } return proxy; @@ -135,20 +130,18 @@ TEST_F(CompactSchemaValidation, validate) EXPECT_EQ(schema.type_name(), actual.type_name); - for(const auto& pair : schema.fields()){ + for (const auto& pair : schema.fields()) { field_descriptor_t descriptor = pair.second; - bool found = find( - begin(actual.descriptors), - end(actual.descriptors), - descriptor - ) != end(actual.descriptors); + bool found = find(begin(actual.descriptors), + end(actual.descriptors), + descriptor) != end(actual.descriptors); EXPECT_TRUE(found); } } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_serialization_test.h b/hazelcast/test/src/compact/compact_serialization_test.h index d0256e54fd..fd83273575 100644 --- a/hazelcast/test/src/compact/compact_serialization_test.h +++ b/hazelcast/test/src/compact/compact_serialization_test.h @@ -38,8 +38,8 @@ using namespace serialization::pimpl; class CompactSerializationTest : public compact_test_base { public: - - SerializationService& serialization_service(){ + SerializationService& serialization_service() + { return spi::ClientContext{ client }.get_serialization_service(); } @@ -150,7 +150,7 @@ TEST_F(CompactSerializationTest, test_read_with_type_mismatch) exception::hazelcast_serialization); } -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/compact_test_base.h b/hazelcast/test/src/compact/compact_test_base.h index 0204e1e8e2..76122f49a5 100644 --- a/hazelcast/test/src/compact/compact_test_base.h +++ b/hazelcast/test/src/compact/compact_test_base.h @@ -42,14 +42,11 @@ class compact_test_base : public testing::Test } protected: + void SetUp() override + { + auto version = client.get_cluster().get_members().front().get_version(); - void SetUp() override { - auto version = client.get_cluster() - .get_members() - .front() - .get_version(); - - if (version < member::version {5,2,0}) + if (version < member::version{ 5, 2, 0 }) GTEST_SKIP(); } @@ -58,9 +55,10 @@ class compact_test_base : public testing::Test { auto schema = get_schema(); - spi::ClientContext context {client}; + spi::ClientContext context{ client }; - ASSERT_NO_THROW(context.get_schema_service().replicate_schema(schema).get()); + ASSERT_NO_THROW( + context.get_schema_service().replicate_schema(schema).get()); } bool check_schema_on_backend(const schema_t& schema) @@ -104,7 +102,6 @@ class compact_test_base : public testing::Test hazelcast_client client; private: - static client_config config() { client_config cfg; @@ -115,7 +112,7 @@ class compact_test_base : public testing::Test } }; -} -} -} -} \ No newline at end of file +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/a_type.h b/hazelcast/test/src/compact/serialization/a_type.h index bf406129e0..8f262b55c7 100644 --- a/hazelcast/test/src/compact/serialization/a_type.h +++ b/hazelcast/test/src/compact/serialization/a_type.h @@ -30,8 +30,8 @@ struct a_type nested_type nested; }; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -61,5 +61,5 @@ struct hz_serializer : compact_serializer }; } // namespace serialization -} -} \ No newline at end of file +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/bits_dto.h b/hazelcast/test/src/compact/serialization/bits_dto.h index 56ab5608b0..21fa16388e 100644 --- a/hazelcast/test/src/compact/serialization/bits_dto.h +++ b/hazelcast/test/src/compact/serialization/bits_dto.h @@ -47,8 +47,8 @@ operator==(const bits_dto& lhs, const bits_dto& rhs) lhs.id == rhs.id && lhs.booleans == rhs.booleans; } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -91,7 +91,7 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "bits_dto"; } }; -} +} // namespace serialization -} -} \ No newline at end of file +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/employee_dto.h b/hazelcast/test/src/compact/serialization/employee_dto.h index 4261b19782..0486a4a6b1 100644 --- a/hazelcast/test/src/compact/serialization/employee_dto.h +++ b/hazelcast/test/src/compact/serialization/employee_dto.h @@ -37,8 +37,8 @@ operator==(const employee_dto& lhs, const employee_dto& rhs) lhs.isHired == rhs.isHired && lhs.isFired == rhs.isFired; } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -67,6 +67,6 @@ struct hz_serializer : public compact_serializer } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/empty_main_dto.h b/hazelcast/test/src/compact/serialization/empty_main_dto.h index f6a8cacbe0..6493448017 100644 --- a/hazelcast/test/src/compact/serialization/empty_main_dto.h +++ b/hazelcast/test/src/compact/serialization/empty_main_dto.h @@ -32,8 +32,8 @@ namespace compact { struct empty_main_dto {}; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -42,7 +42,8 @@ struct hz_serializer : public compact_serializer { static void write(const compact::test::empty_main_dto& object, compact_writer& writer) - {} + { + } static compact::test::empty_main_dto read(compact_reader& reader) { @@ -52,6 +53,6 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "main"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/inner_dto.h b/hazelcast/test/src/compact/serialization/inner_dto.h index 3705c09e15..8bc3b173ac 100644 --- a/hazelcast/test/src/compact/serialization/inner_dto.h +++ b/hazelcast/test/src/compact/serialization/inner_dto.h @@ -153,8 +153,8 @@ create_inner_dto() }; } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -236,6 +236,6 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "inner"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/main_dto.h b/hazelcast/test/src/compact/serialization/main_dto.h index ca2c03d352..6e78518205 100644 --- a/hazelcast/test/src/compact/serialization/main_dto.h +++ b/hazelcast/test/src/compact/serialization/main_dto.h @@ -19,7 +19,7 @@ #include "hazelcast/client/serialization/serialization.h" #include "inner_dto.h" -namespace hazelcast{ +namespace hazelcast { namespace client { namespace test { namespace compact { @@ -100,8 +100,8 @@ create_main_dto() -897543.3678909 }; } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -186,6 +186,6 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "main"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/named_dto.h b/hazelcast/test/src/compact/serialization/named_dto.h index 1546676a3c..237e92f630 100644 --- a/hazelcast/test/src/compact/serialization/named_dto.h +++ b/hazelcast/test/src/compact/serialization/named_dto.h @@ -35,8 +35,8 @@ operator==(const named_dto& lhs, const named_dto& rhs) return lhs.name == rhs.name && lhs.my_int == rhs.my_int; } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -61,6 +61,6 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "named_dto"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/nested_type.h b/hazelcast/test/src/compact/serialization/nested_type.h index b986e4adff..5eb5507991 100644 --- a/hazelcast/test/src/compact/serialization/nested_type.h +++ b/hazelcast/test/src/compact/serialization/nested_type.h @@ -30,8 +30,8 @@ struct nested_type int y; }; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -56,6 +56,6 @@ struct hz_serializer : compact_serializer static std::string type_name() { return "nested_type"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/node_dto.h b/hazelcast/test/src/compact/serialization/node_dto.h index e41b56c094..7a2e17c66f 100644 --- a/hazelcast/test/src/compact/serialization/node_dto.h +++ b/hazelcast/test/src/compact/serialization/node_dto.h @@ -37,8 +37,8 @@ operator==(const node_dto& lhs, const node_dto& rhs) (lhs.child && rhs.child && *lhs.child == *rhs.child)); } -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -70,6 +70,6 @@ struct hz_serializer : public compact_serializer static std::string type_name() { return "node"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/nullable_primitive_object.h b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h index 283d312dbb..da3968c066 100644 --- a/hazelcast/test/src/compact/serialization/nullable_primitive_object.h +++ b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h @@ -41,8 +41,8 @@ struct nullable_primitive_object boost::optional>> nullableDoubles; }; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -100,7 +100,7 @@ struct hz_serializer // class with different serializers. static std::string type_name() { return "primitive_object"; } }; -} +} // namespace serialization -} -} \ No newline at end of file +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/primitive_object.h b/hazelcast/test/src/compact/serialization/primitive_object.h index d14360b49e..c916212bb3 100644 --- a/hazelcast/test/src/compact/serialization/primitive_object.h +++ b/hazelcast/test/src/compact/serialization/primitive_object.h @@ -18,7 +18,7 @@ #include "hazelcast/client/serialization/serialization.h" -namespace hazelcast{ +namespace hazelcast { namespace client { namespace test { namespace compact { @@ -41,8 +41,8 @@ struct primitive_object boost::optional> doubles; }; -} -} +} // namespace compact +} // namespace test namespace serialization { template<> @@ -93,6 +93,6 @@ struct hz_serializer static std::string type_name() { return "primitive_object"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/stress_type.h b/hazelcast/test/src/compact/serialization/stress_type.h index 9009f12fc9..fdaf522cb9 100644 --- a/hazelcast/test/src/compact/serialization/stress_type.h +++ b/hazelcast/test/src/compact/serialization/stress_type.h @@ -23,12 +23,13 @@ namespace compact { template struct stress_type -{}; +{ +}; -} -} -} -} +} // namespace compact +} // namespace test +} // namespace client +} // namespace hazelcast namespace hazelcast { namespace client { @@ -37,10 +38,13 @@ namespace serialization { template struct hz_serializer> : compact_serializer { - static std::string type_name() { return "stress_type_" + std::to_string(Idx); } + static std::string type_name() + { + return "stress_type_" + std::to_string(Idx); + } static void write(const test::compact::stress_type&, - compact_writer& writer) + compact_writer& writer) { writer.write_int32("field_" + std::to_string(Idx), Idx); } @@ -51,6 +55,6 @@ struct hz_serializer> : compact_serializer } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/type_mismatch_obj.h b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h index a08ef378cb..317e892271 100644 --- a/hazelcast/test/src/compact/serialization/type_mismatch_obj.h +++ b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h @@ -28,8 +28,8 @@ struct type_mistmatch_obj int value; }; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -54,6 +54,6 @@ struct hz_serializer : compact_serializer static std::string type_name() { return "type_mistmatch_obj"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h index 341d56ec59..07b88bcfae 100644 --- a/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h +++ b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h @@ -28,8 +28,8 @@ struct wrong_field_name_read_obj int value; }; -} -} +} // namespace compact +} // namespace test namespace serialization { @@ -55,6 +55,6 @@ struct hz_serializer static std::string type_name() { return "wrong_field_name_read_obj"; } }; -} -} -} \ No newline at end of file +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file diff --git a/hazelcast/test/src/compact_test.cpp b/hazelcast/test/src/compact_test.cpp index 12845c4a88..a1132fb031 100644 --- a/hazelcast/test/src/compact_test.cpp +++ b/hazelcast/test/src/compact_test.cpp @@ -19,4 +19,4 @@ #include "compact/compact_nullable_primitive_interoperability_test.h" #include "compact/compact_schema_replication_on_write_test.h" #include "compact/compact_schema_validation_test.h" -#include "compact/compact_schema_replication_stress_test.h" \ No newline at end of file +#include "compact/compact_schema_replication_stress_test.h" From 624e3d0d803699cd15157b0961988a45c3c83709 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 3 Feb 2023 09:01:41 +0300 Subject: [PATCH 05/15] class_to_schema refactored. --- .../serialization/pimpl/compact/compact.h | 3 ++ .../pimpl/compact/compact_impl.h | 52 +++++++++---------- .../compact_schema_replication_stress_test.h | 4 +- .../test/src/compact/compact_test_base.h | 5 +- 4 files changed, 34 insertions(+), 30 deletions(-) diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h index df2749c197..be30ca1720 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h @@ -1388,6 +1388,9 @@ class HAZELCAST_API compact_stream_serializer template void write(const T& object, object_data_output& out); + template + static schema build_schema(const T& object); + private: default_schema_service& schema_service; }; diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h index 55174571b3..a0b5f2aeb8 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h @@ -572,39 +572,32 @@ struct schema_of template const schema schema_of::schema_v = schema_of::build_schema(); -template -schema -build_schema(const T& object) -{ - schema_writer schema_writer(hz_serializer::type_name()); - serialization::compact_writer writer = - create_compact_writer(&schema_writer); - serialization::hz_serializer::write(object, writer); - return std::move(schema_writer).build(); -} - template class class_to_schema { public: - static std::atomic is_initialized; - static std::mutex mtx; + static const schema& get() { return value_; } - static const schema& get() { return *value_; } - - static void set(const schema& schema) + static void set(const T& object) { - value_ = schema; + if (!is_initialized) { + std::lock_guard lck{ mtx }; - is_initialized = true; + if (!is_initialized) { + value_ = compact_stream_serializer::build_schema(object); + is_initialized = true; + } + } } private: - static boost::optional value_; + static std::atomic is_initialized; + static std::mutex mtx; + static schema value_; }; template -boost::optional class_to_schema::value_ = boost::none; +schema class_to_schema::value_; template std::atomic class_to_schema::is_initialized{ false }; @@ -642,13 +635,7 @@ template void inline compact_stream_serializer::write(const T& object, object_data_output& out) { - if (!class_to_schema::is_initialized) { - std::lock_guard lck{ class_to_schema::mtx }; - - if (!class_to_schema::is_initialized) { - class_to_schema::set(build_schema(object)); - } - } + class_to_schema::set(object); const schema& schema_v = class_to_schema::get(); @@ -663,6 +650,17 @@ void inline compact_stream_serializer::write(const T& object, default_writer.end(); } +template +schema +compact_stream_serializer::build_schema(const T& object) +{ + schema_writer schema_writer(hz_serializer::type_name()); + serialization::compact_writer writer = + create_compact_writer(&schema_writer); + serialization::hz_serializer::write(object, writer); + return std::move(schema_writer).build(); +} + } // namespace pimpl } // namespace serialization } // namespace client diff --git a/hazelcast/test/src/compact/compact_schema_replication_stress_test.h b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h index 5bd16ab37a..c06079e04c 100644 --- a/hazelcast/test/src/compact/compact_schema_replication_stress_test.h +++ b/hazelcast/test/src/compact/compact_schema_replication_stress_test.h @@ -46,8 +46,10 @@ struct schema_replicator : schema_replicator schema_replicator(std::shared_ptr m, std::vector& schemas) : schema_replicator(m, schemas) { + using namespace serialization::pimpl; + stress_type instance{}; - auto schema = serialization::pimpl::build_schema(instance); + auto schema = compact_stream_serializer::build_schema(instance); schemas.push_back(std::move(schema)); m->put(Current, instance).get(); } diff --git a/hazelcast/test/src/compact/compact_test_base.h b/hazelcast/test/src/compact/compact_test_base.h index 76122f49a5..9f9678344b 100644 --- a/hazelcast/test/src/compact/compact_test_base.h +++ b/hazelcast/test/src/compact/compact_test_base.h @@ -93,8 +93,9 @@ class compact_test_base : public testing::Test template schema_t get_schema() { - T instance; - return serialization::pimpl::build_schema(instance); + using namespace serialization::pimpl; + + return compact_stream_serializer::build_schema(T{}); } HazelcastServerFactory factory_; From fc5a73a517ec43c885a2454e8b2884822556b0d7 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 3 Feb 2023 10:54:06 +0300 Subject: [PATCH 06/15] Field check is added. --- hazelcast/src/hazelcast/client/compact.cpp | 7 ++- .../src/compact/compact_serialization_test.h | 9 ++++ .../serialization/write_to_field_twice.h | 54 +++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 hazelcast/test/src/compact/serialization/write_to_field_twice.h diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 513003aa77..d9de6b4fc1 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1848,7 +1848,12 @@ schema_writer::schema_writer(std::string type_name) void schema_writer::add_field(std::string field_name, enum field_kind kind) { - field_definition_map[std::move(field_name)] = field_descriptor{ kind }; + if (field_definition_map.find(field_name) != end(field_definition_map)) { + BOOST_THROW_EXCEPTION(exception::hazelcast_serialization{ + "Field with the name '" + field_name + "' already exists." }); + } + + field_definition_map.emplace(move(field_name), field_descriptor{ kind }); } schema diff --git a/hazelcast/test/src/compact/compact_serialization_test.h b/hazelcast/test/src/compact/compact_serialization_test.h index fd83273575..332053413e 100644 --- a/hazelcast/test/src/compact/compact_serialization_test.h +++ b/hazelcast/test/src/compact/compact_serialization_test.h @@ -27,6 +27,7 @@ #include "serialization/employee_dto.h" #include "serialization/wrong_field_name_read_obj.h" #include "serialization/type_mismatch_obj.h" +#include "serialization/write_to_field_twice.h" namespace hazelcast { namespace client { @@ -150,6 +151,14 @@ TEST_F(CompactSerializationTest, test_read_with_type_mismatch) exception::hazelcast_serialization); } +TEST_F(CompactSerializationTest, test_write_to_same_field_twice) +{ + auto& ss = serialization_service(); + write_to_field_twice obj; + + ASSERT_THROW(ss.to_data(obj), exception::hazelcast_serialization); +} + } // namespace compact } // namespace test } // namespace client diff --git a/hazelcast/test/src/compact/serialization/write_to_field_twice.h b/hazelcast/test/src/compact/serialization/write_to_field_twice.h new file mode 100644 index 0000000000..b94a7f00d9 --- /dev/null +++ b/hazelcast/test/src/compact/serialization/write_to_field_twice.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2008-2022, Hazelcast, Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "hazelcast/client/serialization/serialization.h" + +namespace hazelcast { +namespace client { +namespace test { +namespace compact { + +struct write_to_field_twice +{}; + +} // namespace compact +} // namespace test + +namespace serialization { + +template<> +struct hz_serializer : compact_serializer +{ + static void write(const test::compact::write_to_field_twice& obj, + compact_writer& writer) + { + writer.write_int32("a_field", 12); + writer.write_int32("a_field", 12); + } + + static test::compact::write_to_field_twice read(compact_reader& reader) + { + return test::compact::write_to_field_twice{}; + } + + static std::string type_name() { return "write_to_field_twice"; } +}; + +} // namespace serialization +} // namespace client +} // namespace hazelcast \ No newline at end of file From 233bb879cbae944c90ff97740c40548c2a8b5a72 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 09:14:35 +0300 Subject: [PATCH 07/15] codec is generated by the tool. --- .../hazelcast/client/protocol/codec/codecs.cpp | 16 ++++++---------- .../src/hazelcast/client/protocol/codec/codecs.h | 2 +- hazelcast/src/hazelcast/client/compact.cpp | 2 +- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp index 706111de39..cd1cc398aa 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp @@ -5789,20 +5789,16 @@ sql_fetch_encode(const sql::impl::query_id& query_id, } ClientMessage -send_schema_request_encode(const serialization::pimpl::schema& sch) -{ - static constexpr int32_t MESSAGE_TYPE = 4864; // 0x001300 - static constexpr size_t INITIAL_FRAME_SIZE = - ClientMessage::REQUEST_HEADER_LEN; - - ClientMessage msg{ INITIAL_FRAME_SIZE }; +client_sendschema_encode(const serialization::pimpl::schema &schema) { + size_t initial_frame_size = ClientMessage::REQUEST_HEADER_LEN; + ClientMessage msg(initial_frame_size); msg.set_retryable(true); - msg.set_operation_name("Client.SendSchema"); + msg.set_operation_name("client.sendschema"); - msg.set_message_type(MESSAGE_TYPE); + msg.set_message_type(static_cast(4864)); msg.set_partition_id(-1); - msg.set(sch, true); + msg.set(schema, true); return msg; } diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h index c0be339204..8527405a32 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h @@ -3083,7 +3083,7 @@ sql_fetch_encode(const sql::impl::query_id& query_id, * Replicates schema on cluster */ ClientMessage HAZELCAST_API -send_schema_request_encode(const serialization::pimpl::schema& sch); +client_sendschema_encode(const serialization::pimpl::schema& schema); /** * Decodes response of send schema request diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index d9de6b4fc1..6053df9323 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1896,7 +1896,7 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) using hazelcast::client::protocol::ClientMessage; using namespace protocol::codec; - auto message = send_schema_request_encode(s); + auto message = client_sendschema_encode(s); auto invocation = spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); From a869e2f6930f4b8d86d8d91774b46031369084d3 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Fri, 3 Feb 2023 17:06:07 +0300 Subject: [PATCH 08/15] Variable rename --- .../serialization/pimpl/compact/compact_impl.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h index a0b5f2aeb8..41a7504171 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h @@ -580,19 +580,19 @@ class class_to_schema static void set(const T& object) { - if (!is_initialized) { - std::lock_guard lck{ mtx }; + if (!is_initialized_) { + std::lock_guard lck{ mtx_ }; - if (!is_initialized) { + if (!is_initialized_) { value_ = compact_stream_serializer::build_schema(object); - is_initialized = true; + is_initialized_ = true; } } } private: - static std::atomic is_initialized; - static std::mutex mtx; + static std::atomic is_initialized_; + static std::mutex mtx_; static schema value_; }; @@ -600,10 +600,10 @@ template schema class_to_schema::value_; template -std::atomic class_to_schema::is_initialized{ false }; +std::atomic class_to_schema::is_initialized_{ false }; template -std::mutex class_to_schema::mtx; +std::mutex class_to_schema::mtx_; template T inline compact_stream_serializer::read(object_data_input& in) From 8eeede972453363fb0e51d48e379bb80987602ee Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 09:18:29 +0300 Subject: [PATCH 09/15] replicate_schema renamed to replicate_shema_in_clutser --- .../client/serialization/pimpl/compact/default_schema_service.h | 2 +- hazelcast/src/hazelcast/client/compact.cpp | 2 +- hazelcast/src/hazelcast/client/spi.cpp | 2 +- hazelcast/test/src/compact/compact_test_base.h | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h index 5bf2b52dbc..c892386985 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h @@ -60,7 +60,7 @@ class HAZELCAST_API default_schema_service /** * Replicates schema on the cluster */ - boost::future replicate_schema(schema); + boost::future replicate_schema_in_cluster(schema); bool is_schema_replicated(const schema&); diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 6053df9323..09cda3b756 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1885,7 +1885,7 @@ default_schema_service::get(int64_t schemaId) } boost::future -default_schema_service::replicate_schema(schema s) +default_schema_service::replicate_schema_in_cluster(schema s) { return replicate_schema_attempt(std::move(s)); } diff --git a/hazelcast/src/hazelcast/client/spi.cpp b/hazelcast/src/hazelcast/client/spi.cpp index 3bc7a0ba5f..6eadaa5720 100644 --- a/hazelcast/src/hazelcast/client/spi.cpp +++ b/hazelcast/src/hazelcast/client/spi.cpp @@ -1462,7 +1462,7 @@ ClientInvocation::replicate_schemas( end(schemas), back_inserter(replications), [this](const serialization::pimpl::schema& s) { - return schema_service_.replicate_schema(s); + return schema_service_.replicate_schema_in_cluster(s); }); auto self = shared_from_this(); diff --git a/hazelcast/test/src/compact/compact_test_base.h b/hazelcast/test/src/compact/compact_test_base.h index 9f9678344b..f95ac1dd83 100644 --- a/hazelcast/test/src/compact/compact_test_base.h +++ b/hazelcast/test/src/compact/compact_test_base.h @@ -58,7 +58,7 @@ class compact_test_base : public testing::Test spi::ClientContext context{ client }; ASSERT_NO_THROW( - context.get_schema_service().replicate_schema(schema).get()); + context.get_schema_service().replicate_schema_in_cluster(schema).get()); } bool check_schema_on_backend(const schema_t& schema) From 6dd34f2b47426054179edc3ba0e2ca3e0a202c78 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 09:27:05 +0300 Subject: [PATCH 10/15] empty constructor is not allowed for field_descriptor. --- .../client/serialization/pimpl/compact/field_descriptor.h | 2 +- hazelcast/src/hazelcast/client/compact.cpp | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h index b684b681b5..5846dee62e 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h @@ -31,7 +31,7 @@ namespace pimpl { struct HAZELCAST_API field_descriptor { - field_descriptor(field_kind k = field_kind(0), + field_descriptor(field_kind k, int32_t i = -1, int32_t o = -1, int8_t b = -1); diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 09cda3b756..dab8d9e340 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1771,7 +1771,10 @@ schema::schema( } for (auto& item : sorted_fields) { - field_definition_map_[item.first] = item.second; + auto field = field_definition_map_.find(item.first); + + assert(field != end(field_definition_map_)); + field->second = item.second; } number_of_var_size_fields_ = index; From aa2b15e78854afc23c5868321d2fbdb9bb0ec940 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 10:38:33 +0300 Subject: [PATCH 11/15] replicate_schema_in_cluster refactored, invocation runs on user executor. --- hazelcast/src/hazelcast/client/compact.cpp | 76 ++++++++++++---------- 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index dab8d9e340..8bb7d6112f 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -26,6 +26,7 @@ #include "hazelcast/client/spi/impl/ClientInvocation.h" #include "hazelcast/client/spi/ClientContext.h" #include "hazelcast/client/cluster.h" +#include "hazelcast/client/spi/impl/ClientExecutionServiceImpl.h" #include "hazelcast/util/Bits.h" #include "hazelcast/client/client_properties.h" @@ -1889,12 +1890,6 @@ default_schema_service::get(int64_t schemaId) boost::future default_schema_service::replicate_schema_in_cluster(schema s) -{ - return replicate_schema_attempt(std::move(s)); -} - -boost::future -default_schema_service::replicate_schema_attempt(schema s, int attempts) { using hazelcast::client::protocol::ClientMessage; using namespace protocol::codec; @@ -1904,15 +1899,17 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) auto invocation = spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); - return invocation->invoke().then( - boost::launch::sync, - [this, attempts, s](boost::future future) { - auto msg = future.get(); + auto execution_service = context_.get_client_execution_service().shared_from_this(); - auto replicated_member_uuids = send_schema_response_decode(msg); + return invocation->invoke().then( + execution_service->get_user_executor(), + [this, s, execution_service](boost::future future) mutable { + auto response = future.get(); + auto replicated_member_uuids = send_schema_response_decode(response); auto members = context_.get_cluster().get_members(); - for (const member& searchee : members) { + for (int i = 1; i < max_put_retry_count_; ++i){ + for (const member& searchee : members) { auto contains = any_of(begin(replicated_member_uuids), end(replicated_member_uuids), @@ -1921,7 +1918,7 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) }); if (!contains) { - if (attempts >= max_put_retry_count_) { + if (i == (max_put_retry_count_ - 1)) { throw exception::illegal_state{ "default_schema_service::replicate_schema_attempt", (boost::format("The schema %1% cannot be " @@ -1941,31 +1938,38 @@ default_schema_service::replicate_schema_attempt(schema s, int attempts) std::this_thread::sleep_for( std::chrono::milliseconds{ retry_pause_millis_ }); - replicate_schema_attempt(std::move(s), attempts + 1) - .get(); - - return; + break; } } - } - - auto s_p = std::make_shared(std::move(s)); - auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); - - if (!existing) { - return; - } - - if (*s_p != *existing) { - throw exception::illegal_state{ - "default_schema_service::replicate_schema_attempt", - (boost::format("Schema with schemaId %1% " - "already exists. Existing " - "schema %2%, new schema %3%") % - s.schema_id() % *existing % s) - .str() - }; - } + } + + auto message = client_sendschema_encode(s); + + auto invocation = + spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); + + auto response = invocation->invoke().get(); + replicated_member_uuids = send_schema_response_decode(response); + members = context_.get_cluster().get_members(); + } + + auto s_p = std::make_shared(std::move(s)); + auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); + + if (!existing) { + return; + } + + if (*s_p != *existing) { + throw exception::illegal_state{ + "default_schema_service::replicate_schema_attempt", + (boost::format("Schema with schemaId %1% " + "already exists. Existing " + "schema %2%, new schema %3%") % + s.schema_id() % *existing % s) + .str() + }; + } }); } From ddaa9bc6a8107aa5e82fc863c9abe01f4b3d06a3 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 12:12:10 +0300 Subject: [PATCH 12/15] Return type changed to unordered_set. put_if_absent added and replicate_schema method is refactored. --- .../client/protocol/codec/codecs.cpp | 4 +- .../hazelcast/client/protocol/codec/codecs.h | 2 +- .../hazelcast/client/protocol/ClientMessage.h | 22 ++++++++ .../pimpl/compact/default_schema_service.h | 3 +- hazelcast/src/hazelcast/client/compact.cpp | 50 ++++++++++--------- 5 files changed, 53 insertions(+), 28 deletions(-) diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp index cd1cc398aa..d55708ee68 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp @@ -5803,11 +5803,11 @@ client_sendschema_encode(const serialization::pimpl::schema &schema) { return msg; } -std::vector +std::unordered_set> send_schema_response_decode(ClientMessage& m) { m.skip_frame(); - return m.get>(); + return m.get>>(); } } // namespace codec diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h index 8527405a32..57c16215d1 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h @@ -3088,7 +3088,7 @@ client_sendschema_encode(const serialization::pimpl::schema& schema); /** * Decodes response of send schema request */ -std::vector HAZELCAST_API +std::unordered_set> HAZELCAST_API send_schema_response_decode(ClientMessage&); } // namespace codec diff --git a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h index 24995b9040..b7d5968fdc 100644 --- a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h +++ b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -539,6 +540,27 @@ class HAZELCAST_API ClientMessage return result; } + template + typename std::enable_if< + std::is_same>::value, + T>::type + get() + { + T result; + + auto f = reinterpret_cast( + rd_ptr(SIZE_OF_FRAME_LENGTH_AND_FLAGS)); + auto content_length = + static_cast(f->frame_len) - SIZE_OF_FRAME_LENGTH_AND_FLAGS; + size_t item_count = + content_length / ClientMessage::get_sizeof(); + for (size_t i = 0; i < item_count; ++i) { + result.emplace(get()); + } + + return result; + } + template typename std::enable_if< std::is_same>::value && diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h index c892386985..aba8bae5d0 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h @@ -65,7 +65,8 @@ class HAZELCAST_API default_schema_service bool is_schema_replicated(const schema&); private: - boost::future replicate_schema_attempt(schema, int attempts = 0); + + void put_if_absent(schema); int retry_pause_millis_; int max_put_retry_count_; diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 8bb7d6112f..04d6f7c4ab 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1909,13 +1909,9 @@ default_schema_service::replicate_schema_in_cluster(schema s) auto members = context_.get_cluster().get_members(); for (int i = 1; i < max_put_retry_count_; ++i){ - for (const member& searchee : members) { - auto contains = - any_of(begin(replicated_member_uuids), - end(replicated_member_uuids), - [&searchee](const boost::uuids::uuid member_id) { - return searchee.get_uuid() == member_id; - }); + for (const member& member : members) { + + auto contains = replicated_member_uuids.find(member.get_uuid()) != end(replicated_member_uuids); if (!contains) { if (i == (max_put_retry_count_ - 1)) { @@ -1953,23 +1949,7 @@ default_schema_service::replicate_schema_in_cluster(schema s) members = context_.get_cluster().get_members(); } - auto s_p = std::make_shared(std::move(s)); - auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); - - if (!existing) { - return; - } - - if (*s_p != *existing) { - throw exception::illegal_state{ - "default_schema_service::replicate_schema_attempt", - (boost::format("Schema with schemaId %1% " - "already exists. Existing " - "schema %2%, new schema %3%") % - s.schema_id() % *existing % s) - .str() - }; - } + put_if_absent(std::move(s)); }); } @@ -1979,6 +1959,28 @@ default_schema_service::is_schema_replicated(const schema& s) return bool(replicateds_.get(s.schema_id())); } +void +default_schema_service::put_if_absent(schema s) +{ + auto s_p = std::make_shared(std::move(s)); + auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); + + if (!existing) { + return; + } + + if (*s_p != *existing) { + throw exception::illegal_state{ + "default_schema_service::replicate_schema_attempt", + (boost::format("Schema with schemaId %1% " + "already exists. Existing " + "schema %2%, new schema %3%") % + s.schema_id() % *existing % s) + .str() + }; + } +} + compact_stream_serializer::compact_stream_serializer( default_schema_service& service) : schema_service{ service } From 19585c1e33ee489f7336c67cf569c4667960e4c5 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Mon, 13 Feb 2023 12:25:41 +0300 Subject: [PATCH 13/15] Unused variable removed. --- hazelcast/src/hazelcast/client/compact.cpp | 10 +++++----- hazelcast/src/hazelcast/client/compact.cpp' | 0 hazelcast/src/hazelcast/client/spi.cpp | 2 -- 3 files changed, 5 insertions(+), 7 deletions(-) create mode 100644 hazelcast/src/hazelcast/client/compact.cpp' diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 04d6f7c4ab..72a0a65fac 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1963,7 +1963,7 @@ void default_schema_service::put_if_absent(schema s) { auto s_p = std::make_shared(std::move(s)); - auto existing = replicateds_.put_if_absent(s.schema_id(), s_p); + auto existing = replicateds_.put_if_absent(s_p->schema_id(), s_p); if (!existing) { return; @@ -1973,10 +1973,10 @@ default_schema_service::put_if_absent(schema s) throw exception::illegal_state{ "default_schema_service::replicate_schema_attempt", (boost::format("Schema with schemaId %1% " - "already exists. Existing " - "schema %2%, new schema %3%") % - s.schema_id() % *existing % s) - .str() + "already exists. Existing " + "schema %2%, new schema %3%") % + s_p->.schema_id() % *existing % *s_p) + .str() }; } } diff --git a/hazelcast/src/hazelcast/client/compact.cpp' b/hazelcast/src/hazelcast/client/compact.cpp' new file mode 100644 index 0000000000..e69de29bb2 diff --git a/hazelcast/src/hazelcast/client/spi.cpp b/hazelcast/src/hazelcast/client/spi.cpp index 6eadaa5720..cadc871497 100644 --- a/hazelcast/src/hazelcast/client/spi.cpp +++ b/hazelcast/src/hazelcast/client/spi.cpp @@ -1465,8 +1465,6 @@ ClientInvocation::replicate_schemas( return schema_service_.replicate_schema_in_cluster(s); }); - auto self = shared_from_this(); - return boost::when_all(begin(replications), end(replications)); } From e7542c8e0555039589194415cc354feb4e7ce612 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Wed, 22 Feb 2023 09:41:42 +0300 Subject: [PATCH 14/15] Replicate schema is made sync and executed on schema replication thread_pool --- .../client/protocol/codec/codecs.cpp | 10 +- .../hazelcast/client/protocol/codec/codecs.h | 6 - .../hazelcast/client/protocol/ClientMessage.h | 4 +- .../client/serialization/field_kind.h | 2 +- .../pimpl/compact/default_schema_service.h | 13 +- .../pimpl/compact/field_descriptor.h | 2 +- .../serialization/pimpl/compact/schema.h | 2 +- .../spi/impl/ClientExecutionServiceImpl.h | 2 + .../client/spi/impl/ClientInvocation.h | 4 +- hazelcast/src/hazelcast/client/compact.cpp | 117 ++++++++++-------- hazelcast/src/hazelcast/client/spi.cpp | 39 +++--- .../test/src/compact/compact_test_base.h | 2 +- 12 files changed, 109 insertions(+), 94 deletions(-) diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp index d55708ee68..fd63b576d0 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.cpp @@ -5789,7 +5789,8 @@ sql_fetch_encode(const sql::impl::query_id& query_id, } ClientMessage -client_sendschema_encode(const serialization::pimpl::schema &schema) { +client_sendschema_encode(const serialization::pimpl::schema& schema) +{ size_t initial_frame_size = ClientMessage::REQUEST_HEADER_LEN; ClientMessage msg(initial_frame_size); msg.set_retryable(true); @@ -5803,13 +5804,6 @@ client_sendschema_encode(const serialization::pimpl::schema &schema) { return msg; } -std::unordered_set> -send_schema_response_decode(ClientMessage& m) -{ - m.skip_frame(); - return m.get>>(); -} - } // namespace codec } // namespace protocol } // namespace client diff --git a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h index 57c16215d1..f097daa203 100644 --- a/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h +++ b/hazelcast/generated-sources/src/hazelcast/client/protocol/codec/codecs.h @@ -3085,12 +3085,6 @@ sql_fetch_encode(const sql::impl::query_id& query_id, ClientMessage HAZELCAST_API client_sendschema_encode(const serialization::pimpl::schema& schema); -/** - * Decodes response of send schema request - */ -std::unordered_set> HAZELCAST_API -send_schema_response_decode(ClientMessage&); - } // namespace codec } // namespace protocol } // namespace client diff --git a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h index b7d5968fdc..55a9f65c49 100644 --- a/hazelcast/include/hazelcast/client/protocol/ClientMessage.h +++ b/hazelcast/include/hazelcast/client/protocol/ClientMessage.h @@ -542,7 +542,9 @@ class HAZELCAST_API ClientMessage template typename std::enable_if< - std::is_same>::value, + std::is_same< + T, + std::unordered_set>::value, T>::type get() { diff --git a/hazelcast/include/hazelcast/client/serialization/field_kind.h b/hazelcast/include/hazelcast/client/serialization/field_kind.h index 3232d7d890..4403582cfb 100644 --- a/hazelcast/include/hazelcast/client/serialization/field_kind.h +++ b/hazelcast/include/hazelcast/client/serialization/field_kind.h @@ -68,7 +68,7 @@ enum class HAZELCAST_API field_kind ARRAY_OF_NULLABLE_FLOAT64 = 46 }; -std::ostream HAZELCAST_API & +std::ostream HAZELCAST_API& operator<<(std::ostream&, field_kind); } // namespace serialization diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h index aba8bae5d0..57512e3df0 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/default_schema_service.h @@ -25,6 +25,10 @@ namespace hazelcast { namespace client { +namespace protocol { +class ClientMessage; +} + namespace spi { class ClientContext; } @@ -60,14 +64,19 @@ class HAZELCAST_API default_schema_service /** * Replicates schema on the cluster */ - boost::future replicate_schema_in_cluster(schema); + void replicate_schema_in_cluster(schema); bool is_schema_replicated(const schema&); private: - void put_if_absent(schema); + /** + * Decodes response of send schema request + */ + std::unordered_set> + send_schema_response_decode(protocol::ClientMessage&); + int retry_pause_millis_; int max_put_retry_count_; spi::ClientContext& context_; diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h index 5846dee62e..895cae998c 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/field_descriptor.h @@ -60,7 +60,7 @@ struct HAZELCAST_API field_descriptor bool HAZELCAST_API operator==(const field_descriptor& x, const field_descriptor& y); -std::ostream HAZELCAST_API & +std::ostream HAZELCAST_API& operator<<(std::ostream& os, const field_descriptor&); } // namespace pimpl diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h index 34fdd1c908..001e20cb1a 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/schema.h @@ -56,7 +56,7 @@ operator==(const schema& x, const schema& y); bool HAZELCAST_API operator!=(const schema& x, const schema& y); -std::ostream HAZELCAST_API & +std::ostream HAZELCAST_API& operator<<(std::ostream& os, const schema& schema); } // namespace pimpl diff --git a/hazelcast/include/hazelcast/client/spi/impl/ClientExecutionServiceImpl.h b/hazelcast/include/hazelcast/client/spi/impl/ClientExecutionServiceImpl.h index e3eb5e5f46..93dd1c6994 100644 --- a/hazelcast/include/hazelcast/client/spi/impl/ClientExecutionServiceImpl.h +++ b/hazelcast/include/hazelcast/client/spi/impl/ClientExecutionServiceImpl.h @@ -77,10 +77,12 @@ class HAZELCAST_API ClientExecutionServiceImpl static void shutdown_thread_pool(hazelcast::util::hz_thread_pool* pool); util::hz_thread_pool& get_user_executor(); + util::hz_thread_pool& get_schema_replication_executor(); private: std::unique_ptr internal_executor_; std::unique_ptr user_executor_; + std::unique_ptr schema_replication_executor_; spi::lifecycle_service& lifecycle_service_; const client_properties& client_properties_; int32_t user_pool_size_; diff --git a/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h b/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h index 0f81649747..85480a628e 100644 --- a/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h +++ b/hazelcast/include/hazelcast/client/spi/impl/ClientInvocation.h @@ -154,8 +154,8 @@ class HAZELCAST_API ClientInvocation static constexpr int MAX_FAST_INVOCATION_COUNT = 5; static constexpr int UNASSIGNED_PARTITION = -1; - boost::future>> replicate_schemas( - const std::vector& schemas); + boost::future replicate_schemas( + std::vector schemas); logger& logger_; lifecycle_service& lifecycle_service_; diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 72a0a65fac..20e5cb7182 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -1888,69 +1888,64 @@ default_schema_service::get(int64_t schemaId) return *ptr; } -boost::future +void default_schema_service::replicate_schema_in_cluster(schema s) { using hazelcast::client::protocol::ClientMessage; using namespace protocol::codec; - auto message = client_sendschema_encode(s); - - auto invocation = - spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); - - auto execution_service = context_.get_client_execution_service().shared_from_this(); - - return invocation->invoke().then( - execution_service->get_user_executor(), - [this, s, execution_service](boost::future future) mutable { - auto response = future.get(); - auto replicated_member_uuids = send_schema_response_decode(response); - auto members = context_.get_cluster().get_members(); - - for (int i = 1; i < max_put_retry_count_; ++i){ - for (const member& member : members) { - - auto contains = replicated_member_uuids.find(member.get_uuid()) != end(replicated_member_uuids); - - if (!contains) { - if (i == (max_put_retry_count_ - 1)) { - throw exception::illegal_state{ - "default_schema_service::replicate_schema_attempt", - (boost::format("The schema %1% cannot be " - "replicated in the cluster, after " - "%2% retries. It might be the case " - "that the client is experiencing a " - "split-brain, and continue putting " - "the data associated with that " - "schema might result in data loss. " - "It might be possible to replicate " - "the schema after some time, when " - "the cluster is healed.") % - s % max_put_retry_count_) - .str() - }; - } else { - std::this_thread::sleep_for( - std::chrono::milliseconds{ retry_pause_millis_ }); - - break; - } - } + for (int i = 0; i < max_put_retry_count_; ++i) { + auto message = client_sendschema_encode(s); + + auto invocation = + spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); + + auto response = invocation->invoke().get(); + auto replicated_member_uuids = send_schema_response_decode(response); + auto members = context_.get_cluster().get_members(); + + bool contains; + for (const member& member : members) { + + contains = replicated_member_uuids.find(member.get_uuid()) != + end(replicated_member_uuids); + + if (!contains) { + if (i == (max_put_retry_count_ - 1)) { + throw exception::illegal_state{ + "default_schema_service::replicate_schema_attempt", + (boost::format("The schema %1% cannot be " + "replicated in the cluster, after " + "%2% retries. It might be the case " + "that the client is experiencing a " + "split-brain, and continue putting " + "the data associated with that " + "schema might result in data loss. " + "It might be possible to replicate " + "the schema after some time, when " + "the cluster is healed.") % + s % max_put_retry_count_) + .str() + }; + } else { + std::this_thread::sleep_for( + std::chrono::milliseconds{ retry_pause_millis_ }); + + if (!context_.get_lifecycle_service().is_running()) { + return; + } + + break; + } } + } - auto message = client_sendschema_encode(s); - - auto invocation = - spi::impl::ClientInvocation::create(context_, message, SERVICE_NAME); + if (contains) { + put_if_absent(std::move(s)); - auto response = invocation->invoke().get(); - replicated_member_uuids = send_schema_response_decode(response); - members = context_.get_cluster().get_members(); + break; } - - put_if_absent(std::move(s)); - }); + } } bool @@ -1975,12 +1970,24 @@ default_schema_service::put_if_absent(schema s) (boost::format("Schema with schemaId %1% " "already exists. Existing " "schema %2%, new schema %3%") % - s_p->.schema_id() % *existing % *s_p) + s_p->schema_id() % *existing % *s_p) .str() }; } } +/** + * Decodes response of send schema request + */ +std::unordered_set> +default_schema_service::send_schema_response_decode( + protocol::ClientMessage& message) +{ + message.skip_frame(); + return message.get>>(); +} + compact_stream_serializer::compact_stream_serializer( default_schema_service& service) : schema_service{ service } diff --git a/hazelcast/src/hazelcast/client/spi.cpp b/hazelcast/src/hazelcast/client/spi.cpp index cadc871497..cd4b71a826 100644 --- a/hazelcast/src/hazelcast/client/spi.cpp +++ b/hazelcast/src/hazelcast/client/spi.cpp @@ -1323,6 +1323,8 @@ ClientExecutionServiceImpl::start() user_executor_.reset( new hazelcast::util::hz_thread_pool(user_pool_size_)); } + + schema_replication_executor_.reset(new hazelcast::util::hz_thread_pool()); } void @@ -1330,6 +1332,7 @@ ClientExecutionServiceImpl::shutdown() { shutdown_thread_pool(internal_executor_.get()); shutdown_thread_pool(user_executor_.get()); + shutdown_thread_pool(schema_replication_executor_.get()); } util::hz_thread_pool& @@ -1338,6 +1341,12 @@ ClientExecutionServiceImpl::get_user_executor() return *user_executor_; } +util::hz_thread_pool& +ClientExecutionServiceImpl::get_schema_replication_executor() +{ + return *schema_replication_executor_; +} + void ClientExecutionServiceImpl::shutdown_thread_pool( hazelcast::util::hz_thread_pool* pool) @@ -1414,11 +1423,8 @@ ClientInvocation::invoke() return replicate_schemas(schemas) .then(boost::launch::sync, - [this, actual_work, self]( - boost::future>> - replications) { - for (auto& replication : replications.get()) - replication.get(); + [this, actual_work, self](boost::future replication) { + replication.get(); return actual_work(); }) @@ -1450,22 +1456,23 @@ ClientInvocation::invoke_urgent() }); } -boost::future>> +boost::future ClientInvocation::replicate_schemas( - const std::vector& schemas) + std::vector schemas) { - std::vector> replications; + std::weak_ptr self = shared_from_this(); - replications.reserve(schemas.size()); + return boost::async( + execution_service_->get_schema_replication_executor(), [self, schemas]() { + auto invocation = self.lock(); - transform(begin(schemas), - end(schemas), - back_inserter(replications), - [this](const serialization::pimpl::schema& s) { - return schema_service_.replicate_schema_in_cluster(s); - }); + if (!invocation) + return; - return boost::when_all(begin(replications), end(replications)); + for (const serialization::pimpl::schema& s : schemas) { + invocation->schema_service_.replicate_schema_in_cluster(s); + } + }); } void diff --git a/hazelcast/test/src/compact/compact_test_base.h b/hazelcast/test/src/compact/compact_test_base.h index f95ac1dd83..2351b53915 100644 --- a/hazelcast/test/src/compact/compact_test_base.h +++ b/hazelcast/test/src/compact/compact_test_base.h @@ -58,7 +58,7 @@ class compact_test_base : public testing::Test spi::ClientContext context{ client }; ASSERT_NO_THROW( - context.get_schema_service().replicate_schema_in_cluster(schema).get()); + context.get_schema_service().replicate_schema_in_cluster(schema)); } bool check_schema_on_backend(const schema_t& schema) From 1548abefc7fda300b33bab3edb2105e07e68cdf7 Mon Sep 17 00:00:00 2001 From: ozancansel Date: Wed, 22 Feb 2023 11:08:09 +0300 Subject: [PATCH 15/15] compact_serializer, compact_reader, compact_writer is moved to compact namespace. --- examples/serialization/compact/main.cpp | 6 ++--- .../serialization/pimpl/compact/compact.h | 14 +++++++---- .../pimpl/compact/compact_impl.h | 19 +++++++++------ .../client/serialization/pimpl/data_input.h | 2 ++ .../client/serialization/serialization.h | 24 ++++++++++++------- hazelcast/src/hazelcast/client/compact.cpp | 23 +++++++++++------- .../test/src/compact/serialization/a_type.h | 6 ++--- .../test/src/compact/serialization/bits_dto.h | 7 +++--- .../src/compact/serialization/employee_dto.h | 7 +++--- .../compact/serialization/empty_main_dto.h | 7 +++--- .../src/compact/serialization/inner_dto.h | 7 +++--- .../test/src/compact/serialization/main_dto.h | 7 +++--- .../src/compact/serialization/named_dto.h | 7 +++--- .../src/compact/serialization/nested_type.h | 6 ++--- .../test/src/compact/serialization/node_dto.h | 7 +++--- .../serialization/nullable_primitive_object.h | 7 +++--- .../compact/serialization/primitive_object.h | 6 ++--- .../src/compact/serialization/stress_type.h | 7 +++--- .../compact/serialization/type_mismatch_obj.h | 8 ++++--- .../serialization/write_to_field_twice.h | 8 ++++--- .../serialization/wrong_field_name_read_obj.h | 7 +++--- 21 files changed, 115 insertions(+), 77 deletions(-) diff --git a/examples/serialization/compact/main.cpp b/examples/serialization/compact/main.cpp index ff87f3f17e..49eaf279df 100644 --- a/examples/serialization/compact/main.cpp +++ b/examples/serialization/compact/main.cpp @@ -37,16 +37,16 @@ namespace client { namespace serialization { template<> -struct hz_serializer : compact_serializer +struct hz_serializer : compact::compact_serializer { - static void write(const PersonDTO& object, compact_writer& out) + static void write(const PersonDTO& object, compact::compact_writer& out) { out.write_int32("age", object.age); out.write_string("name", object.name); out.write_string("surname", object.surname); } - static PersonDTO read(compact_reader& in) + static PersonDTO read(compact::compact_reader& in) { PersonDTO person; diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h index be30ca1720..9d1d5e3307 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact.h @@ -39,17 +39,19 @@ class ClientContext; } namespace serialization { +namespace compact { class compact_reader; class compact_writer; +} // namespace compact namespace pimpl { class schema; class default_compact_writer; class schema_writer; -compact_writer HAZELCAST_API +compact::compact_writer HAZELCAST_API create_compact_writer(pimpl::default_compact_writer* default_compact_writer); -compact_writer HAZELCAST_API +compact::compact_writer HAZELCAST_API create_compact_writer(pimpl::schema_writer* schema_writer); -compact_reader HAZELCAST_API +compact::compact_reader HAZELCAST_API create_compact_reader( pimpl::compact_stream_serializer& compact_stream_serializer, object_data_input& object_data_input, @@ -57,6 +59,7 @@ create_compact_reader( struct field_descriptor; } // namespace pimpl +namespace compact { /** * Classes derived from this class should implement the following static * methods: @@ -642,7 +645,7 @@ class HAZELCAST_API compact_reader read(); template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, typename boost::optional>::type read(); template @@ -1160,6 +1163,7 @@ class HAZELCAST_API compact_writer pimpl::default_compact_writer* default_compact_writer; pimpl::schema_writer* schema_writer; }; +} // namespace compact namespace pimpl { @@ -1327,7 +1331,7 @@ class HAZELCAST_API default_compact_writer template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, void>::type write(const T& value); diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h index 41a7504171..21ee64a071 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/compact/compact_impl.h @@ -56,6 +56,8 @@ get_offset(serialization::object_data_input& in, } // namespace offset_reader } // namespace pimpl +namespace compact { + template T compact_reader::read_primitive(const std::string& field_name, @@ -164,7 +166,7 @@ compact_reader::read() template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, typename boost::optional>::type compact_reader::read() { @@ -418,6 +420,8 @@ compact_writer::write_array_of_compact( schema_writer->add_field(field_name, field_kind::ARRAY_OF_COMPACT); } } +} // namespace compact + namespace pimpl { template @@ -511,7 +515,7 @@ default_compact_writer::write(const T& value) template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, void>::type default_compact_writer::write(const T& value) { @@ -560,7 +564,7 @@ struct schema_of { T t; schema_writer schema_writer(hz_serializer::type_name()); - serialization::compact_writer writer = + serialization::compact::compact_writer writer = create_compact_writer(&schema_writer); serialization::hz_serializer::write(t, writer); return std::move(schema_writer).build(); @@ -613,7 +617,8 @@ T inline compact_stream_serializer::read(object_data_input& in) // optimization to avoid hitting shared map in the schema_service, // in the case incoming data's schema is same as the local schema if (schema_id == local_schema.schema_id()) { - compact_reader reader = create_compact_reader(*this, in, local_schema); + compact::compact_reader reader = + create_compact_reader(*this, in, local_schema); return hz_serializer::read(reader); } // This path will run only in schema evolution case @@ -627,7 +632,7 @@ T inline compact_stream_serializer::read(object_data_input& in) }; BOOST_THROW_EXCEPTION(exception); } - compact_reader reader = create_compact_reader(*this, in, schema); + compact::compact_reader reader = create_compact_reader(*this, in, schema); return hz_serializer::read(reader); } @@ -645,7 +650,7 @@ void inline compact_stream_serializer::write(const T& object, out.write(schema_v.schema_id()); default_compact_writer default_writer(*this, out, schema_v); - compact_writer writer = create_compact_writer(&default_writer); + compact::compact_writer writer = create_compact_writer(&default_writer); hz_serializer::write(object, writer); default_writer.end(); } @@ -655,7 +660,7 @@ schema compact_stream_serializer::build_schema(const T& object) { schema_writer schema_writer(hz_serializer::type_name()); - serialization::compact_writer writer = + serialization::compact::compact_writer writer = create_compact_writer(&schema_writer); serialization::hz_serializer::write(object, writer); return std::move(schema_writer).build(); diff --git a/hazelcast/include/hazelcast/client/serialization/pimpl/data_input.h b/hazelcast/include/hazelcast/client/serialization/pimpl/data_input.h index 2bf220b471..07af5b63df 100644 --- a/hazelcast/include/hazelcast/client/serialization/pimpl/data_input.h +++ b/hazelcast/include/hazelcast/client/serialization/pimpl/data_input.h @@ -38,7 +38,9 @@ class ByteBuffer; namespace client { namespace serialization { class portable_reader; +namespace compact { class compact_reader; +} namespace pimpl { template class data_input diff --git a/hazelcast/include/hazelcast/client/serialization/serialization.h b/hazelcast/include/hazelcast/client/serialization/serialization.h index 9efbd69fd9..0c9e208281 100644 --- a/hazelcast/include/hazelcast/client/serialization/serialization.h +++ b/hazelcast/include/hazelcast/client/serialization/serialization.h @@ -746,6 +746,12 @@ class PortableVersionHelper } }; +namespace compact { +class compact_writer; +class compact_reader; +class compact_serializer; +} // namespace compact + class HAZELCAST_API object_data_input : public pimpl::data_input> { @@ -755,7 +761,7 @@ class HAZELCAST_API object_data_input uint32_t variable_offsets_pos, uint32_t index); - friend class compact_reader; + friend class compact::compact_reader; friend class portable_reader; public: @@ -799,7 +805,7 @@ class HAZELCAST_API object_data_input template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, boost::optional>::type inline read_object(int32_t type_id); template @@ -822,7 +828,7 @@ class HAZELCAST_API object_data_input typename std::enable_if< !(std::is_base_of>::value || std::is_base_of>::value || - std::is_base_of>::value || + std::is_base_of>::value || std::is_base_of>::value || std::is_base_of>::value), boost::optional>::type inline read_object(int32_t type_id); @@ -886,7 +892,7 @@ class HAZELCAST_API object_data_output : public pimpl::data_output template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, void>::type inline write_object(const T& object); template @@ -899,7 +905,7 @@ class HAZELCAST_API object_data_output : public pimpl::data_output !(std::is_base_of>::value || std::is_base_of>::value || std::is_base_of>::value || - std::is_base_of>::value || + std::is_base_of>::value || std::is_base_of>::value || (std::is_array::value && std::is_same::type, char>::value)), @@ -2305,7 +2311,7 @@ typename std::enable_if< template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, void>::type inline object_data_output::write_object(const T& object) { if (is_no_write_) { @@ -2364,7 +2370,7 @@ typename std::enable_if< !(std::is_base_of>::value || std::is_base_of>::value || std::is_base_of>::value || - std::is_base_of>::value || + std::is_base_of>::value || std::is_base_of>::value || (std::is_array::value && std::is_same::type, char>::value)), @@ -2450,7 +2456,7 @@ typename std::enable_if< template typename std::enable_if< - std::is_base_of>::value, + std::is_base_of>::value, boost::optional>::type inline object_data_input::read_object(int32_t type_id) { @@ -2491,7 +2497,7 @@ template typename std::enable_if< !(std::is_base_of>::value || std::is_base_of>::value || - std::is_base_of>::value || + std::is_base_of>::value || std::is_base_of>::value || std::is_base_of>::value), boost::optional>::type inline object_data_input::read_object(int32_t diff --git a/hazelcast/src/hazelcast/client/compact.cpp b/hazelcast/src/hazelcast/client/compact.cpp index 20e5cb7182..54d1e919e9 100644 --- a/hazelcast/src/hazelcast/client/compact.cpp +++ b/hazelcast/src/hazelcast/client/compact.cpp @@ -209,6 +209,7 @@ operator<<(std::ostream& os, field_kind kind) namespace hazelcast { namespace client { namespace serialization { +namespace compact { compact_writer::compact_writer( pimpl::default_compact_writer* default_compact_writer) @@ -694,21 +695,25 @@ compact_writer::write_array_of_nullable_float64( } } +} // namespace compact + namespace pimpl { -compact_reader +compact::compact_reader create_compact_reader( pimpl::compact_stream_serializer& compact_stream_serializer, object_data_input& object_data_input, const pimpl::schema& schema) { - return compact_reader{ compact_stream_serializer, - object_data_input, - schema }; + return compact::compact_reader{ compact_stream_serializer, + object_data_input, + schema }; } } // namespace pimpl +namespace compact { + const compact_reader::offset_func compact_reader::BYTE_OFFSET_READER = pimpl::offset_reader::get_offset; const compact_reader::offset_func compact_reader::SHORT_OFFSET_READER = @@ -1183,18 +1188,20 @@ compact_reader::read_array_of_nullable_float64(const std::string& field_name) field_kind::ARRAY_OF_NULLABLE_FLOAT64); } +} // namespace compact + namespace pimpl { -compact_writer +compact::compact_writer create_compact_writer(pimpl::default_compact_writer* default_compact_writer) { - return compact_writer{ default_compact_writer }; + return compact::compact_writer{ default_compact_writer }; } -compact_writer +compact::compact_writer create_compact_writer(pimpl::schema_writer* schema_writer) { - return compact_writer{ schema_writer }; + return compact::compact_writer{ schema_writer }; } default_compact_writer::default_compact_writer( diff --git a/hazelcast/test/src/compact/serialization/a_type.h b/hazelcast/test/src/compact/serialization/a_type.h index 8f262b55c7..1c71e7d01f 100644 --- a/hazelcast/test/src/compact/serialization/a_type.h +++ b/hazelcast/test/src/compact/serialization/a_type.h @@ -36,17 +36,17 @@ struct a_type namespace serialization { template<> -struct hz_serializer : compact_serializer +struct hz_serializer : compact::compact_serializer { static void write(const test::compact::a_type& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_boolean("x", object.x); writer.write_compact("nested", object.nested); } - static test::compact::a_type read(compact_reader& reader) + static test::compact::a_type read(compact::compact_reader& reader) { test::compact::a_type object; diff --git a/hazelcast/test/src/compact/serialization/bits_dto.h b/hazelcast/test/src/compact/serialization/bits_dto.h index 21fa16388e..f06de253c4 100644 --- a/hazelcast/test/src/compact/serialization/bits_dto.h +++ b/hazelcast/test/src/compact/serialization/bits_dto.h @@ -53,10 +53,11 @@ operator==(const bits_dto& lhs, const bits_dto& rhs) namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::bits_dto& dto, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_boolean("a", dto.a); writer.write_boolean("b", dto.b); @@ -71,7 +72,7 @@ struct hz_serializer : public compact_serializer writer.write_array_of_boolean("booleans", dto.booleans); } - static test::compact::bits_dto read(compact_reader& reader) + static test::compact::bits_dto read(compact::compact_reader& reader) { test::compact::bits_dto dto; dto.a = reader.read_boolean("a"); diff --git a/hazelcast/test/src/compact/serialization/employee_dto.h b/hazelcast/test/src/compact/serialization/employee_dto.h index 0486a4a6b1..a8dd94b5bb 100644 --- a/hazelcast/test/src/compact/serialization/employee_dto.h +++ b/hazelcast/test/src/compact/serialization/employee_dto.h @@ -43,10 +43,11 @@ operator==(const employee_dto& lhs, const employee_dto& rhs) namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::employee_dto& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("age", object.age); writer.write_int32("rank", object.rank); @@ -55,7 +56,7 @@ struct hz_serializer : public compact_serializer writer.write_boolean("isFired", object.isFired); } - static test::compact::employee_dto read(compact_reader& reader) + static test::compact::employee_dto read(compact::compact_reader& reader) { auto age = reader.read_int32("age"); auto rank = reader.read_int32("rank"); diff --git a/hazelcast/test/src/compact/serialization/empty_main_dto.h b/hazelcast/test/src/compact/serialization/empty_main_dto.h index 6493448017..a357d7c0da 100644 --- a/hazelcast/test/src/compact/serialization/empty_main_dto.h +++ b/hazelcast/test/src/compact/serialization/empty_main_dto.h @@ -38,14 +38,15 @@ struct empty_main_dto namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const compact::test::empty_main_dto& object, - compact_writer& writer) + compact::compact_writer& writer) { } - static compact::test::empty_main_dto read(compact_reader& reader) + static compact::test::empty_main_dto read(compact::compact_reader& reader) { return compact::test::empty_main_dto{}; } diff --git a/hazelcast/test/src/compact/serialization/inner_dto.h b/hazelcast/test/src/compact/serialization/inner_dto.h index 8bc3b173ac..0acae2c1c6 100644 --- a/hazelcast/test/src/compact/serialization/inner_dto.h +++ b/hazelcast/test/src/compact/serialization/inner_dto.h @@ -159,10 +159,11 @@ create_inner_dto() namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::inner_dto& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_array_of_boolean("bools", object.bools); writer.write_array_of_int8("bytes", object.bytes); @@ -196,7 +197,7 @@ struct hz_serializer : public compact_serializer object.nullableDoubles); } - static test::compact::inner_dto read(compact_reader& reader) + static test::compact::inner_dto read(compact::compact_reader& reader) { test::compact::inner_dto object; object.bools = reader.read_array_of_boolean("bools"); diff --git a/hazelcast/test/src/compact/serialization/main_dto.h b/hazelcast/test/src/compact/serialization/main_dto.h index 6e78518205..4da494118f 100644 --- a/hazelcast/test/src/compact/serialization/main_dto.h +++ b/hazelcast/test/src/compact/serialization/main_dto.h @@ -106,10 +106,11 @@ create_main_dto() namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::main_dto& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_boolean("bool", object.boolean); writer.write_int8("b", object.b); @@ -135,7 +136,7 @@ struct hz_serializer : public compact_serializer writer.write_nullable_float64("nullableD", object.nullableD); } - static test::compact::main_dto read(compact_reader& reader) + static test::compact::main_dto read(compact::compact_reader& reader) { auto boolean = reader.read_boolean("bool"); auto b = reader.read_int8("b"); diff --git a/hazelcast/test/src/compact/serialization/named_dto.h b/hazelcast/test/src/compact/serialization/named_dto.h index 237e92f630..7187084169 100644 --- a/hazelcast/test/src/compact/serialization/named_dto.h +++ b/hazelcast/test/src/compact/serialization/named_dto.h @@ -41,16 +41,17 @@ operator==(const named_dto& lhs, const named_dto& rhs) namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::named_dto& dto, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_string("name", dto.name); writer.write_int32("my_int", dto.my_int); } - static test::compact::named_dto read(compact_reader& reader) + static test::compact::named_dto read(compact::compact_reader& reader) { test::compact::named_dto dto; dto.name = reader.read_string("name"); diff --git a/hazelcast/test/src/compact/serialization/nested_type.h b/hazelcast/test/src/compact/serialization/nested_type.h index 5eb5507991..9ed6df7ff9 100644 --- a/hazelcast/test/src/compact/serialization/nested_type.h +++ b/hazelcast/test/src/compact/serialization/nested_type.h @@ -36,15 +36,15 @@ struct nested_type namespace serialization { template<> -struct hz_serializer : compact_serializer +struct hz_serializer : compact::compact_serializer { static void write(const test::compact::nested_type& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("x", object.y); } - static test::compact::nested_type read(compact_reader& reader) + static test::compact::nested_type read(compact::compact_reader& reader) { test::compact::nested_type object; diff --git a/hazelcast/test/src/compact/serialization/node_dto.h b/hazelcast/test/src/compact/serialization/node_dto.h index 7a2e17c66f..52625d40d8 100644 --- a/hazelcast/test/src/compact/serialization/node_dto.h +++ b/hazelcast/test/src/compact/serialization/node_dto.h @@ -43,10 +43,11 @@ operator==(const node_dto& lhs, const node_dto& rhs) namespace serialization { template<> -struct hz_serializer : public compact_serializer +struct hz_serializer + : public compact::compact_serializer { static void write(const test::compact::node_dto& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("id", object.id); writer.write_compact( @@ -55,7 +56,7 @@ struct hz_serializer : public compact_serializer : boost::make_optional(*object.child)); } - static test::compact::node_dto read(compact_reader& reader) + static test::compact::node_dto read(compact::compact_reader& reader) { auto id = reader.read_int32("id"); auto&& child = reader.read_compact("child"); diff --git a/hazelcast/test/src/compact/serialization/nullable_primitive_object.h b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h index da3968c066..679d2d5f85 100644 --- a/hazelcast/test/src/compact/serialization/nullable_primitive_object.h +++ b/hazelcast/test/src/compact/serialization/nullable_primitive_object.h @@ -48,10 +48,10 @@ namespace serialization { template<> struct hz_serializer - : public compact_serializer + : public compact::compact_serializer { static void write(const test::compact::nullable_primitive_object& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_nullable_boolean("boolean", object.nullableBoolean); writer.write_nullable_int8("byte", object.nullableByte); @@ -71,7 +71,8 @@ struct hz_serializer object.nullableDoubles); } - static test::compact::nullable_primitive_object read(compact_reader& reader) + static test::compact::nullable_primitive_object read( + compact::compact_reader& reader) { test::compact::nullable_primitive_object object; diff --git a/hazelcast/test/src/compact/serialization/primitive_object.h b/hazelcast/test/src/compact/serialization/primitive_object.h index c916212bb3..3201f1fe42 100644 --- a/hazelcast/test/src/compact/serialization/primitive_object.h +++ b/hazelcast/test/src/compact/serialization/primitive_object.h @@ -47,10 +47,10 @@ struct primitive_object namespace serialization { template<> struct hz_serializer - : public compact_serializer + : public compact::compact_serializer { static void write(const test::compact::primitive_object& object, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_boolean("boolean", object.boolean_); writer.write_int8("byte", object.byte_); @@ -68,7 +68,7 @@ struct hz_serializer writer.write_array_of_float64("doubles", object.doubles); } - static test::compact::primitive_object read(compact_reader& reader) + static test::compact::primitive_object read(compact::compact_reader& reader) { test::compact::primitive_object object; diff --git a/hazelcast/test/src/compact/serialization/stress_type.h b/hazelcast/test/src/compact/serialization/stress_type.h index fdaf522cb9..8facec971a 100644 --- a/hazelcast/test/src/compact/serialization/stress_type.h +++ b/hazelcast/test/src/compact/serialization/stress_type.h @@ -36,7 +36,8 @@ namespace client { namespace serialization { template -struct hz_serializer> : compact_serializer +struct hz_serializer> + : compact::compact_serializer { static std::string type_name() { @@ -44,12 +45,12 @@ struct hz_serializer> : compact_serializer } static void write(const test::compact::stress_type&, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("field_" + std::to_string(Idx), Idx); } - static test::compact::stress_type read(compact_reader& reader) + static test::compact::stress_type read(compact::compact_reader& reader) { return test::compact::stress_type{}; } diff --git a/hazelcast/test/src/compact/serialization/type_mismatch_obj.h b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h index 317e892271..046e9431dd 100644 --- a/hazelcast/test/src/compact/serialization/type_mismatch_obj.h +++ b/hazelcast/test/src/compact/serialization/type_mismatch_obj.h @@ -34,15 +34,17 @@ struct type_mistmatch_obj namespace serialization { template<> -struct hz_serializer : compact_serializer +struct hz_serializer + : compact::compact_serializer { static void write(const test::compact::type_mistmatch_obj& obj, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("field_1", obj.value); } - static test::compact::type_mistmatch_obj read(compact_reader& reader) + static test::compact::type_mistmatch_obj read( + compact::compact_reader& reader) { test::compact::type_mistmatch_obj obj; diff --git a/hazelcast/test/src/compact/serialization/write_to_field_twice.h b/hazelcast/test/src/compact/serialization/write_to_field_twice.h index b94a7f00d9..0f63f92dff 100644 --- a/hazelcast/test/src/compact/serialization/write_to_field_twice.h +++ b/hazelcast/test/src/compact/serialization/write_to_field_twice.h @@ -32,16 +32,18 @@ struct write_to_field_twice namespace serialization { template<> -struct hz_serializer : compact_serializer +struct hz_serializer + : compact::compact_serializer { static void write(const test::compact::write_to_field_twice& obj, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("a_field", 12); writer.write_int32("a_field", 12); } - static test::compact::write_to_field_twice read(compact_reader& reader) + static test::compact::write_to_field_twice read( + compact::compact_reader& reader) { return test::compact::write_to_field_twice{}; } diff --git a/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h index 07b88bcfae..3298eb7e38 100644 --- a/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h +++ b/hazelcast/test/src/compact/serialization/wrong_field_name_read_obj.h @@ -35,15 +35,16 @@ namespace serialization { template<> struct hz_serializer - : compact_serializer + : compact::compact_serializer { static void write(const test::compact::wrong_field_name_read_obj& obj, - compact_writer& writer) + compact::compact_writer& writer) { writer.write_int32("field_1", obj.value); } - static test::compact::wrong_field_name_read_obj read(compact_reader& reader) + static test::compact::wrong_field_name_read_obj read( + compact::compact_reader& reader) { test::compact::wrong_field_name_read_obj obj;