diff --git a/.clang-format b/.clang-format index 276eaf0a609c..3f91dfb66320 100644 --- a/.clang-format +++ b/.clang-format @@ -1,3 +1,15 @@ -BasedOnStyle: google +BasedOnStyle: Google DerivePointerAlignment: false IncludeBlocks: Preserve +AttributeMacros: ["noexcept"] +IndentRequires: false +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +AccessModifierOffset: -4 +BinPackParameters: false +BinPackArguments: false +AllowAllParametersOfDeclarationOnNextLine: false +AlignAfterOpenBracket: BlockIndent +AlwaysBreakAfterDefinitionReturnType: None +PenaltyReturnTypeOnItsOwnLine: 200 diff --git a/.gitignore b/.gitignore index 77a54fdb5827..0d3c9a79677d 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,6 @@ /build*/ /cmake-build-*/ /docs/ -/third_party/ CMakeLists.txt.user compile_commands.json tags diff --git a/.mapping.json b/.mapping.json index d31349ebf9b1..a336d61e8041 100644 --- a/.mapping.json +++ b/.mapping.json @@ -1865,6 +1865,7 @@ "grpc/include/userver/ugrpc/impl/deadline_timepoint.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/deadline_timepoint.hpp", "grpc/include/userver/ugrpc/impl/internal_tag_fwd.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/internal_tag_fwd.hpp", "grpc/include/userver/ugrpc/impl/maybe_owned_string.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/maybe_owned_string.hpp", + "grpc/include/userver/ugrpc/impl/protobuf_collector.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/protobuf_collector.hpp", "grpc/include/userver/ugrpc/impl/queue_runner.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/queue_runner.hpp", "grpc/include/userver/ugrpc/impl/span.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/span.hpp", "grpc/include/userver/ugrpc/impl/static_metadata.hpp":"taxi/uservices/userver/grpc/include/userver/ugrpc/impl/static_metadata.hpp", @@ -1958,6 +1959,7 @@ "grpc/src/ugrpc/impl/internal_tag.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/internal_tag.hpp", "grpc/src/ugrpc/impl/logging.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/logging.cpp", "grpc/src/ugrpc/impl/logging.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/logging.hpp", + "grpc/src/ugrpc/impl/protobuf_collector.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_collector.cpp", "grpc/src/ugrpc/impl/protobuf_utils.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_utils.cpp", "grpc/src/ugrpc/impl/protobuf_utils.hpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/protobuf_utils.hpp", "grpc/src/ugrpc/impl/queue_runner.cpp":"taxi/uservices/userver/grpc/src/ugrpc/impl/queue_runner.cpp", @@ -2030,6 +2032,7 @@ "grpc/tests/generic_server_test.cpp":"taxi/uservices/userver/grpc/tests/generic_server_test.cpp", "grpc/tests/logging_test.cpp":"taxi/uservices/userver/grpc/tests/logging_test.cpp", "grpc/tests/middlewares_test.cpp":"taxi/uservices/userver/grpc/tests/middlewares_test.cpp", + "grpc/tests/protobuf_collector_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_collector_test.cpp", "grpc/tests/protobuf_visit_test.cpp":"taxi/uservices/userver/grpc/tests/protobuf_visit_test.cpp", "grpc/tests/secret_fields_test.cpp":"taxi/uservices/userver/grpc/tests/secret_fields_test.cpp", "grpc/tests/serialization_test.cpp":"taxi/uservices/userver/grpc/tests/serialization_test.cpp", @@ -3522,17 +3525,43 @@ "third_party/librseq/CMakeLists.txt":"taxi/uservices/userver/third_party/librseq/CMakeLists.txt", "third_party/librseq/LICENSE.md":"taxi/uservices/userver/third_party/librseq/LICENSE.md", "third_party/librseq/README.md":"taxi/uservices/userver/third_party/librseq/README.md", + "third_party/librseq/include/rseq/abi.h":"taxi/uservices/userver/third_party/librseq/include/rseq/abi.h", + "third_party/librseq/include/rseq/arch.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch.h", + "third_party/librseq/include/rseq/arch/aarch64.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/aarch64.h", + "third_party/librseq/include/rseq/arch/aarch64/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/aarch64/bits.h", + "third_party/librseq/include/rseq/arch/arm.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/arm.h", + "third_party/librseq/include/rseq/arch/arm/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/arm/bits.h", + "third_party/librseq/include/rseq/arch/generic/common.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/generic/common.h", + "third_party/librseq/include/rseq/arch/generic/thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/generic/thread-pointer.h", + "third_party/librseq/include/rseq/arch/mips.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/mips.h", + "third_party/librseq/include/rseq/arch/mips/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/mips/bits.h", + "third_party/librseq/include/rseq/arch/ppc.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/ppc.h", + "third_party/librseq/include/rseq/arch/ppc/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/ppc/bits.h", + "third_party/librseq/include/rseq/arch/ppc/thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/ppc/thread-pointer.h", + "third_party/librseq/include/rseq/arch/riscv.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/riscv.h", + "third_party/librseq/include/rseq/arch/riscv/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/riscv/bits.h", + "third_party/librseq/include/rseq/arch/riscv/thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/riscv/thread-pointer.h", + "third_party/librseq/include/rseq/arch/s390.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/s390.h", + "third_party/librseq/include/rseq/arch/s390/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/s390/bits.h", + "third_party/librseq/include/rseq/arch/templates/bits-reset.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/templates/bits-reset.h", + "third_party/librseq/include/rseq/arch/templates/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/templates/bits.h", + "third_party/librseq/include/rseq/arch/x86.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/x86.h", + "third_party/librseq/include/rseq/arch/x86/bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/x86/bits.h", + "third_party/librseq/include/rseq/arch/x86/thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/arch/x86/thread-pointer.h", "third_party/librseq/include/rseq/compiler.h":"taxi/uservices/userver/third_party/librseq/include/rseq/compiler.h", - "third_party/librseq/include/rseq/rseq-abi.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-abi.h", - "third_party/librseq/include/rseq/rseq-bits-reset.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-bits-reset.h", - "third_party/librseq/include/rseq/rseq-bits-template.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-bits-template.h", - "third_party/librseq/include/rseq/rseq-thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-thread-pointer.h", - "third_party/librseq/include/rseq/rseq-x86-bits.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-x86-bits.h", - "third_party/librseq/include/rseq/rseq-x86-thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-x86-thread-pointer.h", - "third_party/librseq/include/rseq/rseq-x86.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq-x86.h", + "third_party/librseq/include/rseq/inject.h":"taxi/uservices/userver/third_party/librseq/include/rseq/inject.h", + "third_party/librseq/include/rseq/mempool.h":"taxi/uservices/userver/third_party/librseq/include/rseq/mempool.h", + "third_party/librseq/include/rseq/pseudocode.h":"taxi/uservices/userver/third_party/librseq/include/rseq/pseudocode.h", "third_party/librseq/include/rseq/rseq.h":"taxi/uservices/userver/third_party/librseq/include/rseq/rseq.h", + "third_party/librseq/include/rseq/thread-pointer.h":"taxi/uservices/userver/third_party/librseq/include/rseq/thread-pointer.h", + "third_party/librseq/include/rseq/utils.h":"taxi/uservices/userver/third_party/librseq/include/rseq/utils.h", "third_party/librseq/src/config.h":"taxi/uservices/userver/third_party/librseq/src/config.h", + "third_party/librseq/src/list.h":"taxi/uservices/userver/third_party/librseq/src/list.h", + "third_party/librseq/src/rseq-mempool.c":"taxi/uservices/userver/third_party/librseq/src/rseq-mempool.c", + "third_party/librseq/src/rseq-utils.h":"taxi/uservices/userver/third_party/librseq/src/rseq-utils.h", "third_party/librseq/src/rseq.c":"taxi/uservices/userver/third_party/librseq/src/rseq.c", + "third_party/librseq/src/smp.c":"taxi/uservices/userver/third_party/librseq/src/smp.c", + "third_party/librseq/src/smp.h":"taxi/uservices/userver/third_party/librseq/src/smp.h", "third_party/llhttp/CMakeLists.txt":"taxi/uservices/userver/third_party/llhttp/CMakeLists.txt", "third_party/llhttp/LICENSE-MIT":"taxi/uservices/userver/third_party/llhttp/LICENSE-MIT", "third_party/llhttp/README.md":"taxi/uservices/userver/third_party/llhttp/README.md", diff --git a/.piglet-meta.json b/.piglet-meta.json index a0eef757e32b..a8db02510b4a 100644 --- a/.piglet-meta.json +++ b/.piglet-meta.json @@ -1,3 +1,4 @@ { - "project":"userver" + "project":"userver", + "repository":"arcadia" } \ No newline at end of file diff --git a/Makefile b/Makefile index 6053544900f8..123953460f49 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ CMAKE_COMMON_FLAGS ?= -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -CMAKE_DEBUG_FLAGS ?= -DUSERVER_SANITIZE=addr;ub +CMAKE_DEBUG_FLAGS ?= '-DUSERVER_SANITIZE=addr;ub' CMAKE_RELEASE_FLAGS ?= KERNEL := $(shell uname -s) NPROCS ?= $(shell nproc) diff --git a/chaotic/golden_tests/output/schemas/allof/allof.cpp b/chaotic/golden_tests/output/schemas/allof/allof.cpp index 11fcb75f902e..e6d56f522812 100644 --- a/chaotic/golden_tests/output/schemas/allof/allof.cpp +++ b/chaotic/golden_tests/output/schemas/allof/allof.cpp @@ -7,139 +7,111 @@ namespace ns { bool operator==(const ns::AllOf::Foo__P0& lhs, const ns::AllOf::Foo__P0& rhs) { - return lhs.foo == rhs.foo && lhs.extra == rhs.extra && + return lhs.foo == rhs.foo && lhs.extra == rhs.extra && - true; + true; } bool operator==(const ns::AllOf::Foo__P1& lhs, const ns::AllOf::Foo__P1& rhs) { - return lhs.bar == rhs.bar && lhs.extra == rhs.extra && + return lhs.bar == rhs.bar && lhs.extra == rhs.extra && - true; + true; } bool operator==(const ns::AllOf::Foo& lhs, const ns::AllOf::Foo& rhs) { - return static_cast(lhs) == - static_cast(rhs) && - static_cast(lhs) == - static_cast(rhs); + return static_cast(lhs) == static_cast(rhs) && + static_cast(lhs) == static_cast(rhs); } -bool operator==(const ns::AllOf& lhs, const ns::AllOf& rhs) { - return lhs.foo == rhs.foo && true; -} +bool operator==(const ns::AllOf& lhs, const ns::AllOf& rhs) { return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, - const ns::AllOf::Foo__P0& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P0& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, - const ns::AllOf::Foo__P1& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P1& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -AllOf::Foo__P0 Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +AllOf::Foo__P0 +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -AllOf::Foo__P1 Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +AllOf::Foo__P1 +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -AllOf::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +AllOf::Foo +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -AllOf Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +AllOf Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not - * generated: ns::AllOf::Foo__P0 has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::AllOf::Foo__P0 has JSON-specific + * field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not - * generated: ns::AllOf::Foo__P0 has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::AllOf::Foo__P0 has JSON-specific + * field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::AllOf::Foo__P0& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::AllOf::Foo__P0& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; - if (value.foo) { - vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::AllOf::Foo__P1& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::AllOf::Foo__P1& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; - if (value.bar) { - vb["bar"] = USERVER_NAMESPACE::chaotic::Primitive{*value.bar}; - } + if (value.bar) { + vb["bar"] = USERVER_NAMESPACE::chaotic::Primitive{*value.bar}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::AllOf::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; - USERVER_NAMESPACE::formats::common::Merge( - vb, - USERVER_NAMESPACE::formats::json::ValueBuilder{ - static_cast(value)} - .ExtractValue()); - USERVER_NAMESPACE::formats::common::Merge( - vb, - USERVER_NAMESPACE::formats::json::ValueBuilder{ - static_cast(value)} - .ExtractValue()); - return vb.ExtractValue(); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::AllOf::Foo& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; + USERVER_NAMESPACE::formats::common::Merge( + vb, USERVER_NAMESPACE::formats::json::ValueBuilder{static_cast(value)}.ExtractValue() + ); + USERVER_NAMESPACE::formats::common::Merge( + vb, USERVER_NAMESPACE::formats::json::ValueBuilder{static_cast(value)}.ExtractValue() + ); + return vb.ExtractValue(); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::AllOf& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::AllOf& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = - USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/allof/allof.hpp b/chaotic/golden_tests/output/schemas/allof/allof.hpp index 8d6ed629d19d..1a22a06c2b93 100644 --- a/chaotic/golden_tests/output/schemas/allof/allof.hpp +++ b/chaotic/golden_tests/output/schemas/allof/allof.hpp @@ -12,27 +12,26 @@ namespace ns { struct AllOf { - struct Foo__P0 { - std::optional foo{}; + struct Foo__P0 { + std::optional foo{}; - USERVER_NAMESPACE::formats::json::Value extra; - }; + USERVER_NAMESPACE::formats::json::Value extra; + }; - struct Foo__P1 { - std::optional bar{}; + struct Foo__P1 { + std::optional bar{}; - USERVER_NAMESPACE::formats::json::Value extra; - }; + USERVER_NAMESPACE::formats::json::Value extra; + }; - struct Foo : public ns::AllOf::Foo__P0, public ns::AllOf::Foo__P1 { - Foo() = default; + struct Foo : public ns::AllOf::Foo__P0, public ns::AllOf::Foo__P1 { + Foo() = default; - Foo(ns::AllOf::Foo__P0&& a0, ns::AllOf::Foo__P1&& a1) - : ns::AllOf::Foo__P0(std::move(a0)), - ns::AllOf::Foo__P1(std::move(a1)) {} - }; + Foo(ns::AllOf::Foo__P0&& a0, ns::AllOf::Foo__P1&& a1) + : ns::AllOf::Foo__P0(std::move(a0)), ns::AllOf::Foo__P1(std::move(a1)) {} + }; - std::optional foo{}; + std::optional foo{}; }; bool operator==(const ns::AllOf::Foo__P0& lhs, const ns::AllOf::Foo__P0& rhs); @@ -43,52 +42,43 @@ bool operator==(const ns::AllOf::Foo& lhs, const ns::AllOf::Foo& rhs); bool operator==(const ns::AllOf& lhs, const ns::AllOf& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P0& value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P0& value); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P1& value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo__P1& value); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo& value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf::Foo& value); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::AllOf& value); -AllOf::Foo__P0 Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +AllOf::Foo__P0 +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -AllOf::Foo__P1 Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +AllOf::Foo__P1 +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -AllOf::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +AllOf::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -AllOf Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +AllOf Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not - * generated: ns::AllOf::Foo__P0 has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::AllOf::Foo__P0 has JSON-specific + * field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not - * generated: ns::AllOf::Foo__P0 has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::AllOf::Foo__P0 has JSON-specific + * field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::AllOf::Foo__P0& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::AllOf::Foo__P0& value, USERVER_NAMESPACE::formats::serialize::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::AllOf::Foo__P1& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::AllOf::Foo__P1& value, USERVER_NAMESPACE::formats::serialize::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::AllOf::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::AllOf::Foo& value, USERVER_NAMESPACE::formats::serialize::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::AllOf& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::AllOf& value, USERVER_NAMESPACE::formats::serialize::To); } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/allof/allof_parsers.ipp b/chaotic/golden_tests/output/schemas/allof/allof_parsers.ipp index fa430d0ecb19..7001e5c8d836 100644 --- a/chaotic/golden_tests/output/schemas/allof/allof_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/allof/allof_parsers.ipp @@ -13,80 +13,64 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__AllOf__Foo__P0_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__AllOf__Foo__P0_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__AllOf__Foo__P1_PropertiesNames = [](auto selector) { - return selector().template Type().Case("bar"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__AllOf__Foo__P1_PropertiesNames = [](auto selector) { + return selector().template Type().Case("bar"); +}; -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__AllOf_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__AllOf_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template -ns::AllOf::Foo__P0 Parse( - Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); +ns::AllOf::Foo__P0 Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::AllOf::Foo__P0 res; + ns::AllOf::Foo__P0 res; - res.foo = value["foo"] - .template As>>(); + res.foo = value["foo"].template As>>(); - res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue( - value, kns__AllOf__Foo__P0_PropertiesNames); + res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue(value, kns__AllOf__Foo__P0_PropertiesNames); - return res; + return res; } template -ns::AllOf::Foo__P1 Parse( - Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); +ns::AllOf::Foo__P1 Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::AllOf::Foo__P1 res; + ns::AllOf::Foo__P1 res; - res.bar = - value["bar"] - .template As< - std::optional>>(); + res.bar = value["bar"].template As>>(); - res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue( - value, kns__AllOf__Foo__P1_PropertiesNames); + res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue(value, kns__AllOf__Foo__P1_PropertiesNames); - return res; + return res; } template -ns::AllOf::Foo Parse(Value value, - USERVER_NAMESPACE::formats::parse::To) { - return ns::AllOf::Foo(value.template As(), - value.template As()); +ns::AllOf::Foo Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + return ns::AllOf::Foo(value.template As(), value.template As()); } template ns::AllOf Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::AllOf res; + ns::AllOf res; - res.foo = value["foo"] - .template As>>(); + res.foo = value["foo"].template As>>(); - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__AllOf_PropertiesNames); + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__AllOf_PropertiesNames); - return res; + return res; } } // namespace ns + diff --git a/chaotic/golden_tests/output/schemas/enum/enum.cpp b/chaotic/golden_tests/output/schemas/enum/enum.cpp index 365115f4fbe7..9c5ff6c4ce03 100644 --- a/chaotic/golden_tests/output/schemas/enum/enum.cpp +++ b/chaotic/golden_tests/output/schemas/enum/enum.cpp @@ -6,94 +6,75 @@ namespace ns { -bool operator==(const ns::Enum& lhs, const ns::Enum& rhs) { - return lhs.foo == rhs.foo && true; -} +bool operator==(const ns::Enum& lhs, const ns::Enum& rhs) { return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value) { - return lh << ToString(value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value) { + return lh << ToString(value); } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Enum Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -ns::Enum::Foo FromString(std::string_view value, - USERVER_NAMESPACE::formats::parse::To) { - const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); - if (result.has_value()) { - return *result; - } - throw std::runtime_error( - fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value)); +ns::Enum::Foo FromString(std::string_view value, USERVER_NAMESPACE::formats::parse::To) { + const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); + if (result.has_value()) { + return *result; + } + throw std::runtime_error(fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value)); } -ns::Enum::Foo Parse(std::string_view value, - USERVER_NAMESPACE::formats::parse::To to) { - return FromString(value, to); +ns::Enum::Foo Parse(std::string_view value, USERVER_NAMESPACE::formats::parse::To to) { + return FromString(value, to); } -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - return USERVER_NAMESPACE::formats::json::ValueBuilder(ToString(value)) - .ExtractValue(); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To) { + return USERVER_NAMESPACE::formats::json::ValueBuilder(ToString(value)).ExtractValue(); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::Enum& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = - USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } std::string ToString(ns::Enum::Foo value) { - const auto result = kns__Enum__Foo_Mapping.TryFindByFirst(value); - if (result.has_value()) { - return std::string{*result}; - } - throw std::runtime_error("Bad enum value"); + const auto result = kns__Enum__Foo_Mapping.TryFindByFirst(value); + if (result.has_value()) { + return std::string{*result}; + } + throw std::runtime_error("Bad enum value"); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/enum/enum.hpp b/chaotic/golden_tests/output/schemas/enum/enum.hpp index e4d334c5e2f2..f7ba74eacc4f 100644 --- a/chaotic/golden_tests/output/schemas/enum/enum.hpp +++ b/chaotic/golden_tests/output/schemas/enum/enum.hpp @@ -10,60 +10,49 @@ namespace ns { struct Enum { - enum class Foo { - kOne, - kTwo, - kThree, - }; - - static constexpr Foo kFooValues[] = { - Foo::kOne, - Foo::kTwo, - Foo::kThree, - }; - - std::optional foo{}; + enum class Foo { + kOne, + kTwo, + kThree, + }; + + static constexpr Foo kFooValues[] = { + Foo::kOne, + Foo::kTwo, + Foo::kThree, + }; + + std::optional foo{}; }; bool operator==(const ns::Enum& lhs, const ns::Enum& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum::Foo& value); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Enum& value); -Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum::Foo Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum::Foo Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum::Foo Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); +Enum Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -Enum::Foo FromString(std::string_view value, - USERVER_NAMESPACE::formats::parse::To); +Enum::Foo FromString(std::string_view value, USERVER_NAMESPACE::formats::parse::To); -Enum::Foo Parse(std::string_view value, - USERVER_NAMESPACE::formats::parse::To); +Enum::Foo Parse(std::string_view value, USERVER_NAMESPACE::formats::parse::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::Enum::Foo& value, USERVER_NAMESPACE::formats::serialize::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::Enum& value, USERVER_NAMESPACE::formats::serialize::To); std::string ToString(ns::Enum::Foo value); diff --git a/chaotic/golden_tests/output/schemas/enum/enum_parsers.ipp b/chaotic/golden_tests/output/schemas/enum/enum_parsers.ipp index d7c36b9c38ef..e38046d403a5 100644 --- a/chaotic/golden_tests/output/schemas/enum/enum_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/enum/enum_parsers.ipp @@ -12,48 +12,43 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialBiMap kns__Enum__Foo_Mapping = - [](auto selector) { - return selector() - .template Type() - .Case(ns::Enum::Foo::kOne, "one") - .Case(ns::Enum::Foo::kTwo, "two") - .Case(ns::Enum::Foo::kThree, "three"); - }; - -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__Enum_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialBiMap kns__Enum__Foo_Mapping = [](auto selector) { + return selector() + .template Type() + .Case(ns::Enum::Foo::kOne, "one") + .Case(ns::Enum::Foo::kTwo, "two") + .Case(ns::Enum::Foo::kThree, "three"); +}; + +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__Enum_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template -ns::Enum::Foo Parse(Value val, - USERVER_NAMESPACE::formats::parse::To) { - const auto value = val.template As(); - const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); - if (result.has_value()) { - return *result; - } - USERVER_NAMESPACE::chaotic::ThrowForValue( - fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value), - val); +ns::Enum::Foo Parse(Value val, USERVER_NAMESPACE::formats::parse::To) { + const auto value = val.template As(); + const auto result = kns__Enum__Foo_Mapping.TryFindBySecond(value); + if (result.has_value()) { + return *result; + } + USERVER_NAMESPACE::chaotic::ThrowForValue( + fmt::format("Invalid enum value ({}) for type ns::Enum::Foo", value), val + ); } template ns::Enum Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::Enum res; + ns::Enum res; - res.foo = value["foo"] - .template As>>(); + res.foo = value["foo"].template As>>(); - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__Enum_PropertiesNames); + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__Enum_PropertiesNames); - return res; + return res; } } // namespace ns + diff --git a/chaotic/golden_tests/output/schemas/int/int.cpp b/chaotic/golden_tests/output/schemas/int/int.cpp index c1f6c5e78948..dd1930114ea1 100644 --- a/chaotic/golden_tests/output/schemas/int/int.cpp +++ b/chaotic/golden_tests/output/schemas/int/int.cpp @@ -6,43 +6,33 @@ namespace ns { -bool operator==(const ns::Int& lhs, const ns::Int& rhs) { - return lhs.foo == rhs.foo && true; -} +bool operator==(const ns::Int& lhs, const ns::Int& rhs) { return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Int& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Int& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -Int Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Int Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Int Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Int Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -Int Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +Int Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::Int& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::Int& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/int/int.hpp b/chaotic/golden_tests/output/schemas/int/int.hpp index c8c38b77ec2b..3e15ffaba23b 100644 --- a/chaotic/golden_tests/output/schemas/int/int.hpp +++ b/chaotic/golden_tests/output/schemas/int/int.hpp @@ -10,25 +10,20 @@ namespace ns { struct Int { - std::optional foo{}; + std::optional foo{}; }; bool operator==(const ns::Int& lhs, const ns::Int& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Int& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::Int& value); -Int Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +Int Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -Int Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); +Int Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To); -Int Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); +Int Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::Int& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::Int& value, USERVER_NAMESPACE::formats::serialize::To); } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/int/int_parsers.ipp b/chaotic/golden_tests/output/schemas/int/int_parsers.ipp index 63313fd998ba..6414ecbb38b9 100644 --- a/chaotic/golden_tests/output/schemas/int/int_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/int/int_parsers.ipp @@ -11,27 +11,23 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__Int_PropertiesNames = - [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__Int_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template ns::Int Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::Int res; + ns::Int res; - res.foo = - value["foo"] - .template As< - std::optional>>(); + res.foo = value["foo"].template As>>(); - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__Int_PropertiesNames); + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__Int_PropertiesNames); - return res; + return res; } } // namespace ns + diff --git a/chaotic/golden_tests/output/schemas/oneof/oneof.cpp b/chaotic/golden_tests/output/schemas/oneof/oneof.cpp index ec9648e8be8c..f739b3158740 100644 --- a/chaotic/golden_tests/output/schemas/oneof/oneof.cpp +++ b/chaotic/golden_tests/output/schemas/oneof/oneof.cpp @@ -6,45 +6,35 @@ namespace ns { -bool operator==(const ns::OneOf& lhs, const ns::OneOf& rhs) { - return lhs.foo == rhs.foo && true; -} +bool operator==(const ns::OneOf& lhs, const ns::OneOf& rhs) { return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOf& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOf& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -OneOf Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +OneOf Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -OneOf Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +OneOf Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -OneOf Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +OneOf Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::OneOf& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::OneOf& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = USERVER_NAMESPACE::chaotic::Variant< - USERVER_NAMESPACE::chaotic::Primitive, - USERVER_NAMESPACE::chaotic::Primitive>{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic:: + Variant, USERVER_NAMESPACE::chaotic::Primitive>{ + *value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/oneof/oneof.hpp b/chaotic/golden_tests/output/schemas/oneof/oneof.hpp index 1015d1065f6f..29abe4972ce0 100644 --- a/chaotic/golden_tests/output/schemas/oneof/oneof.hpp +++ b/chaotic/golden_tests/output/schemas/oneof/oneof.hpp @@ -13,27 +13,22 @@ namespace ns { struct OneOf { - using Foo = std::variant; + using Foo = std::variant; - std::optional foo{}; + std::optional foo{}; }; bool operator==(const ns::OneOf& lhs, const ns::OneOf& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOf& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOf& value); -OneOf Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +OneOf Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -OneOf Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); +OneOf Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To); -OneOf Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); +OneOf Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::OneOf& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::OneOf& value, USERVER_NAMESPACE::formats::serialize::To); } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/oneof/oneof_parsers.ipp b/chaotic/golden_tests/output/schemas/oneof/oneof_parsers.ipp index 72809d23c5e9..6cd99b5f5de9 100644 --- a/chaotic/golden_tests/output/schemas/oneof/oneof_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/oneof/oneof_parsers.ipp @@ -13,27 +13,26 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__OneOf_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__OneOf_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template ns::OneOf Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::OneOf res; + ns::OneOf res; - res.foo = value["foo"] - .template As, - USERVER_NAMESPACE::chaotic::Primitive>>>(); + res.foo = value["foo"] + .template As, + USERVER_NAMESPACE::chaotic::Primitive>>>(); - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__OneOf_PropertiesNames); + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__OneOf_PropertiesNames); - return res; + return res; } } // namespace ns + diff --git a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.cpp b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.cpp index 33d5e4046c35..2f7767001558 100644 --- a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.cpp +++ b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.cpp @@ -7,129 +7,103 @@ namespace ns { bool operator==(const ns::A& lhs, const ns::A& rhs) { - return lhs.type == rhs.type && lhs.a_prop == rhs.a_prop && - lhs.extra == rhs.extra && + return lhs.type == rhs.type && lhs.a_prop == rhs.a_prop && lhs.extra == rhs.extra && - true; + true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::A& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::A& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -A Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +A Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: - * ns::A has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::A has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: - * ns::A has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::A has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::A& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::A& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; - if (value.type) { - vb["type"] = - USERVER_NAMESPACE::chaotic::Primitive{*value.type}; - } + if (value.type) { + vb["type"] = USERVER_NAMESPACE::chaotic::Primitive{*value.type}; + } - if (value.a_prop) { - vb["a_prop"] = USERVER_NAMESPACE::chaotic::Primitive{*value.a_prop}; - } + if (value.a_prop) { + vb["a_prop"] = USERVER_NAMESPACE::chaotic::Primitive{*value.a_prop}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } bool operator==(const ns::B& lhs, const ns::B& rhs) { - return lhs.type == rhs.type && lhs.b_prop == rhs.b_prop && - lhs.extra == rhs.extra && + return lhs.type == rhs.type && lhs.b_prop == rhs.b_prop && lhs.extra == rhs.extra && - true; + true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::B& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::B& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -B Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +B Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: - * ns::B has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::B has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: - * ns::B has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::B has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::B& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::B& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = value.extra; - if (value.type) { - vb["type"] = - USERVER_NAMESPACE::chaotic::Primitive{*value.type}; - } + if (value.type) { + vb["type"] = USERVER_NAMESPACE::chaotic::Primitive{*value.type}; + } - if (value.b_prop) { - vb["b_prop"] = USERVER_NAMESPACE::chaotic::Primitive{*value.b_prop}; - } + if (value.b_prop) { + vb["b_prop"] = USERVER_NAMESPACE::chaotic::Primitive{*value.b_prop}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } -bool operator==(const ns::OneOfDiscriminator& lhs, - const ns::OneOfDiscriminator& rhs) { - return lhs.foo == rhs.foo && true; +bool operator==(const ns::OneOfDiscriminator& lhs, const ns::OneOfDiscriminator& rhs) { + return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, - const ns::OneOfDiscriminator& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOfDiscriminator& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -OneOfDiscriminator Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +OneOfDiscriminator +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) - * was not generated: ns::OneOfDiscriminator::Foo has JSON-specific field - * "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: + * ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was - * not generated: ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: + * ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::OneOfDiscriminator& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::OneOfDiscriminator& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = USERVER_NAMESPACE::chaotic::OneOfWithDiscriminator< - &ns::OneOfDiscriminator::kFoo_Settings, - USERVER_NAMESPACE::chaotic::Primitive, - USERVER_NAMESPACE::chaotic::Primitive>{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::OneOfWithDiscriminator< + &ns::OneOfDiscriminator::kFoo_Settings, + USERVER_NAMESPACE::chaotic::Primitive, + USERVER_NAMESPACE::chaotic::Primitive>{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.hpp b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.hpp index 7debb3e2896d..5c2e324fd0ff 100644 --- a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.hpp +++ b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator.hpp @@ -14,91 +14,72 @@ namespace ns { struct A { - std::optional type{}; - std::optional a_prop{}; + std::optional type{}; + std::optional a_prop{}; - USERVER_NAMESPACE::formats::json::Value extra; + USERVER_NAMESPACE::formats::json::Value extra; }; bool operator==(const ns::A& lhs, const ns::A& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::A& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::A& value); -A Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +A Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: - * ns::A has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::A has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: - * ns::A has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::A has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::A& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::A& value, USERVER_NAMESPACE::formats::serialize::To); struct B { - std::optional type{}; - std::optional b_prop{}; + std::optional type{}; + std::optional b_prop{}; - USERVER_NAMESPACE::formats::json::Value extra; + USERVER_NAMESPACE::formats::json::Value extra; }; bool operator==(const ns::B& lhs, const ns::B& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::B& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::B& value); -B Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +B Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: - * ns::B has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: ns::B has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: - * ns::B has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: ns::B has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::B& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::B& value, USERVER_NAMESPACE::formats::serialize::To); struct OneOfDiscriminator { - [[maybe_unused]] static constexpr USERVER_NAMESPACE::chaotic::OneOfSettings - kFoo_Settings = {"type", - USERVER_NAMESPACE::utils::TrivialSet([](auto selector) { - return selector() - .template Type() - .Case("aaa") - .Case("bbb"); - })}; - - using Foo = std::variant; - - std::optional foo{}; + [[maybe_unused]] static constexpr USERVER_NAMESPACE::chaotic::OneOfSettings kFoo_Settings = { + "type", + USERVER_NAMESPACE::utils::TrivialSet([](auto selector) { + return selector().template Type().Case("aaa").Case("bbb"); + })}; + + using Foo = std::variant; + + std::optional foo{}; }; -bool operator==(const ns::OneOfDiscriminator& lhs, - const ns::OneOfDiscriminator& rhs); +bool operator==(const ns::OneOfDiscriminator& lhs, const ns::OneOfDiscriminator& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, - const ns::OneOfDiscriminator& value); +USERVER_NAMESPACE::logging::LogHelper& +operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::OneOfDiscriminator& value); -OneOfDiscriminator Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +OneOfDiscriminator +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) - * was not generated: ns::OneOfDiscriminator::Foo has JSON-specific field - * "extra" */ +/* Parse(USERVER_NAMESPACE::formats::yaml::Value, To) was not generated: + * ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ -/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was - * not generated: ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ +/* Parse(USERVER_NAMESPACE::yaml_config::Value, To) was not generated: + * ns::OneOfDiscriminator::Foo has JSON-specific field "extra" */ -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::OneOfDiscriminator& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::OneOfDiscriminator& value, USERVER_NAMESPACE::formats::serialize::To); } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator_parsers.ipp b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator_parsers.ipp index 55a080833701..4266f4b8d264 100644 --- a/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/oneofdiscriminator/oneofdiscriminator_parsers.ipp @@ -13,86 +13,65 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__A_PropertiesNames = - [](auto selector) { - return selector().template Type().Case("type").Case( - "a_prop"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__A_PropertiesNames = [](auto selector) { + return selector().template Type().Case("type").Case("a_prop"); +}; template ns::A Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::A res; + ns::A res; - res.type = value["type"] - .template As>>(); - res.a_prop = - value["a_prop"] - .template As< - std::optional>>(); + res.type = value["type"].template As>>(); + res.a_prop = value["a_prop"].template As>>(); - res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue( - value, kns__A_PropertiesNames); + res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue(value, kns__A_PropertiesNames); - return res; + return res; } -static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__B_PropertiesNames = - [](auto selector) { - return selector().template Type().Case("type").Case( - "b_prop"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__B_PropertiesNames = [](auto selector) { + return selector().template Type().Case("type").Case("b_prop"); +}; template ns::B Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::B res; + ns::B res; - res.type = value["type"] - .template As>>(); - res.b_prop = - value["b_prop"] - .template As< - std::optional>>(); + res.type = value["type"].template As>>(); + res.b_prop = value["b_prop"].template As>>(); - res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue( - value, kns__B_PropertiesNames); + res.extra = USERVER_NAMESPACE::chaotic::ExtractAdditionalPropertiesTrue(value, kns__B_PropertiesNames); - return res; + return res; } -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__OneOfDiscriminator_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__OneOfDiscriminator_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template -ns::OneOfDiscriminator Parse( - Value value, - USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); - - ns::OneOfDiscriminator res; - - res.foo = - value["foo"] - .template As< - std::optional, - USERVER_NAMESPACE::chaotic::Primitive>>>(); - - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__OneOfDiscriminator_PropertiesNames); - - return res; +ns::OneOfDiscriminator Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); + + ns::OneOfDiscriminator res; + + res.foo = value["foo"] + .template As, + USERVER_NAMESPACE::chaotic::Primitive>>>(); + + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__OneOfDiscriminator_PropertiesNames); + + return res; } } // namespace ns + diff --git a/chaotic/golden_tests/output/schemas/string/string.cpp b/chaotic/golden_tests/output/schemas/string/string.cpp index 1896de360479..9ba6cc2befdb 100644 --- a/chaotic/golden_tests/output/schemas/string/string.cpp +++ b/chaotic/golden_tests/output/schemas/string/string.cpp @@ -6,43 +6,33 @@ namespace ns { -bool operator==(const ns::String& lhs, const ns::String& rhs) { - return lhs.foo == rhs.foo && true; -} +bool operator==(const ns::String& lhs, const ns::String& rhs) { return lhs.foo == rhs.foo && true; } -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::String& value) { - return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value) - .ExtractValue()); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::String& value) { + return lh << ToString(USERVER_NAMESPACE::formats::json::ValueBuilder(value).ExtractValue()); } -String Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +String Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -String Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +String Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -String Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To to) { - return Parse(json, to); +String Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To to) { + return Parse(json, to); } -USERVER_NAMESPACE::formats::json::Value Serialize( - [[maybe_unused]] const ns::String& value, - USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>) { - USERVER_NAMESPACE::formats::json::ValueBuilder vb = - USERVER_NAMESPACE::formats::common::Type::kObject; +USERVER_NAMESPACE::formats::json::Value +Serialize([[maybe_unused]] const ns::String& value, USERVER_NAMESPACE::formats::serialize::To) { + USERVER_NAMESPACE::formats::json::ValueBuilder vb = USERVER_NAMESPACE::formats::common::Type::kObject; - if (value.foo) { - vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; - } + if (value.foo) { + vb["foo"] = USERVER_NAMESPACE::chaotic::Primitive{*value.foo}; + } - return vb.ExtractValue(); + return vb.ExtractValue(); } } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/string/string.hpp b/chaotic/golden_tests/output/schemas/string/string.hpp index 4cd689d130c7..2df2ba9cff45 100644 --- a/chaotic/golden_tests/output/schemas/string/string.hpp +++ b/chaotic/golden_tests/output/schemas/string/string.hpp @@ -10,25 +10,20 @@ namespace ns { struct String { - std::optional foo{}; + std::optional foo{}; }; bool operator==(const ns::String& lhs, const ns::String& rhs); -USERVER_NAMESPACE::logging::LogHelper& operator<<( - USERVER_NAMESPACE::logging::LogHelper& lh, const ns::String& value); +USERVER_NAMESPACE::logging::LogHelper& operator<<(USERVER_NAMESPACE::logging::LogHelper& lh, const ns::String& value); -String Parse(USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To); +String Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To); -String Parse(USERVER_NAMESPACE::formats::yaml::Value json, - USERVER_NAMESPACE::formats::parse::To); +String Parse(USERVER_NAMESPACE::formats::yaml::Value json, USERVER_NAMESPACE::formats::parse::To); -String Parse(USERVER_NAMESPACE::yaml_config::Value json, - USERVER_NAMESPACE::formats::parse::To); +String Parse(USERVER_NAMESPACE::yaml_config::Value json, USERVER_NAMESPACE::formats::parse::To); -USERVER_NAMESPACE::formats::json::Value Serialize( - const ns::String& value, USERVER_NAMESPACE::formats::serialize::To< - USERVER_NAMESPACE::formats::json::Value>); +USERVER_NAMESPACE::formats::json::Value +Serialize(const ns::String& value, USERVER_NAMESPACE::formats::serialize::To); } // namespace ns diff --git a/chaotic/golden_tests/output/schemas/string/string_parsers.ipp b/chaotic/golden_tests/output/schemas/string/string_parsers.ipp index db4ce96bb50e..a2abbd48ea20 100644 --- a/chaotic/golden_tests/output/schemas/string/string_parsers.ipp +++ b/chaotic/golden_tests/output/schemas/string/string_parsers.ipp @@ -11,27 +11,23 @@ namespace ns { -static constexpr USERVER_NAMESPACE::utils::TrivialSet - kns__String_PropertiesNames = [](auto selector) { - return selector().template Type().Case("foo"); - }; +static constexpr USERVER_NAMESPACE::utils::TrivialSet kns__String_PropertiesNames = [](auto selector) { + return selector().template Type().Case("foo"); +}; template -ns::String Parse(Value value, - USERVER_NAMESPACE::formats::parse::To) { - value.CheckNotMissing(); - value.CheckObjectOrNull(); +ns::String Parse(Value value, USERVER_NAMESPACE::formats::parse::To) { + value.CheckNotMissing(); + value.CheckObjectOrNull(); - ns::String res; + ns::String res; - res.foo = value["foo"] - .template As>>(); + res.foo = value["foo"].template As>>(); - USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties( - value, kns__String_PropertiesNames); + USERVER_NAMESPACE::chaotic::ValidateNoAdditionalProperties(value, kns__String_PropertiesNames); - return res; + return res; } } // namespace ns + diff --git a/chaotic/include/userver/chaotic/array.hpp b/chaotic/include/userver/chaotic/array.hpp index 1bd2f3c0f3eb..dce69acb3af6 100644 --- a/chaotic/include/userver/chaotic/array.hpp +++ b/chaotic/include/userver/chaotic/array.hpp @@ -15,54 +15,47 @@ namespace chaotic { template struct Array final { - const UserType& value; + const UserType& value; }; -template -UserType Parse(const Value& value, - formats::parse::To>) { - UserType arr; - auto inserter = std::inserter(arr, arr.end()); - if constexpr (meta::kIsReservable) { - arr.reserve(value.GetSize()); - } - for (const auto& item : value) { - *inserter = item.template As(); - ++inserter; - } - - chaotic::Validate(arr, value); - - return arr; +template +UserType Parse(const Value& value, formats::parse::To>) { + UserType arr; + auto inserter = std::inserter(arr, arr.end()); + if constexpr (meta::kIsReservable) { + arr.reserve(value.GetSize()); + } + for (const auto& item : value) { + *inserter = item.template As(); + ++inserter; + } + + chaotic::Validate(arr, value); + + return arr; } template -std::vector> Parse( - const Value& value, - formats::parse::To>, - Validators...>>) { - std::vector> arr; - arr.reserve(value.GetSize()); - for (const auto& item : value) { - arr.emplace_back(item.template As()); - } +std::vector> +Parse(const Value& value, formats::parse::To>, Validators...>>) { + std::vector> arr; + arr.reserve(value.GetSize()); + for (const auto& item : value) { + arr.emplace_back(item.template As()); + } - chaotic::Validate(arr, value); + chaotic::Validate(arr, value); - return arr; + return arr; } -template -Value Serialize(const Array& ps, - formats::serialize::To) { - typename Value::Builder vb{formats::common::Type::kArray}; - for (const auto& item : ps.value) { - vb.PushBack(ItemType{item}); - } - return vb.ExtractValue(); +template +Value Serialize(const Array& ps, formats::serialize::To) { + typename Value::Builder vb{formats::common::Type::kArray}; + for (const auto& item : ps.value) { + vb.PushBack(ItemType{item}); + } + return vb.ExtractValue(); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/convert.hpp b/chaotic/include/userver/chaotic/convert.hpp index 3156bed28c8e..d7baff5ae849 100644 --- a/chaotic/include/userver/chaotic/convert.hpp +++ b/chaotic/include/userver/chaotic/convert.hpp @@ -10,13 +10,14 @@ namespace chaotic::convert { template U Convert(const T& value, To) { - static_assert( - std::is_constructible_v, - "There is no `Convert(const Value&, chaotic::convert::To)` in " - "namespace of `T` or `chaotic::convert`. Probably you have not provided " - "a `Convert` function overload."); - - return U{value}; + static_assert( + std::is_constructible_v, + "There is no `Convert(const Value&, chaotic::convert::To)` in " + "namespace of `T` or `chaotic::convert`. Probably you have not provided " + "a `Convert` function overload." + ); + + return U{value}; } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/exception.hpp b/chaotic/include/userver/chaotic/exception.hpp index d47c94665bff..151fec300c91 100644 --- a/chaotic/include/userver/chaotic/exception.hpp +++ b/chaotic/include/userver/chaotic/exception.hpp @@ -11,12 +11,12 @@ USERVER_NAMESPACE_BEGIN namespace chaotic { class Error final : public formats::json::Exception { - using Exception::Exception; + using Exception::Exception; }; template [[noreturn]] inline void ThrowForValue(std::string_view str, Value value) { - throw Error(fmt::format("Error at path '{}': {}", value.GetPath(), str)); + throw Error(fmt::format("Error at path '{}': {}", value.GetPath(), str)); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/io/boost/uuids/uuid.hpp b/chaotic/include/userver/chaotic/io/boost/uuids/uuid.hpp index 080c8330c898..8365631f7e34 100644 --- a/chaotic/include/userver/chaotic/io/boost/uuids/uuid.hpp +++ b/chaotic/include/userver/chaotic/io/boost/uuids/uuid.hpp @@ -8,12 +8,9 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { -boost::uuids::uuid Convert( - const std::string& str, - USERVER_NAMESPACE::chaotic::convert::To); +boost::uuids::uuid Convert(const std::string& str, USERVER_NAMESPACE::chaotic::convert::To); -std::string Convert(const boost::uuids::uuid& uuid, - USERVER_NAMESPACE::chaotic::convert::To); +std::string Convert(const boost::uuids::uuid& uuid, USERVER_NAMESPACE::chaotic::convert::To); } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/days.hpp b/chaotic/include/userver/chaotic/io/std/chrono/days.hpp index a36ac1a57f3d..0b3d0d2b5669 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/days.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/days.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::days value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/duration.hpp b/chaotic/include/userver/chaotic/io/std/chrono/duration.hpp index 07a8edd9f1fe..cbf733b754ef 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/duration.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/duration.hpp @@ -9,9 +9,8 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -double Convert(const std::chrono::duration& value, - chaotic::convert::To) { - return value.count(); +double Convert(const std::chrono::duration& value, chaotic::convert::To) { + return value.count(); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/hours.hpp b/chaotic/include/userver/chaotic/io/std/chrono/hours.hpp index 57e34ada2b6e..1b4e45d7038b 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/hours.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/hours.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::hours value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/microseconds.hpp b/chaotic/include/userver/chaotic/io/std/chrono/microseconds.hpp index c632c2475a90..e2d84905e0d2 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/microseconds.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/microseconds.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::microseconds value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/milliseconds.hpp b/chaotic/include/userver/chaotic/io/std/chrono/milliseconds.hpp index d095d0ba8f7d..c14c7e9608ef 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/milliseconds.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/milliseconds.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::milliseconds value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/minutes.hpp b/chaotic/include/userver/chaotic/io/std/chrono/minutes.hpp index c0e669b79af5..e0d454d85f75 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/minutes.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/minutes.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::minutes value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/seconds.hpp b/chaotic/include/userver/chaotic/io/std/chrono/seconds.hpp index b74ff2238ef6..6b482baa5988 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/seconds.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/seconds.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::seconds value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/chrono/years.hpp b/chaotic/include/userver/chaotic/io/std/chrono/years.hpp index 4b69d8d5c4d3..b700c2643512 100644 --- a/chaotic/include/userver/chaotic/io/std/chrono/years.hpp +++ b/chaotic/include/userver/chaotic/io/std/chrono/years.hpp @@ -11,7 +11,7 @@ namespace chaotic::convert { template T Convert(std::chrono::years value, chaotic::convert::To) { - return utils::numeric_cast(value.count()); + return utils::numeric_cast(value.count()); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/size_t.hpp b/chaotic/include/userver/chaotic/io/std/size_t.hpp index 06d6f2a3c78b..3e4398657556 100644 --- a/chaotic/include/userver/chaotic/io/std/size_t.hpp +++ b/chaotic/include/userver/chaotic/io/std/size_t.hpp @@ -11,18 +11,15 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -std::enable_if_t< - std::is_integral_v && !std::is_same_v, T> +std::enable_if_t && !std::is_same_v, T> Convert(const std::size_t& value, To) { - return utils::numeric_cast(value); + return utils::numeric_cast(value); } template -std::enable_if_t && - !std::is_same_v, - std::size_t> +std::enable_if_t && !std::is_same_v, std::size_t> Convert(const T& value, To) { - return utils::numeric_cast(value); + return utils::numeric_cast(value); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/uint32_t.hpp b/chaotic/include/userver/chaotic/io/std/uint32_t.hpp index 91f087005ad7..53a93f5b2f9a 100644 --- a/chaotic/include/userver/chaotic/io/std/uint32_t.hpp +++ b/chaotic/include/userver/chaotic/io/std/uint32_t.hpp @@ -12,15 +12,13 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -std::enable_if_t, T> Convert(const std::uint32_t& value, - To) { - return utils::numeric_cast(value); +std::enable_if_t, T> Convert(const std::uint32_t& value, To) { + return utils::numeric_cast(value); } template -std::enable_if_t, std::uint32_t> Convert( - const T& value, To) { - return utils::numeric_cast(value); +std::enable_if_t, std::uint32_t> Convert(const T& value, To) { + return utils::numeric_cast(value); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/std/uint64_t.hpp b/chaotic/include/userver/chaotic/io/std/uint64_t.hpp index 0d9f7d02135c..175714b1361a 100644 --- a/chaotic/include/userver/chaotic/io/std/uint64_t.hpp +++ b/chaotic/include/userver/chaotic/io/std/uint64_t.hpp @@ -12,15 +12,13 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -std::enable_if_t, T> Convert(const std::uint64_t& value, - To) { - return utils::numeric_cast(value); +std::enable_if_t, T> Convert(const std::uint64_t& value, To) { + return utils::numeric_cast(value); } template -std::enable_if_t, std::uint64_t> Convert( - const T& value, To) { - return utils::numeric_cast(value); +std::enable_if_t, std::uint64_t> Convert(const T& value, To) { + return utils::numeric_cast(value); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/unsigned.hpp b/chaotic/include/userver/chaotic/io/unsigned.hpp index ef8abe47b1c3..fe3992d2f1d9 100644 --- a/chaotic/include/userver/chaotic/io/unsigned.hpp +++ b/chaotic/include/userver/chaotic/io/unsigned.hpp @@ -13,17 +13,14 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -std::enable_if_t< - std::is_integral_v && !std::is_same_v, T> -Convert(unsigned value, To) { - return utils::numeric_cast(value); +std::enable_if_t && !std::is_same_v, T> Convert(unsigned value, To) { + return utils::numeric_cast(value); } template -std::enable_if_t< - std::is_integral_v && !std::is_same_v, unsigned> +std::enable_if_t && !std::is_same_v, unsigned> Convert(const T& value, To) { - return utils::numeric_cast(value); + return utils::numeric_cast(value); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/userver/decimal64/decimal.hpp b/chaotic/include/userver/chaotic/io/userver/decimal64/decimal.hpp index a716ae4e3fb5..e0d76954d4cf 100644 --- a/chaotic/include/userver/chaotic/io/userver/decimal64/decimal.hpp +++ b/chaotic/include/userver/chaotic/io/userver/decimal64/decimal.hpp @@ -8,29 +8,25 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { template -std::string Convert(const decimal64::Decimal& value, - chaotic::convert::To) { - return ToString(value); +std::string Convert(const decimal64::Decimal& value, chaotic::convert::To) { + return ToString(value); } template -decimal64::Decimal Convert( - const std::string& str, - chaotic::convert::To>) { - return decimal64::Decimal(str); +decimal64::Decimal +Convert(const std::string& str, chaotic::convert::To>) { + return decimal64::Decimal(str); } template -decimal64::Decimal Convert( - const int& str, - chaotic::convert::To>) { - return decimal64::Decimal(str); +decimal64::Decimal +Convert(const int& str, chaotic::convert::To>) { + return decimal64::Decimal(str); } template -int Convert(const decimal64::Decimal& value, - chaotic::convert::To) { - return value.ToInteger(); +int Convert(const decimal64::Decimal& value, chaotic::convert::To) { + return value.ToInteger(); } } // namespace chaotic::convert diff --git a/chaotic/include/userver/chaotic/io/userver/ugrpc/client/qos.hpp b/chaotic/include/userver/chaotic/io/userver/ugrpc/client/qos.hpp index dc014c8a5dae..db1fbb3c48b1 100644 --- a/chaotic/include/userver/chaotic/io/userver/ugrpc/client/qos.hpp +++ b/chaotic/include/userver/chaotic/io/userver/ugrpc/client/qos.hpp @@ -9,16 +9,16 @@ namespace ugrpc::client { template Qos Convert(const T& value, chaotic::convert::To) { - Qos result; - result.timeout = value.timeout_ms; - return result; + Qos result; + result.timeout = value.timeout_ms; + return result; } template T Convert(const Qos& value, chaotic::convert::To) { - T result; - result.timeout_ms = value.timeout; - return result; + T result; + result.timeout_ms = value.timeout; + return result; } } // namespace ugrpc::client diff --git a/chaotic/include/userver/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.hpp b/chaotic/include/userver/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.hpp index d039452f3f9e..4a048af4c7b1 100644 --- a/chaotic/include/userver/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.hpp +++ b/chaotic/include/userver/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.hpp @@ -7,11 +7,9 @@ USERVER_NAMESPACE_BEGIN namespace utils::datetime { -TimePointTzIsoBasic Convert(const std::string& str, - chaotic::convert::To); +TimePointTzIsoBasic Convert(const std::string& str, chaotic::convert::To); -std::string Convert(const TimePointTzIsoBasic& tp, - chaotic::convert::To); +std::string Convert(const TimePointTzIsoBasic& tp, chaotic::convert::To); } // namespace utils::datetime diff --git a/chaotic/include/userver/chaotic/io/userver/utils/default_dict.hpp b/chaotic/include/userver/chaotic/io/userver/utils/default_dict.hpp index e69505a2a59f..c17a8bdbd643 100644 --- a/chaotic/include/userver/chaotic/io/userver/utils/default_dict.hpp +++ b/chaotic/include/userver/chaotic/io/userver/utils/default_dict.hpp @@ -10,24 +10,24 @@ namespace utils { template DefaultDict Convert(const U& value, chaotic::convert::To>) { - auto& extra = value.extra; - auto dict = DefaultDict{{extra.begin(), extra.end()}}; + auto& extra = value.extra; + auto dict = DefaultDict{{extra.begin(), extra.end()}}; - if constexpr (meta::kIsOptional) { - if (value.__default__) dict.SetDefault(*value.__default__); - } else { - dict.SetDefault(value.__default__); - } + if constexpr (meta::kIsOptional) { + if (value.__default__) dict.SetDefault(*value.__default__); + } else { + dict.SetDefault(value.__default__); + } - return dict; + return dict; } template U Convert(const DefaultDict& value, chaotic::convert::To) { - U u; - u.extra = {value.begin(), value.end()}; - if (value.HasDefaultValue()) u.__default__ = value.GetDefaultValue(); - return u; + U u; + u.extra = {value.begin(), value.end()}; + if (value.HasDefaultValue()) u.__default__ = value.GetDefaultValue(); + return u; } } // namespace utils diff --git a/chaotic/include/userver/chaotic/object.hpp b/chaotic/include/userver/chaotic/object.hpp index b115b0665e4d..ceeb810fd25e 100644 --- a/chaotic/include/userver/chaotic/object.hpp +++ b/chaotic/include/userver/chaotic/object.hpp @@ -14,41 +14,37 @@ USERVER_NAMESPACE_BEGIN namespace chaotic { template -Value ExtractAdditionalPropertiesTrue( - const Value& json, const utils::TrivialSet& names_to_exclude) { - typename Value::Builder builder(formats::common::Type::kObject); +Value ExtractAdditionalPropertiesTrue(const Value& json, const utils::TrivialSet& names_to_exclude) { + typename Value::Builder builder(formats::common::Type::kObject); - for (const auto& [name, value] : formats::common::Items(json)) { - if (names_to_exclude.Contains(name)) continue; + for (const auto& [name, value] : formats::common::Items(json)) { + if (names_to_exclude.Contains(name)) continue; - builder[name] = value; - } - return builder.ExtractValue(); + builder[name] = value; + } + return builder.ExtractValue(); } template -void ValidateNoAdditionalProperties( - const Value& json, const utils::TrivialSet& names_to_exclude) { - for (const auto& [name, value] : formats::common::Items(json)) { - if (names_to_exclude.Contains(name)) continue; +void ValidateNoAdditionalProperties(const Value& json, const utils::TrivialSet& names_to_exclude) { + for (const auto& [name, value] : formats::common::Items(json)) { + if (names_to_exclude.Contains(name)) continue; - throw std::runtime_error(fmt::format("Unknown property '{}'", name)); - } + throw std::runtime_error(fmt::format("Unknown property '{}'", name)); + } } -template typename Map, typename Value, - typename BuilderFunc> +template typename Map, typename Value, typename BuilderFunc> Map> -ExtractAdditionalProperties( - const Value& json, const utils::TrivialSet& names_to_exclude) { - Map> map; +ExtractAdditionalProperties(const Value& json, const utils::TrivialSet& names_to_exclude) { + Map> map; - for (const auto& [name, value] : formats::common::Items(json)) { - if (names_to_exclude.Contains(name)) continue; + for (const auto& [name, value] : formats::common::Items(json)) { + if (names_to_exclude.Contains(name)) continue; - map.emplace(name, value.template As()); - } - return map; + map.emplace(name, value.template As()); + } + return map; } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/oneof_with_discriminator.hpp b/chaotic/include/userver/chaotic/oneof_with_discriminator.hpp index 89feddfd8e64..8a87a636098d 100644 --- a/chaotic/include/userver/chaotic/oneof_with_discriminator.hpp +++ b/chaotic/include/userver/chaotic/oneof_with_discriminator.hpp @@ -16,52 +16,46 @@ namespace chaotic { template struct OneOfSettings { - std::string_view property_name; - utils::TrivialSet mapping; + std::string_view property_name; + utils::TrivialSet mapping; }; template -OneOfSettings(const char*, utils::TrivialSet) - -> OneOfSettings; +OneOfSettings(const char*, utils::TrivialSet) -> OneOfSettings; template struct OneOfWithDiscriminator { - const std::variant...>& - value; + const std::variant...>& value; }; template -std::variant...> Parse( - Value value, formats::parse::To>) { - const auto field = value[Settings->property_name].template As(); +std::variant...> +Parse(Value value, formats::parse::To>) { + const auto field = value[Settings->property_name].template As(); - const auto index = Settings->mapping.GetIndex(field); - if (!index.has_value()) { - throw formats::json::UnknownDiscriminatorException(value.GetPath(), field); - } + const auto index = Settings->mapping.GetIndex(field); + if (!index.has_value()) { + throw formats::json::UnknownDiscriminatorException(value.GetPath(), field); + } - using Result = - std::variant...>; + using Result = std::variant...>; - Result result; - utils::WithConstexprIndex( - index.value(), [&](auto index_constant) { + Result result; + utils::WithConstexprIndex(index.value(), [&](auto index_constant) { constexpr auto kIndex = decltype(index_constant)::value; - result.template emplace( - value.template As>()); - }); - return result; + result.template emplace(value.template As>()); + }); + return result; } template -Value Serialize(const OneOfWithDiscriminator& var, - formats::serialize::To) { - return std::visit( - USERVER_NAMESPACE::utils::Overloaded{ - [](const formats::common::ParseType& item) { +Value Serialize(const OneOfWithDiscriminator& var, formats::serialize::To) { + return std::visit( + USERVER_NAMESPACE::utils::Overloaded{[](const formats::common::ParseType& item) { return typename Value::Builder(T{item}).ExtractValue(); - }...}, - var.value); + }...}, + var.value + ); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/primitive.hpp b/chaotic/include/userver/chaotic/primitive.hpp index 46c81fd867f6..e1365a03a55f 100644 --- a/chaotic/include/userver/chaotic/primitive.hpp +++ b/chaotic/include/userver/chaotic/primitive.hpp @@ -10,21 +10,19 @@ namespace chaotic { template struct Primitive final { - const RawType& value; + const RawType& value; }; template -RawType Parse(const Value& value, - formats::parse::To>) { - auto result = value.template As(); - chaotic::Validate(result, value); - return result; +RawType Parse(const Value& value, formats::parse::To>) { + auto result = value.template As(); + chaotic::Validate(result, value); + return result; } template -Value Serialize(const Primitive& ps, - formats::serialize::To) { - return typename Value::Builder{ps.value}.ExtractValue(); +Value Serialize(const Primitive& ps, formats::serialize::To) { + return typename Value::Builder{ps.value}.ExtractValue(); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/ref.hpp b/chaotic/include/userver/chaotic/ref.hpp index 51f56a8878a9..0abb1cabc3c1 100644 --- a/chaotic/include/userver/chaotic/ref.hpp +++ b/chaotic/include/userver/chaotic/ref.hpp @@ -10,19 +10,18 @@ namespace chaotic { template struct Ref { - const utils::Box>& value; + const utils::Box>& value; }; template -utils::Box> Parse( - const Value& value, formats::parse::To>) { - auto result = value.template As(); - return result; +utils::Box> Parse(const Value& value, formats::parse::To>) { + auto result = value.template As(); + return result; } template Value Serialize(const Ref& ps, formats::serialize::To) { - return typename Value::Builder{T{*ps.value}}.ExtractValue(); + return typename Value::Builder{T{*ps.value}}.ExtractValue(); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/validators.hpp b/chaotic/include/userver/chaotic/validators.hpp index cb43c5d9598c..d5b0567a4779 100644 --- a/chaotic/include/userver/chaotic/validators.hpp +++ b/chaotic/include/userver/chaotic/validators.hpp @@ -15,103 +15,93 @@ namespace chaotic { template struct Minimum final { - template - static void Validate(T value) { - static_assert(std::is_arithmetic_v); - - if (value < Value) - throw std::runtime_error( - fmt::format("Invalid value, minimum={}, given={}", Value, value)); - } + template + static void Validate(T value) { + static_assert(std::is_arithmetic_v); + + if (value < Value) throw std::runtime_error(fmt::format("Invalid value, minimum={}, given={}", Value, value)); + } }; template struct Maximum final { - template - static void Validate(T value) { - static_assert(std::is_arithmetic_v); - - if (value > Value) - throw std::runtime_error( - fmt::format("Invalid value, maximum={}, given={}", Value, value)); - } + template + static void Validate(T value) { + static_assert(std::is_arithmetic_v); + + if (value > Value) throw std::runtime_error(fmt::format("Invalid value, maximum={}, given={}", Value, value)); + } }; template struct ExclusiveMinimum final { - template - static void Validate(T value) { - static_assert(std::is_arithmetic_v); - - if (value <= Value) - throw std::runtime_error(fmt::format( - "Invalid value, exclusive minimum={}, given={}", Value, value)); - } + template + static void Validate(T value) { + static_assert(std::is_arithmetic_v); + + if (value <= Value) + throw std::runtime_error(fmt::format("Invalid value, exclusive minimum={}, given={}", Value, value)); + } }; template struct ExclusiveMaximum final { - template - static void Validate(T value) { - static_assert(std::is_arithmetic_v); - - if (value >= Value) - throw std::runtime_error(fmt::format( - "Invalid value, exclusive maximum={}, given={}", Value, value)); - } + template + static void Validate(T value) { + static_assert(std::is_arithmetic_v); + + if (value >= Value) + throw std::runtime_error(fmt::format("Invalid value, exclusive maximum={}, given={}", Value, value)); + } }; template struct MinItems final { - template - static void Validate(const T& value) { - if (value.size() < Value) { - throw std::runtime_error(fmt::format( - "Too short array, minimum length={}, given={}", Value, value.size())); + template + static void Validate(const T& value) { + if (value.size() < Value) { + throw std::runtime_error(fmt::format("Too short array, minimum length={}, given={}", Value, value.size())); + } } - } }; template struct MaxItems final { - template - static void Validate(const T& value) { - if (value.size() > Value) { - throw std::runtime_error(fmt::format( - "Too long array, maximum length={}, given={}", Value, value.size())); + template + static void Validate(const T& value) { + if (value.size() > Value) { + throw std::runtime_error(fmt::format("Too long array, maximum length={}, given={}", Value, value.size())); + } } - } }; template struct MinLength final { - static void Validate(std::string_view value) { - auto length = utils::text::utf8::GetCodePointsCount(value); - if (length < Value) { - throw std::runtime_error(fmt::format( - "Too short string, minimum length={}, given={}", Value, length)); + static void Validate(std::string_view value) { + auto length = utils::text::utf8::GetCodePointsCount(value); + if (length < Value) { + throw std::runtime_error(fmt::format("Too short string, minimum length={}, given={}", Value, length)); + } } - } }; template struct MaxLength final { - static void Validate(std::string_view value) { - auto length = utils::text::utf8::GetCodePointsCount(value); - if (length > Value) { - throw std::runtime_error(fmt::format( - "Too long string, maximum length={}, given={}", Value, length)); + static void Validate(std::string_view value) { + auto length = utils::text::utf8::GetCodePointsCount(value); + if (length > Value) { + throw std::runtime_error(fmt::format("Too long string, maximum length={}, given={}", Value, length)); + } } - } }; template void Validate(const Obj& obj, const Value& value) { - try { - (Validators::Validate(obj), ...); - } catch (const std::exception& e) { - chaotic::ThrowForValue(e.what(), value); - } + try { + (Validators::Validate(obj), ...); + } catch (const std::exception& e) { + chaotic::ThrowForValue(e.what(), value); + } } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/validators_pattern.hpp b/chaotic/include/userver/chaotic/validators_pattern.hpp index 043bbe91e79b..68c1bd171310 100644 --- a/chaotic/include/userver/chaotic/validators_pattern.hpp +++ b/chaotic/include/userver/chaotic/validators_pattern.hpp @@ -11,12 +11,11 @@ namespace chaotic { template struct Pattern final { - static const utils::regex kRegex; + static const utils::regex kRegex; - static void Validate(const std::string& value) { - if (!utils::regex_search(value, kRegex)) - throw std::runtime_error("doesn't match regex"); - } + static void Validate(const std::string& value) { + if (!utils::regex_search(value, kRegex)) throw std::runtime_error("doesn't match regex"); + } }; template diff --git a/chaotic/include/userver/chaotic/variant.hpp b/chaotic/include/userver/chaotic/variant.hpp index 95008b36cff0..878afaceb71c 100644 --- a/chaotic/include/userver/chaotic/variant.hpp +++ b/chaotic/include/userver/chaotic/variant.hpp @@ -14,37 +14,37 @@ namespace chaotic { template auto& GetVariant(std::variant& arg) { - return arg; + return arg; } template const auto& GetVariant(const std::variant& arg) { - return arg; + return arg; } template decltype(T().AsVariant()) GetVariant(T& arg) { - return arg.AsVariant(); + return arg.AsVariant(); } template struct Variant final { - const std::variant(), - formats::parse::To{}))...>& value; + const std::variant(), formats::parse::To{}))...>& value; }; template auto Parse(const Value& value, formats::parse::To>) { - return value.template As>(); + return value.template As>(); } template Value Serialize(const Variant& var, formats::serialize::To) { - return std::visit( - utils::Overloaded{[](const formats::common::ParseType& item) { - return typename Value::Builder(T{item}).ExtractValue(); - }...}, - var.value); + return std::visit( + utils::Overloaded{[](const formats::common::ParseType& item) { + return typename Value::Builder(T{item}).ExtractValue(); + }...}, + var.value + ); } } // namespace chaotic diff --git a/chaotic/include/userver/chaotic/with_type.hpp b/chaotic/include/userver/chaotic/with_type.hpp index 342cda7b7681..c6e7cd2788ae 100644 --- a/chaotic/include/userver/chaotic/with_type.hpp +++ b/chaotic/include/userver/chaotic/with_type.hpp @@ -13,27 +13,23 @@ namespace chaotic { template struct WithType final { - const UserType& value; + const UserType& value; }; template -UserType Parse(const Value& value, - formats::parse::To>) { - auto result = value.template As(); - try { - return Convert(result, convert::To{}); - } catch (const std::exception& e) { - chaotic::ThrowForValue(e.what(), value); - } +UserType Parse(const Value& value, formats::parse::To>) { + auto result = value.template As(); + try { + return Convert(result, convert::To{}); + } catch (const std::exception& e) { + chaotic::ThrowForValue(e.what(), value); + } } template -Value Serialize(const WithType& ps, - formats::serialize::To) { - return typename Value::Builder{ - RawType{Convert(ps.value, - convert::To>())}} - .ExtractValue(); +Value Serialize(const WithType& ps, formats::serialize::To) { + return typename Value::Builder{RawType{Convert(ps.value, convert::To>())}} + .ExtractValue(); } } // namespace chaotic diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_all_of.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_all_of.hpp index 6d373c351dfb..66e7d52882a3 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_all_of.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_all_of.hpp @@ -8,30 +8,25 @@ namespace my { struct CustomAllOf { - CustomAllOf() = default; + CustomAllOf() = default; - template - CustomAllOf(T&& value) - : a(std::move(value.field1)), b(std::move(value.field2)) {} + template + CustomAllOf(T&& value) : a(std::move(value.field1)), b(std::move(value.field2)) {} - CustomAllOf(std::string&& a, std::string&& b) - : a(std::move(a)), b(std::move(b)) {} + CustomAllOf(std::string&& a, std::string&& b) : a(std::move(a)), b(std::move(b)) {} - std::optional a; - std::optional b; + std::optional a; + std::optional b; }; -inline bool operator==(const CustomAllOf& lhs, const CustomAllOf& rhs) { - return lhs.a == rhs.a && lhs.b == rhs.b; -} +inline bool operator==(const CustomAllOf& lhs, const CustomAllOf& rhs) { return lhs.a == rhs.a && lhs.b == rhs.b; } template -T Convert(const CustomAllOf& value, - USERVER_NAMESPACE::chaotic::convert::To) { - T t; - t.field1 = value.a; - t.field2 = value.b; - return t; +T Convert(const CustomAllOf& value, USERVER_NAMESPACE::chaotic::convert::To) { + T t; + t.field1 = value.a; + t.field2 = value.b; + return t; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_array.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_array.hpp index 2db7a2b62f01..10f1ee9e8f69 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_array.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_array.hpp @@ -9,27 +9,24 @@ namespace my { template struct CustomArray final { - template - CustomArray(const U& value) : s(value.begin(), value.end()) {} - std::vector s; + template + CustomArray(const U& value) : s(value.begin(), value.end()) {} + std::vector s; }; template bool operator==(const CustomArray& lhs, const CustomArray& rhs) { - return lhs.s == rhs.s; + return lhs.s == rhs.s; } template -std::vector Convert( - const CustomArray& value, - USERVER_NAMESPACE::chaotic::convert::To>) { - return value.s; +std::vector Convert(const CustomArray& value, USERVER_NAMESPACE::chaotic::convert::To>) { + return value.s; } template -std::set Convert(const CustomArray& value, - USERVER_NAMESPACE::chaotic::convert::To>) { - return {value.s.begin(), value.s.end()}; +std::set Convert(const CustomArray& value, USERVER_NAMESPACE::chaotic::convert::To>) { + return {value.s.begin(), value.s.end()}; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_boolean.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_boolean.hpp index 7894b359cf36..e2dd1c55dd07 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_boolean.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_boolean.hpp @@ -5,18 +5,13 @@ namespace my { struct CustomBoolean final { - explicit CustomBoolean(bool b) : b(b) {} + explicit CustomBoolean(bool b) : b(b) {} - bool b; + bool b; }; -inline bool operator==(const CustomBoolean& lhs, const CustomBoolean& rhs) { - return lhs.b == rhs.b; -} +inline bool operator==(const CustomBoolean& lhs, const CustomBoolean& rhs) { return lhs.b == rhs.b; } -inline bool Convert(const CustomBoolean& b, - USERVER_NAMESPACE::chaotic::convert::To) { - return b.b; -} +inline bool Convert(const CustomBoolean& b, USERVER_NAMESPACE::chaotic::convert::To) { return b.b; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_date_time.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_date_time.hpp index 681dfaaabe56..a1d56d000f9b 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_date_time.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_date_time.hpp @@ -6,21 +6,18 @@ namespace my { struct CustomDateTime { - USERVER_NAMESPACE::utils::datetime::TimePointTz time_point; + USERVER_NAMESPACE::utils::datetime::TimePointTz time_point; - CustomDateTime(USERVER_NAMESPACE::utils::datetime::TimePointTz time_point) - : time_point(time_point) {} + CustomDateTime(USERVER_NAMESPACE::utils::datetime::TimePointTz time_point) : time_point(time_point) {} }; inline bool operator==(const CustomDateTime& lhs, const CustomDateTime& rhs) { - return lhs.time_point == rhs.time_point; + return lhs.time_point == rhs.time_point; } -inline USERVER_NAMESPACE::utils::datetime::TimePointTz Convert( - const CustomDateTime& lhs, - USERVER_NAMESPACE::chaotic::convert::To< - USERVER_NAMESPACE::utils::datetime::TimePointTz>) { - return lhs.time_point; +inline USERVER_NAMESPACE::utils::datetime::TimePointTz +Convert(const CustomDateTime& lhs, USERVER_NAMESPACE::chaotic::convert::To) { + return lhs.time_point; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_number.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_number.hpp index 273fdd109f6d..94880130b359 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_number.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_number.hpp @@ -5,21 +5,13 @@ namespace my { struct CustomNumber final { - double s; + double s; }; -inline bool operator==(const CustomNumber& lhs, const CustomNumber& rhs) { - return lhs.s == rhs.s; -} +inline bool operator==(const CustomNumber& lhs, const CustomNumber& rhs) { return lhs.s == rhs.s; } -inline CustomNumber Convert( - const double& s, USERVER_NAMESPACE::chaotic::convert::To) { - return {s}; -} +inline CustomNumber Convert(const double& s, USERVER_NAMESPACE::chaotic::convert::To) { return {s}; } -inline double Convert(const CustomNumber& num, - USERVER_NAMESPACE::chaotic::convert::To) { - return num.s; -} +inline double Convert(const CustomNumber& num, USERVER_NAMESPACE::chaotic::convert::To) { return num.s; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_object.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_object.hpp index 992a55af8e2d..6ceef5baf4a3 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_object.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_object.hpp @@ -11,21 +11,17 @@ struct CustomObject; namespace my { struct CustomObject { - CustomObject() = default; + CustomObject() = default; - CustomObject(const ns::CustomObject&); + CustomObject(const ns::CustomObject&); - explicit CustomObject(std::string&& foo) : foo(std::move(foo)) {} + explicit CustomObject(std::string&& foo) : foo(std::move(foo)) {} - std::string foo; + std::string foo; }; -inline bool operator==(const CustomObject& a, const CustomObject& b) { - return a.foo == b.foo; -} +inline bool operator==(const CustomObject& a, const CustomObject& b) { return a.foo == b.foo; } -ns::CustomObject Convert( - const CustomObject& value, - USERVER_NAMESPACE::chaotic::convert::To); +ns::CustomObject Convert(const CustomObject& value, USERVER_NAMESPACE::chaotic::convert::To); } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of.hpp index c227fad8e392..1196f84da7dd 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of.hpp @@ -8,21 +8,18 @@ namespace my { struct CustomOneOf { - CustomOneOf() = default; + CustomOneOf() = default; - CustomOneOf(const std::variant& value) : a(value) {} + CustomOneOf(const std::variant& value) : a(value) {} - std::variant a; + std::variant a; }; -inline bool operator==(const CustomOneOf& lhs, const CustomOneOf& rhs) { - return lhs.a == rhs.a; -} +inline bool operator==(const CustomOneOf& lhs, const CustomOneOf& rhs) { return lhs.a == rhs.a; } -inline std::variant Convert( - const CustomOneOf& str, - USERVER_NAMESPACE::chaotic::convert::To>) { - return str.a; +inline std::variant +Convert(const CustomOneOf& str, USERVER_NAMESPACE::chaotic::convert::To>) { + return str.a; } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of_with_discriminator.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of_with_discriminator.hpp index 96873ffa4659..42f6e463f81e 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of_with_discriminator.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_one_of_with_discriminator.hpp @@ -16,34 +16,29 @@ struct CustomStruct2; namespace my { struct CustomOneOfWithDiscriminator { - CustomOneOfWithDiscriminator() = default; + CustomOneOfWithDiscriminator() = default; - CustomOneOfWithDiscriminator(int x) : val(x) {} - CustomOneOfWithDiscriminator(std::string x) : val(x) {} + CustomOneOfWithDiscriminator(int x) : val(x) {} + CustomOneOfWithDiscriminator(std::string x) : val(x) {} - std::variant val; + std::variant val; }; -inline bool operator==(const CustomOneOfWithDiscriminator& lhs, - const CustomOneOfWithDiscriminator& rhs) { - return lhs.val == rhs.val; +inline bool operator==(const CustomOneOfWithDiscriminator& lhs, const CustomOneOfWithDiscriminator& rhs) { + return lhs.val == rhs.val; } template -CustomOneOfWithDiscriminator Convert( - const std::variant& value, - USERVER_NAMESPACE::chaotic::convert::To) { - return USERVER_NAMESPACE::utils::Visit( - value, - [](const U& value) { return CustomOneOfWithDiscriminator{value.field1}; }, - [](const V& value) { - return CustomOneOfWithDiscriminator{value.field2}; - }); +CustomOneOfWithDiscriminator +Convert(const std::variant& value, USERVER_NAMESPACE::chaotic::convert::To) { + return USERVER_NAMESPACE::utils::Visit( + value, + [](const U& value) { return CustomOneOfWithDiscriminator{value.field1}; }, + [](const V& value) { return CustomOneOfWithDiscriminator{value.field2}; } + ); } -std::variant Convert( - const CustomOneOfWithDiscriminator& value, - USERVER_NAMESPACE::chaotic::convert::To< - std::variant>); +std::variant +Convert(const CustomOneOfWithDiscriminator& value, USERVER_NAMESPACE::chaotic::convert::To>); } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_string.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_string.hpp index aca6a85ccb96..3b0b8248e311 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/custom_string.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/custom_string.hpp @@ -8,14 +8,12 @@ namespace my { // Definition of a custom user structure struct CustomString final { - CustomString(const std::string& s) : s(s) {} + CustomString(const std::string& s) : s(s) {} - std::string s; + std::string s; }; -inline bool operator==(const CustomString& lhs, const CustomString& rhs) { - return lhs.s == rhs.s; -} +inline bool operator==(const CustomString& lhs, const CustomString& rhs) { return lhs.s == rhs.s; } // Convert must be located: // 1) either in T's namespace (my) for user types, @@ -23,18 +21,14 @@ inline bool operator==(const CustomString& lhs, const CustomString& rhs) { // The CustomString -> std::string Convert() is used during serialization // (CustomString -> json::Value) -inline std::string Convert( - const CustomString& str, - USERVER_NAMESPACE::chaotic::convert::To) { - return str.s; +inline std::string Convert(const CustomString& str, USERVER_NAMESPACE::chaotic::convert::To) { + return str.s; } // The std::string -> CustomString Convert() is used during parsing // (json::Value -> CustomString) -inline CustomString Convert( - const std::string& str, - USERVER_NAMESPACE::chaotic::convert::To) { - return CustomString(str); +inline CustomString Convert(const std::string& str, USERVER_NAMESPACE::chaotic::convert::To) { + return CustomString(str); } } // namespace my diff --git a/chaotic/integration_tests/include/userver/chaotic/io/my/point.hpp b/chaotic/integration_tests/include/userver/chaotic/io/my/point.hpp index 30f2a177beaf..7ddd2269e680 100644 --- a/chaotic/integration_tests/include/userver/chaotic/io/my/point.hpp +++ b/chaotic/integration_tests/include/userver/chaotic/io/my/point.hpp @@ -7,37 +7,32 @@ namespace my { struct Point { - double lon; - double lat; + double lon; + double lat; }; -bool operator==(const Point& a, const Point& b) { - return a.lon == b.lon && a.lat == b.lat; -} +bool operator==(const Point& a, const Point& b) { return a.lon == b.lon && a.lat == b.lat; } -inline Point Convert(const std::vector& arr, - USERVER_NAMESPACE::chaotic::convert::To) { - return Point{arr.at(0), arr.at(1)}; +inline Point Convert(const std::vector& arr, USERVER_NAMESPACE::chaotic::convert::To) { + return Point{arr.at(0), arr.at(1)}; } -inline std::vector Convert( - const Point& p, - USERVER_NAMESPACE::chaotic::convert::To>) { - return std::vector{p.lon, p.lat}; +inline std::vector Convert(const Point& p, USERVER_NAMESPACE::chaotic::convert::To>) { + return std::vector{p.lon, p.lat}; } template Point Convert(const T& obj, USERVER_NAMESPACE::chaotic::convert::To) { - return Point{obj.lon, obj.lat}; + return Point{obj.lon, obj.lat}; } template T Convert(const Point& p, USERVER_NAMESPACE::chaotic::convert::To) { - T result; - // designated initializers are not available in C++17 :( - result.lon = p.lon; - result.lat = p.lat; - return result; + T result; + // designated initializers are not available in C++17 :( + result.lon = p.lon; + result.lat = p.lat; + return result; } } // namespace my diff --git a/chaotic/integration_tests/tests/lib/array.cpp b/chaotic/integration_tests/tests/lib/array.cpp index 2590918d7caa..dd4d4fd7667f 100644 --- a/chaotic/integration_tests/tests/lib/array.cpp +++ b/chaotic/integration_tests/tests/lib/array.cpp @@ -13,68 +13,60 @@ USERVER_NAMESPACE_BEGIN namespace { TEST(Array, OfInt) { - const auto kJson = formats::json::MakeArray("foo", "bar"); - using Arr = chaotic::Array>; - std::vector x = kJson.As(); + const auto kJson = formats::json::MakeArray("foo", "bar"); + using Arr = chaotic::Array>; + std::vector x = kJson.As(); - ASSERT_THAT(x, ::testing::ElementsAre("foo", "bar")); + ASSERT_THAT(x, ::testing::ElementsAre("foo", "bar")); } TEST(Array, OfIntSerializer) { - const auto kJson = formats::json::MakeArray("foo", "bar"); - using Arr = chaotic::Array>; - std::vector x = kJson.As(); + const auto kJson = formats::json::MakeArray("foo", "bar"); + using Arr = chaotic::Array>; + std::vector x = kJson.As(); - auto result = - formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(); - EXPECT_EQ(result, kJson); + auto result = formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(); + EXPECT_EQ(result, kJson); } TEST(Array, OfIntWithValidators) { - const auto kJson = formats::json::MakeArray("foo", "bar"); - using Arr = chaotic::Array, - chaotic::MinItems<2>>; - std::vector x = kJson.As(); - ASSERT_THAT(x, ::testing::ElementsAre("foo", "bar")); - - const auto kJson1 = formats::json::MakeArray("foo"); - UEXPECT_THROW_MSG( - kJson1.As(), chaotic::Error, - "Error at path '/': Too short array, minimum length=2, given=1"); + const auto kJson = formats::json::MakeArray("foo", "bar"); + using Arr = chaotic::Array, chaotic::MinItems<2>>; + std::vector x = kJson.As(); + ASSERT_THAT(x, ::testing::ElementsAre("foo", "bar")); + + const auto kJson1 = formats::json::MakeArray("foo"); + UEXPECT_THROW_MSG( + kJson1.As(), chaotic::Error, "Error at path '/': Too short array, minimum length=2, given=1" + ); } TEST(Array, OfIntWithValidatorsSerializer) { - const auto kJson = formats::json::MakeArray("foo", "bar"); - using Arr = chaotic::Array, - chaotic::MinItems<2>>; - EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), - kJson); + const auto kJson = formats::json::MakeArray("foo", "bar"); + using Arr = chaotic::Array, chaotic::MinItems<2>>; + EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), kJson); } TEST(Array, OfArrayOfString) { - const auto kJson = formats::json::MakeArray(formats::json::MakeArray("foo")); + const auto kJson = formats::json::MakeArray(formats::json::MakeArray("foo")); - using Arr = - chaotic::Array>, - std::vector>>; - std::vector> x = kJson.As(); + using Arr = + chaotic::Array>, std::vector>>; + std::vector> x = kJson.As(); } TEST(Array, OfArrayOfStringSerializer) { - const auto kJson = formats::json::MakeArray(formats::json::MakeArray("foo")); + const auto kJson = formats::json::MakeArray(formats::json::MakeArray("foo")); - using Arr = - chaotic::Array>, - std::vector>>; - EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), - kJson); + using Arr = + chaotic::Array>, std::vector>>; + EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), kJson); } TEST(Array, OfEmptyArraySerializer) { - const auto kJson = formats::json::MakeArray(); - using Arr = chaotic::Array>; - EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), - kJson); + const auto kJson = formats::json::MakeArray(); + using Arr = chaotic::Array>; + EXPECT_EQ(formats::json::ValueBuilder{Arr{kJson.As()}}.ExtractValue(), kJson); } } // namespace diff --git a/chaotic/integration_tests/tests/lib/oneof_with_discriminator.cpp b/chaotic/integration_tests/tests/lib/oneof_with_discriminator.cpp index 28f9aa7f6264..82343dd7d337 100644 --- a/chaotic/integration_tests/tests/lib/oneof_with_discriminator.cpp +++ b/chaotic/integration_tests/tests/lib/oneof_with_discriminator.cpp @@ -10,135 +10,118 @@ USERVER_NAMESPACE_BEGIN namespace { -static const auto kJsonShort = - formats::json::MakeObject("type", "ObjectStringWithDiscriminator"); +static const auto kJsonShort = formats::json::MakeObject("type", "ObjectStringWithDiscriminator"); static const auto kJson1 = - formats::json::MakeObject("type", "ObjectStringWithDiscriminator", "value", - "What is the meaning of life?"); + formats::json::MakeObject("type", "ObjectStringWithDiscriminator", "value", "What is the meaning of life?"); -static const auto kJson2 = formats::json::MakeObject( - "type", "ObjectIntWithDiscriminator", "value", 42); +static const auto kJson2 = formats::json::MakeObject("type", "ObjectIntWithDiscriminator", "value", 42); -static const auto kJsonBad = - formats::json::MakeObject("type", "SomeObject", "value", 42); +static const auto kJsonBad = formats::json::MakeObject("type", "SomeObject", "value", 42); struct ObjectIntWithDiscriminator { - std::optional type; - std::optional value; + std::optional type; + std::optional value; }; -ObjectIntWithDiscriminator Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To) { - json.CheckNotMissing(); - json.CheckObjectOrNull(); +ObjectIntWithDiscriminator +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To) { + json.CheckNotMissing(); + json.CheckObjectOrNull(); - ObjectIntWithDiscriminator res; + ObjectIntWithDiscriminator res; - res.type = json["type"] - .As>>(); - res.value = - json["value"] - .As>>(); + res.type = json["type"].As>>(); + res.value = json["value"].As>>(); - return res; + return res; } struct ObjectStringWithDiscriminator { - std::optional type; - std::optional value; + std::optional type; + std::optional value; }; -ObjectStringWithDiscriminator Parse( - USERVER_NAMESPACE::formats::json::Value json, - USERVER_NAMESPACE::formats::parse::To) { - json.CheckNotMissing(); - json.CheckObjectOrNull(); +ObjectStringWithDiscriminator +Parse(USERVER_NAMESPACE::formats::json::Value json, USERVER_NAMESPACE::formats::parse::To) { + json.CheckNotMissing(); + json.CheckObjectOrNull(); - ObjectStringWithDiscriminator res; + ObjectStringWithDiscriminator res; - res.type = json["type"] - .As>>(); - res.value = json["value"] - .As>>(); + res.type = json["type"].As>>(); + res.value = json["value"].As>>(); - return res; + return res; } } // namespace TEST(OneOfWithDiscriminator, Simple) { - static constexpr chaotic::OneOfSettings kSettings{ - "type", utils::TrivialSet([](auto selector) { - return selector() - .Case("ObjectIntWithDiscriminator") - .Case("ObjectStringWithDiscriminator"); - })}; + static constexpr chaotic::OneOfSettings kSettings{ + "type", utils::TrivialSet([](auto selector) { + return selector().Case("ObjectIntWithDiscriminator").Case("ObjectStringWithDiscriminator"); + })}; - using OneOfWithDiscriminator = - chaotic::OneOfWithDiscriminator<&kSettings, ObjectIntWithDiscriminator, - ObjectStringWithDiscriminator>; + using OneOfWithDiscriminator = + chaotic::OneOfWithDiscriminator<&kSettings, ObjectIntWithDiscriminator, ObjectStringWithDiscriminator>; - UEXPECT_NO_THROW(kJson1.As()); + UEXPECT_NO_THROW(kJson1.As()); - auto oneof1 = kJson1.As(); - EXPECT_EQ(oneof1.index(), std::size_t{1}); - EXPECT_EQ(std::get<1>(oneof1).value, "What is the meaning of life?"); + auto oneof1 = kJson1.As(); + EXPECT_EQ(oneof1.index(), std::size_t{1}); + EXPECT_EQ(std::get<1>(oneof1).value, "What is the meaning of life?"); - UEXPECT_NO_THROW(kJson2.As()); + UEXPECT_NO_THROW(kJson2.As()); - auto oneof2 = kJson2.As(); - EXPECT_EQ(oneof2.index(), std::size_t{0}); - EXPECT_EQ(std::get<0>(oneof2).value, 42); + auto oneof2 = kJson2.As(); + EXPECT_EQ(oneof2.index(), std::size_t{0}); + EXPECT_EQ(std::get<0>(oneof2).value, 42); } TEST(OneOfWithDiscriminator, RepeatedTypes) { - static constexpr chaotic::OneOfSettings kSettings{ - "type", utils::TrivialSet([](auto selector) { - return selector() - .Case("ObjectIntWithDiscriminator") - .Case("ObjectIntWithDiscriminator") - .Case("ObjectStringWithDiscriminator") - .Case("ObjectIntWithDiscriminator") - .Case("ObjectStringWithDiscriminator"); - })}; - - using OneOfWithDiscriminator = chaotic::OneOfWithDiscriminator< - &kSettings, ObjectIntWithDiscriminator, ObjectIntWithDiscriminator, - ObjectStringWithDiscriminator, ObjectIntWithDiscriminator, - ObjectStringWithDiscriminator>; - - UEXPECT_NO_THROW(kJson1.As()); - auto oneof1 = kJson1.As(); - EXPECT_EQ(oneof1.index(), std::size_t{2}); - EXPECT_EQ(std::get<2>(oneof1).value, "What is the meaning of life?"); - - UEXPECT_NO_THROW(kJson2.As()); - auto oneof2 = kJson2.As(); - EXPECT_EQ(oneof2.index(), std::size_t{0}); - EXPECT_EQ(std::get<0>(oneof2).value, 42); + static constexpr chaotic::OneOfSettings kSettings{"type", utils::TrivialSet([](auto selector) { + return selector() + .Case("ObjectIntWithDiscriminator") + .Case("ObjectIntWithDiscriminator") + .Case("ObjectStringWithDiscriminator") + .Case("ObjectIntWithDiscriminator") + .Case("ObjectStringWithDiscriminator"); + })}; + + using OneOfWithDiscriminator = chaotic::OneOfWithDiscriminator< + &kSettings, + ObjectIntWithDiscriminator, + ObjectIntWithDiscriminator, + ObjectStringWithDiscriminator, + ObjectIntWithDiscriminator, + ObjectStringWithDiscriminator>; + + UEXPECT_NO_THROW(kJson1.As()); + auto oneof1 = kJson1.As(); + EXPECT_EQ(oneof1.index(), std::size_t{2}); + EXPECT_EQ(std::get<2>(oneof1).value, "What is the meaning of life?"); + + UEXPECT_NO_THROW(kJson2.As()); + auto oneof2 = kJson2.As(); + EXPECT_EQ(oneof2.index(), std::size_t{0}); + EXPECT_EQ(std::get<0>(oneof2).value, 42); } TEST(OneOfWithDiscriminator, ParseError) { - static constexpr chaotic::OneOfSettings kSettings{ - "type", utils::TrivialSet([](auto selector) { - return selector() - .Case("ObjectIntWithDiscriminator") - .Case("ObjectStringWithDiscriminator"); - })}; - - using OneOfWithDiscriminator = - chaotic::OneOfWithDiscriminator<&kSettings, ObjectIntWithDiscriminator, - ObjectStringWithDiscriminator>; - - UEXPECT_THROW_MSG( - kJsonBad.As(), - formats::json::UnknownDiscriminatorException, - "Error at path '/': Unknown discriminator field value 'SomeObject'"); + static constexpr chaotic::OneOfSettings kSettings{ + "type", utils::TrivialSet([](auto selector) { + return selector().Case("ObjectIntWithDiscriminator").Case("ObjectStringWithDiscriminator"); + })}; + + using OneOfWithDiscriminator = + chaotic::OneOfWithDiscriminator<&kSettings, ObjectIntWithDiscriminator, ObjectStringWithDiscriminator>; + + UEXPECT_THROW_MSG( + kJsonBad.As(), + formats::json::UnknownDiscriminatorException, + "Error at path '/': Unknown discriminator field value 'SomeObject'" + ); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/lib/primitive.cpp b/chaotic/integration_tests/tests/lib/primitive.cpp index 935b1303c074..b5aa22877065 100644 --- a/chaotic/integration_tests/tests/lib/primitive.cpp +++ b/chaotic/integration_tests/tests/lib/primitive.cpp @@ -14,117 +14,103 @@ const auto kJson = formats::json::MakeObject("foo", 1, "bar", 0, "zoo", 6); } TEST(Primitive, NoValidator) { - using Int = chaotic::Primitive; - int x = kJson["foo"].As(); - EXPECT_EQ(x, 1); + using Int = chaotic::Primitive; + int x = kJson["foo"].As(); + EXPECT_EQ(x, 1); } TEST(Primitive, NoValidatorSerializer) { - using Int = chaotic::Primitive; - EXPECT_EQ( - formats::json::ValueBuilder{Int{kJson["foo"].As()}}.ExtractValue(), - kJson["foo"]); + using Int = chaotic::Primitive; + EXPECT_EQ(formats::json::ValueBuilder{Int{kJson["foo"].As()}}.ExtractValue(), kJson["foo"]); } struct MyInt { - MyInt(std::int32_t value) : value(value) {} + MyInt(std::int32_t value) : value(value) {} - std::int32_t value; + std::int32_t value; }; -MyInt Convert(const std::int32_t& i, chaotic::convert::To) { - return {i}; -} +MyInt Convert(const std::int32_t& i, chaotic::convert::To) { return {i}; } -std::int32_t Convert(const MyInt& i, chaotic::convert::To) { - return i.value; -} +std::int32_t Convert(const MyInt& i, chaotic::convert::To) { return i.value; } TEST(Primitive, UserType) { - using Int = chaotic::WithType, MyInt>; - MyInt x = kJson["foo"].As(); - EXPECT_EQ(x.value, 1); + using Int = chaotic::WithType, MyInt>; + MyInt x = kJson["foo"].As(); + EXPECT_EQ(x.value, 1); } TEST(Primitive, UserTypeSerializer) { - using Int = chaotic::WithType, MyInt>; - MyInt x = kJson["foo"].As(); + using Int = chaotic::WithType, MyInt>; + MyInt x = kJson["foo"].As(); - EXPECT_EQ(formats::json::ValueBuilder{Int{x}}.ExtractValue(), kJson["foo"]); + EXPECT_EQ(formats::json::ValueBuilder{Int{x}}.ExtractValue(), kJson["foo"]); } TEST(Primitive, WrongType) { - using String = chaotic::Primitive; - try { - std::string x = kJson["foo"].As(); - } catch (const std::exception& e) { - EXPECT_EQ(std::string(e.what()), - "Error at path 'foo': Wrong type. Expected: stringValue, actual: " - "intValue"); - } + using String = chaotic::Primitive; + try { + std::string x = kJson["foo"].As(); + } catch (const std::exception& e) { + EXPECT_EQ( + std::string(e.what()), + "Error at path 'foo': Wrong type. Expected: stringValue, actual: " + "intValue" + ); + } } constexpr auto kOne = 1; constexpr auto kFive = 5; TEST(Primitive, IntMinMax) { - using Int = chaotic::Primitive, - chaotic::Maximum>; + using Int = chaotic::Primitive, chaotic::Maximum>; - int x = kJson["foo"].As(); - EXPECT_EQ(x, 1); + int x = kJson["foo"].As(); + EXPECT_EQ(x, 1); - UEXPECT_THROW_MSG(kJson["bar"].As(), chaotic::Error, - "Error at path 'bar': Invalid value, minimum=1, given=0"); - UEXPECT_THROW_MSG(kJson["zoo"].As(), chaotic::Error, - "Error at path 'zoo': Invalid value, maximum=5, given=6"); + UEXPECT_THROW_MSG(kJson["bar"].As(), chaotic::Error, "Error at path 'bar': Invalid value, minimum=1, given=0"); + UEXPECT_THROW_MSG(kJson["zoo"].As(), chaotic::Error, "Error at path 'zoo': Invalid value, maximum=5, given=6"); } TEST(Primitive, UserTypeMinMax) { - using Int = - chaotic::WithType, - chaotic::Maximum>, - MyInt>; - - MyInt x = kJson["foo"].As(); - EXPECT_EQ(x.value, 1); - - UEXPECT_THROW_MSG(kJson["bar"].As(), chaotic::Error, - "Error at path 'bar': Invalid value, minimum=1, given=0"); - UEXPECT_THROW_MSG(kJson["zoo"].As(), chaotic::Error, - "Error at path 'zoo': Invalid value, maximum=5, given=6"); + using Int = + chaotic::WithType, chaotic::Maximum>, MyInt>; + + MyInt x = kJson["foo"].As(); + EXPECT_EQ(x.value, 1); + + UEXPECT_THROW_MSG(kJson["bar"].As(), chaotic::Error, "Error at path 'bar': Invalid value, minimum=1, given=0"); + UEXPECT_THROW_MSG(kJson["zoo"].As(), chaotic::Error, "Error at path 'zoo': Invalid value, maximum=5, given=6"); } TEST(Primitive, StringMinMaxLength) { - auto kLocalJson = - formats::json::MakeObject("1", "1", "2", "12", "6", "123456"); + auto kLocalJson = formats::json::MakeObject("1", "1", "2", "12", "6", "123456"); - using Str = chaotic::Primitive, - chaotic::MaxLength<5>>; + using Str = chaotic::Primitive, chaotic::MaxLength<5>>; - std::string x = kLocalJson["2"].As(); - EXPECT_EQ(x, "12"); + std::string x = kLocalJson["2"].As(); + EXPECT_EQ(x, "12"); - UEXPECT_THROW_MSG( - kLocalJson["1"].As(), chaotic::Error, - "Error at path '1': Too short string, minimum length=2, given=1"); - UEXPECT_THROW_MSG( - kLocalJson["6"].As(), chaotic::Error, - "Error at path '6': Too long string, maximum length=5, given=6"); + UEXPECT_THROW_MSG( + kLocalJson["1"].As(), chaotic::Error, "Error at path '1': Too short string, minimum length=2, given=1" + ); + UEXPECT_THROW_MSG( + kLocalJson["6"].As(), chaotic::Error, "Error at path '6': Too long string, maximum length=5, given=6" + ); } static constexpr std::string_view kPattern = "fo.*"; TEST(Primitive, StringPattern) { - auto kLocalJson = formats::json::MakeObject("1", "foo", "2", "bar"); + auto kLocalJson = formats::json::MakeObject("1", "foo", "2", "bar"); - using Str = chaotic::Primitive>; + using Str = chaotic::Primitive>; - std::string x = kLocalJson["1"].As(); - EXPECT_EQ(x, "foo"); + std::string x = kLocalJson["1"].As(); + EXPECT_EQ(x, "foo"); - UEXPECT_THROW_MSG(kLocalJson["2"].As(), chaotic::Error, - "doesn't match regex"); + UEXPECT_THROW_MSG(kLocalJson["2"].As(), chaotic::Error, "doesn't match regex"); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/my/custom_object.cpp b/chaotic/integration_tests/tests/my/custom_object.cpp index 78fd411df20d..7cd04cded8a7 100644 --- a/chaotic/integration_tests/tests/my/custom_object.cpp +++ b/chaotic/integration_tests/tests/my/custom_object.cpp @@ -6,12 +6,10 @@ namespace my { CustomObject::CustomObject(const ns::CustomObject& obj) : foo(obj.foo) {} -ns::CustomObject Convert( - const CustomObject& value, - USERVER_NAMESPACE::chaotic::convert::To) { - ns::CustomObject obj; - obj.foo = value.foo; - return obj; +ns::CustomObject Convert(const CustomObject& value, USERVER_NAMESPACE::chaotic::convert::To) { + ns::CustomObject obj; + obj.foo = value.foo; + return obj; } } // namespace my diff --git a/chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp b/chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp index 2360ffe7df36..ad345adf622d 100644 --- a/chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp +++ b/chaotic/integration_tests/tests/my/custom_one_of_with_discriminator.cpp @@ -6,21 +6,19 @@ namespace my { -std::variant Convert( - const CustomOneOfWithDiscriminator& value, - USERVER_NAMESPACE::chaotic::convert::To< - std::variant>) { - return std::visit( - USERVER_NAMESPACE::utils::Overloaded{ - [](int x) -> std::variant { - return ns::CustomStruct1{"CustomStruct1", x}; - }, - [](const std::string& x) - -> std::variant { - return ns::CustomStruct2{"CustomStruct2", x}; - }, - }, - value.val); +std::variant +Convert(const CustomOneOfWithDiscriminator& value, USERVER_NAMESPACE::chaotic::convert::To>) { + return std::visit( + USERVER_NAMESPACE::utils::Overloaded{ + [](int x) -> std::variant { + return ns::CustomStruct1{"CustomStruct1", x}; + }, + [](const std::string& x) -> std::variant { + return ns::CustomStruct2{"CustomStruct2", x}; + }, + }, + value.val + ); } } // namespace my diff --git a/chaotic/integration_tests/tests/render/custom.cpp b/chaotic/integration_tests/tests/render/custom.cpp index dce0b8deb81d..70f0182ae6fa 100644 --- a/chaotic/integration_tests/tests/render/custom.cpp +++ b/chaotic/integration_tests/tests/render/custom.cpp @@ -8,109 +8,104 @@ USERVER_NAMESPACE_BEGIN TEST(Custom, Int) { - auto json = formats::json::MakeObject("integer", 12); - auto custom = json.As(); - EXPECT_EQ(custom.integer, std::chrono::milliseconds(12)); + auto json = formats::json::MakeObject("integer", 12); + auto custom = json.As(); + EXPECT_EQ(custom.integer, std::chrono::milliseconds(12)); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, String) { - auto json = formats::json::MakeObject("string", "make love"); - auto custom = json.As(); - EXPECT_EQ(custom.string, my::CustomString{"make love"}); + auto json = formats::json::MakeObject("string", "make love"); + auto custom = json.As(); + EXPECT_EQ(custom.string, my::CustomString{"make love"}); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, Decimal) { - auto json = formats::json::MakeObject("decimal", "12.3456789"); - auto custom = json.As(); - EXPECT_EQ(custom.decimal, decimal64::Decimal<10>::FromBiased(1234567890, 8)); + auto json = formats::json::MakeObject("decimal", "12.3456789"); + auto custom = json.As(); + EXPECT_EQ(custom.decimal, decimal64::Decimal<10>::FromBiased(1234567890, 8)); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, Boolean) { - auto json = formats::json::MakeObject("boolean", true); - auto custom = json.As(); - EXPECT_EQ(custom.boolean, my::CustomBoolean{true}); + auto json = formats::json::MakeObject("boolean", true); + auto custom = json.As(); + EXPECT_EQ(custom.boolean, my::CustomBoolean{true}); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, Number) { - auto json = formats::json::MakeObject("number", 1.23); - auto custom = json.As(); - EXPECT_EQ(custom.number, my::CustomNumber{1.23}); + auto json = formats::json::MakeObject("number", 1.23); + auto custom = json.As(); + EXPECT_EQ(custom.number, my::CustomNumber{1.23}); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, Object) { - auto json = formats::json::MakeObject( - "object", formats::json::MakeObject("foo", "bar")); - auto custom = json.As(); - EXPECT_EQ(custom.object, my::CustomObject{"bar"}); + auto json = formats::json::MakeObject("object", formats::json::MakeObject("foo", "bar")); + auto custom = json.As(); + EXPECT_EQ(custom.object, my::CustomObject{"bar"}); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, XCppContainer) { - auto json = formats::json::MakeObject("std_array", - formats::json::MakeArray("bar", "foo")); - auto custom = json.As(); - EXPECT_EQ(custom.std_array, (std::set{"foo", "bar"})); + auto json = formats::json::MakeObject("std_array", formats::json::MakeArray("bar", "foo")); + auto custom = json.As(); + EXPECT_EQ(custom.std_array, (std::set{"foo", "bar"})); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, XCppType) { - auto json = formats::json::MakeObject("custom_array", - formats::json::MakeArray("foo", "bar")); - auto custom = json.As(); - EXPECT_EQ(custom.custom_array, - (my::CustomArray{std::set{"foo", "bar"}})); - - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json = formats::json::MakeObject("custom_array", formats::json::MakeArray("foo", "bar")); + auto custom = json.As(); + EXPECT_EQ(custom.custom_array, (my::CustomArray{std::set{"foo", "bar"}})); + + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, OneOf) { - auto json = formats::json::MakeObject("oneOf", 5); - auto custom = json.As(); - EXPECT_EQ(*custom.oneOf, my::CustomOneOf(5)); + auto json = formats::json::MakeObject("oneOf", 5); + auto custom = json.As(); + EXPECT_EQ(*custom.oneOf, my::CustomOneOf(5)); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back) << " " << ToString(json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back) << " " << ToString(json); } TEST(Custom, OneOfWithDiscriminator) { - auto json = formats::json::MakeObject( - "oneOfWithDiscriminator", - formats::json::MakeObject("type", "CustomStruct1", "field1", 3)); - auto custom = json.As(); - EXPECT_EQ(custom.oneOfWithDiscriminator, my::CustomOneOfWithDiscriminator(3)); - - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json = formats::json::MakeObject( + "oneOfWithDiscriminator", formats::json::MakeObject("type", "CustomStruct1", "field1", 3) + ); + auto custom = json.As(); + EXPECT_EQ(custom.oneOfWithDiscriminator, my::CustomOneOfWithDiscriminator(3)); + + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } TEST(Custom, AllOf) { - auto json = formats::json::MakeObject( - "allOf", formats::json::MakeObject("field1", "foo", "field2", "bar")); - auto custom = json.As(); - EXPECT_EQ(custom.allOf, (my::CustomAllOf{"foo", "bar"})); + auto json = formats::json::MakeObject("allOf", formats::json::MakeObject("field1", "foo", "field2", "bar")); + auto custom = json.As(); + EXPECT_EQ(custom.allOf, (my::CustomAllOf{"foo", "bar"})); - auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); - EXPECT_EQ(json_back, json); + auto json_back = formats::json::ValueBuilder{custom}.ExtractValue(); + EXPECT_EQ(json_back, json); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/render/fwd.cpp b/chaotic/integration_tests/tests/render/fwd.cpp index 9c30a3242804..2abd65c6fef1 100644 --- a/chaotic/integration_tests/tests/render/fwd.cpp +++ b/chaotic/integration_tests/tests/render/fwd.cpp @@ -17,31 +17,25 @@ USERVER_NAMESPACE_BEGIN TEST(Fwd, DeclaredStruct) { - [[maybe_unused]] ns::Object1* object1_ptr = nullptr; - [[maybe_unused]] ns::ArrayStruct* array_struct_ptr = nullptr; - [[maybe_unused]] ns::CustomStruct1* custom_struct_ptr = nullptr; - [[maybe_unused]] ns::ObjectWithExternalRef* object_with_external_ref_ptr = - nullptr; - [[maybe_unused]] ns::TreeNode* tree_node_ptr = nullptr; - [[maybe_unused]] ns::IntegerObject* integer_object_ptr = nullptr; - [[maybe_unused]] ns::ObjectInvalid* object_invalid_ptr = nullptr; - [[maybe_unused]] ns::ObjectEmpty* object_empty_ptr = nullptr; - [[maybe_unused]] ns::ObjectExtra* object_extra_ptr = nullptr; - [[maybe_unused]] ns::Objectx* objectx_ptr = nullptr; - [[maybe_unused]] ns::SimpleObject* simple_ptr = nullptr; - [[maybe_unused]] ns::ObjectOneOfWithDiscriminator* - object_one_of_with_discriminator_ptr = nullptr; - [[maybe_unused]] ns::ObjectPattern* object_pattern_ptr = nullptr; + [[maybe_unused]] ns::Object1* object1_ptr = nullptr; + [[maybe_unused]] ns::ArrayStruct* array_struct_ptr = nullptr; + [[maybe_unused]] ns::CustomStruct1* custom_struct_ptr = nullptr; + [[maybe_unused]] ns::ObjectWithExternalRef* object_with_external_ref_ptr = nullptr; + [[maybe_unused]] ns::TreeNode* tree_node_ptr = nullptr; + [[maybe_unused]] ns::IntegerObject* integer_object_ptr = nullptr; + [[maybe_unused]] ns::ObjectInvalid* object_invalid_ptr = nullptr; + [[maybe_unused]] ns::ObjectEmpty* object_empty_ptr = nullptr; + [[maybe_unused]] ns::ObjectExtra* object_extra_ptr = nullptr; + [[maybe_unused]] ns::Objectx* objectx_ptr = nullptr; + [[maybe_unused]] ns::SimpleObject* simple_ptr = nullptr; + [[maybe_unused]] ns::ObjectOneOfWithDiscriminator* object_one_of_with_discriminator_ptr = nullptr; + [[maybe_unused]] ns::ObjectPattern* object_pattern_ptr = nullptr; } TEST(Fwd, DeclaredAllOf) { [[maybe_unused]] ns::AllOf* all_of_ptr = nullptr; } -TEST(Fwd, DeclaredIntEnum) { - [[maybe_unused]] ns::IntegerEnum* int_enum_ptr = nullptr; -} +TEST(Fwd, DeclaredIntEnum) { [[maybe_unused]] ns::IntegerEnum* int_enum_ptr = nullptr; } -TEST(Fwd, DeclaredStringEnum) { - [[maybe_unused]] ns::StringEnum* string_enum_ptr = nullptr; -} +TEST(Fwd, DeclaredStringEnum) { [[maybe_unused]] ns::StringEnum* string_enum_ptr = nullptr; } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/render/logging.cpp b/chaotic/integration_tests/tests/render/logging.cpp index 209ee86e25bf..8cbcdeaa443e 100644 --- a/chaotic/integration_tests/tests/render/logging.cpp +++ b/chaotic/integration_tests/tests/render/logging.cpp @@ -12,19 +12,33 @@ USERVER_NAMESPACE_BEGIN using Logging = utest::LogCaptureFixture<>; TEST_F(Logging, Object) { - auto json = formats::json::MakeObject( - "integer", 1, "boolean", true, "number", 1.5, "string", "foo", - "string-enum", "1", "object", formats::json::MakeObject(), "array", - formats::json::MakeArray(1)); - auto obj = json.As(); - - const auto obj_string = GetLogCapture().ToStringViaLogging(obj); - EXPECT_EQ(obj_string, - R"({"boolean":true,"integer":1,"number":1.5,"string":"foo",)" - R"("object":{},"array":[1],"string-enum":"1"})"); - - const auto enum_string = GetLogCapture().ToStringViaLogging(obj.string_enum); - ASSERT_EQ(enum_string, "1"); + auto json = formats::json::MakeObject( + "integer", + 1, + "boolean", + true, + "number", + 1.5, + "string", + "foo", + "string-enum", + "1", + "object", + formats::json::MakeObject(), + "array", + formats::json::MakeArray(1) + ); + auto obj = json.As(); + + const auto obj_string = GetLogCapture().ToStringViaLogging(obj); + EXPECT_EQ( + obj_string, + R"({"boolean":true,"integer":1,"number":1.5,"string":"foo",)" + R"("object":{},"array":[1],"string-enum":"1"})" + ); + + const auto enum_string = GetLogCapture().ToStringViaLogging(obj.string_enum); + ASSERT_EQ(enum_string, "1"); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/render/minmax.cpp b/chaotic/integration_tests/tests/render/minmax.cpp index b269582d9b60..969f92778ccf 100644 --- a/chaotic/integration_tests/tests/render/minmax.cpp +++ b/chaotic/integration_tests/tests/render/minmax.cpp @@ -8,46 +8,47 @@ USERVER_NAMESPACE_BEGIN TEST(MinMax, ExclusiveInt) { - auto json = formats::json::MakeObject("foo", 1); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'foo': Invalid value, exclusive minimum=1, given=1"); - - json = formats::json::MakeObject("foo", 2); - EXPECT_EQ(json.As().foo, 2); - - json = formats::json::MakeObject("foo", 20); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'foo': Invalid value, exclusive maximum=20, given=20"); - - json = formats::json::MakeObject("foo", 19); - EXPECT_EQ(json.As().foo, 19); + auto json = formats::json::MakeObject("foo", 1); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'foo': Invalid value, exclusive minimum=1, given=1" + ); + + json = formats::json::MakeObject("foo", 2); + EXPECT_EQ(json.As().foo, 2); + + json = formats::json::MakeObject("foo", 20); + UEXPECT_THROW_MSG( + json.As(), + chaotic::Error, + "Error at path 'foo': Invalid value, exclusive maximum=20, given=20" + ); + + json = formats::json::MakeObject("foo", 19); + EXPECT_EQ(json.As().foo, 19); } TEST(MinMax, String) { - auto json = formats::json::MakeObject("bar", ""); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'bar': Too short string, minimum length=2, given=0"); - - json = formats::json::MakeObject("bar", "longlonglong"); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'bar': Too long string, maximum length=5, given=12"); + auto json = formats::json::MakeObject("bar", ""); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'bar': Too short string, minimum length=2, given=0" + ); + + json = formats::json::MakeObject("bar", "longlonglong"); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'bar': Too long string, maximum length=5, given=12" + ); } TEST(MinMax, Array) { - auto json = formats::json::MakeObject("zoo", formats::json::MakeArray(1)); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'zoo': Too short array, minimum length=2, given=1"); - - json = formats::json::MakeObject( - "zoo", formats::json::MakeArray(1, 2, 3, 4, 5, 6, 7, 8)); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'zoo': Too long array, maximum length=5, given=8"); + auto json = formats::json::MakeObject("zoo", formats::json::MakeArray(1)); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'zoo': Too short array, minimum length=2, given=1" + ); + + json = formats::json::MakeObject("zoo", formats::json::MakeArray(1, 2, 3, 4, 5, 6, 7, 8)); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'zoo': Too long array, maximum length=5, given=8" + ); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/render/simple.cpp b/chaotic/integration_tests/tests/render/simple.cpp index 9c5ab77ca841..aec4d2e44424 100644 --- a/chaotic/integration_tests/tests/render/simple.cpp +++ b/chaotic/integration_tests/tests/render/simple.cpp @@ -26,326 +26,315 @@ USERVER_NAMESPACE_BEGIN TEST(Simple, Empty) { - auto json = formats::json::MakeObject(); - auto obj = json.As(); - EXPECT_EQ(obj, ns::ObjectEmpty()); + auto json = formats::json::MakeObject(); + auto obj = json.As(); + EXPECT_EQ(obj, ns::ObjectEmpty()); } TEST(Simple, Integer) { - auto json = formats::json::MakeObject("int3", 1, "integer", 3); - auto obj = json.As(); - EXPECT_EQ(obj.integer, 3); + auto json = formats::json::MakeObject("int3", 1, "integer", 3); + auto obj = json.As(); + EXPECT_EQ(obj.integer, 3); } TEST(Simple, DefaultFieldValue) { - ns::SimpleObject obj; - EXPECT_EQ(obj.int_, 1); + ns::SimpleObject obj; + EXPECT_EQ(obj.int_, 1); } TEST(Simple, IntegerMinimum) { - auto json = formats::json::MakeObject("int3", 1, "int", -10); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'int': Invalid value, minimum=-1, given=-10"); + auto json = formats::json::MakeObject("int3", 1, "int", -10); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'int': Invalid value, minimum=-1, given=-10" + ); } TEST(Simple, IntegerMaximum) { - auto json = formats::json::MakeObject("int3", 1, "int", 11); - UEXPECT_THROW_MSG(json.As(), chaotic::Error, - "Error at path 'int': Invalid value, maximum=10, given=11"); + auto json = formats::json::MakeObject("int3", 1, "int", 11); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'int': Invalid value, maximum=10, given=11" + ); } TEST(Simple, ObjectDefault) { - auto json = formats::json::MakeObject("int3", 1); - auto obj = json.As(); - EXPECT_EQ(obj.int_, 1); + auto json = formats::json::MakeObject("int3", 1); + auto obj = json.As(); + EXPECT_EQ(obj.int_, 1); } TEST(Simple, ObjectRequired) { - auto json = formats::json::MakeObject(); - UEXPECT_THROW_MSG(json.As(), - formats::json::MemberMissingException, - "Error at path 'int3': Field is missing"); + auto json = formats::json::MakeObject(); + UEXPECT_THROW_MSG( + json.As(), formats::json::MemberMissingException, "Error at path 'int3': Field is missing" + ); } TEST(Simple, IntegerFormat) { - static_assert( - std::is_same_v>); - static_assert(std::is_same_v); - static_assert(std::is_same_v); + static_assert(std::is_same_v>); + static_assert(std::is_same_v); + static_assert(std::is_same_v); } TEST(Simple, ObjectWithRefType) { - auto json = formats::json::MakeObject("integer", 0); - UEXPECT_THROW_MSG( - json.As(), chaotic::Error, - "Error at path 'integer': Invalid value, minimum=1, given=0"); + auto json = formats::json::MakeObject("integer", 0); + UEXPECT_THROW_MSG( + json.As(), chaotic::Error, "Error at path 'integer': Invalid value, minimum=1, given=0" + ); } TEST(Simple, ObjectTypes) { - auto json = formats::json::MakeObject( - "integer", 1, "boolean", true, "number", 1.1, "string", "foo", - "string-enum", "1", "object", formats::json::MakeObject(), "array", - formats::json::MakeArray(1)); - auto obj = json.As(); - EXPECT_EQ(obj, (ns::ObjectTypes{true, - 1, - 1.1, - "foo", - ns::ObjectTypes::Object{}, - {1}, - {}, - ns::ObjectTypes::String_Enum::kX1})); + auto json = formats::json::MakeObject( + "integer", + 1, + "boolean", + true, + "number", + 1.1, + "string", + "foo", + "string-enum", + "1", + "object", + formats::json::MakeObject(), + "array", + formats::json::MakeArray(1) + ); + auto obj = json.As(); + EXPECT_EQ( + obj, + (ns::ObjectTypes{true, 1, 1.1, "foo", ns::ObjectTypes::Object{}, {1}, {}, ns::ObjectTypes::String_Enum::kX1}) + ); } TEST(Simple, ObjectWithAdditionalPropertiesInt) { - auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3); - auto obj = json.As(); + auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3); + auto obj = json.As(); - EXPECT_EQ(obj.one, 1); - EXPECT_EQ(obj.extra, - (std::unordered_map{{"two", 2}, {"three", 3}})); + EXPECT_EQ(obj.one, 1); + EXPECT_EQ(obj.extra, (std::unordered_map{{"two", 2}, {"three", 3}})); - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back); + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back); } TEST(Simple, ObjectWithAdditionalPropertiesTrue) { - auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3, - "object", formats::json::MakeObject()); - auto obj = json.As(); + auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3, "object", formats::json::MakeObject()); + auto obj = json.As(); - EXPECT_EQ(obj.one, 1); - EXPECT_EQ(obj.extra, formats::json::MakeObject("two", 2, "three", 3, "object", - formats::json::MakeObject())); + EXPECT_EQ(obj.one, 1); + EXPECT_EQ(obj.extra, formats::json::MakeObject("two", 2, "three", 3, "object", formats::json::MakeObject())); - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back); + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back); } TEST(Simple, ObjectExtraMemberFalse) { - auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3, - "object", formats::json::MakeObject()); - auto obj = json.As(); + auto json = formats::json::MakeObject("one", 1, "two", 2, "three", 3, "object", formats::json::MakeObject()); + auto obj = json.As(); - EXPECT_EQ(obj.one, 1); + EXPECT_EQ(obj.one, 1); - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, formats::json::MakeObject("one", 1)) - << ToString(json_back); + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, formats::json::MakeObject("one", 1)) << ToString(json_back); } TEST(Simple, ObjectWithAdditionalPropertiesFalseStrict) { - auto json = formats::json::MakeObject("foo", 1, "bar", 2); - UEXPECT_THROW_MSG(json.As(), - std::runtime_error, "Unknown property 'bar'"); + auto json = formats::json::MakeObject("foo", 1, "bar", 2); + UEXPECT_THROW_MSG( + json.As(), std::runtime_error, "Unknown property 'bar'" + ); } TEST(Simple, IntegerEnum) { - auto json = formats::json::MakeObject("one", 1); - auto obj = json["one"].As(); - EXPECT_EQ(obj, ns::IntegerEnum::k1); - - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json["one"]) << ToString(json_back); - - auto json2 = formats::json::MakeObject("one", 5); - UEXPECT_THROW_MSG( - json2["one"].As(), chaotic::Error, - "Error at path 'one': Invalid enum value (5) for type ns::IntegerEnum"); - - EXPECT_EQ(std::size(ns::kIntegerEnumValues), 3); - - ns::IntegerEnum values[] = {ns::IntegerEnum::k1, ns::IntegerEnum::k2, - ns::IntegerEnum::k3}; - std::size_t index = 0; - for (const auto& value : ns::kIntegerEnumValues) { - EXPECT_EQ(value, values[index]); - ++index; - } + auto json = formats::json::MakeObject("one", 1); + auto obj = json["one"].As(); + EXPECT_EQ(obj, ns::IntegerEnum::k1); + + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json["one"]) << ToString(json_back); + + auto json2 = formats::json::MakeObject("one", 5); + UEXPECT_THROW_MSG( + json2["one"].As(), + chaotic::Error, + "Error at path 'one': Invalid enum value (5) for type ns::IntegerEnum" + ); + + EXPECT_EQ(std::size(ns::kIntegerEnumValues), 3); + + ns::IntegerEnum values[] = {ns::IntegerEnum::k1, ns::IntegerEnum::k2, ns::IntegerEnum::k3}; + std::size_t index = 0; + for (const auto& value : ns::kIntegerEnumValues) { + EXPECT_EQ(value, values[index]); + ++index; + } } TEST(Simple, StringEnum) { - auto json = formats::json::MakeObject("one", "foo"); - auto obj = json["one"].As(); - EXPECT_EQ(obj, ns::StringEnum::kFoo); - - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json["one"]) << ToString(json_back); - - auto json2 = formats::json::MakeObject("one", "zoo"); - UEXPECT_THROW_MSG( - json2["one"].As(), chaotic::Error, - "Error at path 'one': Invalid enum value (zoo) for type ns::StringEnum"); - - EXPECT_EQ("foo", ToString(ns::StringEnum::kFoo)); - EXPECT_EQ("bar", ToString(ns::StringEnum::kBar)); - EXPECT_EQ("some!thing", ToString(ns::StringEnum::kSomeThing)); - - EXPECT_EQ(FromString("foo", formats::parse::To{}), - ns::StringEnum::kFoo); - UEXPECT_THROW_MSG(FromString("zoo", formats::parse::To{}), - std::runtime_error, - "Invalid enum value (zoo) for type ns::StringEnum"); - - EXPECT_EQ(Parse("foo", formats::parse::To{}), - ns::StringEnum::kFoo); - UEXPECT_THROW_MSG(Parse("zoo", formats::parse::To{}), - std::runtime_error, - "Invalid enum value (zoo) for type ns::StringEnum"); - - EXPECT_EQ(std::size(ns::kStringEnumValues), 3); - - ns::StringEnum values[] = {ns::StringEnum::kFoo, ns::StringEnum::kBar, - ns::StringEnum::kSomeThing}; - std::size_t index = 0; - for (const auto& value : ns::kStringEnumValues) { - EXPECT_EQ(value, values[index]); - ++index; - } + auto json = formats::json::MakeObject("one", "foo"); + auto obj = json["one"].As(); + EXPECT_EQ(obj, ns::StringEnum::kFoo); + + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json["one"]) << ToString(json_back); + + auto json2 = formats::json::MakeObject("one", "zoo"); + UEXPECT_THROW_MSG( + json2["one"].As(), + chaotic::Error, + "Error at path 'one': Invalid enum value (zoo) for type ns::StringEnum" + ); + + EXPECT_EQ("foo", ToString(ns::StringEnum::kFoo)); + EXPECT_EQ("bar", ToString(ns::StringEnum::kBar)); + EXPECT_EQ("some!thing", ToString(ns::StringEnum::kSomeThing)); + + EXPECT_EQ(FromString("foo", formats::parse::To{}), ns::StringEnum::kFoo); + UEXPECT_THROW_MSG( + FromString("zoo", formats::parse::To{}), + std::runtime_error, + "Invalid enum value (zoo) for type ns::StringEnum" + ); + + EXPECT_EQ(Parse("foo", formats::parse::To{}), ns::StringEnum::kFoo); + UEXPECT_THROW_MSG( + Parse("zoo", formats::parse::To{}), + std::runtime_error, + "Invalid enum value (zoo) for type ns::StringEnum" + ); + + EXPECT_EQ(std::size(ns::kStringEnumValues), 3); + + ns::StringEnum values[] = {ns::StringEnum::kFoo, ns::StringEnum::kBar, ns::StringEnum::kSomeThing}; + std::size_t index = 0; + for (const auto& value : ns::kStringEnumValues) { + EXPECT_EQ(value, values[index]); + ++index; + } } TEST(Simple, AllOf) { - auto json = formats::json::MakeObject("foo", 1, "bar", 2); - auto obj = json.As(); + auto json = formats::json::MakeObject("foo", 1, "bar", 2); + auto obj = json.As(); - EXPECT_EQ(obj.foo, 1); - EXPECT_EQ(obj.bar, 2); + EXPECT_EQ(obj.foo, 1); + EXPECT_EQ(obj.bar, 2); - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back); + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back); } TEST(Simple, OneOf) { - auto json = formats::json::MakeObject(); - auto obj = json.As(); + auto json = formats::json::MakeObject(); + auto obj = json.As(); - EXPECT_EQ(std::get(obj), ns::OneOf__O2()); + EXPECT_EQ(std::get(obj), ns::OneOf__O2()); - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back); + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back); } TEST(Simple, OneOfWithDiscriminator) { - auto json = formats::json::MakeObject( - "oneof", formats::json::MakeObject("type", "ObjectFoo", "foo", 42)); - auto obj = json.As(); - EXPECT_EQ(std::get<0>(obj.oneof.value()).type, "ObjectFoo"); - EXPECT_EQ(std::get<0>(obj.oneof.value()).foo, 42); - - auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); - EXPECT_EQ(json_back, json) << ToString(json_back); + auto json = formats::json::MakeObject("oneof", formats::json::MakeObject("type", "ObjectFoo", "foo", 42)); + auto obj = json.As(); + EXPECT_EQ(std::get<0>(obj.oneof.value()).type, "ObjectFoo"); + EXPECT_EQ(std::get<0>(obj.oneof.value()).foo, 42); + + auto json_back = formats::json::ValueBuilder{obj}.ExtractValue(); + EXPECT_EQ(json_back, json) << ToString(json_back); } TEST(Simple, Indirect) { - auto json = formats::json::MakeObject( - "data", "smth", "left", formats::json::MakeObject("data", "left"), - "right", - formats::json::MakeObject( - "data", "right", "left", - formats::json::MakeObject("data", "rightleft"))); - - auto obj = json.As(); - EXPECT_EQ(obj.data, "smth"); - EXPECT_EQ(obj.left, (ns::TreeNode{"left", std::nullopt, std::nullopt})); - EXPECT_EQ(obj.right, - (ns::TreeNode{"right", - ns::TreeNode{"rightleft", std::nullopt, std::nullopt}, - std::nullopt})); + auto json = formats::json::MakeObject( + "data", + "smth", + "left", + formats::json::MakeObject("data", "left"), + "right", + formats::json::MakeObject("data", "right", "left", formats::json::MakeObject("data", "rightleft")) + ); + + auto obj = json.As(); + EXPECT_EQ(obj.data, "smth"); + EXPECT_EQ(obj.left, (ns::TreeNode{"left", std::nullopt, std::nullopt})); + EXPECT_EQ(obj.right, (ns::TreeNode{"right", ns::TreeNode{"rightleft", std::nullopt, std::nullopt}, std::nullopt})); } TEST(Simple, HyphenField) { - ns::ObjectWithHyphenField obj; - EXPECT_EQ(obj.foo_field, std::nullopt); + ns::ObjectWithHyphenField obj; + EXPECT_EQ(obj.foo_field, std::nullopt); } -TEST(Simple, SubSubObjectSmoke) { - [[maybe_unused]] ns::Objectx::Objectx_::Objectx__ x; -} +TEST(Simple, SubSubObjectSmoke) { [[maybe_unused]] ns::Objectx::Objectx_::Objectx__ x; } TEST(Simple, ExtraType) { - static_assert( - std::is_same_v().extra), - std::map>); + static_assert(std::is_same_v< + decltype(std::declval().extra), + std::map>); } TEST(Simple, CppName) { - ns::ObjectName obj; - EXPECT_EQ(obj.bar, std::nullopt); + ns::ObjectName obj; + EXPECT_EQ(obj.bar, std::nullopt); } TEST(Simple, Date) { - auto json = formats::json::MakeObject("created_at", "2020-10-01"); - auto obj = json.As(); + auto json = formats::json::MakeObject("created_at", "2020-10-01"); + auto obj = json.As(); - EXPECT_EQ(obj.created_at, utils::datetime::Date(2020, 10, 01)); + EXPECT_EQ(obj.created_at, utils::datetime::Date(2020, 10, 01)); } TEST(Simple, DateTime) { - auto date = "2020-10-01T12:34:56+12:34"; - auto json = formats::json::MakeObject("updated_at", date); - auto obj = json.As(); - - utils::datetime::TimePointTz tp{ - utils::datetime::Stringtime("2020-10-01T00:00:56Z"), - std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; - EXPECT_EQ(obj.updated_at, tp); - - auto str = - Serialize(obj, - formats::serialize::To())["updated_at"] - .As(); - EXPECT_EQ(str, date); + auto date = "2020-10-01T12:34:56+12:34"; + auto json = formats::json::MakeObject("updated_at", date); + auto obj = json.As(); + + utils::datetime::TimePointTz tp{ + utils::datetime::Stringtime("2020-10-01T00:00:56Z"), std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; + EXPECT_EQ(obj.updated_at, tp); + + auto str = Serialize(obj, formats::serialize::To())["updated_at"].As(); + EXPECT_EQ(str, date); } TEST(Simple, DateTimeExtra) { - auto date = "2020-10-01T12:34:56+12:34"; - auto json = formats::json::MakeObject("updated_at_extra", date); - auto obj = json.As(); - - utils::datetime::TimePointTz tp{ - utils::datetime::Stringtime("2020-10-01T00:00:56Z"), - std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; - EXPECT_EQ(obj.updated_at_extra->time_point, tp); - - auto str = - Serialize( - obj, - formats::serialize::To())["updated_at_extra"] - .As(); - EXPECT_EQ(str, date); + auto date = "2020-10-01T12:34:56+12:34"; + auto json = formats::json::MakeObject("updated_at_extra", date); + auto obj = json.As(); + + utils::datetime::TimePointTz tp{ + utils::datetime::Stringtime("2020-10-01T00:00:56Z"), std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; + EXPECT_EQ(obj.updated_at_extra->time_point, tp); + + auto str = Serialize(obj, formats::serialize::To())["updated_at_extra"].As(); + EXPECT_EQ(str, date); } TEST(Simple, DateTimeIsoBasic) { - auto date = "2020-10-01T12:34:56+1234"; - auto json = formats::json::MakeObject("deleted_at", date); - auto obj = json.As(); - - utils::datetime::TimePointTzIsoBasic tp{ - utils::datetime::Stringtime("2020-10-01T00:00:56Z"), - std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; - EXPECT_EQ(obj.deleted_at, tp); - - auto str = - Serialize(obj, - formats::serialize::To())["deleted_at"] - .As(); - EXPECT_EQ(str, date); + auto date = "2020-10-01T12:34:56+1234"; + auto json = formats::json::MakeObject("deleted_at", date); + auto obj = json.As(); + + utils::datetime::TimePointTzIsoBasic tp{ + utils::datetime::Stringtime("2020-10-01T00:00:56Z"), std::chrono::seconds(12 * 60 * 60 + 34 * 60)}; + EXPECT_EQ(obj.deleted_at, tp); + + auto str = Serialize(obj, formats::serialize::To())["deleted_at"].As(); + EXPECT_EQ(str, date); } TEST(Simple, Uuid) { - auto uuid = "01234567-89ab-cdef-0123-456789abcdef"; - auto json = formats::json::MakeObject("uuid", uuid); - auto obj = json.As(); - - boost::uuids::string_generator gen; - boost::uuids::uuid expected = gen(uuid); - EXPECT_EQ(obj.uuid, expected); - - auto str = - Serialize(obj, formats::serialize::To())["uuid"] - .As(); - EXPECT_EQ(str, uuid); + auto uuid = "01234567-89ab-cdef-0123-456789abcdef"; + auto json = formats::json::MakeObject("uuid", uuid); + auto obj = json.As(); + + boost::uuids::string_generator gen; + boost::uuids::uuid expected = gen(uuid); + EXPECT_EQ(obj.uuid, expected); + + auto str = Serialize(obj, formats::serialize::To())["uuid"].As(); + EXPECT_EQ(str, uuid); } USERVER_NAMESPACE_END diff --git a/chaotic/integration_tests/tests/render/yaml_config.cpp b/chaotic/integration_tests/tests/render/yaml_config.cpp index af37a5021460..5032523992ed 100644 --- a/chaotic/integration_tests/tests/render/yaml_config.cpp +++ b/chaotic/integration_tests/tests/render/yaml_config.cpp @@ -9,27 +9,22 @@ USERVER_NAMESPACE_BEGIN TEST(YamlConfig, Presence) { - static_assert(formats::common::impl::kHasParse< - USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomStruct1>); + static_assert(formats::common::impl::kHasParse); - // Due to JSON extra - static_assert( - !formats::common::impl::kHasParse< - USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf__P0>); + // Due to JSON extra + static_assert(!formats::common::impl::kHasParse); - // Transitively - static_assert(!formats::common::impl::kHasParse< - USERVER_NAMESPACE::yaml_config::YamlConfig, ns::CustomAllOf>); + // Transitively + static_assert(!formats::common::impl::kHasParse); } TEST(YamlConfig, Parse) { - auto value = formats::yaml::FromString(R"--( + auto value = formats::yaml::FromString(R"--( type: some string field1: 123 )--"); - yaml_config::YamlConfig config{value, {}}; - EXPECT_EQ(config.As(), - (ns::CustomStruct1{"some string", 123})); + yaml_config::YamlConfig config{value, {}}; + EXPECT_EQ(config.As(), (ns::CustomStruct1{"some string", 123})); } USERVER_NAMESPACE_END diff --git a/chaotic/src/chaotic/io/boost/uuids/uuid.cpp b/chaotic/src/chaotic/io/boost/uuids/uuid.cpp index e9086edd1a9a..ddf2fd530da7 100644 --- a/chaotic/src/chaotic/io/boost/uuids/uuid.cpp +++ b/chaotic/src/chaotic/io/boost/uuids/uuid.cpp @@ -6,15 +6,12 @@ USERVER_NAMESPACE_BEGIN namespace chaotic::convert { -boost::uuids::uuid Convert( - const std::string& str, - USERVER_NAMESPACE::chaotic::convert::To) { - return USERVER_NAMESPACE::utils::BoostUuidFromString(str); +boost::uuids::uuid Convert(const std::string& str, USERVER_NAMESPACE::chaotic::convert::To) { + return USERVER_NAMESPACE::utils::BoostUuidFromString(str); } -std::string Convert(const boost::uuids::uuid& uuid, - USERVER_NAMESPACE::chaotic::convert::To) { - return USERVER_NAMESPACE::utils::ToString(uuid); +std::string Convert(const boost::uuids::uuid& uuid, USERVER_NAMESPACE::chaotic::convert::To) { + return USERVER_NAMESPACE::utils::ToString(uuid); } } // namespace chaotic::convert diff --git a/chaotic/src/chaotic/io/userver/utils/datetime/date.cpp b/chaotic/src/chaotic/io/userver/utils/datetime/date.cpp index 6f21b89abb8e..d3f90a88121f 100644 --- a/chaotic/src/chaotic/io/userver/utils/datetime/date.cpp +++ b/chaotic/src/chaotic/io/userver/utils/datetime/date.cpp @@ -4,13 +4,9 @@ USERVER_NAMESPACE_BEGIN namespace utils::datetime { -Date Convert(const std::string& value, chaotic::convert::To) { - return DateFromRFC3339String(value); -} +Date Convert(const std::string& value, chaotic::convert::To) { return DateFromRFC3339String(value); } -std::string Convert(const Date& value, chaotic::convert::To) { - return ToString(value); -} +std::string Convert(const Date& value, chaotic::convert::To) { return ToString(value); } } // namespace utils::datetime diff --git a/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz.cpp b/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz.cpp index 8fe327449d79..875887f0833d 100644 --- a/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz.cpp +++ b/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz.cpp @@ -16,22 +16,18 @@ constexpr std::string_view kZeroTimePoint = "1970-01-01T00:00:00"; } TimePointTz Convert(const std::string& str, chaotic::convert::To) { - auto s = str; - auto tp = - utils::datetime::FromStringSaturating(s, utils::datetime::kRfc3339Format); - - UINVARIANT(s.size() >= kZeroTimePoint.size(), "Invalid datetime"); - memcpy(s.data(), kZeroTimePoint.data(), kZeroTimePoint.length()); - auto tp_tz = utils::datetime::Stringtime(s, utils::datetime::kDefaultTimezone, - utils::datetime::kRfc3339Format); - return TimePointTz{tp, -std::chrono::duration_cast( - tp_tz.time_since_epoch())}; + auto s = str; + auto tp = utils::datetime::FromStringSaturating(s, utils::datetime::kRfc3339Format); + + UINVARIANT(s.size() >= kZeroTimePoint.size(), "Invalid datetime"); + memcpy(s.data(), kZeroTimePoint.data(), kZeroTimePoint.length()); + auto tp_tz = utils::datetime::Stringtime(s, utils::datetime::kDefaultTimezone, utils::datetime::kRfc3339Format); + return TimePointTz{tp, -std::chrono::duration_cast(tp_tz.time_since_epoch())}; } std::string Convert(const TimePointTz& tp, chaotic::convert::To) { - auto offset = tp.GetTzOffset(); - return cctz::format(utils::datetime::kRfc3339Format, tp.GetTimePoint(), - cctz::fixed_time_zone(offset)); + auto offset = tp.GetTzOffset(); + return cctz::format(utils::datetime::kRfc3339Format, tp.GetTimePoint(), cctz::fixed_time_zone(offset)); } } // namespace utils::datetime diff --git a/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.cpp b/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.cpp index 547fd44dd311..a2803b577a52 100644 --- a/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.cpp +++ b/chaotic/src/chaotic/io/userver/utils/datetime/time_point_tz_iso_basic.cpp @@ -15,26 +15,19 @@ namespace { constexpr std::string_view kZeroTimePoint = "1970-01-01T00:00:00"; } -TimePointTzIsoBasic Convert(const std::string& str, - chaotic::convert::To) { - auto s = str; - auto tp = - utils::datetime::FromStringSaturating(s, utils::datetime::kDefaultFormat); - - UINVARIANT(s.size() >= kZeroTimePoint.size(), "Invalid datetime"); - memcpy(s.data(), kZeroTimePoint.data(), kZeroTimePoint.length()); - auto tp_tz = utils::datetime::Stringtime(s, utils::datetime::kDefaultTimezone, - utils::datetime::kDefaultFormat); - return TimePointTzIsoBasic{tp, - -std::chrono::duration_cast( - tp_tz.time_since_epoch())}; +TimePointTzIsoBasic Convert(const std::string& str, chaotic::convert::To) { + auto s = str; + auto tp = utils::datetime::FromStringSaturating(s, utils::datetime::kDefaultFormat); + + UINVARIANT(s.size() >= kZeroTimePoint.size(), "Invalid datetime"); + memcpy(s.data(), kZeroTimePoint.data(), kZeroTimePoint.length()); + auto tp_tz = utils::datetime::Stringtime(s, utils::datetime::kDefaultTimezone, utils::datetime::kDefaultFormat); + return TimePointTzIsoBasic{tp, -std::chrono::duration_cast(tp_tz.time_since_epoch())}; } -std::string Convert(const TimePointTzIsoBasic& tp, - chaotic::convert::To) { - auto offset = tp.GetTzOffset(); - return cctz::format(utils::datetime::kDefaultFormat, tp.GetTimePoint(), - cctz::fixed_time_zone(offset)); +std::string Convert(const TimePointTzIsoBasic& tp, chaotic::convert::To) { + auto offset = tp.GetTzOffset(); + return cctz::format(utils::datetime::kDefaultFormat, tp.GetTimePoint(), cctz::fixed_time_zone(offset)); } } // namespace utils::datetime diff --git a/clickhouse/functional_tests/basic_chaos/clickhouse_service.cpp b/clickhouse/functional_tests/basic_chaos/clickhouse_service.cpp index 208025bc35d0..5e5c896d40ef 100644 --- a/clickhouse/functional_tests/basic_chaos/clickhouse_service.cpp +++ b/clickhouse/functional_tests/basic_chaos/clickhouse_service.cpp @@ -20,13 +20,13 @@ namespace chaos { static constexpr std::chrono::milliseconds kDefaultTimeout{2000}; struct KeyValueRow final { - std::string key; - std::string value; + std::string key; + std::string value; }; struct PairOfUuids final { - boost::uuids::uuid uuid_mismatched; - boost::uuids::uuid uuid_correct; + boost::uuids::uuid uuid_mismatched; + boost::uuids::uuid uuid_correct; }; } // namespace chaos @@ -36,13 +36,12 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse final { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse final { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io @@ -52,171 +51,143 @@ USERVER_NAMESPACE_END namespace chaos { class KeyValue final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName{"handler-chaos"}; +public: + static constexpr std::string_view kName{"handler-chaos"}; - KeyValue(const components::ComponentConfig& config, - const components::ComponentContext& context); + KeyValue(const components::ComponentConfig& config, const components::ComponentContext& context); - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override; + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override; - private: - std::string GetValue(std::string_view key, - const server::http::HttpRequest& request) const; - std::string PostValue(std::string_view key, - const server::http::HttpRequest& request) const; - std::string DeleteValue(std::string_view key) const; +private: + std::string GetValue(std::string_view key, const server::http::HttpRequest& request) const; + std::string PostValue(std::string_view key, const server::http::HttpRequest& request) const; + std::string DeleteValue(std::string_view key) const; - storages::clickhouse::ClusterPtr clickhouse_client_; - storages::clickhouse::CommandControl cc_{kDefaultTimeout}; + storages::clickhouse::ClusterPtr clickhouse_client_; + storages::clickhouse::CommandControl cc_{kDefaultTimeout}; }; -KeyValue::KeyValue(const components::ComponentConfig& config, - const components::ComponentContext& context) +KeyValue::KeyValue(const components::ComponentConfig& config, const components::ComponentContext& context) : server::handlers::HttpHandlerBase{config, context}, - clickhouse_client_{ - context.FindComponent("clickhouse-database") - .GetCluster()} {} - -std::string KeyValue::HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const { - const auto& key = request.GetArg("key"); - if (key.empty()) { - throw server::handlers::ClientError{ - server::handlers::ExternalBody{"No 'key' query argument"}}; - } - - switch (request.GetMethod()) { - case server::http::HttpMethod::kGet: - return GetValue(key, request); - case server::http::HttpMethod::kPost: - return PostValue(key, request); - case server::http::HttpMethod::kDelete: - return DeleteValue(key); - default: - throw server::handlers::ClientError{server::handlers::ExternalBody{ - fmt::format("Unsupported method {}", request.GetMethod())}}; - } + clickhouse_client_{context.FindComponent("clickhouse-database").GetCluster()} {} + +std::string KeyValue::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const { + const auto& key = request.GetArg("key"); + if (key.empty()) { + throw server::handlers::ClientError{server::handlers::ExternalBody{"No 'key' query argument"}}; + } + + switch (request.GetMethod()) { + case server::http::HttpMethod::kGet: + return GetValue(key, request); + case server::http::HttpMethod::kPost: + return PostValue(key, request); + case server::http::HttpMethod::kDelete: + return DeleteValue(key); + default: + throw server::handlers::ClientError{ + server::handlers::ExternalBody{fmt::format("Unsupported method {}", request.GetMethod())}}; + } } -std::string KeyValue::GetValue(std::string_view key, - const server::http::HttpRequest& request) const { - const auto result = - clickhouse_client_ - ->Execute(cc_, "SELECT key, value FROM kv WHERE key = {}", key) - .AsContainer>(); - if (result.size() != 1) { - request.SetResponseStatus(server::http::HttpStatus::kNotFound); - return {}; - } +std::string KeyValue::GetValue(std::string_view key, const server::http::HttpRequest& request) const { + const auto result = clickhouse_client_->Execute(cc_, "SELECT key, value FROM kv WHERE key = {}", key) + .AsContainer>(); + if (result.size() != 1) { + request.SetResponseStatus(server::http::HttpStatus::kNotFound); + return {}; + } - return result.front().value; + return result.front().value; } -std::string KeyValue::PostValue( - std::string_view key, const server::http::HttpRequest& request) const { - const auto& value = request.GetArg("value"); - if (value.empty()) { - throw server::handlers::ClientError{ - server::handlers::ExternalBody{"No 'value' query argument"}}; - } +std::string KeyValue::PostValue(std::string_view key, const server::http::HttpRequest& request) const { + const auto& value = request.GetArg("value"); + if (value.empty()) { + throw server::handlers::ClientError{server::handlers::ExternalBody{"No 'value' query argument"}}; + } - const std::vector rows{{std::string{key}, value}}; - clickhouse_client_->InsertRows(cc_, "kv", {"key", "value"}, rows); + const std::vector rows{{std::string{key}, value}}; + clickhouse_client_->InsertRows(cc_, "kv", {"key", "value"}, rows); - request.SetResponseStatus(server::http::HttpStatus::kCreated); - return value; + request.SetResponseStatus(server::http::HttpStatus::kCreated); + return value; } std::string KeyValue::DeleteValue(std::string_view key) const { - clickhouse_client_->Execute(cc_, "ALTER TABLE kv DELETE WHERE key={}", key); + clickhouse_client_->Execute(cc_, "ALTER TABLE kv DELETE WHERE key={}", key); - return {}; + return {}; } -formats::json::Value Serialize(const PairOfUuids& value, - formats::serialize::To) { - return formats::json::MakeObject( - "uuid_mismatched", utils::ToString(value.uuid_mismatched), "uuid_correct", - utils::ToString(value.uuid_correct)); +formats::json::Value Serialize(const PairOfUuids& value, formats::serialize::To) { + return formats::json::MakeObject( + "uuid_mismatched", utils::ToString(value.uuid_mismatched), "uuid_correct", utils::ToString(value.uuid_correct) + ); } -PairOfUuids Parse(const formats::json::Value& value, - formats::parse::To) { - PairOfUuids result{}; - result.uuid_mismatched = - utils::BoostUuidFromString(value["uuid_mismatched"].As()); - result.uuid_correct = - utils::BoostUuidFromString(value["uuid_correct"].As()); +PairOfUuids Parse(const formats::json::Value& value, formats::parse::To) { + PairOfUuids result{}; + result.uuid_mismatched = utils::BoostUuidFromString(value["uuid_mismatched"].As()); + result.uuid_correct = utils::BoostUuidFromString(value["uuid_correct"].As()); - return result; + return result; } class UuidsHandler final : public server::handlers::HttpHandlerJsonBase { - public: - static constexpr std::string_view kName{"handler-uuids"}; - - UuidsHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : server::handlers::HttpHandlerJsonBase{config, context}, - clickhouse_client_{ - context.FindComponent("clickhouse-database") - .GetCluster()} {} - - formats::json::Value HandleRequestJsonThrow( - const server::http::HttpRequest& request, - const formats::json::Value& request_json, - server::request::RequestContext&) const override { - switch (request.GetMethod()) { - case server::http::HttpMethod::kPost: - return PostValue(request_json); - case server::http::HttpMethod::kGet: - return GetValues(); - default: - throw server::handlers::ClientError{server::handlers::ExternalBody{ - fmt::format("Unsupported method {}", request.GetMethod())}}; +public: + static constexpr std::string_view kName{"handler-uuids"}; + + UuidsHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : server::handlers::HttpHandlerJsonBase{config, context}, + clickhouse_client_{context.FindComponent("clickhouse-database").GetCluster()} {} + + formats::json::Value + HandleRequestJsonThrow(const server::http::HttpRequest& request, const formats::json::Value& request_json, server::request::RequestContext&) + const override { + switch (request.GetMethod()) { + case server::http::HttpMethod::kPost: + return PostValue(request_json); + case server::http::HttpMethod::kGet: + return GetValues(); + default: + throw server::handlers::ClientError{ + server::handlers::ExternalBody{fmt::format("Unsupported method {}", request.GetMethod())}}; + } } - } - private: - formats::json::Value PostValue( - const formats::json::Value& request_json) const { - const auto pair_of_uuids = request_json.As(); - const std::vector rows{ - {pair_of_uuids.uuid_mismatched, pair_of_uuids.uuid_correct}}; - clickhouse_client_->InsertRows(cc_, "uuids", - {"uuid_mismatched", "uuid_correct"}, rows); +private: + formats::json::Value PostValue(const formats::json::Value& request_json) const { + const auto pair_of_uuids = request_json.As(); + const std::vector rows{{pair_of_uuids.uuid_mismatched, pair_of_uuids.uuid_correct}}; + clickhouse_client_->InsertRows(cc_, "uuids", {"uuid_mismatched", "uuid_correct"}, rows); - return {}; - } + return {}; + } - formats::json::Value GetValues() const { - const auto rows = - clickhouse_client_ - ->Execute(cc_, "SELECT uuid_mismatched, uuid_correct FROM uuids") - .AsRows(); + formats::json::Value GetValues() const { + const auto rows = + clickhouse_client_->Execute(cc_, "SELECT uuid_mismatched, uuid_correct FROM uuids").AsRows(); - return formats::json::ValueBuilder{rows}.ExtractValue(); - } + return formats::json::ValueBuilder{rows}.ExtractValue(); + } - storages::clickhouse::ClusterPtr clickhouse_client_; - storages::clickhouse::CommandControl cc_{kDefaultTimeout}; + storages::clickhouse::ClusterPtr clickhouse_client_; + storages::clickhouse::CommandControl cc_{kDefaultTimeout}; }; } // namespace chaos int main(int argc, char* argv[]) { - const auto component_list = - components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append("clickhouse-database"); - - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append("clickhouse-database"); + + return utils::DaemonMain(argc, argv, component_list); } diff --git a/clickhouse/functional_tests/metrics/service.cpp b/clickhouse/functional_tests/metrics/service.cpp index 09890efbaca3..9ce2eda225b6 100644 --- a/clickhouse/functional_tests/metrics/service.cpp +++ b/clickhouse/functional_tests/metrics/service.cpp @@ -27,99 +27,91 @@ namespace clickhouse::metrics { struct KeyValueRow { - std::string key; - std::string value; - std::chrono::system_clock::time_point updated; + std::string key; + std::string value; + std::chrono::system_clock::time_point updated; }; struct KeyValue { - std::vector keys; - std::vector values; - std::vector updates; + std::vector keys; + std::vector values; + std::vector updates; }; struct Result { - std::vector values; + std::vector values; }; -class HandlerMetricsClickhouse final - : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-metrics-clickhouse"; +class HandlerMetricsClickhouse final : public server::handlers::HttpHandlerBase { +public: + static constexpr std::string_view kName = "handler-metrics-clickhouse"; - HandlerMetricsClickhouse(const components::ComponentConfig& config, - const components::ComponentContext& context); + HandlerMetricsClickhouse(const components::ComponentConfig& config, const components::ComponentContext& context); - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext& context) const override; + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext& context) + const override; - private: - storages::clickhouse::ClusterPtr clickhouse_; +private: + storages::clickhouse::ClusterPtr clickhouse_; }; HandlerMetricsClickhouse::HandlerMetricsClickhouse( const components::ComponentConfig& config, - const components::ComponentContext& context) + const components::ComponentContext& context +) : server::handlers::HttpHandlerBase{config, context}, - clickhouse_{ - context.FindComponent("clickhouse-database") - .GetCluster()} {} - -std::string HandlerMetricsClickhouse::HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const { - const auto& key = request.GetArg("key"); - const auto& value = request.GetArg("value"); - if (key.empty()) { - request.GetHttpResponse().SetStatus(server::http::HttpStatus::kBadRequest); - } - - if (request.GetMethod() == server::http::HttpMethod::kPost) { - if (value.empty()) { - request.GetHttpResponse().SetStatus( - server::http::HttpStatus::kBadRequest); - return "Bad Request"; + clickhouse_{context.FindComponent("clickhouse-database").GetCluster()} {} + +std::string +HandlerMetricsClickhouse::HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const { + const auto& key = request.GetArg("key"); + const auto& value = request.GetArg("value"); + if (key.empty()) { + request.GetHttpResponse().SetStatus(server::http::HttpStatus::kBadRequest); } - KeyValue data; - data.keys.push_back(key); - data.values.push_back(value); - data.updates.push_back(utils::datetime::Now()); - clickhouse_->Insert("key_value_table", {"key", "value", "updated"}, data); - } else if (request.GetMethod() == server::http::HttpMethod::kDelete) { - const storages::clickhouse::Query query{ - "ALTER TABLE key_value_table DELETE WHERE key={}"}; - clickhouse_->Execute(query, key); - return fmt::format("Deleted by key: {}", key); - } - const storages::clickhouse::Query query{ - "SELECT key, value, updated FROM key_value_table WHERE key={}"}; - - const auto result = clickhouse_->Execute(query, key).As(); - - std::string ret{}; - if (!result.keys.empty()) { - ret += fmt::format("{}: {}", result.keys.back(), result.values.back()); - } - return ret; + + if (request.GetMethod() == server::http::HttpMethod::kPost) { + if (value.empty()) { + request.GetHttpResponse().SetStatus(server::http::HttpStatus::kBadRequest); + return "Bad Request"; + } + KeyValue data; + data.keys.push_back(key); + data.values.push_back(value); + data.updates.push_back(utils::datetime::Now()); + clickhouse_->Insert("key_value_table", {"key", "value", "updated"}, data); + } else if (request.GetMethod() == server::http::HttpMethod::kDelete) { + const storages::clickhouse::Query query{"ALTER TABLE key_value_table DELETE WHERE key={}"}; + clickhouse_->Execute(query, key); + return fmt::format("Deleted by key: {}", key); + } + const storages::clickhouse::Query query{"SELECT key, value, updated FROM key_value_table WHERE key={}"}; + + const auto result = clickhouse_->Execute(query, key).As(); + + std::string ret{}; + if (!result.keys.empty()) { + ret += fmt::format("{}: {}", result.keys.back(), result.values.back()); + } + return ret; } } // namespace clickhouse::metrics int main(int argc, char* argv[]) { - const auto components_list = - components::MinimalServerComponentList() - .Append() - .Append() - .Append("clickhouse-database") - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - - return utils::DaemonMain(argc, argv, components_list); + const auto components_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append("clickhouse-database") + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + + return utils::DaemonMain(argc, argv, components_list); } USERVER_NAMESPACE_BEGIN @@ -127,19 +119,17 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse<::clickhouse::metrics::KeyValue> final { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse<::clickhouse::metrics::KeyValueRow> final { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse<::clickhouse::metrics::Result> final { - using mapped_type = std::tuple<::clickhouse::metrics::KeyValue>; + using mapped_type = std::tuple<::clickhouse::metrics::KeyValue>; }; USERVER_NAMESPACE_END diff --git a/clickhouse/include/userver/storages/clickhouse/cluster.hpp b/clickhouse/include/userver/storages/clickhouse/cluster.hpp index ed7a2211052a..738b078afe87 100644 --- a/clickhouse/include/userver/storages/clickhouse/cluster.hpp +++ b/clickhouse/include/userver/storages/clickhouse/cluster.hpp @@ -34,159 +34,164 @@ struct ClickhouseSettings; /// /// Usually retrieved from components::ClickHouse component. class Cluster final { - public: - /// Cluster constructor - /// @param resolver asynchronous DNS resolver - /// @param settings struct with settings fields: - /// endpoints - list of endpoints (host + port) - /// auth_settings - authentication settings (user, password, database) - /// @param config components::ClickHouse component config - Cluster(clients::dns::Resolver& resolver, - const impl::ClickhouseSettings& settings, - const components::ComponentConfig& config); - /// Cluster destructor - ~Cluster(); - - Cluster(const Cluster&) = delete; - - /// @brief Execute a statement at some host of the cluster - /// with args as query parameters. - template - ExecutionResult Execute(const Query& query, const Args&... args) const; - - /// @brief Execute a statement with specified command control settings - /// at some host of the cluster with args as query parameters. - template - ExecutionResult Execute(OptionalCommandControl, const Query& query, - const Args&... args) const; - - /// @brief Insert data at some host of the cluster; - /// `T` is expected to be a struct of vectors of same length. - /// @param table_name table to insert into - /// @param column_names names of columns of the table - /// @param data data to insert - /// See @ref clickhouse_io for better understanding of T's requirements. - template - void Insert(const std::string& table_name, - const std::vector& column_names, - const T& data) const; - - /// @brief Insert data with specified command control settings - /// at some host of the cluster; - /// `T` is expected to be a struct of vectors of same length. - /// @param table_name table to insert into - /// @param column_names names of columns of the table - /// @param data data to insert - /// See @ref clickhouse_io for better understanding of T's requirements. - template - void Insert(OptionalCommandControl, const std::string& table_name, - const std::vector& column_names, - const T& data) const; - - /// @brief Insert data at some host of the cluster; - /// `Container` is expected to be an iterable of clickhouse-mapped type. - /// @param table_name table to insert into - /// @param column_names names of columns of the table - /// @param data data to insert - /// See @ref clickhouse_io for better understanding of - /// `Container::value_type`'s requirements. - /// @note This version of insert is less performant than `Insert` (it makes 2 - /// copies of data instead of just 1 copy) due to implementation details, so - /// consider using less convenient but more performant analogue if performance - /// is a concern. - template - void InsertRows(const std::string& table_name, - const std::vector& column_names, - const Container& data) const; - - /// @brief Insert data with specified command control settings - /// at some host of the cluster; - /// `Container` is expected to be an iterable of clickhouse-mapped type. - /// @param table_name table to insert into - /// @param column_names names of columns of the table - /// @param data data to insert - /// See @ref clickhouse_io for better understanding of - /// `Container::value_type`'s requirements. - /// @note This version of insert is less performant than `Insert` (it makes 2 - /// copies of data instead of just 1 copy) due to implementation details, so - /// consider using less convenient but more performant analogue if performance - /// is a concern. - template - void InsertRows(OptionalCommandControl, const std::string& table_name, - const std::vector& column_names, - const Container& data) const; - - /// Write cluster statistics - void WriteStatistics( - USERVER_NAMESPACE::utils::statistics::Writer& writer) const; - - /// Exception that is thrown if all specified endpoints are unavailable - class NoAvailablePoolError : public std::runtime_error { - using std::runtime_error::runtime_error; - }; - - private: - void DoInsert(OptionalCommandControl, - const impl::InsertionRequest& request) const; - - ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const; - - const impl::Pool& GetPool() const; - - std::vector pools_; - mutable std::atomic current_pool_ind_{0}; +public: + /// Cluster constructor + /// @param resolver asynchronous DNS resolver + /// @param settings struct with settings fields: + /// endpoints - list of endpoints (host + port) + /// auth_settings - authentication settings (user, password, database) + /// @param config components::ClickHouse component config + Cluster( + clients::dns::Resolver& resolver, + const impl::ClickhouseSettings& settings, + const components::ComponentConfig& config + ); + /// Cluster destructor + ~Cluster(); + + Cluster(const Cluster&) = delete; + + /// @brief Execute a statement at some host of the cluster + /// with args as query parameters. + template + ExecutionResult Execute(const Query& query, const Args&... args) const; + + /// @brief Execute a statement with specified command control settings + /// at some host of the cluster with args as query parameters. + template + ExecutionResult Execute(OptionalCommandControl, const Query& query, const Args&... args) const; + + /// @brief Insert data at some host of the cluster; + /// `T` is expected to be a struct of vectors of same length. + /// @param table_name table to insert into + /// @param column_names names of columns of the table + /// @param data data to insert + /// See @ref clickhouse_io for better understanding of T's requirements. + template + void Insert(const std::string& table_name, const std::vector& column_names, const T& data) const; + + /// @brief Insert data with specified command control settings + /// at some host of the cluster; + /// `T` is expected to be a struct of vectors of same length. + /// @param table_name table to insert into + /// @param column_names names of columns of the table + /// @param data data to insert + /// See @ref clickhouse_io for better understanding of T's requirements. + template + void Insert( + OptionalCommandControl, + const std::string& table_name, + const std::vector& column_names, + const T& data + ) const; + + /// @brief Insert data at some host of the cluster; + /// `Container` is expected to be an iterable of clickhouse-mapped type. + /// @param table_name table to insert into + /// @param column_names names of columns of the table + /// @param data data to insert + /// See @ref clickhouse_io for better understanding of + /// `Container::value_type`'s requirements. + /// @note This version of insert is less performant than `Insert` (it makes 2 + /// copies of data instead of just 1 copy) due to implementation details, so + /// consider using less convenient but more performant analogue if performance + /// is a concern. + template + void InsertRows( + const std::string& table_name, + const std::vector& column_names, + const Container& data + ) const; + + /// @brief Insert data with specified command control settings + /// at some host of the cluster; + /// `Container` is expected to be an iterable of clickhouse-mapped type. + /// @param table_name table to insert into + /// @param column_names names of columns of the table + /// @param data data to insert + /// See @ref clickhouse_io for better understanding of + /// `Container::value_type`'s requirements. + /// @note This version of insert is less performant than `Insert` (it makes 2 + /// copies of data instead of just 1 copy) due to implementation details, so + /// consider using less convenient but more performant analogue if performance + /// is a concern. + template + void InsertRows( + OptionalCommandControl, + const std::string& table_name, + const std::vector& column_names, + const Container& data + ) const; + + /// Write cluster statistics + void WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const; + + /// Exception that is thrown if all specified endpoints are unavailable + class NoAvailablePoolError : public std::runtime_error { + using std::runtime_error::runtime_error; + }; + +private: + void DoInsert(OptionalCommandControl, const impl::InsertionRequest& request) const; + + ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const; + + const impl::Pool& GetPool() const; + + std::vector pools_; + mutable std::atomic current_pool_ind_{0}; }; template -void Cluster::Insert(const std::string& table_name, - const std::vector& column_names, - const T& data) const { - Insert(OptionalCommandControl{}, table_name, column_names, data); +void Cluster::Insert(const std::string& table_name, const std::vector& column_names, const T& data) + const { + Insert(OptionalCommandControl{}, table_name, column_names, data); } template -void Cluster::Insert(OptionalCommandControl optional_cc, - const std::string& table_name, - const std::vector& column_names, - const T& data) const { - const auto request = - impl::InsertionRequest::Create(table_name, column_names, data); - - DoInsert(optional_cc, request); +void Cluster::Insert( + OptionalCommandControl optional_cc, + const std::string& table_name, + const std::vector& column_names, + const T& data +) const { + const auto request = impl::InsertionRequest::Create(table_name, column_names, data); + + DoInsert(optional_cc, request); } template -void Cluster::InsertRows(const std::string& table_name, - const std::vector& column_names, - const Container& data) const { - InsertRows(OptionalCommandControl{}, table_name, column_names, data); +void Cluster::InsertRows( + const std::string& table_name, + const std::vector& column_names, + const Container& data +) const { + InsertRows(OptionalCommandControl{}, table_name, column_names, data); } template -void Cluster::InsertRows(OptionalCommandControl optional_cc, - const std::string& table_name, - const std::vector& column_names, - const Container& data) const { - if (data.empty()) return; +void Cluster::InsertRows( + OptionalCommandControl optional_cc, + const std::string& table_name, + const std::vector& column_names, + const Container& data +) const { + if (data.empty()) return; - const auto request = - impl::InsertionRequest::CreateFromRows(table_name, column_names, data); + const auto request = impl::InsertionRequest::CreateFromRows(table_name, column_names, data); - DoInsert(optional_cc, request); + DoInsert(optional_cc, request); } template -ExecutionResult Cluster::Execute(const Query& query, - const Args&... args) const { - return Execute(OptionalCommandControl{}, query, args...); +ExecutionResult Cluster::Execute(const Query& query, const Args&... args) const { + return Execute(OptionalCommandControl{}, query, args...); } template -ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc, - const Query& query, - const Args&... args) const { - const auto formatted_query = query.WithArgs(args...); - return DoExecute(optional_cc, formatted_query); +ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc, const Query& query, const Args&... args) const { + const auto formatted_query = query.WithArgs(args...); + return DoExecute(optional_cc, formatted_query); } } // namespace storages::clickhouse diff --git a/clickhouse/include/userver/storages/clickhouse/component.hpp b/clickhouse/include/userver/storages/clickhouse/component.hpp index 02890d825f84..6975b9789c2e 100644 --- a/clickhouse/include/userver/storages/clickhouse/component.hpp +++ b/clickhouse/include/userver/storages/clickhouse/component.hpp @@ -55,22 +55,22 @@ namespace components { // clang-format on class ClickHouse : public ComponentBase { - public: - /// Component constructor - ClickHouse(const ComponentConfig&, const ComponentContext&); - /// Component destructor - ~ClickHouse() override; +public: + /// Component constructor + ClickHouse(const ComponentConfig&, const ComponentContext&); + /// Component destructor + ~ClickHouse() override; - /// Cluster accessor - std::shared_ptr GetCluster() const; + /// Cluster accessor + std::shared_ptr GetCluster() const; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - clients::dns::Component& dns_; +private: + clients::dns::Component& dns_; - std::shared_ptr cluster_; - utils::statistics::Entry statistics_holder_; + std::shared_ptr cluster_; + utils::statistics::Entry statistics_holder_; }; template <> diff --git a/clickhouse/include/userver/storages/clickhouse/execution_result.hpp b/clickhouse/include/userver/storages/clickhouse/execution_result.hpp index b67c49e9d411..c4661181dece 100644 --- a/clickhouse/include/userver/storages/clickhouse/execution_result.hpp +++ b/clickhouse/include/userver/storages/clickhouse/execution_result.hpp @@ -30,74 +30,74 @@ namespace storages::clickhouse { // clang-format on class ExecutionResult final { - public: - explicit ExecutionResult(impl::BlockWrapperPtr); - ExecutionResult(ExecutionResult&&) noexcept; - ~ExecutionResult(); - - /// Returns number of columns in underlying block. - size_t GetColumnsCount() const; - - /// Returns number of rows in underlying block columns. - size_t GetRowsCount() const; - - /// Converts underlying block to strongly-typed struct of vectors. - /// See @ref clickhouse_io for better understanding of `T`'s requirements. - template - T As() &&; - - /// Converts underlying block to iterable of strongly-typed struct. - /// See @ref clickhouse_io for better understanding of `T`'s requirements. - template - auto AsRows() &&; - - /// Converts underlying block to strongly-typed container. - /// See @ref clickhouse_io for better understanding - /// of `Container::value_type`'s requirements. - template - Container AsContainer() &&; - - private: - impl::BlockWrapperPtr block_; +public: + explicit ExecutionResult(impl::BlockWrapperPtr); + ExecutionResult(ExecutionResult&&) noexcept; + ~ExecutionResult(); + + /// Returns number of columns in underlying block. + size_t GetColumnsCount() const; + + /// Returns number of rows in underlying block columns. + size_t GetRowsCount() const; + + /// Converts underlying block to strongly-typed struct of vectors. + /// See @ref clickhouse_io for better understanding of `T`'s requirements. + template + T As() &&; + + /// Converts underlying block to iterable of strongly-typed struct. + /// See @ref clickhouse_io for better understanding of `T`'s requirements. + template + auto AsRows() &&; + + /// Converts underlying block to strongly-typed container. + /// See @ref clickhouse_io for better understanding + /// of `Container::value_type`'s requirements. + template + Container AsContainer() &&; + +private: + impl::BlockWrapperPtr block_; }; template T ExecutionResult::As() && { - UASSERT(block_); - T result{}; - io::impl::ValidateColumnsMapping(result); - io::impl::ValidateColumnsCount(GetColumnsCount()); + UASSERT(block_); + T result{}; + io::impl::ValidateColumnsMapping(result); + io::impl::ValidateColumnsCount(GetColumnsCount()); - using MappedType = typename io::CppToClickhouse::mapped_type; - io::ColumnsMapper mapper{*block_}; + using MappedType = typename io::CppToClickhouse::mapped_type; + io::ColumnsMapper mapper{*block_}; - boost::pfr::for_each_field(result, mapper); + boost::pfr::for_each_field(result, mapper); - return result; + return result; } template auto ExecutionResult::AsRows() && { - UASSERT(block_); - io::impl::ValidateRowsMapping(); - io::impl::ValidateColumnsCount(GetColumnsCount()); + UASSERT(block_); + io::impl::ValidateRowsMapping(); + io::impl::ValidateColumnsCount(GetColumnsCount()); - return io::RowsMapper{std::move(block_)}; + return io::RowsMapper{std::move(block_)}; } template Container ExecutionResult::AsContainer() && { - UASSERT(block_); - using Row = typename Container::value_type; + UASSERT(block_); + using Row = typename Container::value_type; - Container result; - if constexpr (io::traits::kIsReservable) { - result.reserve(GetRowsCount()); - } + Container result; + if constexpr (io::traits::kIsReservable) { + result.reserve(GetRowsCount()); + } - auto rows = std::move(*this).AsRows(); - std::move(rows.begin(), rows.end(), io::traits::Inserter(result)); - return result; + auto rows = std::move(*this).AsRows(); + std::move(rows.begin(), rows.end(), io::traits::Inserter(result)); + return result; } } // namespace storages::clickhouse diff --git a/clickhouse/include/userver/storages/clickhouse/impl/block_wrapper_fwd.hpp b/clickhouse/include/userver/storages/clickhouse/impl/block_wrapper_fwd.hpp index 5f052fca857a..4cac47b39ba8 100644 --- a/clickhouse/include/userver/storages/clickhouse/impl/block_wrapper_fwd.hpp +++ b/clickhouse/include/userver/storages/clickhouse/impl/block_wrapper_fwd.hpp @@ -8,7 +8,7 @@ namespace storages::clickhouse::impl { class BlockWrapper; struct BlockWrapperDeleter final { - void operator()(BlockWrapper* ptr) const noexcept; + void operator()(BlockWrapper* ptr) const noexcept; }; using BlockWrapperPtr = std::unique_ptr; diff --git a/clickhouse/include/userver/storages/clickhouse/impl/insertion_request.hpp b/clickhouse/include/userver/storages/clickhouse/impl/insertion_request.hpp index d8bbcbf45503..ede4fc2a49e8 100644 --- a/clickhouse/include/userver/storages/clickhouse/impl/insertion_request.hpp +++ b/clickhouse/include/userver/storages/clickhouse/impl/insertion_request.hpp @@ -20,120 +20,116 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { class InsertionRequest final { - public: - InsertionRequest(const std::string& table_name, - const std::vector& column_names); - InsertionRequest(InsertionRequest&&) noexcept; - ~InsertionRequest(); - - template - static InsertionRequest Create( - const std::string& table_name, - const std::vector& column_names, const T& data); - - template - static InsertionRequest CreateFromRows( - const std::string& table_name, - const std::vector& column_names, const Container& data); - - const std::string& GetTableName() const; - - const impl::BlockWrapper& GetBlock() const; - - private: - template - class ColumnsMapper final { - public: - ColumnsMapper(impl::BlockWrapper& block, - const std::vector& column_names) - : block_{block}, column_names_{column_names} {} - - template - void operator()(const Field& field, - std::integral_constant i) { - using ColumnType = std::tuple_element_t; - static_assert(std::is_same_v); - - io::columns::AppendWrappedColumn(block_, ColumnType::Serialize(field), - column_names_[i], i); - } - - private: - impl::BlockWrapper& block_; +public: + InsertionRequest(const std::string& table_name, const std::vector& column_names); + InsertionRequest(InsertionRequest&&) noexcept; + ~InsertionRequest(); + + template + static InsertionRequest + Create(const std::string& table_name, const std::vector& column_names, const T& data); + + template + static InsertionRequest CreateFromRows( + const std::string& table_name, + const std::vector& column_names, + const Container& data + ); + + const std::string& GetTableName() const; + + const impl::BlockWrapper& GetBlock() const; + +private: + template + class ColumnsMapper final { + public: + ColumnsMapper(impl::BlockWrapper& block, const std::vector& column_names) + : block_{block}, column_names_{column_names} {} + + template + void operator()(const Field& field, std::integral_constant i) { + using ColumnType = std::tuple_element_t; + static_assert(std::is_same_v); + + io::columns::AppendWrappedColumn(block_, ColumnType::Serialize(field), column_names_[i], i); + } + + private: + impl::BlockWrapper& block_; + const std::vector& column_names_; + }; + + template + class RowsMapper final { + public: + RowsMapper(impl::BlockWrapper& block, const std::vector& column_names, const Container& data) + : block_{block}, column_names_{column_names}, data_{data} {} + + template + void operator()(const Field&, std::integral_constant i) { + using ColumnType = std::tuple_element_t; + static_assert(std::is_same_v); + + std::vector column_data; + column_data.reserve(data_.size()); + for (const auto& row : data_) { + column_data.emplace_back(boost::pfr::get(row)); + } + + io::columns::AppendWrappedColumn(block_, ColumnType::Serialize(column_data), column_names_[i], i); + } + + private: + impl::BlockWrapper& block_; + const std::vector& column_names_; + const Container& data_; + }; + + const std::string& table_name_; const std::vector& column_names_; - }; - - template - class RowsMapper final { - public: - RowsMapper(impl::BlockWrapper& block, - const std::vector& column_names, - const Container& data) - : block_{block}, column_names_{column_names}, data_{data} {} - - template - void operator()(const Field&, std::integral_constant i) { - using ColumnType = std::tuple_element_t; - static_assert(std::is_same_v); - - std::vector column_data; - column_data.reserve(data_.size()); - for (const auto& row : data_) { - column_data.emplace_back(boost::pfr::get(row)); - } - - io::columns::AppendWrappedColumn( - block_, ColumnType::Serialize(column_data), column_names_[i], i); - } - - private: - impl::BlockWrapper& block_; - const std::vector& column_names_; - const Container& data_; - }; - - const std::string& table_name_; - const std::vector& column_names_; - std::unique_ptr block_; + std::unique_ptr block_; }; template InsertionRequest InsertionRequest::Create( const std::string& table_name, - const std::vector& column_names, const T& data) { - io::impl::ValidateColumnsMapping(data); - io::impl::ValidateRowsCount(data); - // TODO : static_assert this when std::span comes - io::impl::ValidateColumnsCount(column_names.size()); - - InsertionRequest request{table_name, column_names}; - using MappedType = typename io::CppToClickhouse::mapped_type; - auto mapper = InsertionRequest::ColumnsMapper{ - *request.block_, request.column_names_}; - - boost::pfr::for_each_field(data, mapper); - return request; + const std::vector& column_names, + const T& data +) { + io::impl::ValidateColumnsMapping(data); + io::impl::ValidateRowsCount(data); + // TODO : static_assert this when std::span comes + io::impl::ValidateColumnsCount(column_names.size()); + + InsertionRequest request{table_name, column_names}; + using MappedType = typename io::CppToClickhouse::mapped_type; + auto mapper = InsertionRequest::ColumnsMapper{*request.block_, request.column_names_}; + + boost::pfr::for_each_field(data, mapper); + return request; } template InsertionRequest InsertionRequest::CreateFromRows( const std::string& table_name, - const std::vector& column_names, const Container& data) { - using T = typename Container::value_type; - io::impl::CommonValidateMapping(); - // TODO : static_assert this when std::span comes - io::impl::ValidateColumnsCount(column_names.size()); - - UINVARIANT(!data.empty(), "An attempt to insert empty chunk of data"); - - InsertionRequest request{table_name, column_names}; - using MappedType = typename io::CppToClickhouse::mapped_type; - auto mapper = InsertionRequest::RowsMapper{ - *request.block_, request.column_names_, data}; - - boost::pfr::for_each_field(data.front(), mapper); - return request; + const std::vector& column_names, + const Container& data +) { + using T = typename Container::value_type; + io::impl::CommonValidateMapping(); + // TODO : static_assert this when std::span comes + io::impl::ValidateColumnsCount(column_names.size()); + + UINVARIANT(!data.empty(), "An attempt to insert empty chunk of data"); + + InsertionRequest request{table_name, column_names}; + using MappedType = typename io::CppToClickhouse::mapped_type; + auto mapper = InsertionRequest::RowsMapper{*request.block_, request.column_names_, data}; + + boost::pfr::for_each_field(data.front(), mapper); + return request; } } // namespace storages::clickhouse::impl diff --git a/clickhouse/include/userver/storages/clickhouse/impl/iterators_helper.hpp b/clickhouse/include/userver/storages/clickhouse/impl/iterators_helper.hpp index 69ce69366540..d421545e343c 100644 --- a/clickhouse/include/userver/storages/clickhouse/impl/iterators_helper.hpp +++ b/clickhouse/include/userver/storages/clickhouse/impl/iterators_helper.hpp @@ -15,46 +15,45 @@ struct IteratorsTuple; template struct IteratorsTuple> { - using type = std::tuple; + using type = std::tuple; }; template using IteratorsTupleT = typename IteratorsTuple::type; -template >> +template >> class IteratorsHelper; template class IteratorsHelper> { - public: - static void Init(IteratorsTupleT& begin_iterators, - IteratorsTupleT& end_iterators, - clickhouse::impl::BlockWrapper& block) { - (..., (std::get(begin_iterators) = GetBegin(block))); - (..., (std::get(end_iterators) = GetEnd(block))); - } - - static void PrefixIncrement(IteratorsTupleT& iterators) { - (..., ++std::get(iterators)); - } - - static IteratorsTupleT PostfixIncrement(IteratorsTupleT& iterators) { - return IteratorsTupleT{std::get(iterators)++...}; - } - - private: - template - static auto GetBegin(clickhouse::impl::BlockWrapper& block) { - using ColumnType = std::tuple_element_t; - return ColumnType{io::columns::GetWrappedColumn(block, Index)}.begin(); - } - - template - static auto GetEnd(clickhouse::impl::BlockWrapper& block) { - using ColumnType = std::tuple_element_t; - return ColumnType{io::columns::GetWrappedColumn(block, Index)}.end(); - } +public: + static void Init( + IteratorsTupleT& begin_iterators, + IteratorsTupleT& end_iterators, + clickhouse::impl::BlockWrapper& block + ) { + (..., (std::get(begin_iterators) = GetBegin(block))); + (..., (std::get(end_iterators) = GetEnd(block))); + } + + static void PrefixIncrement(IteratorsTupleT& iterators) { (..., ++std::get(iterators)); } + + static IteratorsTupleT PostfixIncrement(IteratorsTupleT& iterators) { + return IteratorsTupleT{std::get(iterators)++...}; + } + +private: + template + static auto GetBegin(clickhouse::impl::BlockWrapper& block) { + using ColumnType = std::tuple_element_t; + return ColumnType{io::columns::GetWrappedColumn(block, Index)}.begin(); + } + + template + static auto GetEnd(clickhouse::impl::BlockWrapper& block) { + using ColumnType = std::tuple_element_t; + return ColumnType{io::columns::GetWrappedColumn(block, Index)}.end(); + } }; } // namespace storages::clickhouse::impl diff --git a/clickhouse/include/userver/storages/clickhouse/impl/pool.hpp b/clickhouse/include/userver/storages/clickhouse/impl/pool.hpp index a9fe65d39528..4653519aaef4 100644 --- a/clickhouse/include/userver/storages/clickhouse/impl/pool.hpp +++ b/clickhouse/include/userver/storages/clickhouse/impl/pool.hpp @@ -20,24 +20,23 @@ struct PoolSettings; class InsertionRequest; class Pool final { - public: - Pool(clients::dns::Resolver&, PoolSettings&&); - ~Pool(); +public: + Pool(clients::dns::Resolver&, PoolSettings&&); + ~Pool(); - Pool(const Pool&) = delete; - Pool(Pool&&) = default; + Pool(const Pool&) = delete; + Pool(Pool&&) = default; - ExecutionResult Execute(OptionalCommandControl, const Query& query) const; + ExecutionResult Execute(OptionalCommandControl, const Query& query) const; - void Insert(OptionalCommandControl, const InsertionRequest& request) const; + void Insert(OptionalCommandControl, const InsertionRequest& request) const; - void WriteStatistics( - USERVER_NAMESPACE::utils::statistics::Writer& writer) const; + void WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const; - bool IsAvailable() const; + bool IsAvailable() const; - private: - std::shared_ptr impl_; +private: + std::shared_ptr impl_; }; } // namespace impl diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/array_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/array_column.hpp index 48fc787798e3..9147fa82f03e 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/array_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/array_column.hpp @@ -14,8 +14,8 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::columns { struct ArrayColumnMeta final { - ColumnRef data; - ColumnRef offsets; + ColumnRef data; + ColumnRef offsets; }; ColumnRef ConvertMetaToColumn(ArrayColumnMeta&& meta); @@ -25,126 +25,116 @@ ColumnRef ExtractArrayItem(const ColumnRef& column, std::size_t ind); /// where T is a ClickhouseColumn as well template class ArrayColumn final : public ClickhouseColumn> { - public: - using cpp_type = std::vector; - using container_type = std::vector; - - ArrayColumn(ColumnRef column); - - class ArrayDataHolder final { - public: - ArrayDataHolder() = default; - ArrayDataHolder( - typename ColumnIterator>::IteratorPosition iter_position, - ColumnRef&& column); - - ArrayDataHolder operator++(int); - ArrayDataHolder& operator++(); - cpp_type& UpdateValue(); - - bool operator==(const ArrayDataHolder& other) const; - - private: - ColumnRef inner_{}; - std::size_t ind_{0}; - std::optional current_value_ = std::nullopt; - }; - using iterator_data = ArrayDataHolder; - - static ColumnRef Serialize(const container_type& from); - static cpp_type RetrieveElement(const ColumnRef& ref, std::size_t ind); +public: + using cpp_type = std::vector; + using container_type = std::vector; + + ArrayColumn(ColumnRef column); + + class ArrayDataHolder final { + public: + ArrayDataHolder() = default; + ArrayDataHolder(typename ColumnIterator>::IteratorPosition iter_position, ColumnRef&& column); + + ArrayDataHolder operator++(int); + ArrayDataHolder& operator++(); + cpp_type& UpdateValue(); + + bool operator==(const ArrayDataHolder& other) const; + + private: + ColumnRef inner_{}; + std::size_t ind_{0}; + std::optional current_value_ = std::nullopt; + }; + using iterator_data = ArrayDataHolder; + + static ColumnRef Serialize(const container_type& from); + static cpp_type RetrieveElement(const ColumnRef& ref, std::size_t ind); }; template ArrayColumn::ArrayDataHolder::ArrayDataHolder( typename ColumnIterator>::IteratorPosition iter_position, - ColumnRef&& column) - : inner_{std::move(column)}, - ind_(iter_position == decltype(iter_position)::kEnd - ? GetColumnSize(inner_) - : 0) {} + ColumnRef&& column +) + : inner_{std::move(column)}, ind_(iter_position == decltype(iter_position)::kEnd ? GetColumnSize(inner_) : 0) {} template -typename ArrayColumn::ArrayDataHolder -ArrayColumn::ArrayDataHolder::operator++(int) { - ArrayDataHolder old{}; - old.inner_ = inner_; - old.ind_ = ind_++; - old.current_value_ = std::move_if_noexcept(current_value_); - current_value_.reset(); - - return old; +typename ArrayColumn::ArrayDataHolder ArrayColumn::ArrayDataHolder::operator++(int) { + ArrayDataHolder old{}; + old.inner_ = inner_; + old.ind_ = ind_++; + old.current_value_ = std::move_if_noexcept(current_value_); + current_value_.reset(); + + return old; } template -typename ArrayColumn::ArrayDataHolder& -ArrayColumn::ArrayDataHolder::operator++() { - ++ind_; - current_value_.reset(); +typename ArrayColumn::ArrayDataHolder& ArrayColumn::ArrayDataHolder::operator++() { + ++ind_; + current_value_.reset(); - return *this; + return *this; } template -typename ArrayColumn::cpp_type& -ArrayColumn::ArrayDataHolder::UpdateValue() { - UASSERT(ind_ < GetColumnSize(inner_)); - if (!current_value_.has_value()) { - cpp_type item = RetrieveElement(inner_, ind_); - current_value_.emplace(std::move(item)); - } - - return *current_value_; +typename ArrayColumn::cpp_type& ArrayColumn::ArrayDataHolder::UpdateValue() { + UASSERT(ind_ < GetColumnSize(inner_)); + if (!current_value_.has_value()) { + cpp_type item = RetrieveElement(inner_, ind_); + current_value_.emplace(std::move(item)); + } + + return *current_value_; } template -bool ArrayColumn::ArrayDataHolder::operator==( - const ArrayDataHolder& other) const { - return inner_.get() == other.inner_.get() && ind_ == other.ind_; +bool ArrayColumn::ArrayDataHolder::operator==(const ArrayDataHolder& other) const { + return inner_.get() == other.inner_.get() && ind_ == other.ind_; } template -ArrayColumn::ArrayColumn(ColumnRef column) - : ClickhouseColumn{column} {} +ArrayColumn::ArrayColumn(ColumnRef column) : ClickhouseColumn{column} {} template ColumnRef ArrayColumn::Serialize(const container_type& from) { - uint64_t cumulative_offset = 0; - std::vector offsets; - offsets.reserve(from.size()); - - for (const auto& value : from) { - cumulative_offset += value.size(); - offsets.push_back(cumulative_offset); - } - typename T::container_type values; - values.reserve(cumulative_offset); - - for (const auto& value : from) { - for (const auto& item : value) { - values.push_back(item); + uint64_t cumulative_offset = 0; + std::vector offsets; + offsets.reserve(from.size()); + + for (const auto& value : from) { + cumulative_offset += value.size(); + offsets.push_back(cumulative_offset); } - } + typename T::container_type values; + values.reserve(cumulative_offset); - ArrayColumnMeta array_meta; - array_meta.offsets = UInt64Column::Serialize(offsets); - array_meta.data = T::Serialize(values); + for (const auto& value : from) { + for (const auto& item : value) { + values.push_back(item); + } + } + + ArrayColumnMeta array_meta; + array_meta.offsets = UInt64Column::Serialize(offsets); + array_meta.data = T::Serialize(values); - return ConvertMetaToColumn(std::move(array_meta)); + return ConvertMetaToColumn(std::move(array_meta)); } template -typename ArrayColumn::cpp_type ArrayColumn::RetrieveElement( - const ColumnRef& ref, std::size_t ind) { - auto array_item = ExtractArrayItem(ref, ind); - T typed_column(array_item); - - cpp_type result; - result.reserve(GetColumnSize(array_item)); - for (auto it = typed_column.begin(); it != typed_column.end(); ++it) { - result.push_back(std::move(*it)); - } - return result; +typename ArrayColumn::cpp_type ArrayColumn::RetrieveElement(const ColumnRef& ref, std::size_t ind) { + auto array_item = ExtractArrayItem(ref, ind); + T typed_column(array_item); + + cpp_type result; + result.reserve(GetColumnSize(array_item)); + for (auto it = typed_column.begin(); it != typed_column.end(); ++it) { + result.push_back(std::move(*it)); + } + return result; } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/base_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/base_column.hpp index 15ba71b6d5a3..24842ac46645 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/base_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/base_column.hpp @@ -26,19 +26,19 @@ namespace storages::clickhouse::io::columns { // clang-format on template class ClickhouseColumn { - public: - using iterator = ColumnIterator; +public: + using iterator = ColumnIterator; - ClickhouseColumn(ColumnRef column) : column_{std::move(column)} {} + ClickhouseColumn(ColumnRef column) : column_{std::move(column)} {} - iterator begin() const { return iterator{column_}; } + iterator begin() const { return iterator{column_}; } - iterator end() const { return iterator::End(column_); } + iterator end() const { return iterator::End(column_); } - size_t Size() const { return GetColumnSize(column_); } + size_t Size() const { return GetColumnSize(column_); } - private: - ColumnRef column_; +private: + ColumnRef column_; }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/column_iterator.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/column_iterator.hpp index 02db2f30fb0e..348c2a8fb8d7 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/column_iterator.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/column_iterator.hpp @@ -21,67 +21,67 @@ namespace columns { /// @brief Forward-iterator for iterating over column of type ColumnType template class ColumnIterator final { - public: - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = typename ColumnType::cpp_type; - using reference = value_type&; - using pointer = value_type*; +public: + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = typename ColumnType::cpp_type; + using reference = value_type&; + using pointer = value_type*; - ColumnIterator() = default; - ColumnIterator(ColumnRef column); + ColumnIterator() = default; + ColumnIterator(ColumnRef column); - static ColumnIterator End(ColumnRef column); + static ColumnIterator End(ColumnRef column); - ColumnIterator operator++(int); - ColumnIterator& operator++(); - reference operator*() const; - pointer operator->() const; + ColumnIterator operator++(int); + ColumnIterator& operator++(); + reference operator*() const; + pointer operator->() const; - bool operator==(const ColumnIterator& other) const; - bool operator!=(const ColumnIterator& other) const; + bool operator==(const ColumnIterator& other) const; + bool operator!=(const ColumnIterator& other) const; - enum class IteratorPosition { kBegin, kEnd }; + enum class IteratorPosition { kBegin, kEnd }; - friend class storages::clickhouse::io::IteratorsTester; + friend class storages::clickhouse::io::IteratorsTester; - private: - ColumnIterator(IteratorPosition iter_position, ColumnRef&& column); +private: + ColumnIterator(IteratorPosition iter_position, ColumnRef&& column); - class DataHolder final { - public: - DataHolder() = default; - DataHolder(IteratorPosition iter_position, ColumnRef&& column); + class DataHolder final { + public: + DataHolder() = default; + DataHolder(IteratorPosition iter_position, ColumnRef&& column); - DataHolder operator++(int); - DataHolder& operator++(); - value_type& UpdateValue(); - bool operator==(const DataHolder& other) const; + DataHolder operator++(int); + DataHolder& operator++(); + value_type& UpdateValue(); + bool operator==(const DataHolder& other) const; - value_type Get() const; + value_type Get() const; - friend class storages::clickhouse::io::IteratorsTester; + friend class storages::clickhouse::io::IteratorsTester; - private: - ColumnRef column_; - size_t ind_{0}; + private: + ColumnRef column_; + size_t ind_{0}; - std::optional current_value_ = std::nullopt; - }; + std::optional current_value_ = std::nullopt; + }; - template - struct IteratorDataHolder final { - using type = DataHolder; - }; + template + struct IteratorDataHolder final { + using type = DataHolder; + }; - template - struct IteratorDataHolder> final { - using type = typename T::iterator_data; - }; + template + struct IteratorDataHolder> final { + using type = typename T::iterator_data; + }; - using data_holder = typename IteratorDataHolder::type; + using data_holder = typename IteratorDataHolder::type; - mutable data_holder data_; + mutable data_holder data_; }; template @@ -90,102 +90,93 @@ ColumnIterator::ColumnIterator(ColumnRef column) template ColumnIterator ColumnIterator::End(ColumnRef column) { - return ColumnIterator{IteratorPosition::kEnd, std::move(column)}; + return ColumnIterator{IteratorPosition::kEnd, std::move(column)}; } template -ColumnIterator::ColumnIterator(IteratorPosition iter_position, - ColumnRef&& column) +ColumnIterator::ColumnIterator(IteratorPosition iter_position, ColumnRef&& column) : data_{data_holder{iter_position, std::move(column)}} {} template ColumnIterator ColumnIterator::operator++(int) { - ColumnIterator old{}; - old.data_ = data_++; + ColumnIterator old{}; + old.data_ = data_++; - return old; + return old; } template ColumnIterator& ColumnIterator::operator++() { - ++data_; - return *this; + ++data_; + return *this; } template -typename ColumnIterator::reference -ColumnIterator::operator*() const { - return data_.UpdateValue(); +typename ColumnIterator::reference ColumnIterator::operator*() const { + return data_.UpdateValue(); } template -typename ColumnIterator::pointer -ColumnIterator::operator->() const { - return &data_.UpdateValue(); +typename ColumnIterator::pointer ColumnIterator::operator->() const { + return &data_.UpdateValue(); } template bool ColumnIterator::operator==(const ColumnIterator& other) const { - return data_ == other.data_; + return data_ == other.data_; } template -bool ColumnIterator::operator!=( - const ColumnIterator& other) const { - return !((*this) == other); +bool ColumnIterator::operator!=(const ColumnIterator& other) const { + return !((*this) == other); } template -ColumnIterator::DataHolder::DataHolder( - IteratorPosition iter_position, ColumnRef&& column) +ColumnIterator::DataHolder::DataHolder(IteratorPosition iter_position, ColumnRef&& column) : column_{std::move(column)} { - switch (iter_position) { - case IteratorPosition::kBegin: { - ind_ = 0; - break; + switch (iter_position) { + case IteratorPosition::kBegin: { + ind_ = 0; + break; + } + case IteratorPosition::kEnd: { + ind_ = GetColumnSize(column_); + break; + } } - case IteratorPosition::kEnd: { - ind_ = GetColumnSize(column_); - break; - } - } } template -typename ColumnIterator::DataHolder -ColumnIterator::DataHolder::operator++(int) { - DataHolder old{}; - old.column_ = column_; - old.ind_ = ind_++; - old.current_value_ = std::move_if_noexcept(current_value_); - current_value_.reset(); - - return old; +typename ColumnIterator::DataHolder ColumnIterator::DataHolder::operator++(int) { + DataHolder old{}; + old.column_ = column_; + old.ind_ = ind_++; + old.current_value_ = std::move_if_noexcept(current_value_); + current_value_.reset(); + + return old; } template -typename ColumnIterator::DataHolder& -ColumnIterator::DataHolder::operator++() { - ++ind_; - current_value_.reset(); +typename ColumnIterator::DataHolder& ColumnIterator::DataHolder::operator++() { + ++ind_; + current_value_.reset(); - return *this; + return *this; } template -typename ColumnIterator::value_type& -ColumnIterator::DataHolder::UpdateValue() { - UASSERT(ind_ < GetColumnSize(column_)); - if (!current_value_.has_value()) { - current_value_.emplace(Get()); - } - return *current_value_; +typename ColumnIterator::value_type& ColumnIterator::DataHolder::UpdateValue() { + UASSERT(ind_ < GetColumnSize(column_)); + if (!current_value_.has_value()) { + current_value_.emplace(Get()); + } + return *current_value_; } template -bool ColumnIterator::DataHolder::operator==( - const DataHolder& other) const { - return ind_ == other.ind_ && column_.get() == other.column_.get(); +bool ColumnIterator::DataHolder::operator==(const DataHolder& other) const { + return ind_ == other.ind_ && column_.get() == other.column_.get(); } } // namespace columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/column_wrapper.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/column_wrapper.hpp index 9b516c433cbf..90e86c69982a 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/column_wrapper.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/column_wrapper.hpp @@ -17,8 +17,7 @@ using ColumnRef = std::shared_ptr<::clickhouse::Column>; ColumnRef GetWrappedColumn(clickhouse::impl::BlockWrapper& block, size_t ind); -void AppendWrappedColumn(clickhouse::impl::BlockWrapper& block, - ColumnRef&& column, std::string_view name, size_t ind); +void AppendWrappedColumn(clickhouse::impl::BlockWrapper& block, ColumnRef&& column, std::string_view name, size_t ind); size_t GetColumnSize(const ColumnRef& column); diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/datetime64_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/datetime64_column.hpp index d31f1a7e028e..4f38230ceaf4 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/datetime64_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/datetime64_column.hpp @@ -21,24 +21,22 @@ namespace storages::clickhouse::io::columns { template class DateTime64Column; -template typename Duration> +template typename Duration> class DateTime64Column> - : public ClickhouseColumn< - DateTime64Column>> { - public: - using cpp_type = std::chrono::system_clock::time_point; - using container_type = std::vector; + : public ClickhouseColumn>> { +public: + using cpp_type = std::chrono::system_clock::time_point; + using container_type = std::vector; - struct Tag final { - static constexpr size_t kPrecision = Precision; - using time_resolution = Duration; - }; - using time_resolution = typename Tag::time_resolution; + struct Tag final { + static constexpr size_t kPrecision = Precision; + using time_resolution = Duration; + }; + using time_resolution = typename Tag::time_resolution; - DateTime64Column(ColumnRef column); + DateTime64Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; /// @brief Represents ClickHouse DateTime64(3) column diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/datetime_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/datetime_column.hpp index 727d9fefc725..2a2105ce98df 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/datetime_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/datetime_column.hpp @@ -14,13 +14,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse DateTime column class DateTimeColumn final : public ClickhouseColumn { - public: - using cpp_type = std::chrono::system_clock::time_point; - using container_type = std::vector; +public: + using cpp_type = std::chrono::system_clock::time_point; + using container_type = std::vector; - DateTimeColumn(ColumnRef column); + DateTimeColumn(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/float32_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/float32_column.hpp index 21b294201ba0..89b39a1e1aa5 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/float32_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/float32_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents Clickhouse Float32 column class Float32Column final : public ClickhouseColumn { - public: - using cpp_type = float; - using container_type = std::vector; +public: + using cpp_type = float; + using container_type = std::vector; - Float32Column(ColumnRef column); + Float32Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/float64_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/float64_column.hpp index b1d4ea4eeaad..525369058d80 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/float64_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/float64_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents Clickhouse Float64 column class Float64Column final : public ClickhouseColumn { - public: - using cpp_type = double; - using container_type = std::vector; +public: + using cpp_type = double; + using container_type = std::vector; - Float64Column(ColumnRef column); + Float64Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/int32_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/int32_column.hpp index 10edb234d1c1..7bfe4a0e779f 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/int32_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/int32_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents Clickhouse Int32 column class Int32Column final : public ClickhouseColumn { - public: - using cpp_type = std::int32_t; - using container_type = std::vector; +public: + using cpp_type = std::int32_t; + using container_type = std::vector; - Int32Column(ColumnRef column); + Int32Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/int64_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/int64_column.hpp index 38d051f7abc5..b093c3327308 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/int64_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/int64_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse Int64 column class Int64Column final : public ClickhouseColumn { - public: - using cpp_type = std::int64_t; - using container_type = std::vector; +public: + using cpp_type = std::int64_t; + using container_type = std::vector; - Int64Column(ColumnRef column); + Int64Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/int8_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/int8_column.hpp index e32e92ee6e42..83dece1fd84c 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/int8_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/int8_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse UInt8 Column class Int8Column final : public ClickhouseColumn { - public: - using cpp_type = std::int8_t; - using container_type = std::vector; +public: + using cpp_type = std::int8_t; + using container_type = std::vector; - Int8Column(ColumnRef column); + Int8Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/nullable_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/nullable_column.hpp index 808cee590b3e..2cf904de0257 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/nullable_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/nullable_column.hpp @@ -17,8 +17,8 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::columns { struct NullableColumnMeta final { - ColumnRef nulls; - ColumnRef inner; + ColumnRef nulls; + ColumnRef inner; }; NullableColumnMeta ExtractNullableMeta(const ColumnRef& column); @@ -29,127 +29,122 @@ ColumnRef ConvertMetaToColumn(NullableColumnMeta&& meta); /// where T is a ClickhouseColumn as well template class NullableColumn final : public ClickhouseColumn> { - public: - using cpp_type = std::optional; - using container_type = std::vector; - - class NullableDataHolder final { - public: - NullableDataHolder() = default; - NullableDataHolder(typename ColumnIterator< - NullableColumn>::IteratorPosition iter_position, - ColumnRef&& column); - - NullableDataHolder operator++(int); - NullableDataHolder& operator++(); - void Next(); - cpp_type& UpdateValue(); - - bool operator==(const NullableDataHolder& other) const; - - private: - NullableDataHolder(typename ColumnIterator< - NullableColumn>::IteratorPosition iter_position, - NullableColumnMeta&& meta); - - UInt8Column::iterator nulls_; - typename T::iterator inner_; - cpp_type current_value_ = std::nullopt; - bool has_value_ = false; - }; - using iterator_data = NullableDataHolder; - - NullableColumn(ColumnRef column); - - static ColumnRef Serialize(const container_type& from); +public: + using cpp_type = std::optional; + using container_type = std::vector; + + class NullableDataHolder final { + public: + NullableDataHolder() = default; + NullableDataHolder( + typename ColumnIterator>::IteratorPosition iter_position, + ColumnRef&& column + ); + + NullableDataHolder operator++(int); + NullableDataHolder& operator++(); + void Next(); + cpp_type& UpdateValue(); + + bool operator==(const NullableDataHolder& other) const; + + private: + NullableDataHolder( + typename ColumnIterator>::IteratorPosition iter_position, + NullableColumnMeta&& meta + ); + + UInt8Column::iterator nulls_; + typename T::iterator inner_; + cpp_type current_value_ = std::nullopt; + bool has_value_ = false; + }; + using iterator_data = NullableDataHolder; + + NullableColumn(ColumnRef column); + + static ColumnRef Serialize(const container_type& from); }; template -NullableColumn::NullableColumn(ColumnRef column) - : ClickhouseColumn{column} {} +NullableColumn::NullableColumn(ColumnRef column) : ClickhouseColumn{column} {} template NullableColumn::NullableDataHolder::NullableDataHolder( typename ColumnIterator>::IteratorPosition iter_position, - ColumnRef&& column) + ColumnRef&& column +) : NullableDataHolder(iter_position, ExtractNullableMeta(column)) {} template NullableColumn::NullableDataHolder::NullableDataHolder( typename ColumnIterator>::IteratorPosition iter_position, - NullableColumnMeta&& meta) - : nulls_{iter_position == decltype(iter_position)::kEnd - ? UInt8Column{meta.nulls}.end() - : UInt8Column{meta.nulls}.begin()}, - inner_{iter_position == decltype(iter_position)::kEnd - ? T{meta.inner}.end() - : T{meta.inner}.begin()} {} + NullableColumnMeta&& meta +) + : nulls_{iter_position == decltype(iter_position)::kEnd ? UInt8Column{meta.nulls}.end() : UInt8Column{meta.nulls}.begin()}, + inner_{iter_position == decltype(iter_position)::kEnd ? T{meta.inner}.end() : T{meta.inner}.begin()} {} template -typename NullableColumn::NullableDataHolder -NullableColumn::NullableDataHolder::operator++(int) { - NullableDataHolder old{}; - old.nulls_ = nulls_++; - old.inner_ = inner_++; - old.current_value_ = std::move_if_noexcept(current_value_); - old.has_value_ = std::exchange(has_value_, false); - - return old; +typename NullableColumn::NullableDataHolder NullableColumn::NullableDataHolder::operator++(int) { + NullableDataHolder old{}; + old.nulls_ = nulls_++; + old.inner_ = inner_++; + old.current_value_ = std::move_if_noexcept(current_value_); + old.has_value_ = std::exchange(has_value_, false); + + return old; } template -typename NullableColumn::NullableDataHolder& -NullableColumn::NullableDataHolder::operator++() { - ++nulls_; - ++inner_; - current_value_.reset(); - has_value_ = false; - - return *this; +typename NullableColumn::NullableDataHolder& NullableColumn::NullableDataHolder::operator++() { + ++nulls_; + ++inner_; + current_value_.reset(); + has_value_ = false; + + return *this; } template -typename NullableColumn::cpp_type& -NullableColumn::NullableDataHolder::UpdateValue() { - if (!has_value_) { - if (*nulls_) { - current_value_.reset(); - } else { - current_value_.emplace(std::move_if_noexcept(*inner_)); +typename NullableColumn::cpp_type& NullableColumn::NullableDataHolder::UpdateValue() { + if (!has_value_) { + if (*nulls_) { + current_value_.reset(); + } else { + current_value_.emplace(std::move_if_noexcept(*inner_)); + } + has_value_ = true; } - has_value_ = true; - } - return current_value_; + return current_value_; } template -bool NullableColumn::NullableDataHolder::operator==( - const NullableDataHolder& other) const { - return nulls_ == other.nulls_ && inner_ == other.inner_; +bool NullableColumn::NullableDataHolder::operator==(const NullableDataHolder& other) const { + return nulls_ == other.nulls_ && inner_ == other.inner_; } template ColumnRef NullableColumn::Serialize(const container_type& from) { - typename T::container_type values; - values.reserve(from.size()); - std::vector nulls; - nulls.reserve(from.size()); - - for (auto& opt_v : from) { - nulls.push_back(static_cast(opt_v.has_value() ? 0 : 1)); - - if (opt_v.has_value()) { - values.push_back(*opt_v); - } else { - values.push_back(typename T::cpp_type{}); + typename T::container_type values; + values.reserve(from.size()); + std::vector nulls; + nulls.reserve(from.size()); + + for (auto& opt_v : from) { + nulls.push_back(static_cast(opt_v.has_value() ? 0 : 1)); + + if (opt_v.has_value()) { + values.push_back(*opt_v); + } else { + values.push_back(typename T::cpp_type{}); + } } - } - NullableColumnMeta nullable_meta; - nullable_meta.nulls = UInt8Column::Serialize(nulls); - nullable_meta.inner = T::Serialize(values); - return ConvertMetaToColumn(std::move(nullable_meta)); + NullableColumnMeta nullable_meta; + nullable_meta.nulls = UInt8Column::Serialize(nulls); + nullable_meta.inner = T::Serialize(values); + return ConvertMetaToColumn(std::move(nullable_meta)); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/string_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/string_column.hpp index 5c7ff7807fd0..02f2bee124c4 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/string_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/string_column.hpp @@ -14,13 +14,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse String column class StringColumn final : public ClickhouseColumn { - public: - using cpp_type = std::string; - using container_type = std::vector; +public: + using cpp_type = std::string; + using container_type = std::vector; - StringColumn(ColumnRef column); + StringColumn(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/uint16_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/uint16_column.hpp index 34b4bddac0c7..d1e13d0f51b4 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/uint16_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/uint16_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents Clickhouse UInt16 column class UInt16Column final : public ClickhouseColumn { - public: - using cpp_type = uint16_t; - using container_type = std::vector; +public: + using cpp_type = uint16_t; + using container_type = std::vector; - UInt16Column(ColumnRef column); + UInt16Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/uint32_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/uint32_column.hpp index 6c8efb834e43..f29cdad34d43 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/uint32_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/uint32_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse UInt32 column class UInt32Column final : public ClickhouseColumn { - public: - using cpp_type = std::uint32_t; - using container_type = std::vector; +public: + using cpp_type = std::uint32_t; + using container_type = std::vector; - UInt32Column(ColumnRef column); + UInt32Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/uint64_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/uint64_column.hpp index 24fc83cb2575..b50f4c4fca7a 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/uint64_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/uint64_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse UInt64 column class UInt64Column final : public ClickhouseColumn { - public: - using cpp_type = std::uint64_t; - using container_type = std::vector; +public: + using cpp_type = std::uint64_t; + using container_type = std::vector; - UInt64Column(ColumnRef column); + UInt64Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/uint8_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/uint8_column.hpp index 1cb905094e64..dd7d835b16e1 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/uint8_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/uint8_column.hpp @@ -12,13 +12,13 @@ namespace storages::clickhouse::io::columns { /// @brief Represents ClickHouse UInt8 Column class UInt8Column final : public ClickhouseColumn { - public: - using cpp_type = std::uint8_t; - using container_type = std::vector; +public: + using cpp_type = std::uint8_t; + using container_type = std::vector; - UInt8Column(ColumnRef column); + UInt8Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/columns/uuid_column.hpp b/clickhouse/include/userver/storages/clickhouse/io/columns/uuid_column.hpp index b0103e5a7889..7322d19ae87c 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/columns/uuid_column.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/columns/uuid_column.hpp @@ -21,54 +21,55 @@ namespace storages::clickhouse::io::columns { /// of 8 hex bytes group is bytewise reversed). /// /// Requires **both** writes and reads to be performed via userver to work. -class MismatchedEndiannessUuidColumn final - : public ClickhouseColumn { - public: - using cpp_type = boost::uuids::uuid; - using container_type = std::vector; +class MismatchedEndiannessUuidColumn final : public ClickhouseColumn { +public: + using cpp_type = boost::uuids::uuid; + using container_type = std::vector; - MismatchedEndiannessUuidColumn(ColumnRef column); + MismatchedEndiannessUuidColumn(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; /// @brief Represents ClickHouse UUID column. class UuidRfc4122Column final : public ClickhouseColumn { - public: - using cpp_type = boost::uuids::uuid; - using container_type = std::vector; +public: + using cpp_type = boost::uuids::uuid; + using container_type = std::vector; - UuidRfc4122Column(ColumnRef column); + UuidRfc4122Column(ColumnRef column); - static ColumnRef Serialize(const container_type& from); + static ColumnRef Serialize(const container_type& from); }; // Dummy implementation to force a compile-time error on usage attempt. class UuidColumn final : public ClickhouseColumn { - public: - using cpp_type = boost::uuids::uuid; - using container_type = std::vector; - - template - UuidColumn(T) { - ReportMisuse(); - } - - template - static ColumnRef Serialize(const T&) { - ReportMisuse(); - return {}; - } - - private: - template - static void ReportMisuse() { - static_assert(!sizeof(T), - "UuidColumn is deprecated: for old code rename it to " - "MismatchedEndiannessUuidColumn, for new code we encourage " - "you to use UuidRfc4122Column instead. See the " - "MismatchedEndiannessUuidColumn docs for explanation."); - } +public: + using cpp_type = boost::uuids::uuid; + using container_type = std::vector; + + template + UuidColumn(T) { + ReportMisuse(); + } + + template + static ColumnRef Serialize(const T&) { + ReportMisuse(); + return {}; + } + +private: + template + static void ReportMisuse() { + static_assert( + !sizeof(T), + "UuidColumn is deprecated: for old code rename it to " + "MismatchedEndiannessUuidColumn, for new code we encourage " + "you to use UuidRfc4122Column instead. See the " + "MismatchedEndiannessUuidColumn docs for explanation." + ); + } }; } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/include/userver/storages/clickhouse/io/impl/escape.hpp b/clickhouse/include/userver/storages/clickhouse/io/impl/escape.hpp index 1ee15a0c31f4..0184ecdeb3d7 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/impl/escape.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/impl/escape.hpp @@ -34,36 +34,35 @@ std::string Escape(DateTime64Nano source); template std::string Escape(const Container& source) { - static_assert(traits::kIsRange, - "There's no escape implementation for the type."); + static_assert(traits::kIsRange, "There's no escape implementation for the type."); - std::string result; - if constexpr (traits::kIsSizeable) { - // just an approximation, wild guess - constexpr size_t kResultReserveMultiplier = 5; - result.reserve(source.size() * kResultReserveMultiplier); - } - result.push_back('['); + std::string result; + if constexpr (traits::kIsSizeable) { + // just an approximation, wild guess + constexpr size_t kResultReserveMultiplier = 5; + result.reserve(source.size() * kResultReserveMultiplier); + } + result.push_back('['); - bool is_first_item = true; - for (const auto& item : source) { - if (!is_first_item) { - result.push_back(','); + bool is_first_item = true; + for (const auto& item : source) { + if (!is_first_item) { + result.push_back(','); + } + result += impl::Escape(item); + is_first_item = false; } - result += impl::Escape(item); - is_first_item = false; - } - result.push_back(']'); + result.push_back(']'); - return result; + return result; } template std::string Escape(const std::optional& source) { - if (!source.has_value()) { - return "NULL"; - } - return Escape(source.value()); + if (!source.has_value()) { + return "NULL"; + } + return Escape(source.value()); } } // namespace storages::clickhouse::io::impl diff --git a/clickhouse/include/userver/storages/clickhouse/io/impl/validate.hpp b/clickhouse/include/userver/storages/clickhouse/io/impl/validate.hpp index f65c42a525ba..f59d684ad2fc 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/impl/validate.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/impl/validate.hpp @@ -21,35 +21,31 @@ namespace storages::clickhouse::io::impl { template constexpr void EnsureInstantiationOfVector([[maybe_unused]] const T& t) { - static_assert(meta::kIsInstantiationOf); + static_assert(meta::kIsInstantiationOf); } template struct EnsureInstantiationOfColumn { - ~EnsureInstantiationOfColumn() { - static_assert(!std::is_same_v, T>); - static_assert(std::is_base_of_v, T>); - } + ~EnsureInstantiationOfColumn() { + static_assert(!std::is_same_v, T>); + static_assert(std::is_base_of_v, T>); + } }; template struct EnsureInstantiationOfColumn> { - ~EnsureInstantiationOfColumn() { - static_assert(!std::is_same_v, T>); - static_assert(std::is_base_of_v, T>); - } + ~EnsureInstantiationOfColumn() { + static_assert(!std::is_same_v, T>); + static_assert(std::is_base_of_v, T>); + } }; -template >> +template >> struct TupleColumnsValidate; template struct TupleColumnsValidate> { - ~TupleColumnsValidate() { - (..., - (void)impl::EnsureInstantiationOfColumn>{}); - } + ~TupleColumnsValidate() { (..., (void)impl::EnsureInstantiationOfColumn>{}); } }; template @@ -59,30 +55,27 @@ template using MappedType = typename CppToClickhouse::mapped_type; template -using ClickhouseType = - typename std::tuple_element_t>::cpp_type; +using ClickhouseType = typename std::tuple_element_t>::cpp_type; template inline constexpr auto kCppTypeColumnsCount = boost::pfr::tuple_size_v; template -inline constexpr auto kClickhouseTypeColumnsCount = - std::tuple_size_v>; +inline constexpr auto kClickhouseTypeColumnsCount = std::tuple_size_v>; template constexpr void CommonValidateMapping() { - static_assert(traits::kIsMappedToClickhouse, "not mapped to clickhouse"); - static_assert(kCppTypeColumnsCount == kClickhouseTypeColumnsCount); + static_assert(traits::kIsMappedToClickhouse, "not mapped to clickhouse"); + static_assert(kCppTypeColumnsCount == kClickhouseTypeColumnsCount); - [[maybe_unused]] TupleColumnsValidate> validator{}; + [[maybe_unused]] TupleColumnsValidate> validator{}; } template constexpr void ValidateColumnsMapping(const T& t) { - boost::pfr::for_each_field( - t, [](const auto& field) { impl::EnsureInstantiationOfVector(field); }); + boost::pfr::for_each_field(t, [](const auto& field) { impl::EnsureInstantiationOfVector(field); }); - impl::CommonValidateMapping(); + impl::CommonValidateMapping(); } template @@ -90,50 +83,47 @@ struct FailIndexAssertion : std::false_type {}; template constexpr size_t FieldTypeFindMismatch(std::index_sequence) { - constexpr bool results[] = { - std::is_same_v, ClickhouseType>...}; + constexpr bool results[] = {std::is_same_v, ClickhouseType>...}; - size_t i = 0; - for (bool v : results) { - if (!v) return i; - ++i; - } + size_t i = 0; + for (bool v : results) { + if (!v) return i; + ++i; + } - return i; + return i; } template constexpr void ValidateRowsMapping() { - impl::CommonValidateMapping(); - - constexpr auto columns_count = kClickhouseTypeColumnsCount; - constexpr auto type_mismatch_index = - FieldTypeFindMismatch(std::make_index_sequence()); - if constexpr (type_mismatch_index != columns_count) { - static_assert(std::is_same_v, - ClickhouseType>, - "Make sure your ClickHouse mapping is correct."); - static_assert(FailIndexAssertion::value, - "Recheck your mapping at this index."); - } + impl::CommonValidateMapping(); + + constexpr auto columns_count = kClickhouseTypeColumnsCount; + constexpr auto type_mismatch_index = FieldTypeFindMismatch(std::make_index_sequence()); + if constexpr (type_mismatch_index != columns_count) { + static_assert( + std::is_same_v, ClickhouseType>, + "Make sure your ClickHouse mapping is correct." + ); + static_assert(FailIndexAssertion::value, "Recheck your mapping at this index."); + } } template void ValidateRowsCount(const T& t) { - std::optional rows_count; - boost::pfr::for_each_field(t, [&rows_count](const auto& field) { - if (!rows_count.has_value()) { - rows_count.emplace(field.size()); - } - UINVARIANT(*rows_count == field.size(), - "All rows should have same number of elements"); - }); + std::optional rows_count; + boost::pfr::for_each_field(t, [&rows_count](const auto& field) { + if (!rows_count.has_value()) { + rows_count.emplace(field.size()); + } + UINVARIANT(*rows_count == field.size(), "All rows should have same number of elements"); + }); } template void ValidateColumnsCount(size_t expected) { - constexpr auto columns_count = kCppTypeColumnsCount; - UINVARIANT(columns_count == expected, "Columns count mismatch."); + constexpr auto columns_count = kCppTypeColumnsCount; + UINVARIANT(columns_count == expected, "Columns count mismatch."); } } // namespace storages::clickhouse::io::impl diff --git a/clickhouse/include/userver/storages/clickhouse/io/result_mapper.hpp b/clickhouse/include/userver/storages/clickhouse/io/result_mapper.hpp index 9f8607fa516f..2fe0114053e3 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/result_mapper.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/result_mapper.hpp @@ -21,160 +21,151 @@ class IteratorsTester; template class ColumnsMapper final { - public: - explicit ColumnsMapper(clickhouse::impl::BlockWrapper& block) - : block_{block} {} - - template - void operator()(Field& field, std::integral_constant i) { - using ColumnType = std::tuple_element_t; - static_assert(std::is_same_v); - - auto column = ColumnType{io::columns::GetWrappedColumn(block_, i)}; - field.reserve(column.Size()); - for (auto& it : column) field.push_back(std::move(it)); - } - - private: - clickhouse::impl::BlockWrapper& block_; +public: + explicit ColumnsMapper(clickhouse::impl::BlockWrapper& block) : block_{block} {} + + template + void operator()(Field& field, std::integral_constant i) { + using ColumnType = std::tuple_element_t; + static_assert(std::is_same_v); + + auto column = ColumnType{io::columns::GetWrappedColumn(block_, i)}; + field.reserve(column.Size()); + for (auto& it : column) field.push_back(std::move(it)); + } + +private: + clickhouse::impl::BlockWrapper& block_; }; template class RowsMapper final { - public: - using MappedType = typename CppToClickhouse::mapped_type; - explicit RowsMapper(clickhouse::impl::BlockWrapperPtr&& block) - : block_{block.release()} { - IteratorsHelperT::Init(begin_iterators_, end_iterators_, *block_); - } - ~RowsMapper() = default; - - using IteratorsTupleT = clickhouse::impl::IteratorsTupleT; - - class Iterator final { - public: - using iterator_category = std::forward_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = Row; - using reference = value_type&; - using pointer = value_type*; - - Iterator() = default; - Iterator(IteratorsTupleT iterators); - - Iterator operator++(int); - Iterator& operator++(); - reference operator*() const; - pointer operator->() const; - - bool operator==(const Iterator& other) const; - bool operator!=(const Iterator& other) const; - - friend class IteratorsTester; - - private: - Row& UpdateValue() const; - - class FieldMapper final { - public: - FieldMapper(const IteratorsTupleT& iterators) : iterators_{iterators} {} - - template - void operator()( - Field& field, - [[maybe_unused]] std::integral_constant i) const { - if constexpr (kCanMoveFromIterators) { - field = std::move(*std::get(iterators_)); - } else { - field = *std::get(iterators_); - } - } - - private: - const IteratorsTupleT& iterators_; +public: + using MappedType = typename CppToClickhouse::mapped_type; + explicit RowsMapper(clickhouse::impl::BlockWrapperPtr&& block) : block_{block.release()} { + IteratorsHelperT::Init(begin_iterators_, end_iterators_, *block_); + } + ~RowsMapper() = default; + + using IteratorsTupleT = clickhouse::impl::IteratorsTupleT; + + class Iterator final { + public: + using iterator_category = std::forward_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = Row; + using reference = value_type&; + using pointer = value_type*; + + Iterator() = default; + Iterator(IteratorsTupleT iterators); + + Iterator operator++(int); + Iterator& operator++(); + reference operator*() const; + pointer operator->() const; + + bool operator==(const Iterator& other) const; + bool operator!=(const Iterator& other) const; + + friend class IteratorsTester; + + private: + Row& UpdateValue() const; + + class FieldMapper final { + public: + FieldMapper(const IteratorsTupleT& iterators) : iterators_{iterators} {} + + template + void operator()(Field& field, [[maybe_unused]] std::integral_constant i) const { + if constexpr (kCanMoveFromIterators) { + field = std::move(*std::get(iterators_)); + } else { + field = *std::get(iterators_); + } + } + + private: + const IteratorsTupleT& iterators_; + }; + + IteratorsTupleT iterators_; + mutable std::optional current_value_ = std::nullopt; }; - IteratorsTupleT iterators_; - mutable std::optional current_value_ = std::nullopt; - }; + Iterator begin() const { return Iterator{begin_iterators_}; } + Iterator end() const { return Iterator{end_iterators_}; } - Iterator begin() const { return Iterator{begin_iterators_}; } - Iterator end() const { return Iterator{end_iterators_}; } - - friend class IteratorsTester; + friend class IteratorsTester; - private: - template - struct IteratorValuesAreNoexceptMovable; +private: + template + struct IteratorValuesAreNoexceptMovable; - template - struct IteratorValuesAreNoexceptMovable> - : std::conjunction...> {}; + template + struct IteratorValuesAreNoexceptMovable> + : std::conjunction...> {}; - static constexpr auto kCanMoveFromIterators = - IteratorValuesAreNoexceptMovable::value; + static constexpr auto kCanMoveFromIterators = IteratorValuesAreNoexceptMovable::value; - using IteratorsHelperT = clickhouse::impl::IteratorsHelper; + using IteratorsHelperT = clickhouse::impl::IteratorsHelper; - clickhouse::impl::BlockWrapperPtr block_; - IteratorsTupleT begin_iterators_{}; - IteratorsTupleT end_iterators_{}; + clickhouse::impl::BlockWrapperPtr block_; + IteratorsTupleT begin_iterators_{}; + IteratorsTupleT end_iterators_{}; }; template -RowsMapper::Iterator::Iterator(IteratorsTupleT iterators) - : iterators_{std::move(iterators)} {} +RowsMapper::Iterator::Iterator(IteratorsTupleT iterators) : iterators_{std::move(iterators)} {} template typename RowsMapper::Iterator RowsMapper::Iterator::operator++(int) { - Iterator old{}; - old.iterators_ = IteratorsHelperT::PostfixIncrement(iterators_); - old.current_value_ = std::move_if_noexcept(current_value_); - current_value_.reset(); + Iterator old{}; + old.iterators_ = IteratorsHelperT::PostfixIncrement(iterators_); + old.current_value_ = std::move_if_noexcept(current_value_); + current_value_.reset(); - return old; + return old; } template typename RowsMapper::Iterator& RowsMapper::Iterator::operator++() { - IteratorsHelperT::PrefixIncrement(iterators_); - current_value_.reset(); + IteratorsHelperT::PrefixIncrement(iterators_); + current_value_.reset(); - return *this; + return *this; } template -typename RowsMapper::Iterator::reference -RowsMapper::Iterator::operator*() const { - return UpdateValue(); +typename RowsMapper::Iterator::reference RowsMapper::Iterator::operator*() const { + return UpdateValue(); } template -typename RowsMapper::Iterator::pointer -RowsMapper::Iterator::operator->() const { - return &UpdateValue(); +typename RowsMapper::Iterator::pointer RowsMapper::Iterator::operator->() const { + return &UpdateValue(); } template Row& RowsMapper::Iterator::UpdateValue() const { - if (!current_value_.has_value()) { - Row result{}; - boost::pfr::for_each_field(result, FieldMapper{iterators_}); - current_value_.emplace(std::move(result)); - } + if (!current_value_.has_value()) { + Row result{}; + boost::pfr::for_each_field(result, FieldMapper{iterators_}); + current_value_.emplace(std::move(result)); + } - return *current_value_; + return *current_value_; } template bool RowsMapper::Iterator::operator==(const Iterator& other) const { - return iterators_ == other.iterators_; + return iterators_ == other.iterators_; } template bool RowsMapper::Iterator::operator!=(const Iterator& other) const { - return !((*this) == other); + return !((*this) == other); } } // namespace storages::clickhouse::io diff --git a/clickhouse/include/userver/storages/clickhouse/io/type_traits.hpp b/clickhouse/include/userver/storages/clickhouse/io/type_traits.hpp index 41e629964219..82afc0f615e0 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/type_traits.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/type_traits.hpp @@ -10,12 +10,11 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::traits { template -inline constexpr bool kIsMappedToClickhouse = - utils::IsDeclComplete>::value; +inline constexpr bool kIsMappedToClickhouse = utils::IsDeclComplete>::value; template auto Inserter(T& container) { - return meta::Inserter(container); + return meta::Inserter(container); } template diff --git a/clickhouse/include/userver/storages/clickhouse/io/typedefs.hpp b/clickhouse/include/userver/storages/clickhouse/io/typedefs.hpp index 2f3ed6f20dea..0261196a2719 100644 --- a/clickhouse/include/userver/storages/clickhouse/io/typedefs.hpp +++ b/clickhouse/include/userver/storages/clickhouse/io/typedefs.hpp @@ -12,18 +12,18 @@ namespace storages::clickhouse::io { /// @brief StrongTypedef for serializing `system_clock::time_point` /// to DateTime64(3) format when used as a query argument -using DateTime64Milli = USERVER_NAMESPACE::utils::StrongTypedef< - columns::DateTime64ColumnMilli::Tag, std::chrono::system_clock::time_point>; +using DateTime64Milli = + USERVER_NAMESPACE::utils::StrongTypedef; /// @brief StrongTypedef for serializing `system_clock::time_point` /// to DateTime64(6) format when used as a query argument -using DateTime64Micro = USERVER_NAMESPACE::utils::StrongTypedef< - columns::DateTime64ColumnMicro::Tag, std::chrono::system_clock::time_point>; +using DateTime64Micro = + USERVER_NAMESPACE::utils::StrongTypedef; /// @brief StrongTypedef for serializing `system_clock::time_point` /// to DateTime64(9) format when used as a query argument -using DateTime64Nano = USERVER_NAMESPACE::utils::StrongTypedef< - columns::DateTime64ColumnNano::Tag, std::chrono::system_clock::time_point>; +using DateTime64Nano = + USERVER_NAMESPACE::utils::StrongTypedef; } // namespace storages::clickhouse::io diff --git a/clickhouse/include/userver/storages/clickhouse/options.hpp b/clickhouse/include/userver/storages/clickhouse/options.hpp index bb2877669145..305424df8ee8 100644 --- a/clickhouse/include/userver/storages/clickhouse/options.hpp +++ b/clickhouse/include/userver/storages/clickhouse/options.hpp @@ -25,11 +25,10 @@ namespace storages::clickhouse { /// connection (no further reuse will take place), /// otherwise the connection is returned to the pool. struct CommandControl final { - /// Overall timeout for a command being executed. - std::chrono::milliseconds execute; + /// Overall timeout for a command being executed. + std::chrono::milliseconds execute; - explicit constexpr CommandControl(std::chrono::milliseconds execute) - : execute{execute} {} + explicit constexpr CommandControl(std::chrono::milliseconds execute) : execute{execute} {} }; /// @brief storages::clickhouse::CommandControl that may not be set. diff --git a/clickhouse/include/userver/storages/clickhouse/query.hpp b/clickhouse/include/userver/storages/clickhouse/query.hpp index a935d321a538..7d91bd1909ea 100644 --- a/clickhouse/include/userver/storages/clickhouse/query.hpp +++ b/clickhouse/include/userver/storages/clickhouse/query.hpp @@ -31,34 +31,32 @@ class QueryTester; /// In case query is expected to be executed with parameters, /// query text should conform to fmt format class Query final { - public: - using Name = - USERVER_NAMESPACE::utils::StrongTypedef; +public: + using Name = USERVER_NAMESPACE::utils::StrongTypedef; - Query(const char* text, std::optional = std::nullopt); - Query(std::string text, std::optional = std::nullopt); + Query(const char* text, std::optional = std::nullopt); + Query(std::string text, std::optional = std::nullopt); - const std::string& QueryText() const&; + const std::string& QueryText() const&; - const std::optional& QueryName() const&; + const std::optional& QueryName() const&; - friend class Cluster; - friend class QueryTester; - friend class impl::Pool; + friend class Cluster; + friend class QueryTester; + friend class impl::Pool; - private: - template - Query WithArgs(const Args&... args) const { - // we should throw on params count mismatch - // TODO : https://st.yandex-team.ru/TAXICOMMON-5066 - return Query{fmt::format(fmt::runtime(text_), io::impl::Escape(args)...), - name_}; - } +private: + template + Query WithArgs(const Args&... args) const { + // we should throw on params count mismatch + // TODO : https://st.yandex-team.ru/TAXICOMMON-5066 + return Query{fmt::format(fmt::runtime(text_), io::impl::Escape(args)...), name_}; + } - void FillSpanTags(tracing::Span&) const; + void FillSpanTags(tracing::Span&) const; - std::string text_; - std::optional name_; + std::string text_; + std::optional name_; }; } // namespace storages::clickhouse diff --git a/clickhouse/src/storages/clickhouse/cluster.cpp b/clickhouse/src/storages/clickhouse/cluster.cpp index f510949f857d..f1610185dc52 100644 --- a/clickhouse/src/storages/clickhouse/cluster.cpp +++ b/clickhouse/src/storages/clickhouse/cluster.cpp @@ -16,70 +16,67 @@ namespace storages::clickhouse { namespace { -size_t WrappingIncrement(std::atomic& value, size_t mod, - size_t inc = 1) { - // we don't actually care about order being broken once in 2^64 iterations - return value.fetch_add(inc) % mod; +size_t WrappingIncrement(std::atomic& value, size_t mod, size_t inc = 1) { + // we don't actually care about order being broken once in 2^64 iterations + return value.fetch_add(inc) % mod; } } // namespace -Cluster::Cluster(clients::dns::Resolver& resolver, - const impl::ClickhouseSettings& settings, - const components::ComponentConfig& config) { - const auto& endpoints = settings.endpoints; - const auto& auth_settings = settings.auth_settings; - - std::vector> init_tasks; - init_tasks.reserve(endpoints.size()); - for (const auto& endpoint : endpoints) { - init_tasks.emplace_back(USERVER_NAMESPACE::utils::Async( - fmt::format("create_pool_{}", endpoint.host), - [&resolver, &endpoint, &auth_settings, &config]() { - return impl::Pool{ - resolver, impl::PoolSettings{config, endpoint, auth_settings}}; - })); - } - - pools_.reserve(init_tasks.size()); - for (auto& init_task : init_tasks) { - pools_.emplace_back(init_task.Get()); - } +Cluster::Cluster( + clients::dns::Resolver& resolver, + const impl::ClickhouseSettings& settings, + const components::ComponentConfig& config +) { + const auto& endpoints = settings.endpoints; + const auto& auth_settings = settings.auth_settings; + + std::vector> init_tasks; + init_tasks.reserve(endpoints.size()); + for (const auto& endpoint : endpoints) { + init_tasks.emplace_back(USERVER_NAMESPACE::utils::Async( + fmt::format("create_pool_{}", endpoint.host), + [&resolver, &endpoint, &auth_settings, &config]() { + return impl::Pool{resolver, impl::PoolSettings{config, endpoint, auth_settings}}; + } + )); + } + + pools_.reserve(init_tasks.size()); + for (auto& init_task : init_tasks) { + pools_.emplace_back(init_task.Get()); + } } Cluster::~Cluster() = default; -ExecutionResult Cluster::DoExecute(OptionalCommandControl optional_cc, - const Query& query) const { - return GetPool().Execute(optional_cc, query); +ExecutionResult Cluster::DoExecute(OptionalCommandControl optional_cc, const Query& query) const { + return GetPool().Execute(optional_cc, query); } -void Cluster::DoInsert(OptionalCommandControl optional_cc, - const impl::InsertionRequest& request) const { - GetPool().Insert(optional_cc, request); +void Cluster::DoInsert(OptionalCommandControl optional_cc, const impl::InsertionRequest& request) const { + GetPool().Insert(optional_cc, request); } const impl::Pool& Cluster::GetPool() const { - const auto pools_count = pools_.size(); - const auto current_pool_ind = - WrappingIncrement(current_pool_ind_, pools_count); - - for (size_t i = 0; i < pools_count; ++i) { - const auto& pool = pools_[(current_pool_ind + i) % pools_count]; - if (pool.IsAvailable()) { - WrappingIncrement(current_pool_ind_, pools_count, i); - return pool; + const auto pools_count = pools_.size(); + const auto current_pool_ind = WrappingIncrement(current_pool_ind_, pools_count); + + for (size_t i = 0; i < pools_count; ++i) { + const auto& pool = pools_[(current_pool_ind + i) % pools_count]; + if (pool.IsAvailable()) { + WrappingIncrement(current_pool_ind_, pools_count, i); + return pool; + } } - } - throw NoAvailablePoolError{"No available pools in cluster."}; + throw NoAvailablePoolError{"No available pools in cluster."}; } -void Cluster::WriteStatistics( - USERVER_NAMESPACE::utils::statistics::Writer& writer) const { - for (const auto& pool : pools_) { - pool.WriteStatistics(writer); - } +void Cluster::WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const { + for (const auto& pool : pools_) { + pool.WriteStatistics(writer); + } } } // namespace storages::clickhouse diff --git a/clickhouse/src/storages/clickhouse/component.cpp b/clickhouse/src/storages/clickhouse/component.cpp index 41b4da416f05..1c8883f7b05b 100644 --- a/clickhouse/src/storages/clickhouse/component.cpp +++ b/clickhouse/src/storages/clickhouse/component.cpp @@ -16,39 +16,32 @@ USERVER_NAMESPACE_BEGIN namespace components { -ClickHouse::ClickHouse(const ComponentConfig& config, - const ComponentContext& context) - : ComponentBase{config, context}, - dns_{context.FindComponent()} { - const auto& secdist = context.FindComponent().Get(); - const auto& settings_multi = - secdist.Get(); - const auto& settings = - settings_multi.Get(storages::clickhouse::impl::GetSecdistAlias(config)); +ClickHouse::ClickHouse(const ComponentConfig& config, const ComponentContext& context) + : ComponentBase{config, context}, dns_{context.FindComponent()} { + const auto& secdist = context.FindComponent().Get(); + const auto& settings_multi = secdist.Get(); + const auto& settings = settings_multi.Get(storages::clickhouse::impl::GetSecdistAlias(config)); - cluster_ = std::make_shared(dns_.GetResolver(), - settings, config); + cluster_ = std::make_shared(dns_.GetResolver(), settings, config); - auto& statistics_storage = - context.FindComponent(); - statistics_holder_ = statistics_storage.GetStorage().RegisterWriter( - "clickhouse", - [this](utils::statistics::Writer& writer) { - if (cluster_) { - cluster_->WriteStatistics(writer); - } - }, - {{"clickhouse_database", settings.auth_settings.database}}); + auto& statistics_storage = context.FindComponent(); + statistics_holder_ = statistics_storage.GetStorage().RegisterWriter( + "clickhouse", + [this](utils::statistics::Writer& writer) { + if (cluster_) { + cluster_->WriteStatistics(writer); + } + }, + {{"clickhouse_database", settings.auth_settings.database}} + ); } ClickHouse::~ClickHouse() { statistics_holder_.Unregister(); } -storages::clickhouse::ClusterPtr ClickHouse::GetCluster() const { - return cluster_; -} +storages::clickhouse::ClusterPtr ClickHouse::GetCluster() const { return cluster_; } yaml_config::Schema ClickHouse::GetStaticConfigSchema() { - return yaml_config::MergeSchemas(R"( + return yaml_config::MergeSchemas(R"( type: object description: ClickHouse client component additionalProperties: false diff --git a/clickhouse/src/storages/clickhouse/execution_result.cpp b/clickhouse/src/storages/clickhouse/execution_result.cpp index 67f9a688f611..c4af0f762fcb 100644 --- a/clickhouse/src/storages/clickhouse/execution_result.cpp +++ b/clickhouse/src/storages/clickhouse/execution_result.cpp @@ -6,16 +6,13 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse { -ExecutionResult::ExecutionResult(impl::BlockWrapperPtr block) - : block_{std::move(block)} {} +ExecutionResult::ExecutionResult(impl::BlockWrapperPtr block) : block_{std::move(block)} {} ExecutionResult::ExecutionResult(ExecutionResult&&) noexcept = default; ExecutionResult::~ExecutionResult() = default; -size_t ExecutionResult::GetColumnsCount() const { - return block_->GetColumnsCount(); -} +size_t ExecutionResult::GetColumnsCount() const { return block_->GetColumnsCount(); } size_t ExecutionResult::GetRowsCount() const { return block_->GetRowsCount(); } diff --git a/clickhouse/src/storages/clickhouse/impl/block_wrapper.cpp b/clickhouse/src/storages/clickhouse/impl/block_wrapper.cpp index 0e37e39d43cd..6f0eeab9913d 100644 --- a/clickhouse/src/storages/clickhouse/impl/block_wrapper.cpp +++ b/clickhouse/src/storages/clickhouse/impl/block_wrapper.cpp @@ -6,26 +6,19 @@ namespace storages::clickhouse::impl { BlockWrapper::BlockWrapper(clickhouse_cpp::Block&& block) : native_{block} {} -clickhouse_cpp::ColumnRef BlockWrapper::At(size_t ind) const { - return native_[ind]; -} +clickhouse_cpp::ColumnRef BlockWrapper::At(size_t ind) const { return native_[ind]; } -size_t BlockWrapper::GetColumnsCount() const { - return native_.GetColumnCount(); -} +size_t BlockWrapper::GetColumnsCount() const { return native_.GetColumnCount(); } size_t BlockWrapper::GetRowsCount() const { return native_.GetRowCount(); } -void BlockWrapper::AppendColumn(std::string_view name, - const clickhouse_cpp::ColumnRef& column) { - native_.AppendColumn(std::string{name}, column); +void BlockWrapper::AppendColumn(std::string_view name, const clickhouse_cpp::ColumnRef& column) { + native_.AppendColumn(std::string{name}, column); } const clickhouse_cpp::Block& BlockWrapper::GetNative() const { return native_; } -void BlockWrapperDeleter::operator()(BlockWrapper* ptr) const noexcept { - std::default_delete{}(ptr); -} +void BlockWrapperDeleter::operator()(BlockWrapper* ptr) const noexcept { std::default_delete{}(ptr); } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/block_wrapper.hpp b/clickhouse/src/storages/clickhouse/impl/block_wrapper.hpp index 91d56c06160b..9ca9fbc2747c 100644 --- a/clickhouse/src/storages/clickhouse/impl/block_wrapper.hpp +++ b/clickhouse/src/storages/clickhouse/impl/block_wrapper.hpp @@ -11,22 +11,21 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { class BlockWrapper final { - public: - BlockWrapper(clickhouse_cpp::Block&& block); +public: + BlockWrapper(clickhouse_cpp::Block&& block); - clickhouse_cpp::ColumnRef At(size_t ind) const; + clickhouse_cpp::ColumnRef At(size_t ind) const; - size_t GetColumnsCount() const; + size_t GetColumnsCount() const; - size_t GetRowsCount() const; + size_t GetRowsCount() const; - void AppendColumn(std::string_view name, - const clickhouse_cpp::ColumnRef& column); + void AppendColumn(std::string_view name, const clickhouse_cpp::ColumnRef& column); - const clickhouse_cpp::Block& GetNative() const; + const clickhouse_cpp::Block& GetNative() const; - private: - clickhouse_cpp::Block native_; +private: + clickhouse_cpp::Block native_; }; } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/connection.cpp b/clickhouse/src/storages/clickhouse/impl/connection.cpp index 4b18edf18c9d..b2cc4431e139 100644 --- a/clickhouse/src/storages/clickhouse/impl/connection.cpp +++ b/clickhouse/src/storages/clickhouse/impl/connection.cpp @@ -27,107 +27,98 @@ using NativeBlock = clickhouse_cpp::Block; constexpr std::chrono::milliseconds kDefaultExecuteTimeout{750}; void AppendToBlock(NativeBlock& result, const NativeBlock& new_data) { - if (new_data.GetColumnCount() == 0) return; - if (result.GetRowCount() == 0) { - result = new_data; - return; - } - UINVARIANT(result.GetColumnCount() == new_data.GetColumnCount(), - "Shouldn't happen"); - - for (size_t ind = 0; ind < result.GetColumnCount(); ++ind) { - const auto& result_column = result[ind]; - const auto& new_column = new_data[ind]; - UINVARIANT(result_column->Type()->IsEqual(new_column->Type()), - "Shouldn't happen"); - result_column->Append(new_column); - } - - result.RefreshRowCount(); + if (new_data.GetColumnCount() == 0) return; + if (result.GetRowCount() == 0) { + result = new_data; + return; + } + UINVARIANT(result.GetColumnCount() == new_data.GetColumnCount(), "Shouldn't happen"); + + for (size_t ind = 0; ind < result.GetColumnCount(); ++ind) { + const auto& result_column = result[ind]; + const auto& new_column = new_data[ind]; + UINVARIANT(result_column->Type()->IsEqual(new_column->Type()), "Shouldn't happen"); + result_column->Append(new_column); + } + + result.RefreshRowCount(); } engine::Deadline GetDeadline(OptionalCommandControl optional_cc) { - const auto duration = - optional_cc.has_value() ? optional_cc->execute : kDefaultExecuteTimeout; + const auto duration = optional_cc.has_value() ? optional_cc->execute : kDefaultExecuteTimeout; - return engine::Deadline::FromDuration(duration); + return engine::Deadline::FromDuration(duration); } } // namespace class Connection::ConnectionBrokenGuard final { - public: - ConnectionBrokenGuard(bool& broken) - : exceptions_on_enter_{std::uncaught_exceptions()}, broken_{broken} { - UINVARIANT(!broken_, "Connection is broken"); - } - - ~ConnectionBrokenGuard() { - if (std::uncaught_exceptions() != exceptions_on_enter_) { - broken_ = true; +public: + ConnectionBrokenGuard(bool& broken) : exceptions_on_enter_{std::uncaught_exceptions()}, broken_{broken} { + UINVARIANT(!broken_, "Connection is broken"); } - } - private: - const int exceptions_on_enter_; - bool& broken_; + ~ConnectionBrokenGuard() { + if (std::uncaught_exceptions() != exceptions_on_enter_) { + broken_ = true; + } + } + +private: + const int exceptions_on_enter_; + bool& broken_; }; -Connection::Connection(clients::dns::Resolver& resolver, - const EndpointSettings& endpoint, - const AuthSettings& auth, - const ConnectionSettings& connection_settings) - : client_{NativeClientFactory::Create(resolver, endpoint, auth, - connection_settings)} {} +Connection::Connection( + clients::dns::Resolver& resolver, + const EndpointSettings& endpoint, + const AuthSettings& auth, + const ConnectionSettings& connection_settings +) + : client_{NativeClientFactory::Create(resolver, endpoint, auth, connection_settings)} {} -ExecutionResult Connection::Execute(OptionalCommandControl optional_cc, - const Query& query) { - clickhouse_cpp::Query native_query{query.QueryText()}; - native_query.OnDataCancelable([]([[maybe_unused]] const auto& block) { - // we must return 'true' if we don't want to cancel query - return !engine::current_task::ShouldCancel(); - }); +ExecutionResult Connection::Execute(OptionalCommandControl optional_cc, const Query& query) { + clickhouse_cpp::Query native_query{query.QueryText()}; + native_query.OnDataCancelable([]([[maybe_unused]] const auto& block) { + // we must return 'true' if we don't want to cancel query + return !engine::current_task::ShouldCancel(); + }); - auto& span = tracing::Span::CurrentSpan(); - auto scope = span.CreateScopeTime(scopes::kExec); + auto& span = tracing::Span::CurrentSpan(); + auto scope = span.CreateScopeTime(scopes::kExec); - NativeBlock result{}; - native_query.OnData([&result, &scope](const NativeBlock& data) { - scope.Reset(scopes::kExec); - AppendToBlock(result, data); - }); + NativeBlock result{}; + native_query.OnData([&result, &scope](const NativeBlock& data) { + scope.Reset(scopes::kExec); + AppendToBlock(result, data); + }); - DoExecute(optional_cc, native_query); + DoExecute(optional_cc, native_query); - auto result_ptr = std::make_unique(std::move(result)); + auto result_ptr = std::make_unique(std::move(result)); - return ExecutionResult{BlockWrapperPtr{result_ptr.release()}}; + return ExecutionResult{BlockWrapperPtr{result_ptr.release()}}; } -void Connection::Insert(OptionalCommandControl optional_cc, - const InsertionRequest& request) { - const auto& block = request.GetBlock(); +void Connection::Insert(OptionalCommandControl optional_cc, const InsertionRequest& request) { + const auto& block = request.GetBlock(); - auto guard = GetBrokenGuard(); - client_.Insert(request.GetTableName(), block.GetNative(), - GetDeadline(optional_cc)); + auto guard = GetBrokenGuard(); + client_.Insert(request.GetTableName(), block.GetNative(), GetDeadline(optional_cc)); } void Connection::Ping() { - auto guard = GetBrokenGuard(); - client_.Ping(GetDeadline({})); + auto guard = GetBrokenGuard(); + client_.Ping(GetDeadline({})); } bool Connection::IsBroken() const noexcept { return broken_; } -Connection::ConnectionBrokenGuard Connection::GetBrokenGuard() { - return ConnectionBrokenGuard{broken_}; -} +Connection::ConnectionBrokenGuard Connection::GetBrokenGuard() { return ConnectionBrokenGuard{broken_}; } -void Connection::DoExecute(OptionalCommandControl optional_cc, - const clickhouse_cpp::Query& query) { - auto guard = GetBrokenGuard(); - client_.Execute(query, GetDeadline(optional_cc)); +void Connection::DoExecute(OptionalCommandControl optional_cc, const clickhouse_cpp::Query& query) { + auto guard = GetBrokenGuard(); + client_.Execute(query, GetDeadline(optional_cc)); } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/connection.hpp b/clickhouse/src/storages/clickhouse/impl/connection.hpp index 5b0c2e8fe7e0..4b008123473d 100644 --- a/clickhouse/src/storages/clickhouse/impl/connection.hpp +++ b/clickhouse/src/storages/clickhouse/impl/connection.hpp @@ -22,26 +22,25 @@ struct ConnectionSettings; class InsertionRequest; class Connection final { - public: - Connection(clients::dns::Resolver&, const EndpointSettings&, - const AuthSettings&, const ConnectionSettings&); +public: + Connection(clients::dns::Resolver&, const EndpointSettings&, const AuthSettings&, const ConnectionSettings&); - ExecutionResult Execute(OptionalCommandControl, const Query&); + ExecutionResult Execute(OptionalCommandControl, const Query&); - void Insert(OptionalCommandControl, const InsertionRequest&); + void Insert(OptionalCommandControl, const InsertionRequest&); - void Ping(); + void Ping(); - bool IsBroken() const noexcept; + bool IsBroken() const noexcept; - private: - class ConnectionBrokenGuard; - ConnectionBrokenGuard GetBrokenGuard(); +private: + class ConnectionBrokenGuard; + ConnectionBrokenGuard GetBrokenGuard(); - void DoExecute(OptionalCommandControl, const clickhouse_cpp::Query&); + void DoExecute(OptionalCommandControl, const clickhouse_cpp::Query&); - NativeClientWrapper client_; - bool broken_{false}; + NativeClientWrapper client_; + bool broken_{false}; }; } // namespace impl } // namespace storages::clickhouse diff --git a/clickhouse/src/storages/clickhouse/impl/connection_ptr.cpp b/clickhouse/src/storages/clickhouse/impl/connection_ptr.cpp index 01554a6cf276..6dce4fb5fbb8 100644 --- a/clickhouse/src/storages/clickhouse/impl/connection_ptr.cpp +++ b/clickhouse/src/storages/clickhouse/impl/connection_ptr.cpp @@ -19,9 +19,9 @@ Connection& ConnectionPtr::operator*() const { return *conn_; } Connection* ConnectionPtr::operator->() const noexcept { return conn_.get(); } void ConnectionPtr::Release() noexcept { - if (!conn_) return; + if (!conn_) return; - pool_->Release(conn_.release()); + pool_->Release(conn_.release()); } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/connection_ptr.hpp b/clickhouse/src/storages/clickhouse/impl/connection_ptr.hpp index ed6f067f0b31..331d6657ab0f 100644 --- a/clickhouse/src/storages/clickhouse/impl/connection_ptr.hpp +++ b/clickhouse/src/storages/clickhouse/impl/connection_ptr.hpp @@ -10,20 +10,20 @@ class Connection; class PoolImpl; class ConnectionPtr final { - public: - ConnectionPtr(std::shared_ptr&&, Connection*); - ~ConnectionPtr() noexcept; +public: + ConnectionPtr(std::shared_ptr&&, Connection*); + ~ConnectionPtr() noexcept; - ConnectionPtr(ConnectionPtr&&) noexcept; + ConnectionPtr(ConnectionPtr&&) noexcept; - Connection& operator*() const; - Connection* operator->() const noexcept; + Connection& operator*() const; + Connection* operator->() const noexcept; - private: - void Release() noexcept; +private: + void Release() noexcept; - std::shared_ptr pool_; - std::unique_ptr conn_; + std::shared_ptr pool_; + std::unique_ptr conn_; }; } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/insertion_request.cpp b/clickhouse/src/storages/clickhouse/impl/insertion_request.cpp index a1858499032b..746960823a26 100644 --- a/clickhouse/src/storages/clickhouse/impl/insertion_request.cpp +++ b/clickhouse/src/storages/clickhouse/impl/insertion_request.cpp @@ -8,21 +8,16 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { -InsertionRequest::InsertionRequest( - const std::string& table_name, - const std::vector& column_names) +InsertionRequest::InsertionRequest(const std::string& table_name, const std::vector& column_names) : table_name_{table_name}, column_names_{column_names}, - block_{std::make_unique( - impl::clickhouse_cpp::Block{column_names_.size(), 0})} {} + block_{std::make_unique(impl::clickhouse_cpp::Block{column_names_.size(), 0})} {} InsertionRequest::InsertionRequest(InsertionRequest&&) noexcept = default; InsertionRequest::~InsertionRequest() = default; -const std::string& InsertionRequest::GetTableName() const { - return table_name_; -} +const std::string& InsertionRequest::GetTableName() const { return table_name_; } const impl::BlockWrapper& InsertionRequest::GetBlock() const { return *block_; } diff --git a/clickhouse/src/storages/clickhouse/impl/native_client_factory.cpp b/clickhouse/src/storages/clickhouse/impl/native_client_factory.cpp index 0411aa5431a9..81fc014f5caa 100644 --- a/clickhouse/src/storages/clickhouse/impl/native_client_factory.cpp +++ b/clickhouse/src/storages/clickhouse/impl/native_client_factory.cpp @@ -38,104 +38,94 @@ constexpr std::chrono::milliseconds kConnectTimeout{1500}; template class ClickhouseSocketInput final : public clickhouse_cpp::InputStream { - public: - ClickhouseSocketInput(T& socket, engine::Deadline& deadline) - : socket_{socket}, deadline_{deadline} {} - ~ClickhouseSocketInput() override = default; +public: + ClickhouseSocketInput(T& socket, engine::Deadline& deadline) : socket_{socket}, deadline_{deadline} {} + ~ClickhouseSocketInput() override = default; - protected: - bool Skip([[maybe_unused]] size_t unused) override { return false; } +protected: + bool Skip([[maybe_unused]] size_t unused) override { return false; } - size_t DoRead(void* buf, size_t len) override { - if (deadline_.IsReached()) throw engine::io::IoTimeout{}; + size_t DoRead(void* buf, size_t len) override { + if (deadline_.IsReached()) throw engine::io::IoTimeout{}; - const auto read = socket_.RecvSome(buf, len, deadline_); + const auto read = socket_.RecvSome(buf, len, deadline_); - if (!read) throw engine::io::IoException{"socket reset by peer"}; + if (!read) throw engine::io::IoException{"socket reset by peer"}; - return read; - } + return read; + } - private: - T& socket_; - engine::Deadline& deadline_; +private: + T& socket_; + engine::Deadline& deadline_; }; template class ClickhouseSocketOutput final : public clickhouse_cpp::OutputStream { - public: - ClickhouseSocketOutput(T& socket, engine::Deadline& deadline) - : socket_{socket}, deadline_{deadline} {} - ~ClickhouseSocketOutput() override = default; +public: + ClickhouseSocketOutput(T& socket, engine::Deadline& deadline) : socket_{socket}, deadline_{deadline} {} + ~ClickhouseSocketOutput() override = default; - protected: - size_t DoWrite(const void* data, size_t len) override { - if (deadline_.IsReached()) throw engine::io::IoTimeout{}; +protected: + size_t DoWrite(const void* data, size_t len) override { + if (deadline_.IsReached()) throw engine::io::IoTimeout{}; - const auto sent = socket_.SendAll(data, len, deadline_); - if (sent != len) throw engine::io::IoException{"broken pipe?"}; + const auto sent = socket_.SendAll(data, len, deadline_); + if (sent != len) throw engine::io::IoException{"broken pipe?"}; - return sent; - } + return sent; + } - private: - T& socket_; - engine::Deadline& deadline_; +private: + T& socket_; + engine::Deadline& deadline_; }; Socket CreateSocket(engine::io::Sockaddr addr, engine::Deadline deadline) { - Socket socket{addr.Domain(), engine::io::SocketType::kTcp}; - socket.SetOption(IPPROTO_TCP, TCP_NODELAY, 1); - socket.Connect(addr, deadline); + Socket socket{addr.Domain(), engine::io::SocketType::kTcp}; + socket.SetOption(IPPROTO_TCP, TCP_NODELAY, 1); + socket.Connect(addr, deadline); - return socket; + return socket; } class ClickhouseSocketAdapter : public clickhouse_cpp::SocketBase { - public: - ClickhouseSocketAdapter(engine::io::Sockaddr addr, engine::Deadline& deadline) - : deadline_{deadline}, socket_{CreateSocket(addr, deadline_)} {} +public: + ClickhouseSocketAdapter(engine::io::Sockaddr addr, engine::Deadline& deadline) + : deadline_{deadline}, socket_{CreateSocket(addr, deadline_)} {} - ~ClickhouseSocketAdapter() override { socket_.Close(); } + ~ClickhouseSocketAdapter() override { socket_.Close(); } - std::unique_ptr makeInputStream() - const override { - return std::make_unique>(socket_, deadline_); - } + std::unique_ptr makeInputStream() const override { + return std::make_unique>(socket_, deadline_); + } - std::unique_ptr makeOutputStream() - const override { - return std::make_unique>(socket_, deadline_); - } + std::unique_ptr makeOutputStream() const override { + return std::make_unique>(socket_, deadline_); + } - private: - engine::Deadline& deadline_; - mutable Socket socket_; +private: + engine::Deadline& deadline_; + mutable Socket socket_; }; class ClickhouseTlsSocketAdapter : public clickhouse_cpp::SocketBase { - public: - ClickhouseTlsSocketAdapter(engine::io::Sockaddr addr, - engine::Deadline& deadline) - : deadline_{deadline}, - tls_socket_{engine::io::TlsWrapper::StartTlsClient( - CreateSocket(addr, deadline_), {}, deadline_)} {} - - std::unique_ptr makeInputStream() - const override { - return std::make_unique>(tls_socket_, - deadline_); - } - - std::unique_ptr makeOutputStream() - const override { - return std::make_unique>(tls_socket_, - deadline_); - } - - private: - engine::Deadline& deadline_; - mutable TlsSocket tls_socket_; +public: + ClickhouseTlsSocketAdapter(engine::io::Sockaddr addr, engine::Deadline& deadline) + : deadline_{deadline}, + tls_socket_{engine::io::TlsWrapper::StartTlsClient(CreateSocket(addr, deadline_), {}, deadline_)} {} + + std::unique_ptr makeInputStream() const override { + return std::make_unique>(tls_socket_, deadline_); + } + + std::unique_ptr makeOutputStream() const override { + return std::make_unique>(tls_socket_, deadline_); + } + +private: + engine::Deadline& deadline_; + mutable TlsSocket tls_socket_; }; // Clickhouse-cpp broke the API in 2.5.0: @@ -144,140 +134,132 @@ class ClickhouseTlsSocketAdapter : public clickhouse_cpp::SocketBase { // We don't need that anyway, but have to somehow override the function, // so we maintain two versions which both resolve to the same logic. class ClickhouseCppSocketFactoryHack : public clickhouse_cpp::SocketFactory { - public: - // NOLINTNEXTLINE - std::unique_ptr connect( +public: + // NOLINTNEXTLINE + std::unique_ptr connect( const clickhouse_cpp::ClientOptions& opts, // This Endpoint value comes from 'endpoints' field in opts, which we // don't use, since we only have one host/port pair per connection const clickhouse_cpp::Endpoint&) { - return DoConnect(opts); - } - - // NOLINTNEXTLINE - std::unique_ptr connect( - const clickhouse_cpp::ClientOptions& opts) { - return DoConnect(opts); - } - - protected: - virtual std::unique_ptr DoConnect( - const clickhouse_cpp::ClientOptions& opts) = 0; + return DoConnect(opts); + } + + // NOLINTNEXTLINE + std::unique_ptr connect(const clickhouse_cpp::ClientOptions& opts) { + return DoConnect(opts); + } + +protected: + virtual std::unique_ptr DoConnect(const clickhouse_cpp::ClientOptions& opts) = 0; }; class ClickhouseSocketFactory final : public ClickhouseCppSocketFactoryHack { - public: - ClickhouseSocketFactory(clients::dns::Resolver& resolver, ConnectionMode mode, - engine::Deadline& operations_deadline) - : resolver_{resolver}, - mode_{mode}, - operations_deadline_{operations_deadline} {} - - ~ClickhouseSocketFactory() override = default; - - void sleepFor(const std::chrono::milliseconds& duration) override { - engine::SleepFor(duration); - } - - private: - std::unique_ptr DoConnect( - const clickhouse_cpp::ClientOptions& opts) override { - auto addrs = resolver_.Resolve(opts.host, operations_deadline_); - - for (auto&& current_addr : addrs) { - current_addr.SetPort(static_cast(opts.port)); - - try { - // Each connect attempt should have its own timeout to avoid situation - // of one attempt consuming the whole budget. - operations_deadline_ = engine::Deadline::FromDuration(kConnectTimeout); - - switch (mode_) { - case ConnectionMode::kNonSecure: - return std::make_unique( - current_addr, operations_deadline_); - case ConnectionMode::kSecure: - return std::make_unique( - current_addr, operations_deadline_); +public: + ClickhouseSocketFactory( + clients::dns::Resolver& resolver, + ConnectionMode mode, + engine::Deadline& operations_deadline + ) + : resolver_{resolver}, mode_{mode}, operations_deadline_{operations_deadline} {} + + ~ClickhouseSocketFactory() override = default; + + void sleepFor(const std::chrono::milliseconds& duration) override { engine::SleepFor(duration); } + +private: + std::unique_ptr DoConnect(const clickhouse_cpp::ClientOptions& opts) override { + auto addrs = resolver_.Resolve(opts.host, operations_deadline_); + + for (auto&& current_addr : addrs) { + current_addr.SetPort(static_cast(opts.port)); + + try { + // Each connect attempt should have its own timeout to avoid situation + // of one attempt consuming the whole budget. + operations_deadline_ = engine::Deadline::FromDuration(kConnectTimeout); + + switch (mode_) { + case ConnectionMode::kNonSecure: + return std::make_unique(current_addr, operations_deadline_); + case ConnectionMode::kSecure: + return std::make_unique(current_addr, operations_deadline_); + } + } catch (const std::exception&) { + } } - } catch (const std::exception&) { - } - } - throw std::runtime_error{ - fmt::format("Could not connect to any of the resolved addresses: {}", - fmt::join(addrs, ", "))}; - } + throw std::runtime_error{ + fmt::format("Could not connect to any of the resolved addresses: {}", fmt::join(addrs, ", "))}; + } - clients::dns::Resolver& resolver_; - ConnectionMode mode_; + clients::dns::Resolver& resolver_; + ConnectionMode mode_; - engine::Deadline& operations_deadline_; + engine::Deadline& operations_deadline_; }; -clickhouse_cpp::CompressionMethod GetCompressionMethod( - CompressionMethod method) { - switch (method) { - case CompressionMethod::kNone: - return clickhouse_cpp::CompressionMethod::None; - case CompressionMethod::kLZ4: - return clickhouse_cpp::CompressionMethod::LZ4; - } - UINVARIANT(false, "Invalid value of CompressionMethod enum"); +clickhouse_cpp::CompressionMethod GetCompressionMethod(CompressionMethod method) { + switch (method) { + case CompressionMethod::kNone: + return clickhouse_cpp::CompressionMethod::None; + case CompressionMethod::kLZ4: + return clickhouse_cpp::CompressionMethod::LZ4; + } + UINVARIANT(false, "Invalid value of CompressionMethod enum"); } } // namespace NativeClientWrapper::NativeClientWrapper( clients::dns::Resolver& resolver, - const clickhouse_cpp::ClientOptions& options, ConnectionMode mode) { - SetDeadline(engine::Deadline::FromDuration(kConnectTimeout)); + const clickhouse_cpp::ClientOptions& options, + ConnectionMode mode +) { + SetDeadline(engine::Deadline::FromDuration(kConnectTimeout)); - auto socket_factory = std::make_unique( - resolver, mode, operations_deadline_); - native_client_ = std::make_unique( - options, std::move(socket_factory)); + auto socket_factory = std::make_unique(resolver, mode, operations_deadline_); + native_client_ = std::make_unique(options, std::move(socket_factory)); } NativeClientWrapper::~NativeClientWrapper() = default; -void NativeClientWrapper::Execute(const clickhouse_cpp::Query& query, - engine::Deadline deadline) { - SetDeadline(deadline); - native_client_->Execute(query); +void NativeClientWrapper::Execute(const clickhouse_cpp::Query& query, engine::Deadline deadline) { + SetDeadline(deadline); + native_client_->Execute(query); } -void NativeClientWrapper::Insert(const std::string& table_name, - const clickhouse_cpp::Block& block, - engine::Deadline deadline) { - SetDeadline(deadline); - native_client_->Insert(table_name, block); +void NativeClientWrapper::Insert( + const std::string& table_name, + const clickhouse_cpp::Block& block, + engine::Deadline deadline +) { + SetDeadline(deadline); + native_client_->Insert(table_name, block); } void NativeClientWrapper::Ping(engine::Deadline deadline) { - SetDeadline(deadline); - native_client_->Ping(); + SetDeadline(deadline); + native_client_->Ping(); } -void NativeClientWrapper::SetDeadline(engine::Deadline deadline) { - operations_deadline_ = deadline; -} +void NativeClientWrapper::SetDeadline(engine::Deadline deadline) { operations_deadline_ = deadline; } NativeClientWrapper NativeClientFactory::Create( - clients::dns::Resolver& resolver, const EndpointSettings& endpoint, - const AuthSettings& auth, const ConnectionSettings& connection_settings) { - const auto options = clickhouse_cpp::ClientOptions{} - .SetHost(endpoint.host) - .SetPort(endpoint.port) - .SetUser(auth.user) - .SetPassword(auth.password) - .SetDefaultDatabase(auth.database) - .SetCompressionMethod(GetCompressionMethod( - connection_settings.compression_method)); - - tracing::Span span{scopes::kConnect}; - return NativeClientWrapper{resolver, options, - connection_settings.connection_mode}; + clients::dns::Resolver& resolver, + const EndpointSettings& endpoint, + const AuthSettings& auth, + const ConnectionSettings& connection_settings +) { + const auto options = clickhouse_cpp::ClientOptions{} + .SetHost(endpoint.host) + .SetPort(endpoint.port) + .SetUser(auth.user) + .SetPassword(auth.password) + .SetDefaultDatabase(auth.database) + .SetCompressionMethod(GetCompressionMethod(connection_settings.compression_method)); + + tracing::Span span{scopes::kConnect}; + return NativeClientWrapper{resolver, options, connection_settings.connection_mode}; } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/native_client_factory.hpp b/clickhouse/src/storages/clickhouse/impl/native_client_factory.hpp index 63206e45228a..ee87500b2cad 100644 --- a/clickhouse/src/storages/clickhouse/impl/native_client_factory.hpp +++ b/clickhouse/src/storages/clickhouse/impl/native_client_factory.hpp @@ -21,31 +21,30 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { class NativeClientWrapper final { - public: - NativeClientWrapper(clients::dns::Resolver&, - const clickhouse_cpp::ClientOptions&, - ConnectionSettings::ConnectionMode); - ~NativeClientWrapper(); +public: + NativeClientWrapper( + clients::dns::Resolver&, + const clickhouse_cpp::ClientOptions&, + ConnectionSettings::ConnectionMode + ); + ~NativeClientWrapper(); - void Execute(const clickhouse_cpp::Query& query, engine::Deadline deadline); - void Insert(const std::string& table_name, const clickhouse_cpp::Block& block, - engine::Deadline deadline); - void Ping(engine::Deadline deadline); + void Execute(const clickhouse_cpp::Query& query, engine::Deadline deadline); + void Insert(const std::string& table_name, const clickhouse_cpp::Block& block, engine::Deadline deadline); + void Ping(engine::Deadline deadline); - private: - void SetDeadline(engine::Deadline deadline); +private: + void SetDeadline(engine::Deadline deadline); - engine::Deadline operations_deadline_; + engine::Deadline operations_deadline_; - std::unique_ptr native_client_; + std::unique_ptr native_client_; }; class NativeClientFactory final { - public: - static NativeClientWrapper Create(clients::dns::Resolver&, - const EndpointSettings&, - const AuthSettings&, - const ConnectionSettings&); +public: + static NativeClientWrapper + Create(clients::dns::Resolver&, const EndpointSettings&, const AuthSettings&, const ConnectionSettings&); }; } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/pool.cpp b/clickhouse/src/storages/clickhouse/impl/pool.cpp index 9d85cb70bb72..e016f41d43f3 100644 --- a/clickhouse/src/storages/clickhouse/impl/pool.cpp +++ b/clickhouse/src/storages/clickhouse/impl/pool.cpp @@ -17,48 +17,43 @@ namespace storages::clickhouse::impl { namespace { -tracing::Span PrepareExecutionSpan(const std::string& scope, - const std::string& db_instance) { - tracing::Span span{scope}; - span.AddTag(tracing::kDatabaseInstance, db_instance); +tracing::Span PrepareExecutionSpan(const std::string& scope, const std::string& db_instance) { + tracing::Span span{scope}; + span.AddTag(tracing::kDatabaseInstance, db_instance); - return span; + return span; } } // namespace Pool::Pool(clients::dns::Resolver& resolver, PoolSettings&& settings) : impl_{std::make_shared(resolver, std::move(settings))} { - impl_->StartMaintenance(); + impl_->StartMaintenance(); } Pool::~Pool() = default; -ExecutionResult Pool::Execute(OptionalCommandControl optional_cc, - const Query& query) const { - auto conn_ptr = impl_->Acquire(); +ExecutionResult Pool::Execute(OptionalCommandControl optional_cc, const Query& query) const { + auto conn_ptr = impl_->Acquire(); - auto span = PrepareExecutionSpan(impl::scopes::kQuery, impl_->GetHostName()); - query.FillSpanTags(span); + auto span = PrepareExecutionSpan(impl::scopes::kQuery, impl_->GetHostName()); + query.FillSpanTags(span); - const auto timer = impl_->GetExecuteTimer(); - return conn_ptr->Execute(optional_cc, query); + const auto timer = impl_->GetExecuteTimer(); + return conn_ptr->Execute(optional_cc, query); } -void Pool::Insert(OptionalCommandControl optional_cc, - const InsertionRequest& request) const { - auto conn_ptr = impl_->Acquire(); +void Pool::Insert(OptionalCommandControl optional_cc, const InsertionRequest& request) const { + auto conn_ptr = impl_->Acquire(); - auto span = PrepareExecutionSpan(impl::scopes::kInsert, impl_->GetHostName()); + auto span = PrepareExecutionSpan(impl::scopes::kInsert, impl_->GetHostName()); - const auto timer = impl_->GetInsertTimer(); - conn_ptr->Insert(optional_cc, request); + const auto timer = impl_->GetInsertTimer(); + conn_ptr->Insert(optional_cc, request); } -void Pool::WriteStatistics( - USERVER_NAMESPACE::utils::statistics::Writer& writer) const { - writer.ValueWithLabels(impl_->GetStatistics(), - {{"clickhouse_instance", impl_->GetHostName()}}); +void Pool::WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const { + writer.ValueWithLabels(impl_->GetStatistics(), {{"clickhouse_instance", impl_->GetHostName()}}); } bool Pool::IsAvailable() const { return impl_->IsAvailable(); } diff --git a/clickhouse/src/storages/clickhouse/impl/pool_impl.cpp b/clickhouse/src/storages/clickhouse/impl/pool_impl.cpp index 91fec0055e36..64d3cca1f97d 100644 --- a/clickhouse/src/storages/clickhouse/impl/pool_impl.cpp +++ b/clickhouse/src/storages/clickhouse/impl/pool_impl.cpp @@ -23,176 +23,154 @@ const std::string kMaintenanceTaskName = "clickhouse_maintain"; } // namespace bool PoolAvailabilityMonitor::IsAvailable() const { - const auto last_successful_communication = - last_successful_communication_.load(); - if (last_successful_communication == TimePoint{}) { - return last_unsuccessful_communication_.load() == TimePoint{}; - } - - const auto now = Clock::now(); - return std::chrono::duration_cast( - now - last_successful_communication) < PoolUnavailableThreshold; -} + const auto last_successful_communication = last_successful_communication_.load(); + if (last_successful_communication == TimePoint{}) { + return last_unsuccessful_communication_.load() == TimePoint{}; + } -void PoolAvailabilityMonitor::AccountSuccess() noexcept { - last_successful_communication_ = Clock::now(); + const auto now = Clock::now(); + return std::chrono::duration_cast(now - last_successful_communication) < + PoolUnavailableThreshold; } -void PoolAvailabilityMonitor::AccountFailure() noexcept { - last_unsuccessful_communication_ = Clock::now(); -} +void PoolAvailabilityMonitor::AccountSuccess() noexcept { last_successful_communication_ = Clock::now(); } + +void PoolAvailabilityMonitor::AccountFailure() noexcept { last_unsuccessful_communication_ = Clock::now(); } struct PoolImpl::MaintenanceConnectionDeleter final { - void operator()(Connection* connection_ptr) noexcept { - const auto is_broken = connection_ptr->IsBroken(); - if (!is_broken) { - pool.availability_monitor_.AccountSuccess(); - } + void operator()(Connection* connection_ptr) noexcept { + const auto is_broken = connection_ptr->IsBroken(); + if (!is_broken) { + pool.availability_monitor_.AccountSuccess(); + } - pool.DoRelease(ConnectionUniquePtr{connection_ptr}); - } + pool.DoRelease(ConnectionUniquePtr{connection_ptr}); + } - PoolImpl& pool; + PoolImpl& pool; }; PoolImpl::PoolImpl(clients::dns::Resolver& resolver, PoolSettings&& settings) - : drivers::impl::ConnectionPoolBase< - Connection, PoolImpl>{settings.max_pool_size, - kMaxSimultaneouslyConnectingClients}, + : drivers::impl:: + ConnectionPoolBase{settings.max_pool_size, kMaxSimultaneouslyConnectingClients}, resolver_{resolver}, pool_settings_{std::move(settings)} { - try { - Init(pool_settings_.initial_pool_size, kConnectTimeout); - } catch (const std::exception&) { - // This is already logged in base class, and it's also fine: - // host might be under maintenance currently and will become alive at some - // point. - // TODO : rethrow on auth errors, these are fatal - } + try { + Init(pool_settings_.initial_pool_size, kConnectTimeout); + } catch (const std::exception&) { + // This is already logged in base class, and it's also fine: + // host might be under maintenance currently and will become alive at some + // point. + // TODO : rethrow on auth errors, these are fatal + } } PoolImpl::~PoolImpl() { - StopMaintenance(); + StopMaintenance(); - Reset(); + Reset(); } -bool PoolImpl::IsAvailable() const { - return availability_monitor_.IsAvailable(); -} +bool PoolImpl::IsAvailable() const { return availability_monitor_.IsAvailable(); } ConnectionPtr PoolImpl::Acquire() { - auto pool_and_connection = AcquireConnection( - engine::Deadline::FromDuration(pool_settings_.queue_timeout)); + auto pool_and_connection = AcquireConnection(engine::Deadline::FromDuration(pool_settings_.queue_timeout)); - return {std::move(pool_and_connection.pool_ptr), - pool_and_connection.connection_ptr.release()}; + return {std::move(pool_and_connection.pool_ptr), pool_and_connection.connection_ptr.release()}; } void PoolImpl::Release(Connection* connection_ptr) { - UASSERT(connection_ptr); + UASSERT(connection_ptr); - const auto is_broken = connection_ptr->IsBroken(); - if (!is_broken) { - availability_monitor_.AccountSuccess(); - } + const auto is_broken = connection_ptr->IsBroken(); + if (!is_broken) { + availability_monitor_.AccountSuccess(); + } - ReleaseConnection(ConnectionUniquePtr{connection_ptr}); + ReleaseConnection(ConnectionUniquePtr{connection_ptr}); } -stats::PoolStatistics& PoolImpl::GetStatistics() noexcept { - return statistics_; -} +stats::PoolStatistics& PoolImpl::GetStatistics() noexcept { return statistics_; } -const std::string& PoolImpl::GetHostName() const { - return pool_settings_.endpoint_settings.host; -} +const std::string& PoolImpl::GetHostName() const { return pool_settings_.endpoint_settings.host; } -stats::StatementTimer PoolImpl::GetInsertTimer() { - return stats::StatementTimer{statistics_.inserts}; -} +stats::StatementTimer PoolImpl::GetInsertTimer() { return stats::StatementTimer{statistics_.inserts}; } -stats::StatementTimer PoolImpl::GetExecuteTimer() { - return stats::StatementTimer{statistics_.queries}; -} +stats::StatementTimer PoolImpl::GetExecuteTimer() { return stats::StatementTimer{statistics_.queries}; } -void PoolImpl::AccountConnectionAcquired() { - ++GetStatistics().connections.busy; -} +void PoolImpl::AccountConnectionAcquired() { ++GetStatistics().connections.busy; } -void PoolImpl::AccountConnectionReleased() { - --GetStatistics().connections.busy; -} +void PoolImpl::AccountConnectionReleased() { --GetStatistics().connections.busy; } void PoolImpl::AccountConnectionCreated() { - auto& stats = GetStatistics().connections; - ++stats.created; - ++stats.active; + auto& stats = GetStatistics().connections; + ++stats.created; + ++stats.active; } void PoolImpl::AccountConnectionDestroyed() noexcept { - auto& stats = GetStatistics().connections; - ++stats.closed; - --stats.active; + auto& stats = GetStatistics().connections; + ++stats.closed; + --stats.active; } void PoolImpl::AccountOverload() { ++GetStatistics().connections.overload; } PoolImpl::ConnectionUniquePtr PoolImpl::DoCreateConnection(engine::Deadline) { - try { - return std::make_unique( - resolver_, pool_settings_.endpoint_settings, - pool_settings_.auth_settings, pool_settings_.connection_settings); - } catch (const std::exception&) { - availability_monitor_.AccountFailure(); - throw; - } + try { + return std::make_unique( + resolver_, + pool_settings_.endpoint_settings, + pool_settings_.auth_settings, + pool_settings_.connection_settings + ); + } catch (const std::exception&) { + availability_monitor_.AccountFailure(); + throw; + } } void PoolImpl::StartMaintenance() { - using PeriodicTask = USERVER_NAMESPACE::utils::PeriodicTask; + using PeriodicTask = USERVER_NAMESPACE::utils::PeriodicTask; - maintenance_task_.Start( - kMaintenanceTaskName, - {kMaintenanceInterval, {PeriodicTask::Flags::kStrong}}, - [this] { MaintainConnections(); }); + maintenance_task_.Start(kMaintenanceTaskName, {kMaintenanceInterval, {PeriodicTask::Flags::kStrong}}, [this] { + MaintainConnections(); + }); } void PoolImpl::StopMaintenance() { maintenance_task_.Stop(); } void PoolImpl::MaintainConnections() { - const auto failsafe_push_connection = [this] { - try { - PushConnection(engine::Deadline::FromDuration(kConnectTimeout)); - } catch (const std::exception& ex) { - LOG_ERROR() << "Failed to create connection: " << ex; + const auto failsafe_push_connection = [this] { + try { + PushConnection(engine::Deadline::FromDuration(kConnectTimeout)); + } catch (const std::exception& ex) { + LOG_ERROR() << "Failed to create connection: " << ex; + } + }; + + ConnectionUniquePtr connection_ptr = TryPop(); + if (!connection_ptr) { + if (AliveConnectionsCountApprox() < pool_settings_.initial_pool_size) { + failsafe_push_connection(); + } + + return; } - }; - ConnectionUniquePtr connection_ptr = TryPop(); - if (!connection_ptr) { - if (AliveConnectionsCountApprox() < pool_settings_.initial_pool_size) { - failsafe_push_connection(); + { + using Deleter = MaintenanceConnectionDeleter; + auto conn = std::unique_ptr{connection_ptr.release(), Deleter{*this}}; + try { + conn->Ping(); + } catch (const std::exception& ex) { + LOG_LIMITED_WARNING() << "Exception while pinging connection to '" << GetHostName() << "': " << ex; + } } - return; - } - - { - using Deleter = MaintenanceConnectionDeleter; - auto conn = std::unique_ptr{connection_ptr.release(), - Deleter{*this}}; - try { - conn->Ping(); - } catch (const std::exception& ex) { - LOG_LIMITED_WARNING() << "Exception while pinging connection to '" - << GetHostName() << "': " << ex; + if (AliveConnectionsCountApprox() < pool_settings_.initial_pool_size) { + failsafe_push_connection(); } - } - - if (AliveConnectionsCountApprox() < pool_settings_.initial_pool_size) { - failsafe_push_connection(); - } } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/pool_impl.hpp b/clickhouse/src/storages/clickhouse/impl/pool_impl.hpp index d2e093c3d8f6..51d0822de88f 100644 --- a/clickhouse/src/storages/clickhouse/impl/pool_impl.hpp +++ b/clickhouse/src/storages/clickhouse/impl/pool_impl.hpp @@ -25,65 +25,64 @@ class Connection; class ConnectionPtr; class PoolAvailabilityMonitor { - public: - using Clock = USERVER_NAMESPACE::utils::datetime::SteadyCoarseClock; - using TimePoint = Clock::time_point; +public: + using Clock = USERVER_NAMESPACE::utils::datetime::SteadyCoarseClock; + using TimePoint = Clock::time_point; - bool IsAvailable() const; + bool IsAvailable() const; - void AccountSuccess() noexcept; - void AccountFailure() noexcept; + void AccountSuccess() noexcept; + void AccountFailure() noexcept; - private: - std::atomic last_successful_communication_{TimePoint{}}; - std::atomic last_unsuccessful_communication_{TimePoint{}}; +private: + std::atomic last_successful_communication_{TimePoint{}}; + std::atomic last_unsuccessful_communication_{TimePoint{}}; - static_assert(std::atomic::is_always_lock_free); + static_assert(std::atomic::is_always_lock_free); }; -class PoolImpl final - : public drivers::impl::ConnectionPoolBase { - public: - PoolImpl(clients::dns::Resolver&, PoolSettings&& settings); - ~PoolImpl(); +class PoolImpl final : public drivers::impl::ConnectionPoolBase { +public: + PoolImpl(clients::dns::Resolver&, PoolSettings&& settings); + ~PoolImpl(); - bool IsAvailable() const; + bool IsAvailable() const; - ConnectionPtr Acquire(); - void Release(Connection*); + ConnectionPtr Acquire(); + void Release(Connection*); - stats::PoolStatistics& GetStatistics() noexcept; + stats::PoolStatistics& GetStatistics() noexcept; - const std::string& GetHostName() const; + const std::string& GetHostName() const; - void StartMaintenance(); + void StartMaintenance(); - stats::StatementTimer GetInsertTimer(); - stats::StatementTimer GetExecuteTimer(); + stats::StatementTimer GetInsertTimer(); + stats::StatementTimer GetExecuteTimer(); - private: - friend class drivers::impl::ConnectionPoolBase; +private: + friend class drivers::impl::ConnectionPoolBase; - void AccountConnectionAcquired(); - void AccountConnectionReleased(); - void AccountConnectionCreated(); - void AccountConnectionDestroyed() noexcept; - void AccountOverload(); + void AccountConnectionAcquired(); + void AccountConnectionReleased(); + void AccountConnectionCreated(); + void AccountConnectionDestroyed() noexcept; + void AccountOverload(); - ConnectionUniquePtr DoCreateConnection(engine::Deadline deadline); + ConnectionUniquePtr DoCreateConnection(engine::Deadline deadline); - void StopMaintenance(); - void MaintainConnections(); + void StopMaintenance(); + void MaintainConnections(); - struct MaintenanceConnectionDeleter; + struct MaintenanceConnectionDeleter; - clients::dns::Resolver& resolver_; - const PoolSettings pool_settings_; + clients::dns::Resolver& resolver_; + const PoolSettings pool_settings_; - stats::PoolStatistics statistics_{}; + stats::PoolStatistics statistics_{}; - PoolAvailabilityMonitor availability_monitor_{}; - USERVER_NAMESPACE::utils::PeriodicTask maintenance_task_; + PoolAvailabilityMonitor availability_monitor_{}; + USERVER_NAMESPACE::utils::PeriodicTask maintenance_task_; }; } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/settings.cpp b/clickhouse/src/storages/clickhouse/impl/settings.cpp index fd50375c0af5..0bfc6d0b75f4 100644 --- a/clickhouse/src/storages/clickhouse/impl/settings.cpp +++ b/clickhouse/src/storages/clickhouse/impl/settings.cpp @@ -17,39 +17,33 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { namespace { -ConnectionSettings::ConnectionMode GetConnectionMode( - bool use_secure_connection) { - return use_secure_connection ? ConnectionSettings::ConnectionMode::kSecure - : ConnectionSettings::ConnectionMode::kNonSecure; +ConnectionSettings::ConnectionMode GetConnectionMode(bool use_secure_connection) { + return use_secure_connection ? ConnectionSettings::ConnectionMode::kSecure + : ConnectionSettings::ConnectionMode::kNonSecure; } std::vector ParseHosts(const formats::json::Value& doc) { - const auto hosts_json = doc["hosts"]; - auto hosts = hosts_json.As>(); + const auto hosts_json = doc["hosts"]; + auto hosts = hosts_json.As>(); - UINVARIANT(!hosts.empty(), "Empty list of hosts in clickhouse secdist"); - const auto unique_count = - std::unordered_set{hosts.begin(), hosts.end()}.size(); + UINVARIANT(!hosts.empty(), "Empty list of hosts in clickhouse secdist"); + const auto unique_count = std::unordered_set{hosts.begin(), hosts.end()}.size(); - UINVARIANT(unique_count == hosts.size(), - "Hosts are not unique in clickhouse secdist"); + UINVARIANT(unique_count == hosts.size(), "Hosts are not unique in clickhouse secdist"); - return hosts; + return hosts; } using CompressionMethod = ConnectionSettings::CompressionMethod; } // namespace -static CompressionMethod Parse(const yaml_config::YamlConfig& value, - formats::parse::To) { - static constexpr utils::TrivialBiMap kMap([](auto selector) { - return selector() - .Case(CompressionMethod::kNone, "none") - .Case(CompressionMethod::kLZ4, "lz4"); - }); +static CompressionMethod Parse(const yaml_config::YamlConfig& value, formats::parse::To) { + static constexpr utils::TrivialBiMap kMap([](auto selector) { + return selector().Case(CompressionMethod::kNone, "none").Case(CompressionMethod::kLZ4, "lz4"); + }); - return utils::ParseFromValueString(value, kMap); + return utils::ParseFromValueString(value, kMap); } AuthSettings::AuthSettings() = default; @@ -59,21 +53,18 @@ AuthSettings::AuthSettings(const formats::json::Value& doc) password{doc["password"].As()}, database{doc["dbname"].As()} {} -ConnectionSettings::ConnectionSettings( - const components::ComponentConfig& config) - : connection_mode{GetConnectionMode( - config["use_secure_connection"].As(true))}, - compression_method{config["compression"].As( - CompressionMethod::kNone)} {} - -PoolSettings::PoolSettings(const components::ComponentConfig& config, - const EndpointSettings& endpoint, - const AuthSettings& auth) - : initial_pool_size{std::max(config["initial_pool_size"].As(5), - std::size_t{1})}, +ConnectionSettings::ConnectionSettings(const components::ComponentConfig& config) + : connection_mode{GetConnectionMode(config["use_secure_connection"].As(true))}, + compression_method{config["compression"].As(CompressionMethod::kNone)} {} + +PoolSettings::PoolSettings( + const components::ComponentConfig& config, + const EndpointSettings& endpoint, + const AuthSettings& auth +) + : initial_pool_size{std::max(config["initial_pool_size"].As(5), std::size_t{1})}, max_pool_size{config["max_pool_size"].As(10)}, - queue_timeout{config["queue_timeout"].As( - std::chrono::milliseconds{200})}, + queue_timeout{config["queue_timeout"].As(std::chrono::milliseconds{200})}, endpoint_settings{endpoint}, auth_settings{auth}, connection_settings{config} {} @@ -81,47 +72,43 @@ PoolSettings::PoolSettings(const components::ComponentConfig& config, ClickhouseSettings::ClickhouseSettings() = default; ClickhouseSettings::ClickhouseSettings(const formats::json::Value& doc) { - auto port = doc["port"].As(); - auto hosts = ParseHosts(doc); + auto port = doc["port"].As(); + auto hosts = ParseHosts(doc); - endpoints.reserve(hosts.size()); - for (auto& host : hosts) { - endpoints.emplace_back(EndpointSettings{std::move(host), port}); - } + endpoints.reserve(hosts.size()); + for (auto& host : hosts) { + endpoints.emplace_back(EndpointSettings{std::move(host), port}); + } - auth_settings = AuthSettings{doc}; + auth_settings = AuthSettings{doc}; } -ClickhouseSettings Parse(const formats::json::Value& doc, - formats::parse::To) { - return ClickhouseSettings{doc}; +ClickhouseSettings Parse(const formats::json::Value& doc, formats::parse::To) { + return ClickhouseSettings{doc}; } -ClickhouseSettingsMulti::ClickhouseSettingsMulti( - const formats::json::Value& doc) { - const auto clickhouse_settings = doc["clickhouse_settings"]; - secdist::CheckIsObject(clickhouse_settings, "clickhouse_settings"); +ClickhouseSettingsMulti::ClickhouseSettingsMulti(const formats::json::Value& doc) { + const auto clickhouse_settings = doc["clickhouse_settings"]; + secdist::CheckIsObject(clickhouse_settings, "clickhouse_settings"); - databases_ = clickhouse_settings - .As>(); + databases_ = clickhouse_settings.As>(); } -const ClickhouseSettings& ClickhouseSettingsMulti::Get( - const std::string& dbname) const { - const auto it = databases_.find(dbname); - if (it == databases_.end()) { - throw std::runtime_error{fmt::format( - "database '{}' is not found in secdist. Available databases: [{}]", - dbname, fmt::join(databases_ | boost::adaptors::map_keys, ", "))}; - } - - return it->second; +const ClickhouseSettings& ClickhouseSettingsMulti::Get(const std::string& dbname) const { + const auto it = databases_.find(dbname); + if (it == databases_.end()) { + throw std::runtime_error{fmt::format( + "database '{}' is not found in secdist. Available databases: [{}]", + dbname, + fmt::join(databases_ | boost::adaptors::map_keys, ", ") + )}; + } + + return it->second; } std::string GetSecdistAlias(const components::ComponentConfig& config) { - return config.HasMember("secdist_alias") - ? config["secdist_alias"].As() - : config.Name(); + return config.HasMember("secdist_alias") ? config["secdist_alias"].As() : config.Name(); } } // namespace storages::clickhouse::impl diff --git a/clickhouse/src/storages/clickhouse/impl/settings.hpp b/clickhouse/src/storages/clickhouse/impl/settings.hpp index 59d492d0ff5a..1be8ae67e2ea 100644 --- a/clickhouse/src/storages/clickhouse/impl/settings.hpp +++ b/clickhouse/src/storages/clickhouse/impl/settings.hpp @@ -12,65 +12,64 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::impl { struct AuthSettings final { - std::string user; - std::string password; - std::string database; + std::string user; + std::string password; + std::string database; - // for testing purposes only - AuthSettings(); + // for testing purposes only + AuthSettings(); - AuthSettings(const formats::json::Value&); + AuthSettings(const formats::json::Value&); }; struct EndpointSettings final { - std::string host; - uint32_t port; + std::string host; + uint32_t port; }; struct ConnectionSettings final { - enum class ConnectionMode { kNonSecure, kSecure }; + enum class ConnectionMode { kNonSecure, kSecure }; - enum class CompressionMethod { kNone, kLZ4 }; + enum class CompressionMethod { kNone, kLZ4 }; - ConnectionMode connection_mode{ConnectionMode::kSecure}; + ConnectionMode connection_mode{ConnectionMode::kSecure}; - CompressionMethod compression_method{CompressionMethod::kNone}; + CompressionMethod compression_method{CompressionMethod::kNone}; - ConnectionSettings(const components::ComponentConfig&); + ConnectionSettings(const components::ComponentConfig&); }; struct PoolSettings final { - size_t initial_pool_size; - size_t max_pool_size; - std::chrono::milliseconds queue_timeout; + size_t initial_pool_size; + size_t max_pool_size; + std::chrono::milliseconds queue_timeout; - EndpointSettings endpoint_settings; - AuthSettings auth_settings; - ConnectionSettings connection_settings; + EndpointSettings endpoint_settings; + AuthSettings auth_settings; + ConnectionSettings connection_settings; - PoolSettings(const components::ComponentConfig&, const EndpointSettings&, - const AuthSettings&); + PoolSettings(const components::ComponentConfig&, const EndpointSettings&, const AuthSettings&); }; struct ClickhouseSettings final { - std::vector endpoints; + std::vector endpoints; - AuthSettings auth_settings; + AuthSettings auth_settings; - // for testing purposes only - ClickhouseSettings(); + // for testing purposes only + ClickhouseSettings(); - ClickhouseSettings(const formats::json::Value&); + ClickhouseSettings(const formats::json::Value&); }; class ClickhouseSettingsMulti final { - public: - ClickhouseSettingsMulti(const formats::json::Value&); +public: + ClickhouseSettingsMulti(const formats::json::Value&); - const ClickhouseSettings& Get(const std::string& dbname) const; + const ClickhouseSettings& Get(const std::string& dbname) const; - private: - std::unordered_map databases_; +private: + std::unordered_map databases_; }; std::string GetSecdistAlias(const components::ComponentConfig&); diff --git a/clickhouse/src/storages/clickhouse/io/columns/array_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/array_column.cpp index b995afbfa3b4..b166f1a3ab7e 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/array_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/array_column.cpp @@ -12,15 +12,13 @@ using UInt64NativeType = clickhouse::impl::clickhouse_cpp::ColumnUInt64; } // namespace ColumnRef ExtractArrayItem(const ColumnRef& column, size_t ind) { - auto array_native = column->As(); - return array_native->GetAsColumn(ind); + auto array_native = column->As(); + return array_native->GetAsColumn(ind); } ColumnRef ConvertMetaToColumn(ArrayColumnMeta&& meta) { - auto offsets_native = - impl::GetTypedColumn(meta.offsets); - return std::make_shared(std::move(meta.data), - std::move(offsets_native)); + auto offsets_native = impl::GetTypedColumn(meta.offsets); + return std::make_shared(std::move(meta.data), std::move(offsets_native)); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/column_wrapper.cpp b/clickhouse/src/storages/clickhouse/io/columns/column_wrapper.cpp index 85382dfe2643..b90d8caedc07 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/column_wrapper.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/column_wrapper.cpp @@ -9,17 +9,15 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::columns { ColumnRef GetWrappedColumn(clickhouse::impl::BlockWrapper& block, size_t ind) { - UINVARIANT(ind < block.GetColumnsCount(), "Shouldn't happen"); + UINVARIANT(ind < block.GetColumnsCount(), "Shouldn't happen"); - return block.At(ind); + return block.At(ind); } -void AppendWrappedColumn(clickhouse::impl::BlockWrapper& block, - ColumnRef&& column, std::string_view name, - size_t ind) { - UINVARIANT(block.GetColumnsCount() == ind, "Shouldn't happen"); +void AppendWrappedColumn(clickhouse::impl::BlockWrapper& block, ColumnRef&& column, std::string_view name, size_t ind) { + UINVARIANT(block.GetColumnsCount() == ind, "Shouldn't happen"); - block.AppendColumn(name, column); + block.AppendColumn(name, column); } size_t GetColumnSize(const ColumnRef& column) { return column->Size(); } diff --git a/clickhouse/src/storages/clickhouse/io/columns/datetime64_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/datetime64_column.cpp index ab4eabdd6cc7..8c509e32ea62 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/datetime64_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/datetime64_column.cpp @@ -15,33 +15,29 @@ namespace { using NativeType = clickhouse::impl::clickhouse_cpp::ColumnDateTime64; template -std::chrono::system_clock::time_point DoGetDate(const ColumnRef& column, - size_t ind) { - const auto tics = impl::NativeGetAt(column, ind); +std::chrono::system_clock::time_point DoGetDate(const ColumnRef& column, size_t ind) { + const auto tics = impl::NativeGetAt(column, ind); - using clock = std::chrono::system_clock; - return clock::time_point{std::chrono::duration_cast( - typename DateColumnType::time_resolution{tics})}; + using clock = std::chrono::system_clock; + return clock::time_point{ + std::chrono::duration_cast(typename DateColumnType::time_resolution{tics})}; } template -ColumnRef DoSerializeDate( - const std::vector& from) { - auto column = clickhouse::impl::clickhouse_cpp::ColumnDateTime64( - DateColumnType::Tag::kPrecision); - for (const auto tp : from) { - column.Append( - std::chrono::duration_cast( - tp.time_since_epoch()) - .count()); - } - - return std::make_shared(std::move(column)); +ColumnRef DoSerializeDate(const std::vector& from) { + auto column = clickhouse::impl::clickhouse_cpp::ColumnDateTime64(DateColumnType::Tag::kPrecision); + for (const auto tp : from) { + column.Append( + std::chrono::duration_cast(tp.time_since_epoch()).count() + ); + } + + return std::make_shared(std::move(column)); } template ColumnRef GetDatetimeColumn(const ColumnRef& column) { - return impl::GetTypedColumn(column); + return impl::GetTypedColumn(column); } } // namespace @@ -59,36 +55,33 @@ DateTime64ColumnNano::DateTime64Column(ColumnRef column) : ClickhouseColumn{GetDatetimeColumn(column)} {} template <> -DateTime64ColumnMilli::cpp_type -ColumnIterator::DataHolder::Get() const { - return DoGetDate(column_, ind_); +DateTime64ColumnMilli::cpp_type ColumnIterator::DataHolder::Get() const { + return DoGetDate(column_, ind_); } template <> -DateTime64ColumnMicro::cpp_type -ColumnIterator::DataHolder::Get() const { - return DoGetDate(column_, ind_); +DateTime64ColumnMicro::cpp_type ColumnIterator::DataHolder::Get() const { + return DoGetDate(column_, ind_); } template <> -DateTime64ColumnNano::cpp_type -ColumnIterator::DataHolder::Get() const { - return DoGetDate(column_, ind_); +DateTime64ColumnNano::cpp_type ColumnIterator::DataHolder::Get() const { + return DoGetDate(column_, ind_); } template <> ColumnRef DateTime64ColumnMilli::Serialize(const container_type& from) { - return DoSerializeDate(from); + return DoSerializeDate(from); } template <> ColumnRef DateTime64ColumnMicro::Serialize(const container_type& from) { - return DoSerializeDate(from); + return DoSerializeDate(from); } template <> ColumnRef DateTime64ColumnNano::Serialize(const container_type& from) { - return DoSerializeDate(from); + return DoSerializeDate(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/datetime_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/datetime_column.cpp index 5076fc40c6aa..d8d1d58776aa 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/datetime_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/datetime_column.cpp @@ -13,24 +13,22 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnDateTime; } DateTimeColumn::DateTimeColumn(ColumnRef column) - : ClickhouseColumn{ - impl::GetTypedColumn(column)} {} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> -DateTimeColumn::cpp_type ColumnIterator::DataHolder::Get() - const { - const auto time = impl::NativeGetAt(column_, ind_); - return std::chrono::system_clock::from_time_t(time); +DateTimeColumn::cpp_type ColumnIterator::DataHolder::Get() const { + const auto time = impl::NativeGetAt(column_, ind_); + return std::chrono::system_clock::from_time_t(time); } ColumnRef DateTimeColumn::Serialize(const container_type& from) { - auto column = clickhouse::impl::clickhouse_cpp::ColumnDateTime{}; + auto column = clickhouse::impl::clickhouse_cpp::ColumnDateTime{}; - for (const auto tp : from) { - column.Append(std::chrono::system_clock::to_time_t(tp)); - } + for (const auto tp : from) { + column.Append(std::chrono::system_clock::to_time_t(tp)); + } - return std::make_shared(std::move(column)); + return std::make_shared(std::move(column)); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/float32_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/float32_column.cpp index 80951565e2b3..d2d18b1fddf0 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/float32_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/float32_column.cpp @@ -11,16 +11,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnFloat32; } Float32Column::Float32Column(ColumnRef column) - : ClickhouseColumn{ - impl::GetTypedColumn(column)} {} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> Float32Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef Float32Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/float64_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/float64_column.cpp index 509de5748cd6..9085df49533f 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/float64_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/float64_column.cpp @@ -11,16 +11,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnFloat64; } Float64Column::Float64Column(ColumnRef column) - : ClickhouseColumn{ - impl::GetTypedColumn(column)} {} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> Float64Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef Float64Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/impl/column_types_mapping.hpp b/clickhouse/src/storages/clickhouse/io/columns/impl/column_types_mapping.hpp index 25f1ff893c02..102f1fdff768 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/impl/column_types_mapping.hpp +++ b/clickhouse/src/storages/clickhouse/io/columns/impl/column_types_mapping.hpp @@ -13,24 +13,23 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::columns::impl { template -auto GetTypedColumn( - const clickhouse::impl::clickhouse_cpp::ColumnRef& generic_column_ptr) { - auto column_ptr = generic_column_ptr->As(); - if (!column_ptr) { - throw std::runtime_error{ - fmt::format("failed to cast column of type '{}' to '{}'", - generic_column_ptr->Type()->GetName(), - USERVER_NAMESPACE::compiler::GetTypeName())}; - } - - return column_ptr; +auto GetTypedColumn(const clickhouse::impl::clickhouse_cpp::ColumnRef& generic_column_ptr) { + auto column_ptr = generic_column_ptr->As(); + if (!column_ptr) { + throw std::runtime_error{fmt::format( + "failed to cast column of type '{}' to '{}'", + generic_column_ptr->Type()->GetName(), + USERVER_NAMESPACE::compiler::GetTypeName() + )}; + } + + return column_ptr; } template -auto NativeGetAt(const clickhouse::impl::clickhouse_cpp::ColumnRef& column, - size_t ind) { - UASSERT(column->As() != nullptr); - return static_cast(column.get())->At(ind); +auto NativeGetAt(const clickhouse::impl::clickhouse_cpp::ColumnRef& column, size_t ind) { + UASSERT(column->As() != nullptr); + return static_cast(column.get())->At(ind); } } // namespace storages::clickhouse::io::columns::impl diff --git a/clickhouse/src/storages/clickhouse/io/columns/impl/numeric_column.hpp b/clickhouse/src/storages/clickhouse/io/columns/impl/numeric_column.hpp index 8e5cfd0111b6..2c9adb5a60df 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/impl/numeric_column.hpp +++ b/clickhouse/src/storages/clickhouse/io/columns/impl/numeric_column.hpp @@ -15,14 +15,12 @@ namespace storages::clickhouse::io::columns::impl { template struct NumericColumn final { - using value_type = typename ColumnType::cpp_type; - using container_type = typename ColumnType::container_type; - - static clickhouse::impl::clickhouse_cpp::ColumnRef Serialize( - const container_type& from) { - return std::make_shared< - clickhouse::impl::clickhouse_cpp::ColumnVector>(from); - } + using value_type = typename ColumnType::cpp_type; + using container_type = typename ColumnType::container_type; + + static clickhouse::impl::clickhouse_cpp::ColumnRef Serialize(const container_type& from) { + return std::make_shared>(from); + } }; } // namespace storages::clickhouse::io::columns::impl diff --git a/clickhouse/src/storages/clickhouse/io/columns/int32_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/int32_column.cpp index 6bee355e6206..27ca6d6dfe0d 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/int32_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/int32_column.cpp @@ -10,16 +10,15 @@ namespace { using NativeType = clickhouse::impl::clickhouse_cpp::ColumnInt32; } -Int32Column::Int32Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} {} +Int32Column::Int32Column(ColumnRef column) : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> Int32Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef Int32Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/int64_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/int64_column.cpp index 77e08c54b42f..c04b367d9666 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/int64_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/int64_column.cpp @@ -10,16 +10,15 @@ namespace { using NativeType = clickhouse::impl::clickhouse_cpp::ColumnInt64; } -Int64Column::Int64Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} {} +Int64Column::Int64Column(ColumnRef column) : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> Int64Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef Int64Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/int8_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/int8_column.cpp index c16309a228ae..f792e30caa73 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/int8_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/int8_column.cpp @@ -10,17 +10,14 @@ namespace { using NativeType = clickhouse::impl::clickhouse_cpp::ColumnInt8; } -Int8Column::Int8Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} {} +Int8Column::Int8Column(ColumnRef column) : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> Int8Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } -ColumnRef Int8Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); -} +ColumnRef Int8Column::Serialize(const container_type& from) { return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/nullable_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/nullable_column.cpp index 54837641c16e..7fde5c0ca492 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/nullable_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/nullable_column.cpp @@ -9,24 +9,21 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::io::columns { NullableColumnMeta ExtractNullableMeta(const ColumnRef& column) { - auto nullable = - column->As(); - if (!nullable) { - throw std::runtime_error{ - fmt::format("failed to cast column of type '{}' to Nullable", - column->Type()->GetName())}; - } - - NullableColumnMeta result; - result.nulls = nullable->Nulls(); - result.inner = nullable->Nested(); - return result; + auto nullable = column->As(); + if (!nullable) { + throw std::runtime_error{ + fmt::format("failed to cast column of type '{}' to Nullable", column->Type()->GetName())}; + } + + NullableColumnMeta result; + result.nulls = nullable->Nulls(); + result.inner = nullable->Nested(); + return result; } ColumnRef ConvertMetaToColumn(NullableColumnMeta&& meta) { - auto nullable = clickhouse::impl::clickhouse_cpp::ColumnNullable( - std::move(meta.inner), std::move(meta.nulls)); - return std::make_shared(std::move(nullable)); + auto nullable = clickhouse::impl::clickhouse_cpp::ColumnNullable(std::move(meta.inner), std::move(meta.nulls)); + return std::make_shared(std::move(nullable)); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/string_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/string_column.cpp index 5b12bb77df29..2c0662782427 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/string_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/string_column.cpp @@ -13,16 +13,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnString; } StringColumn::StringColumn(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} { -} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> StringColumn::cpp_type ColumnIterator::DataHolder::Get() const { - return std::string{impl::NativeGetAt(column_, ind_)}; + return std::string{impl::NativeGetAt(column_, ind_)}; } ColumnRef StringColumn::Serialize(const container_type& from) { - return std::make_shared(from); + return std::make_shared(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/uint16_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/uint16_column.cpp index e056e33f6e6e..dca40a9e0623 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/uint16_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/uint16_column.cpp @@ -11,16 +11,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnUInt16; } UInt16Column::UInt16Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} { -} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> UInt16Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef UInt16Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/uint32_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/uint32_column.cpp index e18a51e2479a..ef0fe38ecda3 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/uint32_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/uint32_column.cpp @@ -11,16 +11,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnUInt32; } UInt32Column::UInt32Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} { -} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> UInt32Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef UInt32Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/uint64_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/uint64_column.cpp index 0416d899d485..0663fa88a316 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/uint64_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/uint64_column.cpp @@ -11,16 +11,15 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnUInt64; } UInt64Column::UInt64Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} { -} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> UInt64Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef UInt64Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/uint8_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/uint8_column.cpp index 68736bd17d89..65f16b2aa453 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/uint8_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/uint8_column.cpp @@ -10,16 +10,15 @@ namespace { using NativeType = clickhouse::impl::clickhouse_cpp::ColumnUInt8; } -UInt8Column::UInt8Column(ColumnRef column) - : ClickhouseColumn{impl::GetTypedColumn(column)} {} +UInt8Column::UInt8Column(ColumnRef column) : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> UInt8Column::cpp_type ColumnIterator::DataHolder::Get() const { - return impl::NativeGetAt(column_, ind_); + return impl::NativeGetAt(column_, ind_); } ColumnRef UInt8Column::Serialize(const container_type& from) { - return impl::NumericColumn::Serialize(from); + return impl::NumericColumn::Serialize(from); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/columns/uuid_column.cpp b/clickhouse/src/storages/clickhouse/io/columns/uuid_column.cpp index 0fd285df4acd..d5a3ba0c309d 100644 --- a/clickhouse/src/storages/clickhouse/io/columns/uuid_column.cpp +++ b/clickhouse/src/storages/clickhouse/io/columns/uuid_column.cpp @@ -16,103 +16,91 @@ using NativeType = clickhouse::impl::clickhouse_cpp::ColumnUUID; enum class Endianness { kLE, kBE }; std::uint64_t ApplyEndianness(std::uint64_t value, Endianness endianness) { - switch (endianness) { - case Endianness::kLE: - // the driver only works with LE host systems, so this is a no-op - return value; - case Endianness::kBE: { - return boost::endian::endian_reverse(value); + switch (endianness) { + case Endianness::kLE: + // the driver only works with LE host systems, so this is a no-op + return value; + case Endianness::kBE: { + return boost::endian::endian_reverse(value); + } } - } - UINVARIANT(false, "Unreachable"); + UINVARIANT(false, "Unreachable"); } -std::pair SerializeToNative( - const boost::uuids::uuid& user_uuid, Endianness endianness) { - std::uint64_t first{}; - std::uint64_t second{}; +std::pair SerializeToNative(const boost::uuids::uuid& user_uuid, Endianness endianness) { + std::uint64_t first{}; + std::uint64_t second{}; - std::memcpy(&first, &user_uuid.data[0], 8); - std::memcpy(&second, &user_uuid.data[8], 8); + std::memcpy(&first, &user_uuid.data[0], 8); + std::memcpy(&second, &user_uuid.data[8], 8); - return {ApplyEndianness(first, endianness), - ApplyEndianness(second, endianness)}; + return {ApplyEndianness(first, endianness), ApplyEndianness(second, endianness)}; } -boost::uuids::uuid ParseFromNative(const ::clickhouse::UUID& native_uuid, - Endianness endianness) { - boost::uuids::uuid result{}; - const auto format = [&result, endianness](std::size_t offset, - std::uint64_t data) { - data = ApplyEndianness(data, endianness); - std::memcpy(&result.data[offset], &data, sizeof(data)); - }; +boost::uuids::uuid ParseFromNative(const ::clickhouse::UUID& native_uuid, Endianness endianness) { + boost::uuids::uuid result{}; + const auto format = [&result, endianness](std::size_t offset, std::uint64_t data) { + data = ApplyEndianness(data, endianness); + std::memcpy(&result.data[offset], &data, sizeof(data)); + }; - format(0, native_uuid.first); - format(8, native_uuid.second); + format(0, native_uuid.first); + format(8, native_uuid.second); - return result; + return result; } -ColumnRef SerializeToNative(const std::vector& what, - Endianness endianness) { - std::vector data; - data.reserve(what.size() * 2); +ColumnRef SerializeToNative(const std::vector& what, Endianness endianness) { + std::vector data; + data.reserve(what.size() * 2); - for (const auto& user_uuid : what) { - const auto native_representation = SerializeToNative(user_uuid, endianness); - data.push_back(native_representation.first); - data.push_back(native_representation.second); - } + for (const auto& user_uuid : what) { + const auto native_representation = SerializeToNative(user_uuid, endianness); + data.push_back(native_representation.first); + data.push_back(native_representation.second); + } - return std::make_shared( - std::make_shared( - std::move(data))); + return std::make_shared(std::make_shared(std::move(data) + )); } } // namespace -static_assert(std::is_trivially_copyable_v< - decltype(MismatchedEndiannessUuidColumn::cpp_type::data)>, - "Can not use memcpy."); -static_assert(sizeof(MismatchedEndiannessUuidColumn::cpp_type::data) == - sizeof(std::uint64_t) * 2, - "Unexpected uuid size."); +static_assert( + std::is_trivially_copyable_v, + "Can not use memcpy." +); +static_assert( + sizeof(MismatchedEndiannessUuidColumn::cpp_type::data) == sizeof(std::uint64_t) * 2, + "Unexpected uuid size." +); MismatchedEndiannessUuidColumn::MismatchedEndiannessUuidColumn(ColumnRef column) - : ClickhouseColumn{ - impl::GetTypedColumn( - column)} {} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> -MismatchedEndiannessUuidColumn::cpp_type -ColumnIterator::DataHolder::Get() const { - const auto ch_uuid = impl::NativeGetAt(column_, ind_); +MismatchedEndiannessUuidColumn::cpp_type ColumnIterator::DataHolder::Get() const { + const auto ch_uuid = impl::NativeGetAt(column_, ind_); - return ParseFromNative(ch_uuid, Endianness::kLE); + return ParseFromNative(ch_uuid, Endianness::kLE); } -ColumnRef MismatchedEndiannessUuidColumn::Serialize( - const container_type& from) { - return SerializeToNative(from, Endianness::kLE); +ColumnRef MismatchedEndiannessUuidColumn::Serialize(const container_type& from) { + return SerializeToNative(from, Endianness::kLE); } UuidRfc4122Column::UuidRfc4122Column(ColumnRef column) - : ClickhouseColumn{ - impl::GetTypedColumn(column)} {} + : ClickhouseColumn{impl::GetTypedColumn(column)} {} template <> -UuidRfc4122Column::cpp_type ColumnIterator::DataHolder::Get() - const { - const auto ch_uuid = impl::NativeGetAt(column_, ind_); +UuidRfc4122Column::cpp_type ColumnIterator::DataHolder::Get() const { + const auto ch_uuid = impl::NativeGetAt(column_, ind_); - return ParseFromNative(ch_uuid, Endianness::kBE); + return ParseFromNative(ch_uuid, Endianness::kBE); } -ColumnRef UuidRfc4122Column::Serialize(const container_type& from) { - return SerializeToNative(from, Endianness::kBE); -} +ColumnRef UuidRfc4122Column::Serialize(const container_type& from) { return SerializeToNative(from, Endianness::kBE); } } // namespace storages::clickhouse::io::columns diff --git a/clickhouse/src/storages/clickhouse/io/impl/escape.cpp b/clickhouse/src/storages/clickhouse/io/impl/escape.cpp index 3fe637d71481..a203aba35f40 100644 --- a/clickhouse/src/storages/clickhouse/io/impl/escape.cpp +++ b/clickhouse/src/storages/clickhouse/io/impl/escape.cpp @@ -11,7 +11,7 @@ namespace storages::clickhouse::io::impl { namespace { void EscapeSymbol(std::string& result, char c) { - // clang-format off + // clang-format off // taken from https://github.com/mymarilyn/clickhouse-driver/blob/87090902f0270ed51a0b6754d5cbf0dc8544ec4b/clickhouse_driver/util/escape.py#L8 if (c == '\b') result += R"(\b)"; else if (c == '\f') result += R"(\f)"; @@ -25,26 +25,23 @@ void EscapeSymbol(std::string& result, char c) { else if (c == '\'') result += R"(\')"; else result.push_back(c); - // clang-format on + // clang-format on } template std::string FormatScalar(T v) { - return fmt::format("{}", v); + return fmt::format("{}", v); } template std::string FormatDatetime64(Rep source) { - using time_resolution = typename Rep::TagType::time_resolution; - - constexpr auto ratio = time_resolution::period::den; - const auto tics = std::chrono::duration_cast( - source.GetUnderlying().time_since_epoch()) - .count(); - const size_t prefix = tics / ratio; - const size_t suffix = tics % ratio; - return fmt::format("toDateTime64('{0}.{1:0>{2}}', {2})", prefix, suffix, - Rep::TagType::kPrecision); + using time_resolution = typename Rep::TagType::time_resolution; + + constexpr auto ratio = time_resolution::period::den; + const auto tics = std::chrono::duration_cast(source.GetUnderlying().time_since_epoch()).count(); + const size_t prefix = tics / ratio; + const size_t suffix = tics % ratio; + return fmt::format("toDateTime64('{0}.{1:0>{2}}', {2})", prefix, suffix, Rep::TagType::kPrecision); } } // namespace @@ -58,30 +55,25 @@ std::string Escape(int16_t v) { return FormatScalar(v); } std::string Escape(int32_t v) { return FormatScalar(v); } std::string Escape(int64_t v) { return FormatScalar(v); } -std::string Escape(const char* source) { - return Escape(std::string_view{source}); -} +std::string Escape(const char* source) { return Escape(std::string_view{source}); } -std::string Escape(const std::string& source) { - return Escape(std::string_view{source}); -} +std::string Escape(const std::string& source) { return Escape(std::string_view{source}); } std::string Escape(std::string_view source) { - std::string result; - result.reserve(source.size() + 2); + std::string result; + result.reserve(source.size() + 2); - result.push_back('\''); - for (auto c : source) EscapeSymbol(result, c); - result.push_back('\''); + result.push_back('\''); + for (auto c : source) EscapeSymbol(result, c); + result.push_back('\''); - return result; + return result; } std::string Escape(std::chrono::system_clock::time_point source) { - return fmt::format("toDateTime({})", - std::chrono::duration_cast( - source.time_since_epoch()) - .count()); + return fmt::format( + "toDateTime({})", std::chrono::duration_cast(source.time_since_epoch()).count() + ); } std::string Escape(DateTime64Milli source) { return FormatDatetime64(source); } diff --git a/clickhouse/src/storages/clickhouse/query.cpp b/clickhouse/src/storages/clickhouse/query.cpp index d2d6f3988a54..9597056744cf 100644 --- a/clickhouse/src/storages/clickhouse/query.cpp +++ b/clickhouse/src/storages/clickhouse/query.cpp @@ -7,20 +7,18 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse { -Query::Query(const char* text, std::optional name) - : text_{text}, name_{std::move(name)} {} +Query::Query(const char* text, std::optional name) : text_{text}, name_{std::move(name)} {} -Query::Query(std::string text, std::optional name) - : text_{std::move(text)}, name_{std::move(name)} {} +Query::Query(std::string text, std::optional name) : text_{std::move(text)}, name_{std::move(name)} {} const std::string& Query::QueryText() const& { return text_; } const std::optional& Query::QueryName() const& { return name_; } void Query::FillSpanTags(tracing::Span& span) const { - if (name_.has_value()) { - span.AddTag(tracing::kDatabaseStatementName, name_->GetUnderlying()); - } + if (name_.has_value()) { + span.AddTag(tracing::kDatabaseStatementName, name_->GetUnderlying()); + } } } // namespace storages::clickhouse diff --git a/clickhouse/src/storages/clickhouse/stats/pool_statistics.cpp b/clickhouse/src/storages/clickhouse/stats/pool_statistics.cpp index f5645928cb74..0fd748b67bff 100644 --- a/clickhouse/src/storages/clickhouse/stats/pool_statistics.cpp +++ b/clickhouse/src/storages/clickhouse/stats/pool_statistics.cpp @@ -8,27 +8,24 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::stats { -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolStatistics& stats) { - writer["connections"] = stats.connections; - writer["queries"] = stats.queries; - writer["inserts"] = stats.inserts; +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolStatistics& stats) { + writer["connections"] = stats.connections; + writer["queries"] = stats.queries; + writer["inserts"] = stats.inserts; } -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolQueryStatistics& stats) { - writer["total"] = stats.total; - writer["error"] = stats.error; - writer["timings"] = stats.timings; +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolQueryStatistics& stats) { + writer["total"] = stats.total; + writer["error"] = stats.error; + writer["timings"] = stats.timings; } -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolConnectionStatistics& stats) { - writer["closed"] = stats.closed; - writer["created"] = stats.created; - writer["overload"] = stats.overload; - writer["active"] = stats.active; - writer["busy"] = stats.busy; +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolConnectionStatistics& stats) { + writer["closed"] = stats.closed; + writer["created"] = stats.created; + writer["overload"] = stats.overload; + writer["active"] = stats.active; + writer["busy"] = stats.busy; } } // namespace storages::clickhouse::stats diff --git a/clickhouse/src/storages/clickhouse/stats/pool_statistics.hpp b/clickhouse/src/storages/clickhouse/stats/pool_statistics.hpp index 7ca5aace6093..13425fbdb181 100644 --- a/clickhouse/src/storages/clickhouse/stats/pool_statistics.hpp +++ b/clickhouse/src/storages/clickhouse/stats/pool_statistics.hpp @@ -11,39 +11,34 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::stats { using Counter = USERVER_NAMESPACE::utils::statistics::RelaxedCounter; -using Percentile = - USERVER_NAMESPACE::utils::statistics::Percentile<2048, uint64_t, 16, 256>; -using RecentPeriod = - USERVER_NAMESPACE::utils::statistics::RecentPeriod; +using Percentile = USERVER_NAMESPACE::utils::statistics::Percentile<2048, uint64_t, 16, 256>; +using RecentPeriod = USERVER_NAMESPACE::utils::statistics::RecentPeriod; struct PoolConnectionStatistics final { - Counter overload{}; - Counter closed{}; - Counter created{}; - Counter active{}; - Counter busy{}; + Counter overload{}; + Counter closed{}; + Counter created{}; + Counter active{}; + Counter busy{}; }; struct PoolQueryStatistics final { - Counter total{}; - Counter error{}; - RecentPeriod timings{}; + Counter total{}; + Counter error{}; + RecentPeriod timings{}; }; struct PoolStatistics final { - PoolConnectionStatistics connections{}; - PoolQueryStatistics queries{}; - PoolQueryStatistics inserts{}; + PoolConnectionStatistics connections{}; + PoolQueryStatistics queries{}; + PoolQueryStatistics inserts{}; }; -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolStatistics& stats); +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolStatistics& stats); -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolQueryStatistics& stats); +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolQueryStatistics& stats); -void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, - const PoolConnectionStatistics& stats); +void DumpMetric(USERVER_NAMESPACE::utils::statistics::Writer& writer, const PoolConnectionStatistics& stats); } // namespace storages::clickhouse::stats diff --git a/clickhouse/src/storages/clickhouse/stats/statement_timer.cpp b/clickhouse/src/storages/clickhouse/stats/statement_timer.cpp index 93a9bfc330a2..d1eae19123b8 100644 --- a/clickhouse/src/storages/clickhouse/stats/statement_timer.cpp +++ b/clickhouse/src/storages/clickhouse/stats/statement_timer.cpp @@ -9,19 +9,17 @@ USERVER_NAMESPACE_BEGIN namespace storages::clickhouse::stats { StatementTimer::StatementTimer(PoolQueryStatistics& stats) - : stats_{stats}, - exceptions_on_enter_{std::uncaught_exceptions()}, - start_{Now()} {} + : stats_{stats}, exceptions_on_enter_{std::uncaught_exceptions()}, start_{Now()} {} StatementTimer::~StatementTimer() { - ++stats_.total; - if (std::uncaught_exceptions() != exceptions_on_enter_) { - ++stats_.error; - } else { - stats_.timings.GetCurrentCounter().Account( - std::chrono::duration_cast(Now() - start_) - .count()); - } + ++stats_.total; + if (std::uncaught_exceptions() != exceptions_on_enter_) { + ++stats_.error; + } else { + stats_.timings.GetCurrentCounter().Account( + std::chrono::duration_cast(Now() - start_).count() + ); + } } StatementTimer::Clock::time_point StatementTimer::Now() { return Clock::now(); } diff --git a/clickhouse/src/storages/clickhouse/stats/statement_timer.hpp b/clickhouse/src/storages/clickhouse/stats/statement_timer.hpp index 8983d6844f56..a3a264d5711d 100644 --- a/clickhouse/src/storages/clickhouse/stats/statement_timer.hpp +++ b/clickhouse/src/storages/clickhouse/stats/statement_timer.hpp @@ -9,18 +9,18 @@ namespace storages::clickhouse::stats { struct PoolQueryStatistics; class StatementTimer final { - public: - StatementTimer(PoolQueryStatistics& stats); - ~StatementTimer(); +public: + StatementTimer(PoolQueryStatistics& stats); + ~StatementTimer(); - private: - using Clock = std::chrono::steady_clock; +private: + using Clock = std::chrono::steady_clock; - static Clock::time_point Now(); + static Clock::time_point Now(); - PoolQueryStatistics& stats_; - const int exceptions_on_enter_; - Clock::time_point start_; + PoolQueryStatistics& stats_; + const int exceptions_on_enter_; + Clock::time_point start_; }; } // namespace storages::clickhouse::stats diff --git a/clickhouse/src/storages/tests/array_chtest.cpp b/clickhouse/src/storages/tests/array_chtest.cpp index 89b72737786f..edccbd1547f3 100644 --- a/clickhouse/src/storages/tests/array_chtest.cpp +++ b/clickhouse/src/storages/tests/array_chtest.cpp @@ -14,13 +14,13 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithArrays final { - std::vector> array_of_ints; - std::vector key; + std::vector> array_of_ints; + std::vector key; }; struct DataOfArrays final { - uint64_t value; - std::vector data; + uint64_t value; + std::vector data; }; } // namespace @@ -29,77 +29,75 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple, - columns::Int32Column>; + using mapped_type = std::tuple, columns::Int32Column>; }; template <> struct CppToClickhouse { - using mapped_type = std::tuple>; + using mapped_type = std::tuple>; }; } // namespace storages::clickhouse::io UTEST(Array, Works) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Array(UInt64), key Int32)"); - - const auto insertion_data = - DataWithArrays{{{1, 2, 3, 4}, {1}, {}}, {1, 2, 3}}; - cluster->Insert("tmp_table", {"value", "key"}, insertion_data); - - const storages::clickhouse::Query q{ - "SELECT value, key FROM tmp_table ORDER BY key"}; - const auto res = cluster->Execute(q).As(); - EXPECT_EQ(res.array_of_ints.size(), 3); - EXPECT_EQ(res.array_of_ints[0], std::vector({1, 2, 3, 4})); - EXPECT_EQ(res.key[0], 1); - EXPECT_EQ(res.array_of_ints[1], std::vector{1}); - EXPECT_EQ(res.key[1], 2); - EXPECT_EQ(res.array_of_ints[2], std::vector{}); - EXPECT_EQ(res.key[2], 3); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Array(UInt64), key Int32)" + ); + + const auto insertion_data = DataWithArrays{{{1, 2, 3, 4}, {1}, {}}, {1, 2, 3}}; + cluster->Insert("tmp_table", {"value", "key"}, insertion_data); + + const storages::clickhouse::Query q{"SELECT value, key FROM tmp_table ORDER BY key"}; + const auto res = cluster->Execute(q).As(); + EXPECT_EQ(res.array_of_ints.size(), 3); + EXPECT_EQ(res.array_of_ints[0], std::vector({1, 2, 3, 4})); + EXPECT_EQ(res.key[0], 1); + EXPECT_EQ(res.array_of_ints[1], std::vector{1}); + EXPECT_EQ(res.key[1], 2); + EXPECT_EQ(res.array_of_ints[2], std::vector{}); + EXPECT_EQ(res.key[2], 3); } UTEST(Array, IterationWorks) { - ClusterWrapper cluster{}; - auto res = cluster - ->Execute( - "SELECT c.number, arrayMap(x->toString(x), range(0, " - "c.number)) FROM " - "system.numbers c LIMIT 10") - .AsRows(); - size_t ind = 0; - for (auto it = res.begin(); it != res.end(); it++, ++ind) { - ASSERT_EQ(it->value, ind); - ASSERT_EQ(it->data.size(), ind); - for (size_t count = 0; count < ind; ++count) { - ASSERT_EQ(it->data[count], std::to_string(count)); + ClusterWrapper cluster{}; + auto res = cluster + ->Execute( + "SELECT c.number, arrayMap(x->toString(x), range(0, " + "c.number)) FROM " + "system.numbers c LIMIT 10" + ) + .AsRows(); + size_t ind = 0; + for (auto it = res.begin(); it != res.end(); it++, ++ind) { + ASSERT_EQ(it->value, ind); + ASSERT_EQ(it->data.size(), ind); + for (size_t count = 0; count < ind; ++count) { + ASSERT_EQ(it->data[count], std::to_string(count)); + } } - } - ASSERT_EQ(ind, 10); - - ind = 0; - for (auto it = res.begin(); it != res.end(); it++, ++ind) { - ASSERT_EQ(it->value, ind); - ASSERT_EQ(it->data.size(), ind); - for (size_t count = 0; count < ind; ++count) { - ASSERT_EQ(it->data[count], std::to_string(count)); + ASSERT_EQ(ind, 10); + + ind = 0; + for (auto it = res.begin(); it != res.end(); it++, ++ind) { + ASSERT_EQ(it->value, ind); + ASSERT_EQ(it->data.size(), ind); + for (size_t count = 0; count < ind; ++count) { + ASSERT_EQ(it->data[count], std::to_string(count)); + } } - } - ASSERT_EQ(ind, 10); - - ind = 0; - for (auto it = res.begin(); it != res.end(); it++, ++ind) { - ASSERT_EQ(it->value, ind); - ASSERT_EQ(it->data.size(), ind); - for (size_t count = 0; count < ind; ++count) { - ASSERT_EQ(it->data[count], std::to_string(count)); + ASSERT_EQ(ind, 10); + + ind = 0; + for (auto it = res.begin(); it != res.end(); it++, ++ind) { + ASSERT_EQ(it->value, ind); + ASSERT_EQ(it->data.size(), ind); + for (size_t count = 0; count < ind; ++count) { + ASSERT_EQ(it->data[count], std::to_string(count)); + } } - } - ASSERT_EQ(ind, 10); + ASSERT_EQ(ind, 10); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/cluster_test.cpp b/clickhouse/src/storages/tests/cluster_test.cpp index cf1f9fde96a7..cd9447c49760 100644 --- a/clickhouse/src/storages/tests/cluster_test.cpp +++ b/clickhouse/src/storages/tests/cluster_test.cpp @@ -7,12 +7,9 @@ USERVER_NAMESPACE_BEGIN UTEST(Cluster, NoAvailablePools) { - ClusterWrapper cluster{ - false, - {{"unresolved1", 11111}, {"unresolved2", 12222}, {"unresolved3", 12333}}}; + ClusterWrapper cluster{false, {{"unresolved1", 11111}, {"unresolved2", 12222}, {"unresolved3", 12333}}}; - EXPECT_THROW(cluster->Execute("Invalid_query"), - storages::clickhouse::Cluster::NoAvailablePoolError); + EXPECT_THROW(cluster->Execute("Invalid_query"), storages::clickhouse::Cluster::NoAvailablePoolError); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/columns_mismatch_chtest.cpp b/clickhouse/src/storages/tests/columns_mismatch_chtest.cpp index 9485a786f859..d519ac8258cf 100644 --- a/clickhouse/src/storages/tests/columns_mismatch_chtest.cpp +++ b/clickhouse/src/storages/tests/columns_mismatch_chtest.cpp @@ -9,13 +9,13 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithTwoColumns final { - std::vector numbers; - std::vector strings; + std::vector numbers; + std::vector strings; }; struct DataWithTwoFields final { - uint64_t number; - std::string string; + uint64_t number; + std::string string; }; } // namespace @@ -24,46 +24,38 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST_DEATH(ColumnsMismatchDeathTest, Insert) { - ClusterWrapper cluster{}; + ClusterWrapper cluster{}; - const DataWithTwoColumns data{}; - EXPECT_UINVARIANT_FAILURE(cluster->Insert("some_table", {"one"}, data)); - EXPECT_UINVARIANT_FAILURE( - cluster->Insert("some_table", {"one", "two", "three"}, data)); + const DataWithTwoColumns data{}; + EXPECT_UINVARIANT_FAILURE(cluster->Insert("some_table", {"one"}, data)); + EXPECT_UINVARIANT_FAILURE(cluster->Insert("some_table", {"one", "two", "three"}, data)); } UTEST_DEATH(ColumnsMismatchDeathTest, Select) { - ClusterWrapper cluster{}; - - const storages::clickhouse::Query more_columns_query{ - "SELECT toUInt64(0) as one, randomString(2) as two, randomString(2) as " - "three"}; - EXPECT_UINVARIANT_FAILURE( - cluster->Execute(more_columns_query).As()); - EXPECT_UINVARIANT_FAILURE( - cluster->Execute(more_columns_query).AsRows()); - EXPECT_UINVARIANT_FAILURE(cluster->Execute(more_columns_query) - .AsContainer>()); - - const storages::clickhouse::Query less_columns_query{ - "SELECT toUInt64(0) as one"}; - EXPECT_UINVARIANT_FAILURE( - cluster->Execute(less_columns_query).As()); - EXPECT_UINVARIANT_FAILURE( - cluster->Execute(less_columns_query).AsRows()); - EXPECT_UINVARIANT_FAILURE(cluster->Execute(less_columns_query) - .AsContainer>()); + ClusterWrapper cluster{}; + + const storages::clickhouse::Query more_columns_query{ + "SELECT toUInt64(0) as one, randomString(2) as two, randomString(2) as " + "three"}; + EXPECT_UINVARIANT_FAILURE(cluster->Execute(more_columns_query).As()); + EXPECT_UINVARIANT_FAILURE(cluster->Execute(more_columns_query).AsRows()); + EXPECT_UINVARIANT_FAILURE(cluster->Execute(more_columns_query).AsContainer>()); + + const storages::clickhouse::Query less_columns_query{"SELECT toUInt64(0) as one"}; + EXPECT_UINVARIANT_FAILURE(cluster->Execute(less_columns_query).As()); + EXPECT_UINVARIANT_FAILURE(cluster->Execute(less_columns_query).AsRows()); + EXPECT_UINVARIANT_FAILURE(cluster->Execute(less_columns_query).AsContainer>()); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/datetime_chtest.cpp b/clickhouse/src/storages/tests/datetime_chtest.cpp index 1162f7a8118f..b5324b7799b9 100644 --- a/clickhouse/src/storages/tests/datetime_chtest.cpp +++ b/clickhouse/src/storages/tests/datetime_chtest.cpp @@ -13,7 +13,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithDatetime final { - std::vector dates; + std::vector dates; }; } // namespace @@ -22,76 +22,81 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(DateTime, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value DateTime)"); - - const auto now = std::chrono::system_clock::now(); - - const DataWithDatetime insert_data{{now}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT value FROM tmp_table").As(); - EXPECT_EQ(select_data.dates.size(), 1); - EXPECT_EQ(std::chrono::duration_cast( - select_data.dates.front().time_since_epoch()), - std::chrono::duration_cast( - insert_data.dates.front().time_since_epoch())); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value DateTime)" + ); + + const auto now = std::chrono::system_clock::now(); + + const DataWithDatetime insert_data{{now}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT value FROM tmp_table").As(); + EXPECT_EQ(select_data.dates.size(), 1); + EXPECT_EQ( + std::chrono::duration_cast(select_data.dates.front().time_since_epoch()), + std::chrono::duration_cast(insert_data.dates.front().time_since_epoch()) + ); } struct TimepointData final { - std::vector seconds; - std::vector milli; - std::vector micro; - std::vector nano; + std::vector seconds; + std::vector milli; + std::vector micro; + std::vector nano; }; namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = - std::tuple; + using mapped_type = std::tuple< + columns::DateTimeColumn, + columns::DateTime64ColumnMilli, + columns::DateTime64ColumnMicro, + columns::DateTime64ColumnNano>; }; } // namespace storages::clickhouse::io UTEST(Datetime64, Precision) { - ClusterWrapper cluster; - cluster->Execute( - "CREATE TEMPORARY TABLE test_tp" - "(sec DateTime, milli DateTime64(3), " - "micro DateTime64(6), nano DateTime64(9))"); - const auto now = std::chrono::system_clock::now(); - - const TimepointData insert_data{{now}, {now}, {now}, {now}}; - cluster->Insert("test_tp", {"sec", "milli", "micro", "nano"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT sec, milli, micro, nano FROM test_tp") - .As(); - - EXPECT_EQ( - select_data.seconds.front().time_since_epoch(), - std::chrono::duration_cast(now.time_since_epoch())); - EXPECT_EQ(select_data.milli.front().time_since_epoch(), - std::chrono::duration_cast( - now.time_since_epoch())); - EXPECT_EQ(select_data.micro.front().time_since_epoch(), - std::chrono::duration_cast( - now.time_since_epoch())); - EXPECT_EQ(select_data.nano.front().time_since_epoch(), - std::chrono::duration_cast( - now.time_since_epoch())); + ClusterWrapper cluster; + cluster->Execute( + "CREATE TEMPORARY TABLE test_tp" + "(sec DateTime, milli DateTime64(3), " + "micro DateTime64(6), nano DateTime64(9))" + ); + const auto now = std::chrono::system_clock::now(); + + const TimepointData insert_data{{now}, {now}, {now}, {now}}; + cluster->Insert("test_tp", {"sec", "milli", "micro", "nano"}, insert_data); + + const auto select_data = cluster->Execute("SELECT sec, milli, micro, nano FROM test_tp").As(); + + EXPECT_EQ( + select_data.seconds.front().time_since_epoch(), + std::chrono::duration_cast(now.time_since_epoch()) + ); + EXPECT_EQ( + select_data.milli.front().time_since_epoch(), + std::chrono::duration_cast(now.time_since_epoch()) + ); + EXPECT_EQ( + select_data.micro.front().time_since_epoch(), + std::chrono::duration_cast(now.time_since_epoch()) + ); + EXPECT_EQ( + select_data.nano.front().time_since_epoch(), + std::chrono::duration_cast(now.time_since_epoch()) + ); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/escape_chtest.cpp b/clickhouse/src/storages/tests/escape_chtest.cpp index b161ebfad05b..35d12d40ad40 100644 --- a/clickhouse/src/storages/tests/escape_chtest.cpp +++ b/clickhouse/src/storages/tests/escape_chtest.cpp @@ -14,22 +14,22 @@ namespace { namespace io = storages::clickhouse::io; struct DataWithValues final { - std::vector strings; - std::vector values; + std::vector strings; + std::vector values; }; using clock = std::chrono::system_clock; struct DataWithDatetime final { - std::vector datetime; - std::vector datetime_milli; - std::vector datetime_micro; - std::vector datetime_nano; + std::vector datetime; + std::vector datetime_milli; + std::vector datetime_micro; + std::vector datetime_nano; }; struct DataWithOptValue final { - std::string data; - std::optional opt_value; + std::string data; + std::optional opt_value; }; } // namespace @@ -38,81 +38,80 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse { - using mapped_type = - std::tuple; + using mapped_type = std::tuple< + columns::DateTimeColumn, + columns::DateTime64ColumnMilli, + columns::DateTime64ColumnMicro, + columns::DateTime64ColumnNano>; }; template <> struct CppToClickhouse { - using mapped_type = - std::tuple>; + using mapped_type = std::tuple>; }; } // namespace storages::clickhouse::io UTEST(ExecuteWithArgs, Basic) { - ClusterWrapper cluster{}; - const storages::clickhouse::Query q{ - "SELECT {}, * FROM system.numbers limit {}"}; + ClusterWrapper cluster{}; + const storages::clickhouse::Query q{"SELECT {}, * FROM system.numbers limit {}"}; - const auto result = cluster->Execute(q, "we", 5).As(); - EXPECT_EQ(result.values.size(), 5); + const auto result = cluster->Execute(q, "we", 5).As(); + EXPECT_EQ(result.values.size(), 5); - EXPECT_EQ(result.strings.size(), 5); - EXPECT_EQ(result.strings.front(), "we"); + EXPECT_EQ(result.strings.size(), 5); + EXPECT_EQ(result.strings.front(), "we"); } UTEST(ExecuteWithArgs, DatesArgs) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(date DateTime, milli DateTime64(3), " - "micro DateTime64(6), nano DateTime64(9))"); - - const auto now = clock::now(); - const DataWithDatetime insert_data{{now}, {now}, {now}, {now}}; - cluster->Insert("tmp_table", {"date", "milli", "micro", "nano"}, insert_data); - - const storages::clickhouse::Query q{ - "SELECT date, milli, micro, nano FROM tmp_table WHERE " - "date <= {} AND milli <= {} AND micro <= {} AND nano <= {}"}; - const auto res = - cluster - ->Execute(q, now, io::DateTime64Milli{now}, io::DateTime64Micro{now}, - io::DateTime64Nano{now}) - .As(); - ASSERT_EQ(res.datetime.size(), 1); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(date DateTime, milli DateTime64(3), " + "micro DateTime64(6), nano DateTime64(9))" + ); + + const auto now = clock::now(); + const DataWithDatetime insert_data{{now}, {now}, {now}, {now}}; + cluster->Insert("tmp_table", {"date", "milli", "micro", "nano"}, insert_data); + + const storages::clickhouse::Query q{ + "SELECT date, milli, micro, nano FROM tmp_table WHERE " + "date <= {} AND milli <= {} AND micro <= {} AND nano <= {}"}; + const auto res = + cluster->Execute(q, now, io::DateTime64Milli{now}, io::DateTime64Micro{now}, io::DateTime64Nano{now}) + .As(); + ASSERT_EQ(res.datetime.size(), 1); } UTEST(ExecuteWithArgs, MaliciousString) { - ClusterWrapper cluster{}; - - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS users " - "(login String, password String)"); - cluster->Execute( - "INSERT INTO users(login, password) VALUES " - "('itrofimow', 'not_my_password')"); - - const std::string malicious{"incorrect_password' OR login='itrofimow"}; - const storages::clickhouse::Query q{ - "SELECT login FROM users WHERE password = {}"}; - - const auto res = cluster->Execute(q, malicious); - EXPECT_EQ(res.GetRowsCount(), 0); + ClusterWrapper cluster{}; + + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS users " + "(login String, password String)" + ); + cluster->Execute( + "INSERT INTO users(login, password) VALUES " + "('itrofimow', 'not_my_password')" + ); + + const std::string malicious{"incorrect_password' OR login='itrofimow"}; + const storages::clickhouse::Query q{"SELECT login FROM users WHERE password = {}"}; + + const auto res = cluster->Execute(q, malicious); + EXPECT_EQ(res.GetRowsCount(), 0); } UTEST(ExecuteWithArgs, MultilineQueryWithComments) { - ClusterWrapper cluster{}; + ClusterWrapper cluster{}; - const storages::clickhouse::Query q{R"( + const storages::clickhouse::Query q{R"( WITH // first we generate some numbers a AS ( @@ -126,53 +125,55 @@ WITH SELECT b.str, a.num FROM a JOIN b ON a.num = b.num; -- because why not /* note that multi-statements are not allowed by clickhouse! */ )"}; - const auto res = cluster->Execute(q, 5, "we").As(); - EXPECT_EQ(res.strings.size(), 5); - EXPECT_EQ(res.strings.front().size(), 2); + const auto res = cluster->Execute(q, 5, "we").As(); + EXPECT_EQ(res.strings.size(), 5); + EXPECT_EQ(res.strings.front().size(), 2); } UTEST(ExecuteWithArgs, InsertSelectNull) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS fruits " - "(fruit String, price Nullable(UInt64))"); - cluster->Execute( - "INSERT INTO fruits(fruit, price) VALUES " - "('apple', 300), " - "('mango', NULL)"); - - std::optional null_price; - const storages::clickhouse::Query query{ - "SELECT fruit, price FROM fruits " - "WHERE price is {0}"}; - const auto null_rows = cluster->Execute(query, null_price) - .AsContainer>(); - - EXPECT_EQ(null_rows.size(), 1); - EXPECT_EQ(null_rows[0].data, "mango"); - EXPECT_EQ(null_rows[0].opt_value, std::nullopt); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS fruits " + "(fruit String, price Nullable(UInt64))" + ); + cluster->Execute( + "INSERT INTO fruits(fruit, price) VALUES " + "('apple', 300), " + "('mango', NULL)" + ); + + std::optional null_price; + const storages::clickhouse::Query query{ + "SELECT fruit, price FROM fruits " + "WHERE price is {0}"}; + const auto null_rows = cluster->Execute(query, null_price).AsContainer>(); + + EXPECT_EQ(null_rows.size(), 1); + EXPECT_EQ(null_rows[0].data, "mango"); + EXPECT_EQ(null_rows[0].opt_value, std::nullopt); } UTEST(ExecuteWithArgs, InsertSelectNotNull) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS fruits " - "(fruit String, price Nullable(UInt64))"); - cluster->Execute( - "INSERT INTO fruits(fruit, price) VALUES " - "('apple', 300), " - "('mango', NULL)"); - - std::optional price = 300; - const storages::clickhouse::Query query{ - "SELECT fruit, price FROM fruits " - "WHERE price = {0}"}; - const auto not_null_rows = cluster->Execute(query, price) - .AsContainer>(); - - EXPECT_EQ(not_null_rows.size(), 1); - EXPECT_EQ(not_null_rows[0].data, "apple"); - EXPECT_EQ(not_null_rows[0].opt_value.value(), 300); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS fruits " + "(fruit String, price Nullable(UInt64))" + ); + cluster->Execute( + "INSERT INTO fruits(fruit, price) VALUES " + "('apple', 300), " + "('mango', NULL)" + ); + + std::optional price = 300; + const storages::clickhouse::Query query{ + "SELECT fruit, price FROM fruits " + "WHERE price = {0}"}; + const auto not_null_rows = cluster->Execute(query, price).AsContainer>(); + + EXPECT_EQ(not_null_rows.size(), 1); + EXPECT_EQ(not_null_rows[0].data, "apple"); + EXPECT_EQ(not_null_rows[0].opt_value.value(), 300); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/escape_test.cpp b/clickhouse/src/storages/tests/escape_test.cpp index b974e7c4768e..7d79e4eb6936 100644 --- a/clickhouse/src/storages/tests/escape_test.cpp +++ b/clickhouse/src/storages/tests/escape_test.cpp @@ -18,175 +18,169 @@ using clock = std::chrono::system_clock; using QueryTester = storages::clickhouse::QueryTester; constexpr clock::time_point kFakeNow{ - std::chrono::duration_cast( - std::chrono::nanoseconds{1546300800'123456789ULL})}; + std::chrono::duration_cast(std::chrono::nanoseconds{1546300800'123456789ULL})}; constexpr clock::time_point kFakeNowLeadingZeros{ - std::chrono::duration_cast( - std::chrono::nanoseconds{1546300800'001002003ULL})}; + std::chrono::duration_cast(std::chrono::nanoseconds{1546300800'001002003ULL})}; void ValidateEscaping(const std::string& source, const std::string& expected) { - const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + const auto escaped = io::impl::Escape(source); + EXPECT_EQ(escaped, expected); } } // namespace -TEST(EscapeString, Basic) { - ValidateEscaping("just a text", R"('just a text')"); -} +TEST(EscapeString, Basic) { ValidateEscaping("just a text", R"('just a text')"); } -TEST(EscapeString, StringWithSingleQuote) { - ValidateEscaping("with'", R"('with\'')"); -} +TEST(EscapeString, StringWithSingleQuote) { ValidateEscaping("with'", R"('with\'')"); } -TEST(EscapeString, StringWithDoubleQuote) { - ValidateEscaping("with\"", R"('with"')"); -} +TEST(EscapeString, StringWithDoubleQuote) { ValidateEscaping("with\"", R"('with"')"); } TEST(EscapeString, SpecialSymbols) { - ValidateEscaping(std::string{"\b\f\r\n\t\0\a\v\\\'", 10}, - R"('\b\f\r\n\t\0\a\v\\\'')"); + ValidateEscaping(std::string{"\b\f\r\n\t\0\a\v\\\'", 10}, R"('\b\f\r\n\t\0\a\v\\\'')"); } TEST(EscapeScalar, Basic) { - const storages::clickhouse::Query q{"{} {} {} {} {} {} {} {}"}; - const auto formatted_query = QueryTester::WithArgs(q, uint8_t{1}, // - uint16_t{2}, // - uint32_t{3}, // - uint64_t{4}, // - // - int8_t{5}, // - int16_t{6}, // - int32_t{7}, // - int64_t{8}); - - EXPECT_EQ(formatted_query.QueryText(), "1 2 3 4 5 6 7 8"); + const storages::clickhouse::Query q{"{} {} {} {} {} {} {} {}"}; + const auto formatted_query = QueryTester::WithArgs( + q, + uint8_t{1}, // + uint16_t{2}, // + uint32_t{3}, // + uint64_t{4}, // + // + int8_t{5}, // + int16_t{6}, // + int32_t{7}, // + int64_t{8} + ); + + EXPECT_EQ(formatted_query.QueryText(), "1 2 3 4 5 6 7 8"); } TEST(EscapeVectorString, Basic) { - const std::vector source = {"a", "b", "c"}; - const std::string expected = R"(['a','b','c'])"; - const auto escaped = io::impl::Escape(source); + const std::vector source = {"a", "b", "c"}; + const std::string expected = R"(['a','b','c'])"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeSetString, Basic) { - const std::set source = {"a", "b"}; - const std::string expected = R"(['a','b'])"; - const auto escaped = io::impl::Escape(source); + const std::set source = {"a", "b"}; + const std::string expected = R"(['a','b'])"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } template class MyRange final { - public: - MyRange(std::initializer_list data) : data_{data} {} +public: + MyRange(std::initializer_list data) : data_{data} {} - auto begin() const { return data_.begin(); } + auto begin() const { return data_.begin(); } - auto end() const { return data_.end(); } + auto end() const { return data_.end(); } - private: - std::vector data_; +private: + std::vector data_; }; TEST(EscapeRangeInt, Basic) { - const MyRange source{1, 2, 3}; - const std::string expected = R"([1,2,3])"; - const auto escaped = io::impl::Escape(source); + const MyRange source{1, 2, 3}; + const std::string expected = R"([1,2,3])"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeRangeString, Basic) { - const MyRange source{"a", "b", "c"}; - const std::string expected = R"(['a','b','c'])"; - const auto escaped = io::impl::Escape(source); + const MyRange source{"a", "b", "c"}; + const std::string expected = R"(['a','b','c'])"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, Basic) { - const clock::time_point source{kFakeNow}; - const std::string expected = R"(toDateTime(1546300800))"; - const auto escaped = io::impl::Escape(source); + const clock::time_point source{kFakeNow}; + const std::string expected = R"(toDateTime(1546300800))"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, Milli) { - const io::DateTime64Milli source{kFakeNow}; - // precision is 10^-3 - const std::string expected = R"(toDateTime64('1546300800.123', 3))"; - const auto escaped = io::impl::Escape(source); + const io::DateTime64Milli source{kFakeNow}; + // precision is 10^-3 + const std::string expected = R"(toDateTime64('1546300800.123', 3))"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, MilliLeadingZeros) { - const io::DateTime64Milli source{kFakeNowLeadingZeros}; - // precision is 10^-3 - const std::string expected = R"(toDateTime64('1546300800.001', 3))"; - const auto escaped = io::impl::Escape(source); + const io::DateTime64Milli source{kFakeNowLeadingZeros}; + // precision is 10^-3 + const std::string expected = R"(toDateTime64('1546300800.001', 3))"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, Micro) { - const io::DateTime64Micro source{kFakeNow}; - // precision is 10^-6 - const std::string expected = R"(toDateTime64('1546300800.123456', 6))"; - const auto escaped = io::impl::Escape(source); + const io::DateTime64Micro source{kFakeNow}; + // precision is 10^-6 + const std::string expected = R"(toDateTime64('1546300800.123456', 6))"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, MicroLeadingZeros) { - const io::DateTime64Micro source{kFakeNowLeadingZeros}; - // precision is 10^-6 - const std::string expected = R"(toDateTime64('1546300800.001002', 6))"; - const auto escaped = io::impl::Escape(source); + const io::DateTime64Micro source{kFakeNowLeadingZeros}; + // precision is 10^-6 + const std::string expected = R"(toDateTime64('1546300800.001002', 6))"; + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, Nano) { - const io::DateTime64Nano source{kFakeNow}; - // precision is 10^-9 + const io::DateTime64Nano source{kFakeNow}; + // precision is 10^-9 #ifdef _LIBCPP_VERSION - const std::string expected = R"(toDateTime64('1546300800.123456000', 9))"; + const std::string expected = R"(toDateTime64('1546300800.123456000', 9))"; #else - const std::string expected = R"(toDateTime64('1546300800.123456789', 9))"; + const std::string expected = R"(toDateTime64('1546300800.123456789', 9))"; #endif - const auto escaped = io::impl::Escape(source); + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeDatetime, NanoLeadingZeros) { - const io::DateTime64Nano source{kFakeNowLeadingZeros}; - // precision is 10^-9 + const io::DateTime64Nano source{kFakeNowLeadingZeros}; + // precision is 10^-9 #ifdef _LIBCPP_VERSION - const std::string expected = R"(toDateTime64('1546300800.001002000', 9))"; + const std::string expected = R"(toDateTime64('1546300800.001002000', 9))"; #else - const std::string expected = R"(toDateTime64('1546300800.001002003', 9))"; + const std::string expected = R"(toDateTime64('1546300800.001002003', 9))"; #endif - const auto escaped = io::impl::Escape(source); + const auto escaped = io::impl::Escape(source); - EXPECT_EQ(escaped, expected); + EXPECT_EQ(escaped, expected); } TEST(EscapeQuery, ParamsCountMismatch) { - const storages::clickhouse::Query q{"{} {} {}"}; - EXPECT_ANY_THROW(QueryTester::WithArgs(q, 1)); - EXPECT_ANY_THROW(QueryTester::WithArgs(q, 1, 2)); - EXPECT_NO_THROW(QueryTester::WithArgs(q, 1, 2, 3)); - // ideally this should throw, but oh well - // TODO : https://st.yandex-team.ru/TAXICOMMON-5066 - EXPECT_NO_THROW(QueryTester::WithArgs(q, 1, 2, 3, 4)); + const storages::clickhouse::Query q{"{} {} {}"}; + EXPECT_ANY_THROW(QueryTester::WithArgs(q, 1)); + EXPECT_ANY_THROW(QueryTester::WithArgs(q, 1, 2)); + EXPECT_NO_THROW(QueryTester::WithArgs(q, 1, 2, 3)); + // ideally this should throw, but oh well + // TODO : https://st.yandex-team.ru/TAXICOMMON-5066 + EXPECT_NO_THROW(QueryTester::WithArgs(q, 1, 2, 3, 4)); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/execute_chtest.cpp b/clickhouse/src/storages/tests/execute_chtest.cpp index 3788ac107fd2..0ef476e00e89 100644 --- a/clickhouse/src/storages/tests/execute_chtest.cpp +++ b/clickhouse/src/storages/tests/execute_chtest.cpp @@ -18,17 +18,17 @@ const storages::clickhouse::Query common_query{ namespace { struct Data final { - std::vector numbers; - std::vector strings; - std::vector other_numbers; - std::vector tps; + std::vector numbers; + std::vector strings; + std::vector other_numbers; + std::vector tps; }; struct RowData final { - uint64_t number; - std::string string; - uint64_t other_number; - std::chrono::system_clock::time_point tp; + uint64_t number; + std::string string; + uint64_t other_number; + std::chrono::system_clock::time_point tp; }; } // namespace @@ -37,42 +37,39 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse final { - using mapped_type = - std::tuple; + using mapped_type = + std::tuple; }; template <> struct CppToClickhouse final { - using mapped_type = - std::tuple; + using mapped_type = + std::tuple; }; } // namespace storages::clickhouse::io /// [Sample CppToClickhouse specialization] UTEST(Execute, MappingWorks) { - ClusterWrapper cluster{}; - - /// [Sample ExecutionResult usage] - const Data as_columns{cluster->Execute(common_query).As()}; - const std::vector as_rows{ - cluster->Execute(common_query).AsContainer>()}; - const auto as_rows_iterable{cluster->Execute(common_query).AsRows()}; - /// [Sample ExecutionResult usage] - - EXPECT_EQ(as_columns.numbers.size(), 10000); - EXPECT_EQ(as_columns.numbers[5001], 5001); - - EXPECT_EQ(as_rows.size(), 10000); - EXPECT_EQ(as_rows[5001].number, 5001); - - uint64_t sum = 0; - for (auto&& data : as_rows_iterable) { - sum += data.number; - } - EXPECT_EQ(sum, 10000 * (10000 - 1) / 2); + ClusterWrapper cluster{}; + + /// [Sample ExecutionResult usage] + const Data as_columns{cluster->Execute(common_query).As()}; + const std::vector as_rows{cluster->Execute(common_query).AsContainer>()}; + const auto as_rows_iterable{cluster->Execute(common_query).AsRows()}; + /// [Sample ExecutionResult usage] + + EXPECT_EQ(as_columns.numbers.size(), 10000); + EXPECT_EQ(as_columns.numbers[5001], 5001); + + EXPECT_EQ(as_rows.size(), 10000); + EXPECT_EQ(as_rows[5001].number, 5001); + + uint64_t sum = 0; + for (auto&& data : as_rows_iterable) { + sum += data.number; + } + EXPECT_EQ(sum, 10000 * (10000 - 1) / 2); } namespace { @@ -80,45 +77,43 @@ namespace io = storages::clickhouse::io; template class IteratorTester final { - public: - template - static void CheckCurrentValue( - typename io::RowsMapper::Iterator& iterator, U value) { - const auto& iterators = - io::IteratorsTester::GetCurrentIteratorsTuple(iterator); - ASSERT_EQ(*std::get(iterators), value); - } +public: + template + static void CheckCurrentValue(typename io::RowsMapper::Iterator& iterator, U value) { + const auto& iterators = io::IteratorsTester::GetCurrentIteratorsTuple(iterator); + ASSERT_EQ(*std::get(iterators), value); + } }; } // namespace UTEST(Execute, IterationMovesFromUnderlying) { - static_assert(io::IteratorsTester::kCanMoveFromIterators); - - ClusterWrapper cluster{}; - - const size_t limit = 10; - const storages::clickhouse::Query q{ - "SELECT c.number, repeat(toString(c.number), 100), toUInt64(1), NOW64(9) " - "FROM system.numbers c LIMIT 10"}; - - std::vector expected; - expected.reserve(limit); - for (size_t i = 0; i < limit; ++i) expected.emplace_back(100, '0' + i); - - auto ch_res = cluster->Execute(q); - ASSERT_EQ(ch_res.GetRowsCount(), limit); - auto res = std::move(ch_res).AsRows(); - - size_t ind = 0; - for (auto it = res.begin(); it != res.end(); ++it, ++ind) { - ASSERT_LT(ind, limit); - IteratorTester::CheckCurrentValue<1>(it, expected[ind]); - ASSERT_EQ(it->string, expected[ind]); - IteratorTester::CheckCurrentValue<1>(it, std::string{}); - ASSERT_EQ(it->string, expected[ind]); - [[maybe_unused]] std::string tmp{std::move(it->string)}; - ASSERT_TRUE(it->string.empty()); - } + static_assert(io::IteratorsTester::kCanMoveFromIterators); + + ClusterWrapper cluster{}; + + const size_t limit = 10; + const storages::clickhouse::Query q{ + "SELECT c.number, repeat(toString(c.number), 100), toUInt64(1), NOW64(9) " + "FROM system.numbers c LIMIT 10"}; + + std::vector expected; + expected.reserve(limit); + for (size_t i = 0; i < limit; ++i) expected.emplace_back(100, '0' + i); + + auto ch_res = cluster->Execute(q); + ASSERT_EQ(ch_res.GetRowsCount(), limit); + auto res = std::move(ch_res).AsRows(); + + size_t ind = 0; + for (auto it = res.begin(); it != res.end(); ++it, ++ind) { + ASSERT_LT(ind, limit); + IteratorTester::CheckCurrentValue<1>(it, expected[ind]); + ASSERT_EQ(it->string, expected[ind]); + IteratorTester::CheckCurrentValue<1>(it, std::string{}); + ASSERT_EQ(it->string, expected[ind]); + [[maybe_unused]] std::string tmp{std::move(it->string)}; + ASSERT_TRUE(it->string.empty()); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/float32_chtest.cpp b/clickhouse/src/storages/tests/float32_chtest.cpp index b16fc2f906f8..ff74f46291f4 100644 --- a/clickhouse/src/storages/tests/float32_chtest.cpp +++ b/clickhouse/src/storages/tests/float32_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithFloats final { - std::vector floats; + std::vector floats; }; } // namespace @@ -21,27 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Float32, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Float32)"); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Float32)" + ); - const DataWithFloats insert_data{{1.2, 2.3, 3.4}}; - cluster->Insert("tmp_table", {"value"}, insert_data); + const DataWithFloats insert_data{{1.2, 2.3, 3.4}}; + cluster->Insert("tmp_table", {"value"}, insert_data); - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.floats.size(), 3); + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.floats.size(), 3); - for (size_t i = 0; i < insert_data.floats.size(); ++i) { - ASSERT_FLOAT_EQ(insert_data.floats[i], select_data.floats[i]); - } + for (size_t i = 0; i < insert_data.floats.size(); ++i) { + ASSERT_FLOAT_EQ(insert_data.floats[i], select_data.floats[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/float64_chtest.cpp b/clickhouse/src/storages/tests/float64_chtest.cpp index ac78fb25031c..568bfa8de39f 100644 --- a/clickhouse/src/storages/tests/float64_chtest.cpp +++ b/clickhouse/src/storages/tests/float64_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithDoubles final { - std::vector doubles; + std::vector doubles; }; } // namespace @@ -21,27 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Float64, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Float64)"); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Float64)" + ); - const DataWithDoubles insert_data{{3.141592, 1.4142, 10.101010}}; - cluster->Insert("tmp_table", {"value"}, insert_data); + const DataWithDoubles insert_data{{3.141592, 1.4142, 10.101010}}; + cluster->Insert("tmp_table", {"value"}, insert_data); - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.doubles.size(), 3); + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.doubles.size(), 3); - for (size_t i = 0; i < insert_data.doubles.size(); ++i) { - ASSERT_DOUBLE_EQ(insert_data.doubles[i], select_data.doubles[i]); - } + for (size_t i = 0; i < insert_data.doubles.size(); ++i) { + ASSERT_DOUBLE_EQ(insert_data.doubles[i], select_data.doubles[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/int32_chtest.cpp b/clickhouse/src/storages/tests/int32_chtest.cpp index 7f69e1297306..31d033655ea2 100644 --- a/clickhouse/src/storages/tests/int32_chtest.cpp +++ b/clickhouse/src/storages/tests/int32_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,28 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Int32, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Int32)"); - - const DataWithInts insert_data{{std::numeric_limits::min(), -1, 0, 1, - std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 5); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Int32)" + ); + + const DataWithInts insert_data{ + {std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 5); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/int64_chtest.cpp b/clickhouse/src/storages/tests/int64_chtest.cpp index 70af931462a8..618358b5707e 100644 --- a/clickhouse/src/storages/tests/int64_chtest.cpp +++ b/clickhouse/src/storages/tests/int64_chtest.cpp @@ -13,7 +13,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -22,28 +22,28 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Int64, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Int64)"); - - const DataWithInts insert_data{{std::numeric_limits::min(), -1, 0, 1, - std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 5); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Int64)" + ); + + const DataWithInts insert_data{ + {std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 5); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/int8_chtest.cpp b/clickhouse/src/storages/tests/int8_chtest.cpp index 2c322b6741f7..1ca51e3fd482 100644 --- a/clickhouse/src/storages/tests/int8_chtest.cpp +++ b/clickhouse/src/storages/tests/int8_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Int8, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Int8)"); - - const DataWithInts insert_data{{std::numeric_limits::min(), -1, 0, 1, - std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 5); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Int8)" + ); + + const DataWithInts insert_data{{std::numeric_limits::min(), -1, 0, 1, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 5); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/iterator_test.cpp b/clickhouse/src/storages/tests/iterator_test.cpp index 7e6355790d94..f2424442990b 100644 --- a/clickhouse/src/storages/tests/iterator_test.cpp +++ b/clickhouse/src/storages/tests/iterator_test.cpp @@ -13,10 +13,10 @@ namespace clickhouse_cpp = clickhouse; template struct IteratorDefaultConstructorInstantiator final { - ~IteratorDefaultConstructorInstantiator() { - (..., typename Args::iterator{}); - (..., typename columns::NullableColumn::iterator{}); - } + ~IteratorDefaultConstructorInstantiator() { + (..., typename Args::iterator{}); + (..., typename columns::NullableColumn::iterator{}); + } }; [[maybe_unused]] const IteratorDefaultConstructorInstantiator< @@ -49,33 +49,32 @@ USERVER_NAMESPACE_BEGIN namespace { class IteratorTester final { - public: - static void CheckCurrentValue( - columns::ColumnIterator& iterator, - std::optional value) { - EXPECT_EQ(io::IteratorsTester::GetCurrentValue(iterator), value); - } +public: + static void + CheckCurrentValue(columns::ColumnIterator& iterator, std::optional value) { + EXPECT_EQ(io::IteratorsTester::GetCurrentValue(iterator), value); + } }; } // namespace TEST(StringIterator, ResetsCurrentValue) { - std::string first_string(100, 'a'); - std::string second_string(100, 'b'); - - columns::StringColumn column{std::make_shared( - std::vector{first_string, second_string})}; - ASSERT_EQ(column.Size(), 2); - - auto current = column.begin(); - IteratorTester::CheckCurrentValue(current, std::nullopt); - EXPECT_EQ(*current, first_string); - IteratorTester::CheckCurrentValue(current, first_string); - - auto begin = current++; - IteratorTester::CheckCurrentValue(begin, first_string); - IteratorTester::CheckCurrentValue(current, std::nullopt); - EXPECT_EQ(*current, second_string); - IteratorTester::CheckCurrentValue(current, second_string); + std::string first_string(100, 'a'); + std::string second_string(100, 'b'); + + columns::StringColumn column{ + std::make_shared(std::vector{first_string, second_string})}; + ASSERT_EQ(column.Size(), 2); + + auto current = column.begin(); + IteratorTester::CheckCurrentValue(current, std::nullopt); + EXPECT_EQ(*current, first_string); + IteratorTester::CheckCurrentValue(current, first_string); + + auto begin = current++; + IteratorTester::CheckCurrentValue(begin, first_string); + IteratorTester::CheckCurrentValue(current, std::nullopt); + EXPECT_EQ(*current, second_string); + IteratorTester::CheckCurrentValue(current, second_string); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/metrics_chtest.cpp b/clickhouse/src/storages/tests/metrics_chtest.cpp index 08bf654f7fb8..dbceb15a7408 100644 --- a/clickhouse/src/storages/tests/metrics_chtest.cpp +++ b/clickhouse/src/storages/tests/metrics_chtest.cpp @@ -9,7 +9,7 @@ namespace { struct DummyData { - std::vector data; + std::vector data; }; } // namespace @@ -20,56 +20,56 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Metrics, Basic) { - ClusterWrapper cluster{}; + ClusterWrapper cluster{}; - const DummyData data{{"str"}}; + const DummyData data{{"str"}}; - // successful query - cluster->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmp(value String)"); - // successful insert - cluster->Insert("tmp", {"value"}, data); + // successful query + cluster->Execute("CREATE TEMPORARY TABLE IF NOT EXISTS tmp(value String)"); + // successful insert + cluster->Insert("tmp", {"value"}, data); - const auto snapshot = cluster.GetStatistics("clickhouse.connections"); - EXPECT_EQ(snapshot.SingleMetric("active").AsInt(), 1); + const auto snapshot = cluster.GetStatistics("clickhouse.connections"); + EXPECT_EQ(snapshot.SingleMetric("active").AsInt(), 1); - // unsuccessful query - EXPECT_ANY_THROW(cluster->Execute("invalid_query_format")); - // unsuccessful insert - EXPECT_ANY_THROW(cluster->Insert("nonexistent", {"value"}, data)); + // unsuccessful query + EXPECT_ANY_THROW(cluster->Execute("invalid_query_format")); + // unsuccessful insert + EXPECT_ANY_THROW(cluster->Insert("nonexistent", {"value"}, data)); - const auto connection_stats = cluster.GetStatistics("clickhouse.connections"); - const auto queries_stats = cluster.GetStatistics("clickhouse.queries"); + const auto connection_stats = cluster.GetStatistics("clickhouse.connections"); + const auto queries_stats = cluster.GetStatistics("clickhouse.queries"); - const auto insert_stats = cluster.GetStatistics("clickhouse.inserts"); + const auto insert_stats = cluster.GetStatistics("clickhouse.inserts"); - EXPECT_EQ(connection_stats.SingleMetric("closed").AsInt(), 2); + EXPECT_EQ(connection_stats.SingleMetric("closed").AsInt(), 2); - EXPECT_EQ(queries_stats.SingleMetric("total").AsInt(), 2); - EXPECT_EQ(queries_stats.SingleMetric("error").AsInt(), 1); + EXPECT_EQ(queries_stats.SingleMetric("total").AsInt(), 2); + EXPECT_EQ(queries_stats.SingleMetric("error").AsInt(), 1); - EXPECT_EQ(insert_stats.SingleMetric("total").AsInt(), 2); - EXPECT_EQ(insert_stats.SingleMetric("error").AsInt(), 1); + EXPECT_EQ(insert_stats.SingleMetric("total").AsInt(), 2); + EXPECT_EQ(insert_stats.SingleMetric("error").AsInt(), 1); } UTEST(Metrics, ActiveConnections) { - PoolWrapper pool{}; - - std::vector connections; - for (size_t i = 0; i < 3; ++i) { - connections.emplace_back(pool->Acquire()); - } - - EXPECT_EQ(pool->GetStatistics().connections.busy, 3); - EXPECT_EQ(pool->GetStatistics().connections.active, 3); - connections.clear(); - EXPECT_EQ(pool->GetStatistics().connections.busy, 0); - EXPECT_EQ(pool->GetStatistics().connections.active, 3); + PoolWrapper pool{}; + + std::vector connections; + for (size_t i = 0; i < 3; ++i) { + connections.emplace_back(pool->Acquire()); + } + + EXPECT_EQ(pool->GetStatistics().connections.busy, 3); + EXPECT_EQ(pool->GetStatistics().connections.active, 3); + connections.clear(); + EXPECT_EQ(pool->GetStatistics().connections.busy, 0); + EXPECT_EQ(pool->GetStatistics().connections.active, 3); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/misc_chtest.cpp b/clickhouse/src/storages/tests/misc_chtest.cpp index 3ab067add9a3..5060edeb7760 100644 --- a/clickhouse/src/storages/tests/misc_chtest.cpp +++ b/clickhouse/src/storages/tests/misc_chtest.cpp @@ -10,33 +10,31 @@ USERVER_NAMESPACE_BEGIN namespace { struct SomeData final { - std::vector vec_uint64; - std::vector vec_str; - std::vector vec_uint64_2; - std::vector vec_timepoint; + std::vector vec_uint64; + std::vector vec_str; + std::vector vec_uint64_2; + std::vector vec_timepoint; }; struct SomeDataRow final { - uint64_t uint64; - std::string str; - uint64_t uint64_2; - std::chrono::system_clock::time_point timepoint; - - bool operator==(const SomeDataRow& other) const { - return uint64 == other.uint64 && str == other.str && - uint64_2 == other.uint64_2 && timepoint == other.timepoint; - } + uint64_t uint64; + std::string str; + uint64_t uint64_2; + std::chrono::system_clock::time_point timepoint; + + bool operator==(const SomeDataRow& other) const { + return uint64 == other.uint64 && str == other.str && uint64_2 == other.uint64_2 && timepoint == other.timepoint; + } }; struct SomeDataRowWithSleep final { - uint64_t uint64{}; - std::string str; - uint8_t sleep_result{}; - - bool operator==(const SomeDataRowWithSleep& other) const { - return uint64 == other.uint64 && str == other.str && - sleep_result == other.sleep_result; - } + uint64_t uint64{}; + std::string str; + uint8_t sleep_result{}; + + bool operator==(const SomeDataRowWithSleep& other) const { + return uint64 == other.uint64 && str == other.str && sleep_result == other.sleep_result; + } }; } // namespace @@ -45,127 +43,123 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = - std::tuple; + using mapped_type = + std::tuple; }; template <> struct CppToClickhouse { - using mapped_type = - std::tuple; + using mapped_type = + std::tuple; }; template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(Query, Works) { - ClusterWrapper cluster{}; - - const size_t expected_size = 10000; - storages::clickhouse::Query q{ - "SELECT c.number, randomString(10), c.number as t, NOW64() " - "FROM " - "numbers(0, 10000) c "}; - auto res = cluster->Execute(q).As(); - EXPECT_EQ(res.vec_str.size(), expected_size); - - const storages::clickhouse::CommandControl cc{std::chrono::milliseconds{150}}; - auto native_res = cluster->Execute(cc, q); - EXPECT_EQ(native_res.GetColumnsCount(), 4); - EXPECT_EQ(native_res.GetRowsCount(), expected_size); - res = std::move(native_res).As(); - EXPECT_EQ(res.vec_str.size(), expected_size); - EXPECT_EQ(res.vec_uint64.size(), expected_size); - EXPECT_EQ(res.vec_uint64_2.size(), expected_size); - EXPECT_EQ(res.vec_timepoint.size(), expected_size); + ClusterWrapper cluster{}; + + const size_t expected_size = 10000; + storages::clickhouse::Query q{ + "SELECT c.number, randomString(10), c.number as t, NOW64() " + "FROM " + "numbers(0, 10000) c "}; + auto res = cluster->Execute(q).As(); + EXPECT_EQ(res.vec_str.size(), expected_size); + + const storages::clickhouse::CommandControl cc{std::chrono::milliseconds{150}}; + auto native_res = cluster->Execute(cc, q); + EXPECT_EQ(native_res.GetColumnsCount(), 4); + EXPECT_EQ(native_res.GetRowsCount(), expected_size); + res = std::move(native_res).As(); + EXPECT_EQ(res.vec_str.size(), expected_size); + EXPECT_EQ(res.vec_uint64.size(), expected_size); + EXPECT_EQ(res.vec_uint64_2.size(), expected_size); + EXPECT_EQ(res.vec_timepoint.size(), expected_size); } UTEST(Compression, Works) { - ClusterWrapper cluster{true}; - storages::clickhouse::Query q{ - "SELECT c.number, randomString(10), c.number as t, NOW64() " - "FROM " - "numbers(0, 10000) c "}; - auto res = cluster->Execute(q).As(); - EXPECT_EQ(res.vec_str.size(), 10000); + ClusterWrapper cluster{true}; + storages::clickhouse::Query q{ + "SELECT c.number, randomString(10), c.number as t, NOW64() " + "FROM " + "numbers(0, 10000) c "}; + auto res = cluster->Execute(q).As(); + EXPECT_EQ(res.vec_str.size(), 10000); } UTEST(Insert, Works) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table (id UInt64, value " - "String, count UInt64, tp DateTime64(9))"); - - const auto now = std::chrono::system_clock::now(); - - SomeData data; - data.vec_uint64.push_back(1); - data.vec_str.emplace_back("asd"); - data.vec_uint64_2.push_back(2); - data.vec_timepoint.push_back(now); - cluster->Insert("tmp_table", {"id", "value", "count", "tp"}, data); - - auto result = cluster->Execute("SELECT id, value, count, tp FROM tmp_table") - .As(); - EXPECT_EQ(result.vec_uint64.size(), 1); - EXPECT_EQ(result.vec_uint64.back(), 1); - EXPECT_EQ(result.vec_str.back(), "asd"); - EXPECT_EQ(result.vec_uint64_2.back(), 2); - EXPECT_EQ(std::chrono::duration_cast( - result.vec_timepoint.back().time_since_epoch()) - .count(), - std::chrono::duration_cast( - now.time_since_epoch()) - .count()); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table (id UInt64, value " + "String, count UInt64, tp DateTime64(9))" + ); + + const auto now = std::chrono::system_clock::now(); + + SomeData data; + data.vec_uint64.push_back(1); + data.vec_str.emplace_back("asd"); + data.vec_uint64_2.push_back(2); + data.vec_timepoint.push_back(now); + cluster->Insert("tmp_table", {"id", "value", "count", "tp"}, data); + + auto result = cluster->Execute("SELECT id, value, count, tp FROM tmp_table").As(); + EXPECT_EQ(result.vec_uint64.size(), 1); + EXPECT_EQ(result.vec_uint64.back(), 1); + EXPECT_EQ(result.vec_str.back(), "asd"); + EXPECT_EQ(result.vec_uint64_2.back(), 2); + EXPECT_EQ( + std::chrono::duration_cast(result.vec_timepoint.back().time_since_epoch()).count(), + std::chrono::duration_cast(now.time_since_epoch()).count() + ); } UTEST(Insert, AsRowsWorks) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table (id UInt64, value " - "String, count UInt64, tp DateTime64(9))"); - - const auto now = std::chrono::system_clock::now(); - std::vector data{{1, "first", 2, now}, {3, "second", 4, now}}; - cluster->InsertRows("tmp_table", {"id", "value", "count", "tp"}, data); - - const auto result = - cluster->Execute("SELECT id, value, count, tp FROM tmp_table ORDER BY id") - .AsContainer>(); - ASSERT_EQ(result.size(), 2); - EXPECT_EQ(result[0], data[0]); - EXPECT_EQ(result[1], data[1]); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table (id UInt64, value " + "String, count UInt64, tp DateTime64(9))" + ); + + const auto now = std::chrono::system_clock::now(); + std::vector data{{1, "first", 2, now}, {3, "second", 4, now}}; + cluster->InsertRows("tmp_table", {"id", "value", "count", "tp"}, data); + + const auto result = cluster->Execute("SELECT id, value, count, tp FROM tmp_table ORDER BY id") + .AsContainer>(); + ASSERT_EQ(result.size(), 2); + EXPECT_EQ(result[0], data[0]); + EXPECT_EQ(result[1], data[1]); } UTEST(Query, AvoidUnexpectedCancellation) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table_with_sleep (id UInt64, " - "value " - "String, sleep_result UInt8)"); - - std::vector data{{1, "first", 0}, {3, "second", 0}}; - cluster->InsertRows("tmp_table_with_sleep", {"id", "value", "sleep_result"}, - data); - - // 2000ms to avoid flaps in CI, in perfect world ~300 should do - const storages::clickhouse::CommandControl cc{ - std::chrono::milliseconds{2000}}; - const auto result = cluster - ->Execute(cc, - "SELECT id, value, sleepEachRow(0.1) FROM " - "tmp_table_with_sleep ORDER BY id") - .AsContainer>(); - ASSERT_EQ(result.size(), 2); - EXPECT_EQ(result[0], data[0]); - EXPECT_EQ(result[1], data[1]); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table_with_sleep (id UInt64, " + "value " + "String, sleep_result UInt8)" + ); + + std::vector data{{1, "first", 0}, {3, "second", 0}}; + cluster->InsertRows("tmp_table_with_sleep", {"id", "value", "sleep_result"}, data); + + // 2000ms to avoid flaps in CI, in perfect world ~300 should do + const storages::clickhouse::CommandControl cc{std::chrono::milliseconds{2000}}; + const auto result = cluster + ->Execute( + cc, + "SELECT id, value, sleepEachRow(0.1) FROM " + "tmp_table_with_sleep ORDER BY id" + ) + .AsContainer>(); + ASSERT_EQ(result.size(), 2); + EXPECT_EQ(result[0], data[0]); + EXPECT_EQ(result[1], data[1]); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/nullable_chtest.cpp b/clickhouse/src/storages/tests/nullable_chtest.cpp index 2178022f2ba5..454f54a38674 100644 --- a/clickhouse/src/storages/tests/nullable_chtest.cpp +++ b/clickhouse/src/storages/tests/nullable_chtest.cpp @@ -14,13 +14,13 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithNulls final { - std::vector> nullable_ints; - std::vector key; + std::vector> nullable_ints; + std::vector key; }; struct DataOfNulls final { - std::optional value; - std::optional str; + std::optional value; + std::optional str; }; } // namespace @@ -29,76 +29,73 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple, - columns::Int32Column>; + using mapped_type = std::tuple, columns::Int32Column>; }; template <> struct CppToClickhouse { - using mapped_type = - std::tuple, - columns::NullableColumn>; + using mapped_type = + std::tuple, columns::NullableColumn>; }; } // namespace storages::clickhouse::io UTEST(Nullable, Works) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value Nullable(UInt64), key Int32)"); - - const auto insertion_data = - DataWithNulls{{std::nullopt, 1, std::nullopt}, {1, 2, 3}}; - cluster->Insert("tmp_table", {"value", "key"}, insertion_data); - - const storages::clickhouse::Query q{ - "SELECT value, key FROM tmp_table ORDER BY key"}; - const auto res = cluster->Execute(q).As(); - EXPECT_EQ(res.nullable_ints.size(), 3); - EXPECT_EQ(res.nullable_ints[0], std::nullopt); - EXPECT_EQ(res.key[0], 1); - EXPECT_EQ(res.nullable_ints[1], 1); - EXPECT_EQ(res.key[1], 2); - EXPECT_EQ(res.nullable_ints[2], std::nullopt); - EXPECT_EQ(res.key[2], 3); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value Nullable(UInt64), key Int32)" + ); + + const auto insertion_data = DataWithNulls{{std::nullopt, 1, std::nullopt}, {1, 2, 3}}; + cluster->Insert("tmp_table", {"value", "key"}, insertion_data); + + const storages::clickhouse::Query q{"SELECT value, key FROM tmp_table ORDER BY key"}; + const auto res = cluster->Execute(q).As(); + EXPECT_EQ(res.nullable_ints.size(), 3); + EXPECT_EQ(res.nullable_ints[0], std::nullopt); + EXPECT_EQ(res.key[0], 1); + EXPECT_EQ(res.nullable_ints[1], 1); + EXPECT_EQ(res.key[1], 2); + EXPECT_EQ(res.nullable_ints[2], std::nullopt); + EXPECT_EQ(res.key[2], 3); } UTEST(Nullable, IterationWorks) { - ClusterWrapper cluster{}; - auto res = - cluster - ->Execute( - "SELECT toNullable(c.number), toNullable(randomString(10)) FROM " - "system.numbers c LIMIT 10") - .AsRows(); - size_t ind = 0; - for (auto it = res.begin(); it != res.end(); it++, ++ind) { - ASSERT_TRUE(it->value.has_value()); - ASSERT_EQ(*it->value, ind); - ASSERT_TRUE(it->str.has_value()); - ASSERT_TRUE(!it->str->empty()); - } - EXPECT_EQ(ind, 10); - - ind = 0; - for (auto it = res.begin(); it != res.end(); ++it, ++ind) { - ASSERT_TRUE(it->value.has_value()); - ASSERT_EQ(*it->value, ind); - ASSERT_TRUE(it->str.has_value()); - ASSERT_TRUE(!it->str->empty()); - } - EXPECT_EQ(ind, 10); - - ind = 0; - for (auto&& v : res) { - ASSERT_TRUE(v.value.has_value()); - ASSERT_EQ(*v.value, ind); - ASSERT_TRUE(v.str.has_value()); - ASSERT_TRUE(!v.str->empty()); - ++ind; - } - EXPECT_EQ(ind, 10); + ClusterWrapper cluster{}; + auto res = cluster + ->Execute( + "SELECT toNullable(c.number), toNullable(randomString(10)) FROM " + "system.numbers c LIMIT 10" + ) + .AsRows(); + size_t ind = 0; + for (auto it = res.begin(); it != res.end(); it++, ++ind) { + ASSERT_TRUE(it->value.has_value()); + ASSERT_EQ(*it->value, ind); + ASSERT_TRUE(it->str.has_value()); + ASSERT_TRUE(!it->str->empty()); + } + EXPECT_EQ(ind, 10); + + ind = 0; + for (auto it = res.begin(); it != res.end(); ++it, ++ind) { + ASSERT_TRUE(it->value.has_value()); + ASSERT_EQ(*it->value, ind); + ASSERT_TRUE(it->str.has_value()); + ASSERT_TRUE(!it->str->empty()); + } + EXPECT_EQ(ind, 10); + + ind = 0; + for (auto&& v : res) { + ASSERT_TRUE(v.value.has_value()); + ASSERT_EQ(*v.value, ind); + ASSERT_TRUE(v.str.has_value()); + ASSERT_TRUE(!v.str->empty()); + ++ind; + } + EXPECT_EQ(ind, 10); } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/uint16_chtest.cpp b/clickhouse/src/storages/tests/uint16_chtest.cpp index d4de57a608e4..13e7f473623b 100644 --- a/clickhouse/src/storages/tests/uint16_chtest.cpp +++ b/clickhouse/src/storages/tests/uint16_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithUInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(UInt16, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value UInt16)"); - - const DataWithUInts insert_data{ - {0, 1, 10, std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 4); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value UInt16)" + ); + + const DataWithUInts insert_data{{0, 1, 10, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 4); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/uint32_chtest.cpp b/clickhouse/src/storages/tests/uint32_chtest.cpp index 4257a3e0b73d..54cabb1a5d9a 100644 --- a/clickhouse/src/storages/tests/uint32_chtest.cpp +++ b/clickhouse/src/storages/tests/uint32_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithUInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(UInt32, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value UInt32)"); - - const DataWithUInts insert_data{ - {0, 1, 10, std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 4); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value UInt32)" + ); + + const DataWithUInts insert_data{{0, 1, 10, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 4); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/uint64_chtest.cpp b/clickhouse/src/storages/tests/uint64_chtest.cpp index 4cbec930929c..ffefe008be87 100644 --- a/clickhouse/src/storages/tests/uint64_chtest.cpp +++ b/clickhouse/src/storages/tests/uint64_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithUInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(UInt64, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value UInt64)"); - - const DataWithUInts insert_data{ - {0, 1, 10, std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 4); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value UInt64)" + ); + + const DataWithUInts insert_data{{0, 1, 10, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 4); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/uint8_chtest.cpp b/clickhouse/src/storages/tests/uint8_chtest.cpp index 025267003441..d0cba41779e7 100644 --- a/clickhouse/src/storages/tests/uint8_chtest.cpp +++ b/clickhouse/src/storages/tests/uint8_chtest.cpp @@ -12,7 +12,7 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithUInts final { - std::vector ints; + std::vector ints; }; } // namespace @@ -21,28 +21,27 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io UTEST(UInt8, InsertSelect) { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value UInt8)"); - - const DataWithUInts insert_data{ - {0, 1, 10, std::numeric_limits::max()}}; - cluster->Insert("tmp_table", {"value"}, insert_data); - - const auto select_data = - cluster->Execute("SELECT * from tmp_table").As(); - ASSERT_EQ(select_data.ints.size(), 4); - - for (size_t i = 0; i < insert_data.ints.size(); ++i) { - ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); - } + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value UInt8)" + ); + + const DataWithUInts insert_data{{0, 1, 10, std::numeric_limits::max()}}; + cluster->Insert("tmp_table", {"value"}, insert_data); + + const auto select_data = cluster->Execute("SELECT * from tmp_table").As(); + ASSERT_EQ(select_data.ints.size(), 4); + + for (size_t i = 0; i < insert_data.ints.size(); ++i) { + ASSERT_EQ(insert_data.ints[i], select_data.ints[i]); + } } USERVER_NAMESPACE_END diff --git a/clickhouse/src/storages/tests/utils_test.cpp b/clickhouse/src/storages/tests/utils_test.cpp index 4d5dd6616f47..a931a5c54a71 100644 --- a/clickhouse/src/storages/tests/utils_test.cpp +++ b/clickhouse/src/storages/tests/utils_test.cpp @@ -14,106 +14,95 @@ USERVER_NAMESPACE_BEGIN namespace { -constexpr const char* kTestsuiteClickhouseTcpPort = - "TESTSUITE_CLICKHOUSE_SERVER_TCP_PORT"; +constexpr const char* kTestsuiteClickhouseTcpPort = "TESTSUITE_CLICKHOUSE_SERVER_TCP_PORT"; constexpr std::uint32_t kDefaultClickhousePort = 17123; clients::dns::Resolver MakeDnsResolver() { - return clients::dns::Resolver{engine::current_task::GetTaskProcessor(), {}}; + return clients::dns::Resolver{engine::current_task::GetTaskProcessor(), {}}; } components::ComponentConfig GetConfig(bool use_compression) { - USERVER_NAMESPACE::formats::yaml::ValueBuilder config_builder{ - USERVER_NAMESPACE::formats::yaml::FromString( - R"( + USERVER_NAMESPACE::formats::yaml::ValueBuilder config_builder{USERVER_NAMESPACE::formats::yaml::FromString( + R"( initial_pool_size: 1 max_pool_size: 10 queue_timeout: 1s use_secure_connection: false -use_compression: false)")}; - if (use_compression) { - config_builder["compression"] = "lz4"; - } - - USERVER_NAMESPACE::yaml_config::YamlConfig yaml_config{ - config_builder.ExtractValue(), {}}; - return USERVER_NAMESPACE::components::ComponentConfig{std::move(yaml_config)}; +use_compression: false)" + )}; + if (use_compression) { + config_builder["compression"] = "lz4"; + } + + USERVER_NAMESPACE::yaml_config::YamlConfig yaml_config{config_builder.ExtractValue(), {}}; + return USERVER_NAMESPACE::components::ComponentConfig{std::move(yaml_config)}; } storages::clickhouse::impl::AuthSettings GetAuthSettings() { - storages::clickhouse::impl::AuthSettings settings; - settings.user = "default"; - settings.password = ""; - settings.database = "default"; + storages::clickhouse::impl::AuthSettings settings; + settings.user = "default"; + settings.password = ""; + settings.database = "default"; - return settings; + return settings; } storages::clickhouse::Cluster MakeCluster( - clients::dns::Resolver& resolver, bool use_compression, - const std::vector& - endpoints) { - storages::clickhouse::impl::ClickhouseSettings settings; - settings.auth_settings = GetAuthSettings(); - settings.endpoints = endpoints; - - return storages::clickhouse::Cluster{resolver, settings, - GetConfig(use_compression)}; + clients::dns::Resolver& resolver, + bool use_compression, + const std::vector& endpoints +) { + storages::clickhouse::impl::ClickhouseSettings settings; + settings.auth_settings = GetAuthSettings(); + settings.endpoints = endpoints; + + return storages::clickhouse::Cluster{resolver, settings, GetConfig(use_compression)}; } } // namespace uint32_t GetClickhousePort() { - // NOLINTNEXTLINE(concurrency-mt-unsafe) - const auto* clickhouse_port_env = std::getenv(kTestsuiteClickhouseTcpPort); - return clickhouse_port_env - ? utils::FromString(clickhouse_port_env) - : kDefaultClickhousePort; + // NOLINTNEXTLINE(concurrency-mt-unsafe) + const auto* clickhouse_port_env = std::getenv(kTestsuiteClickhouseTcpPort); + return clickhouse_port_env ? utils::FromString(clickhouse_port_env) : kDefaultClickhousePort; } ClusterWrapper::ClusterWrapper( bool use_compression, - const std::vector& endpoints) - : resolver_{MakeDnsResolver()}, - cluster_{MakeCluster(resolver_, use_compression, endpoints)} { - stats_holder_ = statistics_storage_.RegisterWriter( - "clickhouse", [this](utils::statistics::Writer& writer) { + const std::vector& endpoints +) + : resolver_{MakeDnsResolver()}, cluster_{MakeCluster(resolver_, use_compression, endpoints)} { + stats_holder_ = statistics_storage_.RegisterWriter("clickhouse", [this](utils::statistics::Writer& writer) { cluster_.WriteStatistics(writer); - }); + }); } -storages::clickhouse::Cluster* ClusterWrapper::operator->() { - return &cluster_; -} +storages::clickhouse::Cluster* ClusterWrapper::operator->() { return &cluster_; } storages::clickhouse::Cluster& ClusterWrapper::operator*() { return cluster_; } -utils::statistics::Snapshot ClusterWrapper::GetStatistics( - std::string prefix, std::vector require_labels) { - return utils::statistics::Snapshot{statistics_storage_, std::move(prefix), - std::move(require_labels)}; +utils::statistics::Snapshot +ClusterWrapper::GetStatistics(std::string prefix, std::vector require_labels) { + return utils::statistics::Snapshot{statistics_storage_, std::move(prefix), std::move(require_labels)}; } PoolWrapper::PoolWrapper() : resolver_{MakeDnsResolver()}, pool_{std::make_shared( - resolver_, storages::clickhouse::impl::PoolSettings{ - GetConfig(false), - {"localhost", GetClickhousePort()}, - GetAuthSettings()})} {} + resolver_, + storages::clickhouse::impl::PoolSettings{ + GetConfig(false), + {"localhost", GetClickhousePort()}, + GetAuthSettings()} + )} {} -storages::clickhouse::impl::PoolImpl* PoolWrapper::operator->() { - return &*pool_; -} +storages::clickhouse::impl::PoolImpl* PoolWrapper::operator->() { return &*pool_; } -storages::clickhouse::impl::PoolImpl& PoolWrapper::operator*() { - return *pool_; -} +storages::clickhouse::impl::PoolImpl& PoolWrapper::operator*() { return *pool_; } namespace storages::clickhouse::io { -std::optional IteratorsTester::GetCurrentValue( - columns::ColumnIterator& iterator) { - return iterator.data_.current_value_; +std::optional IteratorsTester::GetCurrentValue(columns::ColumnIterator& iterator) { + return iterator.data_.current_value_; } } // namespace storages::clickhouse::io diff --git a/clickhouse/src/storages/tests/utils_test.hpp b/clickhouse/src/storages/tests/utils_test.hpp index d909f70ca35b..670342b2fbec 100644 --- a/clickhouse/src/storages/tests/utils_test.hpp +++ b/clickhouse/src/storages/tests/utils_test.hpp @@ -14,54 +14,51 @@ USERVER_NAMESPACE_BEGIN std::uint32_t GetClickhousePort(); class ClusterWrapper final { - public: - ClusterWrapper( - bool use_compression = false, - const std::vector& - endpoints = {{"localhost", GetClickhousePort()}}); - - storages::clickhouse::Cluster* operator->(); - storages::clickhouse::Cluster& operator*(); - - utils::statistics::Snapshot GetStatistics( - std::string prefix, - std::vector require_labels = {}); - - private: - clients::dns::Resolver resolver_; - USERVER_NAMESPACE::utils::statistics::Storage statistics_storage_; - storages::clickhouse::Cluster cluster_; - utils::statistics::Entry stats_holder_; +public: + ClusterWrapper( + bool use_compression = false, + const std::vector& endpoints = + {{"localhost", GetClickhousePort()}} + ); + + storages::clickhouse::Cluster* operator->(); + storages::clickhouse::Cluster& operator*(); + + utils::statistics::Snapshot + GetStatistics(std::string prefix, std::vector require_labels = {}); + +private: + clients::dns::Resolver resolver_; + USERVER_NAMESPACE::utils::statistics::Storage statistics_storage_; + storages::clickhouse::Cluster cluster_; + utils::statistics::Entry stats_holder_; }; class PoolWrapper final { - public: - PoolWrapper(); +public: + PoolWrapper(); - storages::clickhouse::impl::PoolImpl* operator->(); - storages::clickhouse::impl::PoolImpl& operator*(); + storages::clickhouse::impl::PoolImpl* operator->(); + storages::clickhouse::impl::PoolImpl& operator*(); - private: - clients::dns::Resolver resolver_; - std::shared_ptr pool_; +private: + clients::dns::Resolver resolver_; + std::shared_ptr pool_; }; namespace storages::clickhouse::io { class IteratorsTester final { - public: - static std::optional GetCurrentValue( - columns::ColumnIterator& iterator); - - template - static auto& GetCurrentIteratorsTuple( - typename io::RowsMapper::Iterator& iterator) { - return iterator.iterators_; - } - - template - static constexpr bool kCanMoveFromIterators = - io::RowsMapper::kCanMoveFromIterators; +public: + static std::optional GetCurrentValue(columns::ColumnIterator& iterator); + + template + static auto& GetCurrentIteratorsTuple(typename io::RowsMapper::Iterator& iterator) { + return iterator.iterators_; + } + + template + static constexpr bool kCanMoveFromIterators = io::RowsMapper::kCanMoveFromIterators; }; } // namespace storages::clickhouse::io @@ -69,11 +66,11 @@ class IteratorsTester final { namespace storages::clickhouse { class QueryTester final { - public: - template - static Query WithArgs(const Query& query, const Args&... args) { - return query.WithArgs(args...); - } +public: + template + static Query WithArgs(const Query& query, const Args&... args) { + return query.WithArgs(args...); + } }; } // namespace storages::clickhouse diff --git a/clickhouse/src/storages/tests/uuid_chtest.cpp b/clickhouse/src/storages/tests/uuid_chtest.cpp index 2c095b397007..3b2c1c44d059 100644 --- a/clickhouse/src/storages/tests/uuid_chtest.cpp +++ b/clickhouse/src/storages/tests/uuid_chtest.cpp @@ -15,11 +15,11 @@ USERVER_NAMESPACE_BEGIN namespace { struct DataWithUuidMismatchedEndianness final { - std::vector uuids; + std::vector uuids; }; struct DataWithUuid final { - std::vector uuids; + std::vector uuids; }; } // namespace @@ -28,12 +28,12 @@ namespace storages::clickhouse::io { template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; template <> struct CppToClickhouse { - using mapped_type = std::tuple; + using mapped_type = std::tuple; }; } // namespace storages::clickhouse::io @@ -42,31 +42,27 @@ namespace { template void PerformInsertSelect() { - ClusterWrapper cluster{}; - cluster->Execute( - "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " - "(value UUID)"); + ClusterWrapper cluster{}; + cluster->Execute( + "CREATE TEMPORARY TABLE IF NOT EXISTS tmp_table " + "(value UUID)" + ); - const auto uuid = utils::generators::GenerateBoostUuid(); + const auto uuid = utils::generators::GenerateBoostUuid(); - const UuidType insert_data{{uuid}}; - cluster->Insert("tmp_table", {"value"}, insert_data); + const UuidType insert_data{{uuid}}; + cluster->Insert("tmp_table", {"value"}, insert_data); - const auto select_data = - cluster->Execute("SELECT value FROM tmp_table").As(); + const auto select_data = cluster->Execute("SELECT value FROM tmp_table").As(); - EXPECT_EQ(select_data.uuids.size(), 1); - EXPECT_EQ(select_data.uuids.front(), insert_data.uuids.front()); + EXPECT_EQ(select_data.uuids.size(), 1); + EXPECT_EQ(select_data.uuids.front(), insert_data.uuids.front()); } } // namespace -UTEST(Uuid, MismatchedEndiannessInsertSelect) { - PerformInsertSelect(); -} +UTEST(Uuid, MismatchedEndiannessInsertSelect) { PerformInsertSelect(); } -UTEST(Uuid, CorrectEndiannessInsertSelect) { - PerformInsertSelect(); -} +UTEST(Uuid, CorrectEndiannessInsertSelect) { PerformInsertSelect(); } USERVER_NAMESPACE_END diff --git a/cmake/GrpcTargets.cmake b/cmake/GrpcTargets.cmake index 79a9adcf7504..aae36e682a0a 100644 --- a/cmake/GrpcTargets.cmake +++ b/cmake/GrpcTargets.cmake @@ -24,8 +24,6 @@ function(_userver_prepare_grpc) find_package(gRPC REQUIRED) get_target_property(PROTO_GRPC_CPP_PLUGIN gRPC::grpc_cpp_plugin LOCATION) get_target_property(PROTO_GRPC_PYTHON_PLUGIN gRPC::grpc_python_plugin LOCATION) - set(PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}") - set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT ON) else() include("${CMAKE_CURRENT_LIST_DIR}/SetupGrpc.cmake") endif() @@ -101,7 +99,7 @@ _userver_prepare_grpc() function(userver_generate_grpc_files) set(options) - set(one_value_args CPP_FILES CPP_USRV_FILES GENERATED_INCLUDES SOURCE_PATH) + set(one_value_args CPP_FILES CPP_USRV_FILES GENERATED_INCLUDES SOURCE_PATH OUTPUT_PATH) set(multi_value_args PROTOS INCLUDE_DIRECTORIES) cmake_parse_arguments(GEN_RPC "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) @@ -132,11 +130,19 @@ function(userver_generate_grpc_files) endforeach() endif() - set(GENERATED_PROTO_DIR ${CMAKE_CURRENT_BINARY_DIR}/proto) + if (NOT "${GEN_RPC_OUTPUT_PATH}" STREQUAL "") + if(NOT IS_ABSOLUTE "${GEN_RPC_OUTPUT_PATH}") + message(SEND_ERROR "OUTPUT_PATH='${GEN_RPC_OUTPUT_PATH}' is a relative path, which is unsupported.") + endif() + set(GENERATED_PROTO_DIR "${GEN_RPC_OUTPUT_PATH}") + else() + set(GENERATED_PROTO_DIR "${CMAKE_CURRENT_BINARY_DIR}/proto") + endif() + get_filename_component(GENERATED_PROTO_DIR "${GENERATED_PROTO_DIR}" REALPATH BASE_DIR "/") if(NOT "${GEN_RPC_SOURCE_PATH}" STREQUAL "") - if(NOT IS_ABSOLUTE ${GEN_RPC_SOURCE_PATH}) + if(NOT IS_ABSOLUTE "${GEN_RPC_SOURCE_PATH}") message(SEND_ERROR "SOURCE_PATH='${GEN_RPC_SOURCE_PATH}' is a relative path, which is unsupported.") endif() set(root_path "${GEN_RPC_SOURCE_PATH}") @@ -294,14 +300,15 @@ endfunction() function(userver_add_grpc_library NAME) set(options) - set(one_value_args SOURCE_PATH) + set(one_value_args SOURCE_PATH OUTPUT_PATH) set(multi_value_args PROTOS INCLUDE_DIRECTORIES) cmake_parse_arguments(RPC_LIB "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN}) userver_generate_grpc_files( PROTOS ${RPC_LIB_PROTOS} INCLUDE_DIRECTORIES ${RPC_LIB_INCLUDE_DIRECTORIES} - SOURCE_PATH ${RPC_LIB_SOURCE_PATH} + SOURCE_PATH "${RPC_LIB_SOURCE_PATH}" + OUTPUT_PATH "${RPC_LIB_OUTPUT_PATH}" GENERATED_INCLUDES include_paths CPP_FILES generated_sources CPP_USRV_FILES generated_usrv_sources diff --git a/cmake/SetupGrpc.cmake b/cmake/SetupGrpc.cmake index 7a3110a1c316..da6ea6639471 100644 --- a/cmake/SetupGrpc.cmake +++ b/cmake/SetupGrpc.cmake @@ -18,8 +18,6 @@ macro(try_find_cmake_grpc) # Use the found CMake-enabled gRPC package get_target_property(PROTO_GRPC_CPP_PLUGIN gRPC::grpc_cpp_plugin LOCATION) get_target_property(PROTO_GRPC_PYTHON_PLUGIN gRPC::grpc_python_plugin LOCATION) - set(PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}") - set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT ON) endif() endmacro() @@ -42,8 +40,6 @@ macro(try_find_system_grpc) find_program(PROTO_GRPC_CPP_PLUGIN grpc_cpp_plugin) find_program(PROTO_GRPC_PYTHON_PLUGIN grpc_python_plugin) - set(PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}") - set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT ON) endif() endmacro() @@ -97,8 +93,6 @@ CPMAddPackage( set(gRPC_VERSION "${CPM_PACKAGE_gRPC_VERSION}") set(PROTO_GRPC_CPP_PLUGIN $) set(PROTO_GRPC_PYTHON_PLUGIN $) -set(PROTOBUF_PROTOC $) -set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT OFF) write_package_stub(gRPC) if (NOT TARGET "gRPC::grpc++") add_library(gRPC::grpc++ ALIAS grpc++) diff --git a/cmake/SetupProtobuf.cmake b/cmake/SetupProtobuf.cmake index a1be81f774ac..7369e987289a 100644 --- a/cmake/SetupProtobuf.cmake +++ b/cmake/SetupProtobuf.cmake @@ -27,6 +27,8 @@ endfunction() if(USERVER_CONAN) find_package(Protobuf REQUIRED) _userver_set_protobuf_version_category() + set(PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}") + set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT ON) return() endif() @@ -49,6 +51,8 @@ if(NOT USERVER_FORCE_DOWNLOAD_PROTOBUF) if(Protobuf_FOUND) _userver_set_protobuf_version_category() + set(PROTOBUF_PROTOC "${Protobuf_PROTOC_EXECUTABLE}") + set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT ON) return() endif() endif() @@ -78,3 +82,5 @@ set_target_properties(libprotoc PROPERTIES write_package_stub(Protobuf) mark_targets_as_system("${Protobuf_SOURCE_DIR}") _userver_set_protobuf_version_category() +set(PROTOBUF_PROTOC $) +set(GENERATE_PROTOS_AT_CONFIGURE_DEFAULT OFF) diff --git a/cmake/UserverRequireDWCAS.cpp b/cmake/UserverRequireDWCAS.cpp index e49d7bc2780f..47e38b7c1cde 100644 --- a/cmake/UserverRequireDWCAS.cpp +++ b/cmake/UserverRequireDWCAS.cpp @@ -6,8 +6,8 @@ #endif struct alignas(sizeof(std::uintptr_t) * 2) A final { - std::uintptr_t x{}; - std::uintptr_t y{}; + std::uintptr_t x{}; + std::uintptr_t y{}; }; #ifdef USERVER_USE_STD_DWCAS @@ -22,17 +22,17 @@ extern Atomic a; Atomic a{A{1, 2}}; int main() { - // Clang reports is_always_lock_free == true (which is correct), - // but is_lock_free == false (which makes no sense). - if (!Atomic::is_always_lock_free && !a.is_lock_free()) return 1; + // Clang reports is_always_lock_free == true (which is correct), + // but is_lock_free == false (which makes no sense). + if (!Atomic::is_always_lock_free && !a.is_lock_free()) return 1; - A expected{1, 2}; - A desired{3, 4}; - if (!a.compare_exchange_strong(expected, desired)) return 2; + A expected{1, 2}; + A desired{3, 4}; + if (!a.compare_exchange_strong(expected, desired)) return 2; - expected = {3, 4}; - desired = {5, 6}; - if (!a.compare_exchange_strong(expected, desired)) return 2; + expected = {3, 4}; + desired = {5, 6}; + if (!a.compare_exchange_strong(expected, desired)) return 2; - return 0; + return 0; } diff --git a/conan/test_package/hello.cpp b/conan/test_package/hello.cpp index d80f2ad523d8..1c681967a505 100644 --- a/conan/test_package/hello.cpp +++ b/conan/test_package/hello.cpp @@ -9,30 +9,28 @@ namespace service_template { namespace { class Hello final : public userver::server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-hello"; +public: + static constexpr std::string_view kName = "handler-hello"; - using HttpHandlerBase::HttpHandlerBase; + using HttpHandlerBase::HttpHandlerBase; - std::string HandleRequestThrow( - const userver::server::http::HttpRequest& request, - userver::server::request::RequestContext&) const override { - return service_template::SayHelloTo(request.GetArg("name")); - } + std::string + HandleRequestThrow(const userver::server::http::HttpRequest& request, userver::server::request::RequestContext&) + const override { + return service_template::SayHelloTo(request.GetArg("name")); + } }; } // namespace std::string SayHelloTo(std::string_view name) { - if (name.empty()) { - name = "unknown user"; - } + if (name.empty()) { + name = "unknown user"; + } - return fmt::format("Hello, {}!\n", name); + return fmt::format("Hello, {}!\n", name); } -void AppendHello(userver::components::ComponentList& component_list) { - component_list.Append(); -} +void AppendHello(userver::components::ComponentList& component_list) { component_list.Append(); } } // namespace service_template diff --git a/conan/test_package/hello_service.cpp b/conan/test_package/hello_service.cpp index 9feed3c4248e..9d3aa83ad7a5 100644 --- a/conan/test_package/hello_service.cpp +++ b/conan/test_package/hello_service.cpp @@ -3,20 +3,18 @@ #include class Hello final : public userver::server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-hello-sample"; +public: + static constexpr std::string_view kName = "handler-hello-sample"; - using HttpHandlerBase::HttpHandlerBase; + using HttpHandlerBase::HttpHandlerBase; - std::string HandleRequestThrow( - const userver::server::http::HttpRequest&, - userver::server::request::RequestContext&) const override { - return "Hello world!\n"; - } + std::string HandleRequestThrow(const userver::server::http::HttpRequest&, userver::server::request::RequestContext&) + const override { + return "Hello world!\n"; + } }; int main(int argc, char* argv[]) { - const auto component_list = - userver::components::MinimalServerComponentList().Append(); - return 0; + const auto component_list = userver::components::MinimalServerComponentList().Append(); + return 0; } diff --git a/conan/test_package/hello_service/hello_service.cpp b/conan/test_package/hello_service/hello_service.cpp index e6abc97882ca..e1bf18a1f525 100644 --- a/conan/test_package/hello_service/hello_service.cpp +++ b/conan/test_package/hello_service/hello_service.cpp @@ -7,22 +7,19 @@ namespace samples::hello { class Hello final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-hello-sample"; +public: + static constexpr std::string_view kName = "handler-hello-sample"; - using HttpHandlerBase::HttpHandlerBase; + using HttpHandlerBase::HttpHandlerBase; - std::string HandleRequestThrow( - const server::http::HttpRequest&, - server::request::RequestContext&) const override { - return "Hello world!\n"; - } + std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override { + return "Hello world!\n"; + } }; } // namespace samples::hello int main(int argc, char* argv[]) { - const auto component_list = - components::MinimalServerComponentList().Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::MinimalServerComponentList().Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/conan/test_package/test_clickhouse.cpp b/conan/test_package/test_clickhouse.cpp index 7c64571cc975..cf612ee120a4 100644 --- a/conan/test_package/test_clickhouse.cpp +++ b/conan/test_package/test_clickhouse.cpp @@ -11,17 +11,17 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(""); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_core.cpp b/conan/test_package/test_core.cpp index 837631c763f0..d1d0f94fc1a0 100644 --- a/conan/test_package/test_core.cpp +++ b/conan/test_package/test_core.cpp @@ -9,16 +9,16 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append(); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append(); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_grpc.cpp b/conan/test_package/test_grpc.cpp index cb413821fb0c..6eacdb44619e 100644 --- a/conan/test_package/test_grpc.cpp +++ b/conan/test_package/test_grpc.cpp @@ -14,46 +14,44 @@ namespace samples { -class GreeterServiceComponent final - : public api::GreeterServiceBase::Component { - public: - static constexpr std::string_view kName = "greeter-service"; +class GreeterServiceComponent final : public api::GreeterServiceBase::Component { +public: + static constexpr std::string_view kName = "greeter-service"; - GreeterServiceComponent(const userver::components::ComponentConfig& config, - const userver::components::ComponentContext& context) - : api::GreeterServiceBase::Component(config, context), - prefix_(config["greeting-prefix"].As()) {} + GreeterServiceComponent( + const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context + ) + : api::GreeterServiceBase::Component(config, context), prefix_(config["greeting-prefix"].As()) {} - void SayHello(SayHelloCall& call, api::GreetingRequest&& request) override; + void SayHello(SayHelloCall& call, api::GreetingRequest&& request) override; - private: - const std::string prefix_; +private: + const std::string prefix_; }; -void GreeterServiceComponent::SayHello( - api::GreeterServiceBase::SayHelloCall& call, - api::GreetingRequest&& request) { - api::GreetingResponse response; - response.set_greeting(fmt::format("{}, {}!", prefix_, request.name())); +void GreeterServiceComponent::SayHello(api::GreeterServiceBase::SayHelloCall& call, api::GreetingRequest&& request) { + api::GreetingResponse response; + response.set_greeting(fmt::format("{}, {}!", prefix_, request.name())); - call.Finish(response); + call.Finish(response); } } // namespace samples int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append("") - .Append(); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append("") + .Append(); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_kafka.cpp b/conan/test_package/test_kafka.cpp index 027a1e924a67..f49e26c75375 100644 --- a/conan/test_package/test_kafka.cpp +++ b/conan/test_package/test_kafka.cpp @@ -11,18 +11,18 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_mongo.cpp b/conan/test_package/test_mongo.cpp index e2fad7713780..6325dee4ac1f 100644 --- a/conan/test_package/test_mongo.cpp +++ b/conan/test_package/test_mongo.cpp @@ -10,17 +10,17 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(""); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_postgresql.cpp b/conan/test_package/test_postgresql.cpp index f630e06ff159..71c467438a95 100644 --- a/conan/test_package/test_postgresql.cpp +++ b/conan/test_package/test_postgresql.cpp @@ -10,17 +10,17 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(""); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_rabbitmq.cpp b/conan/test_package/test_rabbitmq.cpp index 7e0e714dad40..1b0fd94d454f 100644 --- a/conan/test_package/test_rabbitmq.cpp +++ b/conan/test_package/test_rabbitmq.cpp @@ -10,17 +10,17 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(""); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_redis.cpp b/conan/test_package/test_redis.cpp index b7cd0579e3b1..276bb4672add 100644 --- a/conan/test_package/test_redis.cpp +++ b/conan/test_package/test_redis.cpp @@ -10,17 +10,17 @@ #include "hello.hpp" int main(int argc, char* argv[]) { - auto component_list = userver::components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(""); + auto component_list = userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(""); - service_template::AppendHello(component_list); + service_template::AppendHello(component_list); - auto size = std::distance(component_list.begin(), component_list.end()); - std::cout << size << std::endl; + auto size = std::distance(component_list.begin(), component_list.end()); + std::cout << size << std::endl; - return 0; + return 0; } diff --git a/conan/test_package/test_ubench.cpp b/conan/test_package/test_ubench.cpp index 528d5778e942..5263f76bc43e 100644 --- a/conan/test_package/test_ubench.cpp +++ b/conan/test_package/test_ubench.cpp @@ -8,16 +8,16 @@ #include void HelloBenchmark(benchmark::State& state) { - userver::engine::RunStandalone([&] { - constexpr std::string_view kNames[] = {"userver", "is", "awesome", "!"}; - std::uint64_t i = 0; + userver::engine::RunStandalone([&] { + constexpr std::string_view kNames[] = {"userver", "is", "awesome", "!"}; + std::uint64_t i = 0; - for (auto _ : state) { - const auto name = kNames[i++ % std::size(kNames)]; - auto result = service_template::SayHelloTo(name); - benchmark::DoNotOptimize(result); - } - }); + for (auto _ : state) { + const auto name = kNames[i++ % std::size(kNames)]; + auto result = service_template::SayHelloTo(name); + benchmark::DoNotOptimize(result); + } + }); } BENCHMARK(HelloBenchmark); diff --git a/conan/test_package/test_universal.cpp b/conan/test_package/test_universal.cpp index 9fcc6380ee8d..3a6c9a9e6f41 100644 --- a/conan/test_package/test_universal.cpp +++ b/conan/test_package/test_universal.cpp @@ -4,8 +4,8 @@ #include int main() { - auto json = userver::formats::json::FromString(R"({ + auto json = userver::formats::json::FromString(R"({ "test": "hello from universal" })"); - std::cout << userver::formats::json::ToString(json) << std::endl; + std::cout << userver::formats::json::ToString(json) << std::endl; } diff --git a/conan/test_package/test_utest.cpp b/conan/test_package/test_utest.cpp index 68186dfde23b..3f6899e19503 100644 --- a/conan/test_package/test_utest.cpp +++ b/conan/test_package/test_utest.cpp @@ -3,6 +3,6 @@ #include UTEST(SayHelloTo, Basic) { - EXPECT_EQ(service_template::SayHelloTo("Developer"), "Hello, Developer!\n"); - EXPECT_EQ(service_template::SayHelloTo({}), "Hello, unknown user!\n"); + EXPECT_EQ(service_template::SayHelloTo("Developer"), "Hello, Developer!\n"); + EXPECT_EQ(service_template::SayHelloTo({}), "Hello, unknown user!\n"); } diff --git a/core/benchmarks/main.cpp b/core/benchmarks/main.cpp index 6bb64332b94c..75484ba06a47 100644 --- a/core/benchmarks/main.cpp +++ b/core/benchmarks/main.cpp @@ -4,12 +4,11 @@ #include int main(int argc, char** argv) { - USERVER_NAMESPACE::utils::impl::FinishStaticRegistration(); + USERVER_NAMESPACE::utils::impl::FinishStaticRegistration(); - const USERVER_NAMESPACE::logging::DefaultLoggerLevelScope level_scope{ - USERVER_NAMESPACE::logging::Level::kError}; + const USERVER_NAMESPACE::logging::DefaultLoggerLevelScope level_scope{USERVER_NAMESPACE::logging::Level::kError}; - ::benchmark::Initialize(&argc, argv); - if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; - ::benchmark::RunSpecifiedBenchmarks(); + ::benchmark::Initialize(&argc, argv); + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1; + ::benchmark::RunSpecifiedBenchmarks(); } diff --git a/core/functional_tests/basic_chaos/httpclient_handlers.hpp b/core/functional_tests/basic_chaos/httpclient_handlers.hpp index 252b343c9a7b..10315e98f386 100644 --- a/core/functional_tests/basic_chaos/httpclient_handlers.hpp +++ b/core/functional_tests/basic_chaos/httpclient_handlers.hpp @@ -18,130 +18,108 @@ namespace chaos { constexpr std::chrono::seconds kDefaultTimeout{15}; class HttpClientHandler final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-chaos-httpclient"; - - HttpClientHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context), - client_( - context.FindComponent().GetHttpClient()) {} - - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override { - const auto& type = request.GetArg("type"); - const auto& port_string = request.GetArg("port"); - const auto& timeout_string = request.GetArg("timeout"); - const auto& attempts_string = request.GetArg("attempts"); - const auto& retry_network_errors_string = - request.GetArg("retry_network_errors"); - - const auto port = utils::FromString(port_string); - const auto timeout = - timeout_string.empty() - ? kDefaultTimeout - : std::chrono::milliseconds{ - utils::FromString( - timeout_string)}; - const auto attempts = attempts_string.empty() - ? short{1} - : utils::FromString(attempts_string); - const auto retry_network_errors = - retry_network_errors_string.empty() || - static_cast(utils::FromString(retry_network_errors_string)); - - if (type == "common") { - auto url = fmt::format("http://localhost:{}/test", port); - auto response = client_.CreateRequest() - .get(url) - .timeout(timeout) - .retry(attempts, retry_network_errors) - .perform(); - response->raise_for_status(); - return response->body(); +public: + static constexpr std::string_view kName = "handler-chaos-httpclient"; + + HttpClientHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context), client_(context.FindComponent().GetHttpClient()) {} + + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override { + const auto& type = request.GetArg("type"); + const auto& port_string = request.GetArg("port"); + const auto& timeout_string = request.GetArg("timeout"); + const auto& attempts_string = request.GetArg("attempts"); + const auto& retry_network_errors_string = request.GetArg("retry_network_errors"); + + const auto port = utils::FromString(port_string); + const auto timeout = + timeout_string.empty() + ? kDefaultTimeout + : std::chrono::milliseconds{utils::FromString(timeout_string)}; + const auto attempts = attempts_string.empty() ? short{1} : utils::FromString(attempts_string); + const auto retry_network_errors = retry_network_errors_string.empty() || + static_cast(utils::FromString(retry_network_errors_string)); + + if (type == "common") { + auto url = fmt::format("http://localhost:{}/test", port); + auto response = + client_.CreateRequest().get(url).timeout(timeout).retry(attempts, retry_network_errors).perform(); + response->raise_for_status(); + return response->body(); + } + + UINVARIANT(false, "Unexpected request type"); } - UINVARIANT(false, "Unexpected request type"); - } - - private: - clients::http::Client& client_; +private: + clients::http::Client& client_; }; class StreamHandler : public server::handlers::HttpHandlerBase { - public: - // `kName` must match component name in config.yaml - static constexpr std::string_view kName = "handler-chaos-stream"; - - StreamHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : server::handlers::HttpHandlerBase(config, context), - http_client_( - context.FindComponent().GetHttpClient()), - config_source_( - context.FindComponent().GetSource()) {} - - /// [HandleStreamRequest] - void HandleStreamRequest( - const server::http::HttpRequest& request, - server::request::RequestContext&, - server::http::ResponseBodyStream& response_body_stream) const override { - ::clients::http::Headers headers; - for (const auto& header_name : request.GetHeaderNames()) { - const auto& header_value = request.GetHeader(header_name); - headers[header_name] = header_value; - } - - const auto& port = request.GetArg("port"); - auto url = fmt::format("http://localhost:{}/test", port); - const auto& timeout_string = request.GetArg("timeout"); - const auto timeout = timeout_string.empty() - ? kDefaultTimeout - : std::chrono::seconds{std::stoi(timeout_string)}; - const auto retries = 1; - - auto external_request = http_client_.CreateRequest() - .get(url) - .headers(std::move(headers)) - .timeout(timeout) - .retry(retries); - - auto queue = concurrent::StringStreamQueue::Create(); - auto client_response = - external_request.async_perform_stream_body(std::move(queue)); - - TESTPOINT("stream_after_start", {}); - - for (const auto& header_item : client_response.GetHeaders()) { - TESTPOINT("stream_after_get_headers", {}); - const auto& header_name = header_item.first; - const auto& header_value = header_item.second; - response_body_stream.SetHeader(header_name, header_value); - } - - auto status_code = client_response.StatusCode(); - response_body_stream.SetStatusCode(status_code); - - response_body_stream.SetHeader(std::string{"abc"}, std::string{"def"}); - response_body_stream.SetEndOfHeaders(); - - TESTPOINT("stream_after_set_end_of_headers", {}); - - std::string body_part; - auto deadline = engine::Deadline::FromDuration(std::chrono::seconds(10)); - while (client_response.ReadChunk(body_part, deadline)) { - TESTPOINT("stream_after_read_chunk", {}); - response_body_stream.PushBodyChunk(std::move(body_part), - engine::Deadline()); - TESTPOINT("stream_after_push_body_chunk", {}); +public: + // `kName` must match component name in config.yaml + static constexpr std::string_view kName = "handler-chaos-stream"; + + StreamHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : server::handlers::HttpHandlerBase(config, context), + http_client_(context.FindComponent().GetHttpClient()), + config_source_(context.FindComponent().GetSource()) {} + + /// [HandleStreamRequest] + void HandleStreamRequest( + const server::http::HttpRequest& request, + server::request::RequestContext&, + server::http::ResponseBodyStream& response_body_stream + ) const override { + ::clients::http::Headers headers; + for (const auto& header_name : request.GetHeaderNames()) { + const auto& header_value = request.GetHeader(header_name); + headers[header_name] = header_value; + } + + const auto& port = request.GetArg("port"); + auto url = fmt::format("http://localhost:{}/test", port); + const auto& timeout_string = request.GetArg("timeout"); + const auto timeout = timeout_string.empty() ? kDefaultTimeout : std::chrono::seconds{std::stoi(timeout_string)}; + const auto retries = 1; + + auto external_request = + http_client_.CreateRequest().get(url).headers(std::move(headers)).timeout(timeout).retry(retries); + + auto queue = concurrent::StringStreamQueue::Create(); + auto client_response = external_request.async_perform_stream_body(std::move(queue)); + + TESTPOINT("stream_after_start", {}); + + for (const auto& header_item : client_response.GetHeaders()) { + TESTPOINT("stream_after_get_headers", {}); + const auto& header_name = header_item.first; + const auto& header_value = header_item.second; + response_body_stream.SetHeader(header_name, header_value); + } + + auto status_code = client_response.StatusCode(); + response_body_stream.SetStatusCode(status_code); + + response_body_stream.SetHeader(std::string{"abc"}, std::string{"def"}); + response_body_stream.SetEndOfHeaders(); + + TESTPOINT("stream_after_set_end_of_headers", {}); + + std::string body_part; + auto deadline = engine::Deadline::FromDuration(std::chrono::seconds(10)); + while (client_response.ReadChunk(body_part, deadline)) { + TESTPOINT("stream_after_read_chunk", {}); + response_body_stream.PushBodyChunk(std::move(body_part), engine::Deadline()); + TESTPOINT("stream_after_push_body_chunk", {}); + } } - } - /// [HandleStreamRequest] + /// [HandleStreamRequest] - private: - clients::http::Client& http_client_; - dynamic_config::Source config_source_; +private: + clients::http::Client& http_client_; + dynamic_config::Source config_source_; }; } // namespace chaos diff --git a/core/functional_tests/basic_chaos/httpserver_handlers.hpp b/core/functional_tests/basic_chaos/httpserver_handlers.hpp index 195060575c81..88d482a3b12c 100644 --- a/core/functional_tests/basic_chaos/httpserver_handlers.hpp +++ b/core/functional_tests/basic_chaos/httpserver_handlers.hpp @@ -12,67 +12,61 @@ namespace chaos { class HttpServerHandler final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-chaos-httpserver"; +public: + static constexpr std::string_view kName = "handler-chaos-httpserver"; - static inline const std::string kDefaultAnswer = "OK!"; + static inline const std::string kDefaultAnswer = "OK!"; - HttpServerHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context) {} + HttpServerHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context) {} - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override { - const auto& type = request.GetArg("type"); + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override { + const auto& type = request.GetArg("type"); - if (type == "common") { - TESTPOINT("testpoint_request", {}); - return kDefaultAnswer; - } + if (type == "common") { + TESTPOINT("testpoint_request", {}); + return kDefaultAnswer; + } - if (type == "sleep") { - TESTPOINT("testpoint_request", {}); - engine::SleepFor(std::chrono::milliseconds{200}); - return kDefaultAnswer; - } + if (type == "sleep") { + TESTPOINT("testpoint_request", {}); + engine::SleepFor(std::chrono::milliseconds{200}); + return kDefaultAnswer; + } - if (type == "cancel") { - engine::InterruptibleSleepFor(std::chrono::seconds(20)); - if (engine::current_task::IsCancelRequested()) { - engine::TaskCancellationBlocker block_cancel; - TESTPOINT("testpoint_cancel", {}); - } - return kDefaultAnswer; - } + if (type == "cancel") { + engine::InterruptibleSleepFor(std::chrono::seconds(20)); + if (engine::current_task::IsCancelRequested()) { + engine::TaskCancellationBlocker block_cancel; + TESTPOINT("testpoint_cancel", {}); + } + return kDefaultAnswer; + } - if (type == "echo") { - UASSERT_MSG(!request.IsBodyCompressed(), - "Body was not decompressed by userver"); - return request.RequestBody(); - } + if (type == "echo") { + UASSERT_MSG(!request.IsBodyCompressed(), "Body was not decompressed by userver"); + return request.RequestBody(); + } - if (type == "echo-and-check-args") { - UASSERT_MSG(!request.IsBodyCompressed(), - "Body was not decompressed by userver"); - if (request.GetArg("srv") != "mt-dev") - throw std::runtime_error("Failed arg 'srv'"); - if (request.GetArg("lang") != "en-ru") - throw std::runtime_error("Failed arg 'lang'"); - return request.RequestBody(); - } + if (type == "echo-and-check-args") { + UASSERT_MSG(!request.IsBodyCompressed(), "Body was not decompressed by userver"); + if (request.GetArg("srv") != "mt-dev") throw std::runtime_error("Failed arg 'srv'"); + if (request.GetArg("lang") != "en-ru") throw std::runtime_error("Failed arg 'lang'"); + return request.RequestBody(); + } - UINVARIANT(false, "Unexpected request type"); - } + UINVARIANT(false, "Unexpected request type"); + } - server::handlers::FormattedErrorData GetFormattedExternalErrorBody( - const server::handlers::CustomHandlerException& exc) const override { - server::handlers::FormattedErrorData result; - result.external_body = - server::handlers::JsonErrorBuilder{exc}.GetExternalBody(); - result.content_type = server::handlers::JsonErrorBuilder::GetContentType(); - return result; - } + server::handlers::FormattedErrorData GetFormattedExternalErrorBody( + const server::handlers::CustomHandlerException& exc + ) const override { + server::handlers::FormattedErrorData result; + result.external_body = server::handlers::JsonErrorBuilder{exc}.GetExternalBody(); + result.content_type = server::handlers::JsonErrorBuilder::GetContentType(); + return result; + } }; } // namespace chaos diff --git a/core/functional_tests/basic_chaos/httpserver_with_exception_handler.hpp b/core/functional_tests/basic_chaos/httpserver_with_exception_handler.hpp index 5e8562e76810..fc9a9d5fe8ce 100644 --- a/core/functional_tests/basic_chaos/httpserver_with_exception_handler.hpp +++ b/core/functional_tests/basic_chaos/httpserver_with_exception_handler.hpp @@ -4,21 +4,19 @@ namespace chaos { -class HttpServerWithExceptionHandler final - : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = - "handler-chaos-httpserver-with-exception"; +class HttpServerWithExceptionHandler final : public server::handlers::HttpHandlerBase { +public: + static constexpr std::string_view kName = "handler-chaos-httpserver-with-exception"; - HttpServerWithExceptionHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context) {} + HttpServerWithExceptionHandler( + const components::ComponentConfig& config, + const components::ComponentContext& context + ) + : HttpHandlerBase(config, context) {} - std::string HandleRequestThrow( - const server::http::HttpRequest&, - server::request::RequestContext&) const override { - throw std::runtime_error("some runtime error"); - } + std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override { + throw std::runtime_error("some runtime error"); + } }; } // namespace chaos diff --git a/core/functional_tests/basic_chaos/resolver_handlers.hpp b/core/functional_tests/basic_chaos/resolver_handlers.hpp index 0ffab16ffc43..5c345c7c16fe 100644 --- a/core/functional_tests/basic_chaos/resolver_handlers.hpp +++ b/core/functional_tests/basic_chaos/resolver_handlers.hpp @@ -21,56 +21,47 @@ static constexpr std::string_view kSeparator = ", "; static constexpr size_t kResolverTimeoutSecs = 15; class ResolverHandler final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-chaos-dns-resolver"; +public: + static constexpr std::string_view kName = "handler-chaos-dns-resolver"; - ResolverHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context), - resolver_{engine::current_task::GetTaskProcessor(), [&config] { - clients::dns::ResolverConfig resolver_config; - resolver_config.network_custom_servers = - config["dns-servers"].As>(); - resolver_config.file_path = - config["hosts-file"].As(); - resolver_config.file_update_interval = - std::chrono::seconds{kResolverTimeoutSecs}; - resolver_config.network_timeout = - std::chrono::seconds{kResolverTimeoutSecs}; - resolver_config.network_attempts = 1; - resolver_config.cache_max_reply_ttl = std::chrono::seconds{ - config["cache-max-ttl"].As()}; - resolver_config.cache_failure_ttl = std::chrono::seconds{ - config["cache-failure-ttl"].As()}; - resolver_config.cache_ways = 1; - resolver_config.cache_size_per_way = - config["cache-size-per-way"].As(); - return resolver_config; - }()} {} + ResolverHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context), + resolver_{engine::current_task::GetTaskProcessor(), [&config] { + clients::dns::ResolverConfig resolver_config; + resolver_config.network_custom_servers = config["dns-servers"].As>(); + resolver_config.file_path = config["hosts-file"].As(); + resolver_config.file_update_interval = std::chrono::seconds{kResolverTimeoutSecs}; + resolver_config.network_timeout = std::chrono::seconds{kResolverTimeoutSecs}; + resolver_config.network_attempts = 1; + resolver_config.cache_max_reply_ttl = + std::chrono::seconds{config["cache-max-ttl"].As()}; + resolver_config.cache_failure_ttl = + std::chrono::seconds{config["cache-failure-ttl"].As()}; + resolver_config.cache_ways = 1; + resolver_config.cache_size_per_way = config["cache-size-per-way"].As(); + return resolver_config; + }()} {} - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override { - const auto& type = request.GetArg("type"); - const auto& timeout = request.GetArg("timeout"); - const std::chrono::seconds timeout_secs{ - timeout.empty() ? kResolverTimeoutSecs : std::stoi(timeout)}; - const auto& to_resolve = request.GetArg("host_to_resolve"); - if (type == "resolve") { - auto res = resolver_.Resolve( - to_resolve, engine::Deadline::FromDuration(timeout_secs)); - return fmt::to_string(fmt::join(res, kSeparator)); - } else if (type == "flush") { - resolver_.FlushNetworkCache(to_resolve); - return "flushed"; - } + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override { + const auto& type = request.GetArg("type"); + const auto& timeout = request.GetArg("timeout"); + const std::chrono::seconds timeout_secs{timeout.empty() ? kResolverTimeoutSecs : std::stoi(timeout)}; + const auto& to_resolve = request.GetArg("host_to_resolve"); + if (type == "resolve") { + auto res = resolver_.Resolve(to_resolve, engine::Deadline::FromDuration(timeout_secs)); + return fmt::to_string(fmt::join(res, kSeparator)); + } else if (type == "flush") { + resolver_.FlushNetworkCache(to_resolve); + return "flushed"; + } - UASSERT(false); - return {}; - } + UASSERT(false); + return {}; + } - static yaml_config::Schema GetStaticConfigSchema() { - return yaml_config::MergeSchemas(R"( + static yaml_config::Schema GetStaticConfigSchema() { + return yaml_config::MergeSchemas(R"( type: object description: Handler for clients::dns::Resolver testing additionalProperties: false @@ -97,10 +88,10 @@ class ResolverHandler final : public server::handlers::HttpHandlerBase { description: size of cache for hosts defaultDescription: 1000 )"); - } + } - private: - mutable clients::dns::Resolver resolver_; +private: + mutable clients::dns::Resolver resolver_; }; } // namespace chaos diff --git a/core/functional_tests/basic_chaos/service.cpp b/core/functional_tests/basic_chaos/service.cpp index 7658998d6871..7a2fda900e55 100644 --- a/core/functional_tests/basic_chaos/service.cpp +++ b/core/functional_tests/basic_chaos/service.cpp @@ -19,26 +19,24 @@ #include "resolver_handlers.hpp" int main(int argc, char* argv[]) { - const auto component_list = - components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append( - "handler-chaos-httpserver-parse-body-args") - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append("handler-chaos-httpserver-parse-body-args") + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); - return utils::DaemonMain(argc, argv, component_list); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/cache_update/service.cpp b/core/functional_tests/cache_update/service.cpp index ef8ba6e9e8e0..0e91f36f033a 100644 --- a/core/functional_tests/cache_update/service.cpp +++ b/core/functional_tests/cache_update/service.cpp @@ -22,99 +22,96 @@ using Data = std::unordered_map; class HandlerCacheState; class AlertCache final : public components::CachingComponentBase { - public: - static constexpr std::string_view kName = "alert-cache"; - - AlertCache(const components::ComponentConfig& config, - const components::ComponentContext& context) - : CachingComponentBase(config, context) { - CacheUpdateTrait::StartPeriodicUpdates(); - } - - ~AlertCache() override { CacheUpdateTrait::StopPeriodicUpdates(); } - - void Update(cache::UpdateType type, - const std::chrono::system_clock::time_point& /*last_update*/, - const std::chrono::system_clock::time_point& /*now*/, - cache::UpdateStatisticsScope& stats_scope) override { - if (type == cache::UpdateType::kIncremental) { - stats_scope.FinishWithError(); - } else { - stats_scope.FinishNoChanges(); +public: + static constexpr std::string_view kName = "alert-cache"; + + AlertCache(const components::ComponentConfig& config, const components::ComponentContext& context) + : CachingComponentBase(config, context) { + CacheUpdateTrait::StartPeriodicUpdates(); + } + + ~AlertCache() override { CacheUpdateTrait::StopPeriodicUpdates(); } + + void Update( + cache::UpdateType type, + const std::chrono::system_clock::time_point& /*last_update*/, + const std::chrono::system_clock::time_point& /*now*/, + cache::UpdateStatisticsScope& stats_scope + ) override { + if (type == cache::UpdateType::kIncremental) { + stats_scope.FinishWithError(); + } else { + stats_scope.FinishNoChanges(); + } } - } }; class CacheSample final : public components::CachingComponentBase { - public: - friend HandlerCacheState; - - static constexpr std::string_view kName = "sample-cache"; - - CacheSample(const components::ComponentConfig& config, - const components::ComponentContext& context) - : CachingComponentBase(config, context) { - CacheUpdateTrait::StartPeriodicUpdates(); - } - - ~CacheSample() override { CacheUpdateTrait::StopPeriodicUpdates(); } - - void Update(cache::UpdateType /*type*/, - const std::chrono::system_clock::time_point& /*last_update*/, - const std::chrono::system_clock::time_point& /*now*/, - cache::UpdateStatisticsScope& stats_scope) override { - static std::atomic set_empty{false}; - - if (set_empty.exchange(true)) { - try { - Set(Data{}); - } catch (const cache::EmptyDataError& e) { - LOG_INFO() << "Trying to install the empty cache"; - Set(Data{{42, 42}}); - } - } else { - Set(Data{{1, 1}}); +public: + friend HandlerCacheState; + + static constexpr std::string_view kName = "sample-cache"; + + CacheSample(const components::ComponentConfig& config, const components::ComponentContext& context) + : CachingComponentBase(config, context) { + CacheUpdateTrait::StartPeriodicUpdates(); } - stats_scope.Finish(1); - } -}; -class HandlerCacheState final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-cache-state"; - - HandlerCacheState(const components::ComponentConfig& config, - const components::ComponentContext& context) - : server::handlers::HttpHandlerBase(config, context), - cache_(context.FindComponent()) {} - std::string HandleRequestThrow( - const server::http::HttpRequest&, - server::request::RequestContext&) const override { - cache_.UpdateSyncDebug(cache::UpdateType::kIncremental); - cache_.UpdateSyncDebug(cache::UpdateType::kIncremental); - - auto data = cache_.Get(); - if (*data == Data{{42, 42}}) { - return "Magic numbers"; + ~CacheSample() override { CacheUpdateTrait::StopPeriodicUpdates(); } + + void Update( + cache::UpdateType /*type*/, + const std::chrono::system_clock::time_point& /*last_update*/, + const std::chrono::system_clock::time_point& /*now*/, + cache::UpdateStatisticsScope& stats_scope + ) override { + static std::atomic set_empty{false}; + + if (set_empty.exchange(true)) { + try { + Set(Data{}); + } catch (const cache::EmptyDataError& e) { + LOG_INFO() << "Trying to install the empty cache"; + Set(Data{{42, 42}}); + } + } else { + Set(Data{{1, 1}}); + } + stats_scope.Finish(1); } - return "Not magic numbers"; - }; +}; - private: - CacheSample& cache_; +class HandlerCacheState final : public server::handlers::HttpHandlerBase { +public: + static constexpr std::string_view kName = "handler-cache-state"; + + HandlerCacheState(const components::ComponentConfig& config, const components::ComponentContext& context) + : server::handlers::HttpHandlerBase(config, context), cache_(context.FindComponent()) {} + std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override { + cache_.UpdateSyncDebug(cache::UpdateType::kIncremental); + cache_.UpdateSyncDebug(cache::UpdateType::kIncremental); + + auto data = cache_.Get(); + if (*data == Data{{42, 42}}) { + return "Magic numbers"; + } + return "Not magic numbers"; + }; + +private: + CacheSample& cache_; }; } // namespace functional_tests int main(int argc, const char* const argv[]) { - const auto component_list = - components::ComponentList() - .AppendComponentList(components::CommonComponentList()) - .AppendComponentList(components::CommonServerComponentList()) - .Append() - .Append() - .Append() - .Append() - .Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::ComponentList() + .AppendComponentList(components::CommonComponentList()) + .AppendComponentList(components::CommonServerComponentList()) + .Append() + .Append() + .Append() + .Append() + .Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/http2server/service.cpp b/core/functional_tests/http2server/service.cpp index 40e1e5ea012e..4a54a2bbf575 100644 --- a/core/functional_tests/http2server/service.cpp +++ b/core/functional_tests/http2server/service.cpp @@ -13,80 +13,80 @@ #include class HandlerHttp2 final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-http2"; +public: + static constexpr std::string_view kName = "handler-http2"; - HandlerHttp2(const components::ComponentConfig& config, - const components::ComponentContext& context) - : server::handlers::HttpHandlerBase(config, context) {} + HandlerHttp2(const components::ComponentConfig& config, const components::ComponentContext& context) + : server::handlers::HttpHandlerBase(config, context) {} - std::string HandleRequestThrow( - const server::http::HttpRequest& req, - server::request::RequestContext&) const override { - const auto& type = req.GetArg("type"); - if (type == "echo-body") { - return req.RequestBody(); - } else if (type == "echo-header") { - return req.GetHeader("echo-header"); - } else if (type == "sleep") { - engine::SleepFor(std::chrono::seconds{1}); - } else if (type == "json") { - formats::json::Value json = formats::json::FromString(req.RequestBody()); - return ToString(json); - } - return ""; - }; + std::string HandleRequestThrow(const server::http::HttpRequest& req, server::request::RequestContext&) + const override { + const auto& type = req.GetArg("type"); + if (type == "echo-body") { + return req.RequestBody(); + } else if (type == "echo-header") { + return req.GetHeader("echo-header"); + } else if (type == "sleep") { + engine::SleepFor(std::chrono::seconds{1}); + } else if (type == "json") { + formats::json::Value json = formats::json::FromString(req.RequestBody()); + return ToString(json); + } + return ""; + }; - void HandleStreamRequest( - const server::http::HttpRequest& req, server::request::RequestContext&, - server::http::ResponseBodyStream& stream) const override { - const auto& type = req.GetArg("type"); - if (type == "eq") { - const auto& body_part = req.GetArg("body_part"); - UASSERT(!body_part.empty()); - const auto& count_str = req.GetArg("count"); - const std::size_t count = std::stoi(count_str); - UASSERT(count != 0); - stream.SetStatusCode(200); - stream.SetEndOfHeaders(); - for (std::size_t i = 0; i < count - 1; i++) { - std::string part{body_part}; - stream.PushBodyChunk(std::move(part), {}); - // Some pause... - engine::SleepFor(std::chrono::milliseconds{2}); - } - std::string part{body_part}; - stream.PushBodyChunk(std::move(part), {}); - } else if (type == "ne") { - stream.SetStatusCode(200); - stream.SetEndOfHeaders(); - const auto& body = req.RequestBody(); - std::size_t pos = 0; - std::size_t size = 1; - while (pos < body.size() - 1) { - stream.PushBodyChunk(body.substr(pos, size), {}); // 1, 2, 4, ... 512 - pos += size; - size *= 2; - engine::SleepFor(std::chrono::milliseconds{10}); - } - stream.PushBodyChunk(body.substr(pos, 1), {}); - } else { - throw std::runtime_error{"non-valid type"}; - } - }; + void HandleStreamRequest( + const server::http::HttpRequest& req, + server::request::RequestContext&, + server::http::ResponseBodyStream& stream + ) const override { + const auto& type = req.GetArg("type"); + if (type == "eq") { + const auto& body_part = req.GetArg("body_part"); + UASSERT(!body_part.empty()); + const auto& count_str = req.GetArg("count"); + const std::size_t count = std::stoi(count_str); + UASSERT(count != 0); + stream.SetStatusCode(200); + stream.SetEndOfHeaders(); + for (std::size_t i = 0; i < count - 1; i++) { + std::string part{body_part}; + stream.PushBodyChunk(std::move(part), {}); + // Some pause... + engine::SleepFor(std::chrono::milliseconds{2}); + } + std::string part{body_part}; + stream.PushBodyChunk(std::move(part), {}); + } else if (type == "ne") { + stream.SetStatusCode(200); + stream.SetEndOfHeaders(); + const auto& body = req.RequestBody(); + std::size_t pos = 0; + std::size_t size = 1; + while (pos < body.size() - 1) { + stream.PushBodyChunk(body.substr(pos, size), {}); // 1, 2, 4, ... 512 + pos += size; + size *= 2; + engine::SleepFor(std::chrono::milliseconds{10}); + } + stream.PushBodyChunk(body.substr(pos, 1), {}); + } else { + throw std::runtime_error{"non-valid type"}; + } + }; }; int main(int argc, char* argv[]) { - auto component_list = components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); + auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); - return utils::DaemonMain(argc, argv, component_list); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/https/httpserver_handlers.hpp b/core/functional_tests/https/httpserver_handlers.hpp index ac6a0b606519..b20f622e8959 100644 --- a/core/functional_tests/https/httpserver_handlers.hpp +++ b/core/functional_tests/https/httpserver_handlers.hpp @@ -12,31 +12,29 @@ namespace https { class HttpServerHandler final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-https-httpserver"; - - static inline const std::string kDefaultAnswer = "OK!"; - - HttpServerHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context) {} - - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override { - const auto& type = request.GetArg("type"); - - if (type == "cancel") { - engine::InterruptibleSleepFor(std::chrono::seconds(20)); - if (engine::current_task::IsCancelRequested()) { - engine::TaskCancellationBlocker block_cancel; - TESTPOINT("testpoint_cancel", {}); - } - return kDefaultAnswer; - } +public: + static constexpr std::string_view kName = "handler-https-httpserver"; + + static inline const std::string kDefaultAnswer = "OK!"; + + HttpServerHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context) {} - UINVARIANT(false, "Unexpected request type"); - } + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override { + const auto& type = request.GetArg("type"); + + if (type == "cancel") { + engine::InterruptibleSleepFor(std::chrono::seconds(20)); + if (engine::current_task::IsCancelRequested()) { + engine::TaskCancellationBlocker block_cancel; + TESTPOINT("testpoint_cancel", {}); + } + return kDefaultAnswer; + } + + UINVARIANT(false, "Unexpected request type"); + } }; } // namespace https diff --git a/core/functional_tests/https/service.cpp b/core/functional_tests/https/service.cpp index 64a7e842782a..f62b986f9663 100644 --- a/core/functional_tests/https/service.cpp +++ b/core/functional_tests/https/service.cpp @@ -18,18 +18,18 @@ #include "httpserver_handlers.hpp" int main(int argc, char* argv[]) { - const auto component_list = components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); - return utils::DaemonMain(argc, argv, component_list); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/https_no_passphrase/httpserver_handlers.hpp b/core/functional_tests/https_no_passphrase/httpserver_handlers.hpp index ac6a0b606519..b20f622e8959 100644 --- a/core/functional_tests/https_no_passphrase/httpserver_handlers.hpp +++ b/core/functional_tests/https_no_passphrase/httpserver_handlers.hpp @@ -12,31 +12,29 @@ namespace https { class HttpServerHandler final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-https-httpserver"; - - static inline const std::string kDefaultAnswer = "OK!"; - - HttpServerHandler(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context) {} - - std::string HandleRequestThrow( - const server::http::HttpRequest& request, - server::request::RequestContext&) const override { - const auto& type = request.GetArg("type"); - - if (type == "cancel") { - engine::InterruptibleSleepFor(std::chrono::seconds(20)); - if (engine::current_task::IsCancelRequested()) { - engine::TaskCancellationBlocker block_cancel; - TESTPOINT("testpoint_cancel", {}); - } - return kDefaultAnswer; - } +public: + static constexpr std::string_view kName = "handler-https-httpserver"; + + static inline const std::string kDefaultAnswer = "OK!"; + + HttpServerHandler(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context) {} - UINVARIANT(false, "Unexpected request type"); - } + std::string HandleRequestThrow(const server::http::HttpRequest& request, server::request::RequestContext&) + const override { + const auto& type = request.GetArg("type"); + + if (type == "cancel") { + engine::InterruptibleSleepFor(std::chrono::seconds(20)); + if (engine::current_task::IsCancelRequested()) { + engine::TaskCancellationBlocker block_cancel; + TESTPOINT("testpoint_cancel", {}); + } + return kDefaultAnswer; + } + + UINVARIANT(false, "Unexpected request type"); + } }; } // namespace https diff --git a/core/functional_tests/https_no_passphrase/service.cpp b/core/functional_tests/https_no_passphrase/service.cpp index a10f3dfc59e5..72daa0512b1f 100644 --- a/core/functional_tests/https_no_passphrase/service.cpp +++ b/core/functional_tests/https_no_passphrase/service.cpp @@ -18,16 +18,16 @@ #include "httpserver_handlers.hpp" int main(int argc, char* argv[]) { - const auto component_list = components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); - return utils::DaemonMain(argc, argv, component_list); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/metrics/service.cpp b/core/functional_tests/metrics/service.cpp index ae214f4c0a50..1d22f50e101c 100644 --- a/core/functional_tests/metrics/service.cpp +++ b/core/functional_tests/metrics/service.cpp @@ -17,54 +17,51 @@ namespace functional_tests { using KeyTranslation = std::unordered_map; static_assert(dump::CheckDumpable()); -class CachedTranslations final - : public components::CachingComponentBase { - public: - static constexpr std::string_view kName = "sample-cache"; +class CachedTranslations final : public components::CachingComponentBase { +public: + static constexpr std::string_view kName = "sample-cache"; - CachedTranslations(const components::ComponentConfig& config, - const components::ComponentContext& context) - : CachingComponentBase(config, context) { - CacheUpdateTrait::StartPeriodicUpdates(); - } + CachedTranslations(const components::ComponentConfig& config, const components::ComponentContext& context) + : CachingComponentBase(config, context) { + CacheUpdateTrait::StartPeriodicUpdates(); + } - ~CachedTranslations() override { CacheUpdateTrait::StopPeriodicUpdates(); } + ~CachedTranslations() override { CacheUpdateTrait::StopPeriodicUpdates(); } - void Update(cache::UpdateType /*type*/, - const std::chrono::system_clock::time_point& /*last_update*/, - const std::chrono::system_clock::time_point& /*now*/, - cache::UpdateStatisticsScope& stats_scope) override { - stats_scope.IncreaseDocumentsReadCount(1); - const auto size = 1; - Set(KeyTranslation{{"1", "1"}}); - stats_scope.Finish(size); - } + void Update( + cache::UpdateType /*type*/, + const std::chrono::system_clock::time_point& /*last_update*/, + const std::chrono::system_clock::time_point& /*now*/, + cache::UpdateStatisticsScope& stats_scope + ) override { + stats_scope.IncreaseDocumentsReadCount(1); + const auto size = 1; + Set(KeyTranslation{{"1", "1"}}); + stats_scope.Finish(size); + } }; -class LruCachedTranslations final - : public cache::LruCacheComponent { - public: - static constexpr std::string_view kName = "sample-lru-cache"; +class LruCachedTranslations final : public cache::LruCacheComponent { +public: + static constexpr std::string_view kName = "sample-lru-cache"; - LruCachedTranslations(const components::ComponentConfig& config, - const components::ComponentContext& context) - : LruCacheComponent(config, context) {} + LruCachedTranslations(const components::ComponentConfig& config, const components::ComponentContext& context) + : LruCacheComponent(config, context) {} - private: - std::string DoGetByKey(const std::string& /*key*/) override { return "1"; } +private: + std::string DoGetByKey(const std::string& /*key*/) override { return "1"; } }; } // namespace functional_tests int main(int argc, const char* const argv[]) { - const auto component_list = - components::ComponentList() - .AppendComponentList(components::CommonComponentList()) - .AppendComponentList(components::CommonServerComponentList()) - .Append() - .Append() - .Append() - .Append() - .Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::ComponentList() + .AppendComponentList(components::CommonComponentList()) + .AppendComponentList(components::CommonServerComponentList()) + .Append() + .Append() + .Append() + .Append() + .Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/tracing/echo_no_body.cpp b/core/functional_tests/tracing/echo_no_body.cpp index fa5d5f162236..73bf19e8779c 100644 --- a/core/functional_tests/tracing/echo_no_body.cpp +++ b/core/functional_tests/tracing/echo_no_body.cpp @@ -14,30 +14,22 @@ #include class EchoNoBody final : public server::handlers::HttpHandlerBase { - public: - static constexpr std::string_view kName = "handler-echo-no-body"; - - EchoNoBody(const components::ComponentConfig& config, - const components::ComponentContext& context) - : HttpHandlerBase(config, context), - echo_url_{config["echo-url"].As()}, - http_client_( - context.FindComponent().GetHttpClient()) {} - - std::string HandleRequestThrow( - const server::http::HttpRequest&, - server::request::RequestContext&) const override { - auto response = http_client_.CreateRequest() - .get(echo_url_) - .retry(2) - .timeout(std::chrono::seconds{5}) - .perform(); - response->raise_for_status(); - return {}; - } - - static yaml_config::Schema GetStaticConfigSchema() { - return yaml_config::MergeSchemas(R"( +public: + static constexpr std::string_view kName = "handler-echo-no-body"; + + EchoNoBody(const components::ComponentConfig& config, const components::ComponentContext& context) + : HttpHandlerBase(config, context), + echo_url_{config["echo-url"].As()}, + http_client_(context.FindComponent().GetHttpClient()) {} + + std::string HandleRequestThrow(const server::http::HttpRequest&, server::request::RequestContext&) const override { + auto response = http_client_.CreateRequest().get(echo_url_).retry(2).timeout(std::chrono::seconds{5}).perform(); + response->raise_for_status(); + return {}; + } + + static yaml_config::Schema GetStaticConfigSchema() { + return yaml_config::MergeSchemas(R"( type: object description: HTTP echo without body component additionalProperties: false @@ -46,19 +38,19 @@ class EchoNoBody final : public server::handlers::HttpHandlerBase { type: string description: some other microservice listens on this URL )"); - } + } - private: - const std::string echo_url_; - clients::http::Client& http_client_; +private: + const std::string echo_url_; + clients::http::Client& http_client_; }; int main(int argc, char* argv[]) { - const auto component_list = components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/uctl/service.cpp b/core/functional_tests/uctl/service.cpp index 6b90d8067eb5..1d8d6348d2be 100644 --- a/core/functional_tests/uctl/service.cpp +++ b/core/functional_tests/uctl/service.cpp @@ -13,12 +13,11 @@ #include int main(int argc, const char* const argv[]) { - const auto component_list = - components::ComponentList() - .AppendComponentList(components::CommonComponentList()) - .AppendComponentList(components::CommonServerComponentList()) - .Append() - .Append() - .Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::ComponentList() + .AppendComponentList(components::CommonComponentList()) + .AppendComponentList(components::CommonServerComponentList()) + .Append() + .Append() + .Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/functional_tests/websocket/service.cpp b/core/functional_tests/websocket/service.cpp index 7cb3a2f5eb1a..ce897150ed5d 100644 --- a/core/functional_tests/websocket/service.cpp +++ b/core/functional_tests/websocket/service.cpp @@ -12,116 +12,111 @@ #include struct HandshakeData { - std::string origin; + std::string origin; }; class WebsocketsHandler final : public server::websocket::WebsocketHandlerBase { - public: - static constexpr std::string_view kName = "websocket-handler"; - - using WebsocketHandlerBase::WebsocketHandlerBase; - - bool HandleHandshake( - const server::http::HttpRequest& request, server::http::HttpResponse&, - server::request::RequestContext& context) const override { - context.SetUserData(HandshakeData{request.GetHeader("Origin")}); - return true; - } - - void Handle(server::websocket::WebSocketConnection& chat, - server::request::RequestContext& context) const override { - const auto& origin = context.GetUserData().origin; - if (!origin.empty()) { - chat.Send({origin, {}, true}); +public: + static constexpr std::string_view kName = "websocket-handler"; + + using WebsocketHandlerBase::WebsocketHandlerBase; + + bool HandleHandshake( + const server::http::HttpRequest& request, + server::http::HttpResponse&, + server::request::RequestContext& context + ) const override { + context.SetUserData(HandshakeData{request.GetHeader("Origin")}); + return true; } - server::websocket::Message message; - while (!engine::current_task::ShouldCancel()) { - chat.Recv(message); + void Handle(server::websocket::WebSocketConnection& chat, server::request::RequestContext& context) const override { + const auto& origin = context.GetUserData().origin; + if (!origin.empty()) { + chat.Send({origin, {}, true}); + } - if (message.close_status) break; + server::websocket::Message message; + while (!engine::current_task::ShouldCancel()) { + chat.Recv(message); + + if (message.close_status) break; - if (message.data == "close") { - chat.Close(server::websocket::CloseStatus::kGoingAway); - break; - } + if (message.data == "close") { + chat.Close(server::websocket::CloseStatus::kGoingAway); + break; + } - chat.Send(std::move(message)); + chat.Send(std::move(message)); + } + if (message.close_status) chat.Close(*message.close_status); } - if (message.close_status) chat.Close(*message.close_status); - } }; -class WebsocketsHandlerAlt final - : public server::websocket::WebsocketHandlerBase { - public: - static constexpr std::string_view kName = "websocket-handler-alt"; - - using WebsocketHandlerBase::WebsocketHandlerBase; - - void Handle(server::websocket::WebSocketConnection& chat, - server::request::RequestContext&) const override { - server::websocket::Message message; - while (!engine::current_task::ShouldCancel()) { - const bool msgIsReceived = chat.TryRecv(message); - if (msgIsReceived) { - if (message.close_status) break; - chat.Send(std::move(message)); - } else { - // we could've sent yet another server::websocket::Message - // e.g. chat.SendBinary(server::websocket::Message{ "blah", {}, true }); - } +class WebsocketsHandlerAlt final : public server::websocket::WebsocketHandlerBase { +public: + static constexpr std::string_view kName = "websocket-handler-alt"; + + using WebsocketHandlerBase::WebsocketHandlerBase; + + void Handle(server::websocket::WebSocketConnection& chat, server::request::RequestContext&) const override { + server::websocket::Message message; + while (!engine::current_task::ShouldCancel()) { + const bool msgIsReceived = chat.TryRecv(message); + if (msgIsReceived) { + if (message.close_status) break; + chat.Send(std::move(message)); + } else { + // we could've sent yet another server::websocket::Message + // e.g. chat.SendBinary(server::websocket::Message{ "blah", {}, true }); + } + } + if (message.close_status) chat.Close(*message.close_status); } - if (message.close_status) chat.Close(*message.close_status); - } }; -class WebsocketsFullDuplexHandler final - : public server::websocket::WebsocketHandlerBase { - public: - static constexpr std::string_view kName = "websocket-duplex-handler"; +class WebsocketsFullDuplexHandler final : public server::websocket::WebsocketHandlerBase { +public: + static constexpr std::string_view kName = "websocket-duplex-handler"; - using WebsocketHandlerBase::WebsocketHandlerBase; + using WebsocketHandlerBase::WebsocketHandlerBase; - void Handle(server::websocket::WebSocketConnection& chat, - server::request::RequestContext&) const override { - // Some sync data - auto queue = concurrent::SpscQueue::Create(); + void Handle(server::websocket::WebSocketConnection& chat, server::request::RequestContext&) const override { + // Some sync data + auto queue = concurrent::SpscQueue::Create(); - auto reader = - utils::Async("reader", [&chat, producer = queue->GetProducer()] { - server::websocket::Message message; - while (!engine::current_task::ShouldCancel()) { - chat.Recv(message); - if (message.close_status) break; - [[maybe_unused]] auto ret = producer.Push(std::move(message.data)); - } + auto reader = utils::Async("reader", [&chat, producer = queue->GetProducer()] { + server::websocket::Message message; + while (!engine::current_task::ShouldCancel()) { + chat.Recv(message); + if (message.close_status) break; + [[maybe_unused]] auto ret = producer.Push(std::move(message.data)); + } }); - auto writer = - utils::Async("writer", [&chat, consumer = queue->GetConsumer()] { - while (!engine::current_task::ShouldCancel()) { - std::string msg; - if (!consumer.Pop(msg)) break; - chat.SendBinary(msg); - } + auto writer = utils::Async("writer", [&chat, consumer = queue->GetConsumer()] { + while (!engine::current_task::ShouldCancel()) { + std::string msg; + if (!consumer.Pop(msg)) break; + chat.SendBinary(msg); + } }); - queue.reset(); + queue.reset(); - reader.Get(); - writer.Get(); - } + reader.Get(); + writer.Get(); + } }; int main(int argc, char* argv[]) { - const auto component_list = components::MinimalServerComponentList() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append() - .Append(); - return utils::DaemonMain(argc, argv, component_list); + const auto component_list = components::MinimalServerComponentList() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + return utils::DaemonMain(argc, argv, component_list); } diff --git a/core/include/userver/alerts/component.hpp b/core/include/userver/alerts/component.hpp index c9584301985c..e4c5ea6bf085 100644 --- a/core/include/userver/alerts/component.hpp +++ b/core/include/userver/alerts/component.hpp @@ -28,18 +28,17 @@ namespace alerts { // clang-format on class StorageComponent final : public components::RawComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of alert::StorageComponent component - static constexpr std::string_view kName = "alerts-storage"; +public: + /// @ingroup userver_component_names + /// @brief The default name of alert::StorageComponent component + static constexpr std::string_view kName = "alerts-storage"; - StorageComponent(const components::ComponentConfig& config, - const components::ComponentContext& context); + StorageComponent(const components::ComponentConfig& config, const components::ComponentContext& context); - Storage& GetStorage() const; + Storage& GetStorage() const; - private: - mutable Storage storage_; +private: + mutable Storage storage_; }; } // namespace alerts @@ -48,7 +47,6 @@ template <> inline constexpr bool components::kHasValidate = true; template <> -inline constexpr auto components::kConfigFileMode = - ConfigFileMode::kNotRequired; +inline constexpr auto components::kConfigFileMode = ConfigFileMode::kNotRequired; USERVER_NAMESPACE_END diff --git a/core/include/userver/alerts/handler.hpp b/core/include/userver/alerts/handler.hpp index 56236fc776c5..efb982e83a03 100644 --- a/core/include/userver/alerts/handler.hpp +++ b/core/include/userver/alerts/handler.hpp @@ -14,21 +14,21 @@ namespace alerts { /// /// @brief Handler that returns the list of active fired alerts. class Handler final : public server::handlers::HttpHandlerJsonBase { - public: - Handler(const components::ComponentConfig& config, - const components::ComponentContext& context); +public: + Handler(const components::ComponentConfig& config, const components::ComponentContext& context); - /// @ingroup userver_component_names - /// @brief The default name of alerts::Handler - static constexpr std::string_view kName = "handler-fired-alerts"; + /// @ingroup userver_component_names + /// @brief The default name of alerts::Handler + static constexpr std::string_view kName = "handler-fired-alerts"; - formats::json::Value HandleRequestJsonThrow( - const server::http::HttpRequest& request, - const formats::json::Value& request_json, - server::request::RequestContext& context) const override; + formats::json::Value HandleRequestJsonThrow( + const server::http::HttpRequest& request, + const formats::json::Value& request_json, + server::request::RequestContext& context + ) const override; - private: - Storage& storage_; +private: + Storage& storage_; }; } // namespace alerts diff --git a/core/include/userver/alerts/storage.hpp b/core/include/userver/alerts/storage.hpp index f9a6af18511a..9bdadc2fb4bd 100644 --- a/core/include/userver/alerts/storage.hpp +++ b/core/include/userver/alerts/storage.hpp @@ -14,9 +14,9 @@ USERVER_NAMESPACE_BEGIN namespace alerts { struct Alert final { - std::string id; - std::string description; - std::chrono::steady_clock::time_point stop_timepoint; + std::string id; + std::string description; + std::chrono::steady_clock::time_point stop_timepoint; }; inline constexpr auto kDefaultDuration = std::chrono::seconds{120}; @@ -26,27 +26,29 @@ inline constexpr auto kInfinity = std::chrono::hours{24 * 999}; /// /// @brief Storage for active fired alerts. class Storage final { - public: - Storage() = default; - Storage(const Storage&) = delete; - Storage(Storage&&) = delete; +public: + Storage() = default; + Storage(const Storage&) = delete; + Storage(Storage&&) = delete; - /// Fire an alert. It will be stopped either after `StopAlertNow` for the - /// `alert_id` is called or after `duration` seconds. - void FireAlert(std::string_view alert_id, std::string_view description, - std::chrono::seconds duration = kDefaultDuration) noexcept; + /// Fire an alert. It will be stopped either after `StopAlertNow` for the + /// `alert_id` is called or after `duration` seconds. + void FireAlert( + std::string_view alert_id, + std::string_view description, + std::chrono::seconds duration = kDefaultDuration + ) noexcept; - /// Stop an alert before its duration has ended. - void StopAlertNow(std::string_view alert_id) noexcept; + /// Stop an alert before its duration has ended. + void StopAlertNow(std::string_view alert_id) noexcept; - /// Collect fired and active alerts. - std::vector CollectActiveAlerts(); + /// Collect fired and active alerts. + std::vector CollectActiveAlerts(); - private: - static void DoStopAlertNow(std::string_view alert_id, - std::vector& alerts); +private: + static void DoStopAlertNow(std::string_view alert_id, std::vector& alerts); - concurrent::Variable> alerts_; + concurrent::Variable> alerts_; }; } // namespace alerts diff --git a/core/include/userver/baggage/baggage.hpp b/core/include/userver/baggage/baggage.hpp index deb9106baf40..31b80f318a1f 100644 --- a/core/include/userver/baggage/baggage.hpp +++ b/core/include/userver/baggage/baggage.hpp @@ -17,35 +17,32 @@ USERVER_NAMESPACE_BEGIN namespace baggage { -using BaggageProperties = - std::vector>>; +using BaggageProperties = std::vector>>; class Baggage; class BaggageEntryProperty; /// @brief Baggage base exception class BaggageException : public std::runtime_error { - public: - explicit BaggageException(const std::string& message) - : std::runtime_error(message) {} +public: + explicit BaggageException(const std::string& message) : std::runtime_error(message) {} }; /// @brief property of entry. Has required key and optional value. /// Keys shouldn't contain '=', ';' and ','. Values shouldn't contains /// ',' and ';' class BaggageEntryProperty { - friend class BaggageEntry; - - public: - BaggageEntryProperty(std::string_view key, - std::optional value = std::nullopt); - std::string ToString() const; - std::optional GetValue() const; - std::string GetKey() const; - - private: - const std::string_view key_; - std::optional value_; + friend class BaggageEntry; + +public: + BaggageEntryProperty(std::string_view key, std::optional value = std::nullopt); + std::string ToString() const; + std::optional GetValue() const; + std::string GetKey() const; + +private: + const std::string_view key_; + std::optional value_; }; /// @brief Baggage Entry. Has required key and value, @@ -53,31 +50,30 @@ class BaggageEntryProperty { /// Keys shouldn't contain '=' and ','. Values shouldn't contains /// ',' and ';' class BaggageEntry { - friend class Baggage; - - public: - BaggageEntry(std::string_view key, std::string_view value, - std::vector properties); - std::string ToString() const; - std::string GetValue() const; - std::string GetKey() const; - - /// @return vector of properties of chosen entry - const std::vector& GetProperties() const; - - /// @brief Check that entry contains property with selected key - bool HasProperty(const std::string& key) const; - - /// @brief Get first property with selected key - /// @throws BaggageException If key doesn't exist - const BaggageEntryProperty& GetProperty(const std::string& key) const; - - private: - /// @brief Add entry to the received header string - void ConcatenateWith(std::string& header) const; - const std::string_view key_; - std::string_view value_; - std::vector properties_; + friend class Baggage; + +public: + BaggageEntry(std::string_view key, std::string_view value, std::vector properties); + std::string ToString() const; + std::string GetValue() const; + std::string GetKey() const; + + /// @return vector of properties of chosen entry + const std::vector& GetProperties() const; + + /// @brief Check that entry contains property with selected key + bool HasProperty(const std::string& key) const; + + /// @brief Get first property with selected key + /// @throws BaggageException If key doesn't exist + const BaggageEntryProperty& GetProperty(const std::string& key) const; + +private: + /// @brief Add entry to the received header string + void ConcatenateWith(std::string& header) const; + const std::string_view key_; + std::string_view value_; + std::vector properties_; }; /// @brief Baggage header. Contains entries (key, value, optional). @@ -87,73 +83,70 @@ class BaggageEntry { /// /// @see baggage::BaggageManagerComponent class Baggage { - public: - Baggage(std::string header, std::unordered_set allowed_keys); - Baggage(const Baggage&) noexcept; - Baggage(Baggage&&) noexcept; - - std::string ToString() const; - - /// @return vector of entries - const std::vector& GetEntries() const; - - /// @brief check that header contains entry with selected key - bool HasEntry(const std::string& key) const; - - /// @brief find first entry with selected key - /// @throws BaggageException If key doesn't exist - const BaggageEntry& GetEntry(const std::string& key) const; - - /// @brief entry's key validation - bool IsValidEntry(const std::string& key) const; - - /// @brief Add entry to baggage header. - /// @throws BaggageException If key, value or properties - /// don't match with requirements or if allowed_keys - /// don't contain selected key - void AddEntry(std::string key, std::string value, - BaggageProperties properties); - - /// @brief get baggage allowed keys - std::unordered_set GetAllowedKeys() const; - - protected: - /// @brief parsers - /// @returns std::nullopt If key, value or properties - /// don't match with requirements or if allowed_keys - /// don't contain selected key - std::optional TryMakeBaggageEntry(std::string_view entry); - static std::optional TryMakeBaggageEntryProperty( - std::string_view property); - - private: - /// @brief Parse baggage_header and fill entries_ - void FillEntries(); - - /// @brief Create result_header - void CreateResultHeader(); - - std::string header_value_; - std::unordered_set allowed_keys_; - std::vector entries_; - - // result header after parsing entities. - // empty string if is_valid_header == true - std::string result_header_; - - // true if requested header == header for sending - bool is_valid_header_ = true; +public: + Baggage(std::string header, std::unordered_set allowed_keys); + Baggage(const Baggage&) noexcept; + Baggage(Baggage&&) noexcept; + + std::string ToString() const; + + /// @return vector of entries + const std::vector& GetEntries() const; + + /// @brief check that header contains entry with selected key + bool HasEntry(const std::string& key) const; + + /// @brief find first entry with selected key + /// @throws BaggageException If key doesn't exist + const BaggageEntry& GetEntry(const std::string& key) const; + + /// @brief entry's key validation + bool IsValidEntry(const std::string& key) const; + + /// @brief Add entry to baggage header. + /// @throws BaggageException If key, value or properties + /// don't match with requirements or if allowed_keys + /// don't contain selected key + void AddEntry(std::string key, std::string value, BaggageProperties properties); + + /// @brief get baggage allowed keys + std::unordered_set GetAllowedKeys() const; + +protected: + /// @brief parsers + /// @returns std::nullopt If key, value or properties + /// don't match with requirements or if allowed_keys + /// don't contain selected key + std::optional TryMakeBaggageEntry(std::string_view entry); + static std::optional TryMakeBaggageEntryProperty(std::string_view property); + +private: + /// @brief Parse baggage_header and fill entries_ + void FillEntries(); + + /// @brief Create result_header + void CreateResultHeader(); + + std::string header_value_; + std::unordered_set allowed_keys_; + std::vector entries_; + + // result header after parsing entities. + // empty string if is_valid_header == true + std::string result_header_; + + // true if requested header == header for sending + bool is_valid_header_ = true; }; /// @brief Parsing function -std::optional TryMakeBaggage( - std::string header, std::unordered_set allowed_keys); +std::optional TryMakeBaggage(std::string header, std::unordered_set allowed_keys); template bool HasInvalidSymbols(const T& obj) { - return std::find_if(obj.begin(), obj.end(), [](unsigned char x) { - return x == ',' || x == ';' || x == '=' || std::isspace(x); - }) != obj.end(); + return std::find_if(obj.begin(), obj.end(), [](unsigned char x) { + return x == ',' || x == ';' || x == '=' || std::isspace(x); + }) != obj.end(); } inline engine::TaskInheritedVariable kInheritedBaggage; diff --git a/core/include/userver/baggage/baggage_manager.hpp b/core/include/userver/baggage/baggage_manager.hpp index 76cf7c502885..31fcf8ee4619 100644 --- a/core/include/userver/baggage/baggage_manager.hpp +++ b/core/include/userver/baggage/baggage_manager.hpp @@ -21,30 +21,29 @@ namespace baggage { /// /// Usually retrieved from baggage::BaggageManagerComponent. class BaggageManager final { - public: - explicit BaggageManager(const dynamic_config::Source& config_source); +public: + explicit BaggageManager(const dynamic_config::Source& config_source); - /// @brief Returns if baggage is enabled - bool IsEnabled() const; + /// @brief Returns if baggage is enabled + bool IsEnabled() const; - /// @brief Add entry to baggage header. - /// @throws BaggageException If key, value or properties - /// don't match with requirements or if allowed_keys - /// don't contain selected key - void AddEntry(std::string key, std::string value, - BaggageProperties properties) const; + /// @brief Add entry to baggage header. + /// @throws BaggageException If key, value or properties + /// don't match with requirements or if allowed_keys + /// don't contain selected key + void AddEntry(std::string key, std::string value, BaggageProperties properties) const; - /// @brief Get const pointer to baggage value from task inherited variable - static const Baggage* TryGetBaggage(); + /// @brief Get const pointer to baggage value from task inherited variable + static const Baggage* TryGetBaggage(); - /// @brief Set new baggage value to task inherited variable - void SetBaggage(std::string header) const; + /// @brief Set new baggage value to task inherited variable + void SetBaggage(std::string header) const; - /// @brief Delete header from task inherited variable - static void ResetBaggage(); + /// @brief Delete header from task inherited variable + static void ResetBaggage(); - private: - dynamic_config::Source config_source_; +private: + dynamic_config::Source config_source_; }; /// @ingroup userver_components @@ -54,20 +53,19 @@ class BaggageManager final { /// ## Static options: /// Inherits options from components::ComponentBase. class BaggageManagerComponent final : public components::ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of baggage::BaggageManagerComponent - static constexpr std::string_view kName = "baggage-manager"; +public: + /// @ingroup userver_component_names + /// @brief The default name of baggage::BaggageManagerComponent + static constexpr std::string_view kName = "baggage-manager"; - BaggageManagerComponent(const components::ComponentConfig& config, - const components::ComponentContext& context); + BaggageManagerComponent(const components::ComponentConfig& config, const components::ComponentContext& context); - BaggageManager& GetManager(); + BaggageManager& GetManager(); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - BaggageManager baggage_manager_; +private: + BaggageManager baggage_manager_; }; } // namespace baggage diff --git a/core/include/userver/baggage/baggage_settings.hpp b/core/include/userver/baggage/baggage_settings.hpp index f86f446630d8..0c7e72124dfb 100644 --- a/core/include/userver/baggage/baggage_settings.hpp +++ b/core/include/userver/baggage/baggage_settings.hpp @@ -11,11 +11,10 @@ USERVER_NAMESPACE_BEGIN namespace baggage { struct BaggageSettings final { - std::unordered_set allowed_keys; + std::unordered_set allowed_keys; }; -BaggageSettings Parse(const formats::json::Value& value, - formats::parse::To); +BaggageSettings Parse(const formats::json::Value& value, formats::parse::To); extern const dynamic_config::Key kBaggageSettings; diff --git a/core/include/userver/baggage/fwd.hpp b/core/include/userver/baggage/fwd.hpp index 654c55d7b7db..b59b95a1f215 100644 --- a/core/include/userver/baggage/fwd.hpp +++ b/core/include/userver/baggage/fwd.hpp @@ -14,7 +14,6 @@ class Baggage; class BaggageEntry; class BaggageEntryProperty; -using BaggageProperties = - std::vector>>; +using BaggageProperties = std::vector>>; } // namespace baggage diff --git a/core/include/userver/cache/cache_config.hpp b/core/include/userver/cache/cache_config.hpp index d045ad4ec92c..e2235dfc1ca4 100644 --- a/core/include/userver/cache/cache_config.hpp +++ b/core/include/userver/cache/cache_config.hpp @@ -20,77 +20,72 @@ struct Config; namespace cache { class ConfigError : public std::logic_error { - public: - using std::logic_error::logic_error; +public: + using std::logic_error::logic_error; }; enum class FirstUpdateMode { - kRequired, - kBestEffort, - kSkip, + kRequired, + kBestEffort, + kSkip, }; -FirstUpdateMode Parse(const yaml_config::YamlConfig& config, - formats::parse::To); +FirstUpdateMode Parse(const yaml_config::YamlConfig& config, formats::parse::To); std::string_view ToString(FirstUpdateMode); enum class FirstUpdateType { - kFull, - kIncremental, - kIncrementalThenAsyncFull, + kFull, + kIncremental, + kIncrementalThenAsyncFull, }; -FirstUpdateType Parse(const yaml_config::YamlConfig& config, - formats::parse::To); +FirstUpdateType Parse(const yaml_config::YamlConfig& config, formats::parse::To); std::string_view ToString(FirstUpdateType); struct ConfigPatch final { - std::chrono::milliseconds update_interval{}; - std::chrono::milliseconds update_jitter{}; - std::chrono::milliseconds full_update_interval{}; - std::chrono::milliseconds full_update_jitter{}; - std::optional exception_interval{}; - bool updates_enabled{true}; - std::uint64_t alert_on_failing_to_update_times{0}; + std::chrono::milliseconds update_interval{}; + std::chrono::milliseconds update_jitter{}; + std::chrono::milliseconds full_update_interval{}; + std::chrono::milliseconds full_update_jitter{}; + std::optional exception_interval{}; + bool updates_enabled{true}; + std::uint64_t alert_on_failing_to_update_times{0}; }; -ConfigPatch Parse(const formats::json::Value& value, - formats::parse::To); +ConfigPatch Parse(const formats::json::Value& value, formats::parse::To); struct Config final { - Config() = default; - explicit Config(const yaml_config::YamlConfig& config, - const std::optional& dump_config); - - Config MergeWith(const ConfigPatch& patch) const; - - AllowedUpdateTypes allowed_update_types{}; - bool allow_first_update_failure{}; - std::optional force_periodic_update; - bool config_updates_enabled{}; - bool has_pre_assign_check{}; - std::optional task_processor_name; - std::chrono::milliseconds cleanup_interval{}; - bool is_strong_period{}; - std::optional failed_updates_before_expiration; - bool is_safe_data_lifetime{}; - - FirstUpdateMode first_update_mode{}; - FirstUpdateType first_update_type{}; - - std::chrono::milliseconds update_interval{}; - std::chrono::milliseconds update_jitter{}; - std::chrono::milliseconds full_update_interval{}; - std::chrono::milliseconds full_update_jitter{}; - std::optional exception_interval; - bool updates_enabled{}; - std::uint64_t alert_on_failing_to_update_times{}; + Config() = default; + explicit Config(const yaml_config::YamlConfig& config, const std::optional& dump_config); + + Config MergeWith(const ConfigPatch& patch) const; + + AllowedUpdateTypes allowed_update_types{}; + bool allow_first_update_failure{}; + std::optional force_periodic_update; + bool config_updates_enabled{}; + bool has_pre_assign_check{}; + std::optional task_processor_name; + std::chrono::milliseconds cleanup_interval{}; + bool is_strong_period{}; + std::optional failed_updates_before_expiration; + bool is_safe_data_lifetime{}; + + FirstUpdateMode first_update_mode{}; + FirstUpdateType first_update_type{}; + + std::chrono::milliseconds update_interval{}; + std::chrono::milliseconds update_jitter{}; + std::chrono::milliseconds full_update_interval{}; + std::chrono::milliseconds full_update_jitter{}; + std::optional exception_interval; + bool updates_enabled{}; + std::uint64_t alert_on_failing_to_update_times{}; }; -extern const dynamic_config::Key> - kCacheConfigSet; +extern const dynamic_config::Key> kCacheConfigSet; } // namespace cache diff --git a/core/include/userver/cache/cache_statistics.hpp b/core/include/userver/cache/cache_statistics.hpp index e1d3cca9274e..84d2aee94f6e 100644 --- a/core/include/userver/cache/cache_statistics.hpp +++ b/core/include/userver/cache/cache_statistics.hpp @@ -19,26 +19,24 @@ namespace cache { namespace impl { struct UpdateStatistics final { - utils::statistics::RateCounter update_attempt_count{0}; - utils::statistics::RateCounter update_no_changes_count{0}; - utils::statistics::RateCounter update_failures_count{0}; + utils::statistics::RateCounter update_attempt_count{0}; + utils::statistics::RateCounter update_no_changes_count{0}; + utils::statistics::RateCounter update_failures_count{0}; - utils::statistics::RateCounter documents_read_count{0}; - utils::statistics::RateCounter documents_parse_failures{0}; + utils::statistics::RateCounter documents_read_count{0}; + utils::statistics::RateCounter documents_parse_failures{0}; - std::atomic last_update_start_time{{}}; - std::atomic - last_successful_update_start_time{{}}; - std::atomic last_update_duration{{}}; + std::atomic last_update_start_time{{}}; + std::atomic last_successful_update_start_time{{}}; + std::atomic last_update_duration{{}}; }; -void DumpMetric(utils::statistics::Writer& writer, - const UpdateStatistics& stats); +void DumpMetric(utils::statistics::Writer& writer, const UpdateStatistics& stats); struct Statistics final { - UpdateStatistics full_update; - UpdateStatistics incremental_update; - std::atomic documents_current_count{0}; + UpdateStatistics full_update; + UpdateStatistics incremental_update; + std::atomic documents_current_count{0}; }; void DumpMetric(utils::statistics::Writer& writer, const Statistics& stats); @@ -55,46 +53,46 @@ enum class UpdateState { kNotFinished, kSuccess, kFailure }; /// See components::CachingComponentBase::Set() for information on actual cache /// update, rather than statistics update. class UpdateStatisticsScope final { - public: - /// @cond - // For internal use only - UpdateStatisticsScope(impl::Statistics& stats, cache::UpdateType type); - - ~UpdateStatisticsScope(); - - // For internal use only - impl::UpdateState GetState(utils::impl::InternalTag) const; - /// @endcond - - /// @brief Mark that the `Update` has finished with changes - /// @param documents_count the new total number of items stored in the cache - void Finish(std::size_t total_documents_count); - - /// @brief Mark that the `Update` has finished without changes - void FinishNoChanges(); - - /// @brief Mark that the `Update` failed - void FinishWithError(); - - /// @brief Each item received from the data source should be accounted with - /// this function - /// @note This method can be called multiple times per `Update` - /// @param add the number of items (both valid and non-valid) newly received - void IncreaseDocumentsReadCount(std::size_t add); - - /// @brief Each received item that failed validation should be accounted with - /// this function, in addition to IncreaseDocumentsReadCount - /// @note This method can be called multiple times per `Update` - /// @param add the number of non-valid items newly received - void IncreaseDocumentsParseFailures(std::size_t add); - - private: - void DoFinish(impl::UpdateState new_state); - - impl::Statistics& stats_; - impl::UpdateStatistics& update_stats_; - impl::UpdateState state_{impl::UpdateState::kNotFinished}; - const std::chrono::steady_clock::time_point update_start_time_; +public: + /// @cond + // For internal use only + UpdateStatisticsScope(impl::Statistics& stats, cache::UpdateType type); + + ~UpdateStatisticsScope(); + + // For internal use only + impl::UpdateState GetState(utils::impl::InternalTag) const; + /// @endcond + + /// @brief Mark that the `Update` has finished with changes + /// @param documents_count the new total number of items stored in the cache + void Finish(std::size_t total_documents_count); + + /// @brief Mark that the `Update` has finished without changes + void FinishNoChanges(); + + /// @brief Mark that the `Update` failed + void FinishWithError(); + + /// @brief Each item received from the data source should be accounted with + /// this function + /// @note This method can be called multiple times per `Update` + /// @param add the number of items (both valid and non-valid) newly received + void IncreaseDocumentsReadCount(std::size_t add); + + /// @brief Each received item that failed validation should be accounted with + /// this function, in addition to IncreaseDocumentsReadCount + /// @note This method can be called multiple times per `Update` + /// @param add the number of non-valid items newly received + void IncreaseDocumentsParseFailures(std::size_t add); + +private: + void DoFinish(impl::UpdateState new_state); + + impl::Statistics& stats_; + impl::UpdateStatistics& update_stats_; + impl::UpdateState state_{impl::UpdateState::kNotFinished}; + const std::chrono::steady_clock::time_point update_start_time_; }; } // namespace cache diff --git a/core/include/userver/cache/cache_update_trait.hpp b/core/include/userver/cache/cache_update_trait.hpp index 9454dd450c79..6f2b0d6408eb 100644 --- a/core/include/userver/cache/cache_update_trait.hpp +++ b/core/include/userver/cache/cache_update_trait.hpp @@ -28,131 +28,132 @@ struct Config; /// @note Don't use directly, inherit from components::CachingComponentBase /// instead class CacheUpdateTrait { - public: - CacheUpdateTrait(CacheUpdateTrait&&) = delete; - CacheUpdateTrait& operator=(CacheUpdateTrait&&) = delete; - - /// @brief Non-blocking forced cache update of specified type - /// @see PeriodicTask::ForceStepAsync for behavior details - void InvalidateAsync(UpdateType update_type); - - /// @brief Forces a cache update of specified type - /// @throws If `Update` throws - void UpdateSyncDebug(UpdateType update_type); - - /// @return name of the component - const std::string& Name() const; - - protected: - /// @cond - // For internal use only - CacheUpdateTrait(const components::ComponentConfig& config, - const components::ComponentContext& context); - - // For internal use only - explicit CacheUpdateTrait(CacheDependencies&& dependencies); - - virtual ~CacheUpdateTrait(); - /// @endcond - - /// Update types configured for the cache - AllowedUpdateTypes GetAllowedUpdateTypes() const; - - /// Periodic update flags - enum class Flag { - kNone = 0, - - /// @brief Disable initial update on start - /// @deprecated Use `first-update-fail-ok: true` instead - kNoFirstUpdate = 1 << 0, - }; - - /// Starts periodic updates - void StartPeriodicUpdates(utils::Flags flags = {}); - - /// @brief Stops periodic updates - /// @warning Should be called in destructor of derived class. - void StopPeriodicUpdates(); - - void AssertPeriodicUpdateStarted(); - - void AssertPeriodicUpdateStopped(); - - /// Called in `CachingComponentBase::Set` during update to indicate - /// that the cached data has been modified - void OnCacheModified(); - - /// @cond - // For internal use only - rcu::ReadablePtr GetConfig() const; - - // Checks for the presence of the flag for pre-assign check. - // For internal use only. - bool HasPreAssignCheck() const; - - // Returns value of the flag safe-data-lifetime. - // For internal use only. - bool IsSafeDataLifetime() const; - - // For internal use only. - void SetDataSizeStatistic(std::size_t size) noexcept; - - // For internal use only - // TODO remove after TAXICOMMON-3959 - engine::TaskProcessor& GetCacheTaskProcessor() const; - /// @endcond - - /// @brief Should be overridden in a derived class to align the stored data - /// with some data source. - /// - /// `Update` implementation should do one of the following: - /// - /// A. If the update succeeded and has changes... - /// 1. call CachingComponentBase::Set to update the stored value and send a - /// notification to subscribers - /// 2. call UpdateStatisticsScope::Finish - /// 3. return normally (an exception is allowed in edge cases) - /// - /// B. If the update succeeded and verified that there are no changes... - /// 1. DON'T call CachingComponentBase::Set - /// 2. call UpdateStatisticsScope::FinishNoChanges - /// 3. return normally (an exception is allowed in edge cases) - /// - /// C. If the update failed... - /// 1. DON'T call CachingComponentBase::Set - /// 2. call UpdateStatisticsScope::FinishWithError, or... - /// 3. throw an exception, which will be logged nicely - /// (if there already is an exception, prefer rethrowing it instead - /// of calling UpdateStatisticsScope::FinishWithError) - /// - /// @param type type of the update - /// @param last_update time of the last update (value of `now` from previous - /// invocation of Update or default constructed value if this is the first - /// Update). - /// @param now current time point - /// - /// @throws std::exception on update failure - /// - /// @warning If `Update` returns without throwing an exception and without - /// calling one of the `Finish*` methods, the behavior is undefined. - /// - /// @see @ref scripts/docs/en/userver/caches.md - virtual void Update(UpdateType type, - const std::chrono::system_clock::time_point& last_update, - const std::chrono::system_clock::time_point& now, - UpdateStatisticsScope& stats_scope) = 0; - - private: - virtual void Cleanup() = 0; - - virtual void MarkAsExpired(); - - virtual void GetAndWrite(dump::Writer& writer) const; - - virtual void ReadAndSet(dump::Reader& reader); - - class Impl; - std::unique_ptr impl_; +public: + CacheUpdateTrait(CacheUpdateTrait&&) = delete; + CacheUpdateTrait& operator=(CacheUpdateTrait&&) = delete; + + /// @brief Non-blocking forced cache update of specified type + /// @see PeriodicTask::ForceStepAsync for behavior details + void InvalidateAsync(UpdateType update_type); + + /// @brief Forces a cache update of specified type + /// @throws If `Update` throws + void UpdateSyncDebug(UpdateType update_type); + + /// @return name of the component + const std::string& Name() const; + +protected: + /// @cond + // For internal use only + CacheUpdateTrait(const components::ComponentConfig& config, const components::ComponentContext& context); + + // For internal use only + explicit CacheUpdateTrait(CacheDependencies&& dependencies); + + virtual ~CacheUpdateTrait(); + /// @endcond + + /// Update types configured for the cache + AllowedUpdateTypes GetAllowedUpdateTypes() const; + + /// Periodic update flags + enum class Flag { + kNone = 0, + + /// @brief Disable initial update on start + /// @deprecated Use `first-update-fail-ok: true` instead + kNoFirstUpdate = 1 << 0, + }; + + /// Starts periodic updates + void StartPeriodicUpdates(utils::Flags flags = {}); + + /// @brief Stops periodic updates + /// @warning Should be called in destructor of derived class. + void StopPeriodicUpdates(); + + void AssertPeriodicUpdateStarted(); + + void AssertPeriodicUpdateStopped(); + + /// Called in `CachingComponentBase::Set` during update to indicate + /// that the cached data has been modified + void OnCacheModified(); + + /// @cond + // For internal use only + rcu::ReadablePtr GetConfig() const; + + // Checks for the presence of the flag for pre-assign check. + // For internal use only. + bool HasPreAssignCheck() const; + + // Returns value of the flag safe-data-lifetime. + // For internal use only. + bool IsSafeDataLifetime() const; + + // For internal use only. + void SetDataSizeStatistic(std::size_t size) noexcept; + + // For internal use only + // TODO remove after TAXICOMMON-3959 + engine::TaskProcessor& GetCacheTaskProcessor() const; + /// @endcond + + /// @brief Should be overridden in a derived class to align the stored data + /// with some data source. + /// + /// `Update` implementation should do one of the following: + /// + /// A. If the update succeeded and has changes... + /// 1. call CachingComponentBase::Set to update the stored value and send a + /// notification to subscribers + /// 2. call UpdateStatisticsScope::Finish + /// 3. return normally (an exception is allowed in edge cases) + /// + /// B. If the update succeeded and verified that there are no changes... + /// 1. DON'T call CachingComponentBase::Set + /// 2. call UpdateStatisticsScope::FinishNoChanges + /// 3. return normally (an exception is allowed in edge cases) + /// + /// C. If the update failed... + /// 1. DON'T call CachingComponentBase::Set + /// 2. call UpdateStatisticsScope::FinishWithError, or... + /// 3. throw an exception, which will be logged nicely + /// (if there already is an exception, prefer rethrowing it instead + /// of calling UpdateStatisticsScope::FinishWithError) + /// + /// @param type type of the update + /// @param last_update time of the last update (value of `now` from previous + /// invocation of Update or default constructed value if this is the first + /// Update). + /// @param now current time point + /// + /// @throws std::exception on update failure + /// + /// @warning If `Update` returns without throwing an exception and without + /// calling one of the `Finish*` methods, the behavior is undefined. + /// + /// @see @ref scripts/docs/en/userver/caches.md + virtual void Update( + UpdateType type, + const std::chrono::system_clock::time_point& last_update, + const std::chrono::system_clock::time_point& now, + UpdateStatisticsScope& stats_scope + ) = 0; + +private: + virtual void Cleanup() = 0; + + virtual void MarkAsExpired(); + + virtual void GetAndWrite(dump::Writer& writer) const; + + virtual void ReadAndSet(dump::Reader& reader); + + class Impl; + std::unique_ptr impl_; }; } // namespace cache diff --git a/core/include/userver/cache/caching_component_base.hpp b/core/include/userver/cache/caching_component_base.hpp index e0f11fe2d3e8..0e42accc9ae3 100644 --- a/core/include/userver/cache/caching_component_base.hpp +++ b/core/include/userver/cache/caching_component_base.hpp @@ -150,232 +150,223 @@ namespace components { template // NOLINTNEXTLINE(fuchsia-multiple-inheritance) -class CachingComponentBase : public ComponentBase, - protected cache::CacheUpdateTrait { - public: - CachingComponentBase(const ComponentConfig& config, const ComponentContext&); - ~CachingComponentBase() override; +class CachingComponentBase : public ComponentBase, protected cache::CacheUpdateTrait { +public: + CachingComponentBase(const ComponentConfig& config, const ComponentContext&); + ~CachingComponentBase() override; - using cache::CacheUpdateTrait::Name; + using cache::CacheUpdateTrait::Name; - using cache::CacheUpdateTrait::InvalidateAsync; + using cache::CacheUpdateTrait::InvalidateAsync; - using DataType = T; + using DataType = T; - /// @return cache contents. May be `nullptr` if and only if @ref MayReturnNull - /// returns `true`. - /// @throws cache::EmptyCacheError if the contents are `nullptr`, and - /// @ref MayReturnNull returns `false` (which is the default behavior). - utils::SharedReadablePtr Get() const; + /// @return cache contents. May be `nullptr` if and only if @ref MayReturnNull + /// returns `true`. + /// @throws cache::EmptyCacheError if the contents are `nullptr`, and + /// @ref MayReturnNull returns `false` (which is the default behavior). + utils::SharedReadablePtr Get() const; - /// @return cache contents. May be nullptr regardless of MayReturnNull(). - utils::SharedReadablePtr GetUnsafe() const; + /// @return cache contents. May be nullptr regardless of MayReturnNull(). + utils::SharedReadablePtr GetUnsafe() const; - /// Subscribes to cache updates using a member function. Also immediately - /// invokes the function with the current cache contents. - template - concurrent::AsyncEventSubscriberScope UpdateAndListen( - Class* obj, std::string name, - void (Class::*func)(const std::shared_ptr&)); + /// Subscribes to cache updates using a member function. Also immediately + /// invokes the function with the current cache contents. + template + concurrent::AsyncEventSubscriberScope + UpdateAndListen(Class* obj, std::string name, void (Class::*func)(const std::shared_ptr&)); - concurrent::AsyncEventChannel&>& - GetEventChannel(); + concurrent::AsyncEventChannel&>& GetEventChannel(); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - protected: - /// Sets the new value of cache. As a result the Get() member function starts - /// returning the value passed into this function after the Update() finishes. - /// - /// @warning Do not forget to update cache::UpdateStatisticsScope, otherwise - /// the behavior is undefined. - void Set(std::unique_ptr value_ptr); +protected: + /// Sets the new value of cache. As a result the Get() member function starts + /// returning the value passed into this function after the Update() finishes. + /// + /// @warning Do not forget to update cache::UpdateStatisticsScope, otherwise + /// the behavior is undefined. + void Set(std::unique_ptr value_ptr); - /// @overload - void Set(T&& value); + /// @overload + void Set(T&& value); - /// @overload Set() - template - void Emplace(Args&&... args); + /// @overload Set() + template + void Emplace(Args&&... args); - /// Clears the content of the cache by string a default constructed T. - void Clear(); + /// Clears the content of the cache by string a default constructed T. + void Clear(); - /// Whether @ref Get is expected to return `nullptr`. - virtual bool MayReturnNull() const; + /// Whether @ref Get is expected to return `nullptr`. + virtual bool MayReturnNull() const; - /// @{ - /// Override to use custom serialization for cache dumps - virtual void WriteContents(dump::Writer& writer, const T& contents) const; + /// @{ + /// Override to use custom serialization for cache dumps + virtual void WriteContents(dump::Writer& writer, const T& contents) const; - virtual std::unique_ptr ReadContents(dump::Reader& reader) const; - /// @} + virtual std::unique_ptr ReadContents(dump::Reader& reader) const; + /// @} - /// @brief If the option has-pre-assign-check is set true in static config, - /// this function is called before assigning the new value to the cache - /// @note old_value_ptr and new_value_ptr can be nullptr. - virtual void PreAssignCheck(const T* old_value_ptr, - const T* new_value_ptr) const; + /// @brief If the option has-pre-assign-check is set true in static config, + /// this function is called before assigning the new value to the cache + /// @note old_value_ptr and new_value_ptr can be nullptr. + virtual void PreAssignCheck(const T* old_value_ptr, const T* new_value_ptr) const; - private: - void OnAllComponentsLoaded() final; +private: + void OnAllComponentsLoaded() final; - void Cleanup() final; + void Cleanup() final; - void MarkAsExpired() final; + void MarkAsExpired() final; - void GetAndWrite(dump::Writer& writer) const final; - void ReadAndSet(dump::Reader& reader) final; + void GetAndWrite(dump::Writer& writer) const final; + void ReadAndSet(dump::Reader& reader) final; - std::shared_ptr TransformNewValue( - std::unique_ptr new_value); + std::shared_ptr TransformNewValue(std::unique_ptr new_value); - rcu::Variable> cache_; - concurrent::AsyncEventChannel&> event_channel_; - utils::impl::WaitTokenStorage wait_token_storage_; + rcu::Variable> cache_; + concurrent::AsyncEventChannel&> event_channel_; + utils::impl::WaitTokenStorage wait_token_storage_; }; template -CachingComponentBase::CachingComponentBase(const ComponentConfig& config, - const ComponentContext& context) +CachingComponentBase::CachingComponentBase(const ComponentConfig& config, const ComponentContext& context) : ComponentBase(config, context), cache::CacheUpdateTrait(config, context), - event_channel_(components::GetCurrentComponentName(config), - [this](auto& function) { - const auto ptr = cache_.ReadCopy(); - if (ptr) function(ptr); - }) { - const auto initial_config = GetConfig(); + event_channel_(components::GetCurrentComponentName(config), [this](auto& function) { + const auto ptr = cache_.ReadCopy(); + if (ptr) function(ptr); + }) { + const auto initial_config = GetConfig(); } template CachingComponentBase::~CachingComponentBase() { - // Avoid a deadlock in WaitForAllTokens - cache_.Assign(nullptr); - // We must wait for destruction of all instances of T to finish, otherwise - // it's UB if T's destructor accesses dependent components - wait_token_storage_.WaitForAllTokens(); + // Avoid a deadlock in WaitForAllTokens + cache_.Assign(nullptr); + // We must wait for destruction of all instances of T to finish, otherwise + // it's UB if T's destructor accesses dependent components + wait_token_storage_.WaitForAllTokens(); } template utils::SharedReadablePtr CachingComponentBase::Get() const { - auto ptr = GetUnsafe(); - if (!ptr && !MayReturnNull()) { - throw cache::EmptyCacheError(Name()); - } - return ptr; + auto ptr = GetUnsafe(); + if (!ptr && !MayReturnNull()) { + throw cache::EmptyCacheError(Name()); + } + return ptr; } template template concurrent::AsyncEventSubscriberScope CachingComponentBase::UpdateAndListen( - Class* obj, std::string name, - void (Class::*func)(const std::shared_ptr&)) { - return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] { - auto ptr = Get(); // TODO: extra ref - (obj->*func)(ptr); - }); + Class* obj, + std::string name, + void (Class::*func)(const std::shared_ptr&) +) { + return event_channel_.DoUpdateAndListen(obj, std::move(name), func, [&] { + auto ptr = Get(); // TODO: extra ref + (obj->*func)(ptr); + }); } template -concurrent::AsyncEventChannel&>& -CachingComponentBase::GetEventChannel() { - return event_channel_; +concurrent::AsyncEventChannel&>& CachingComponentBase::GetEventChannel() { + return event_channel_; } template utils::SharedReadablePtr CachingComponentBase::GetUnsafe() const { - return utils::SharedReadablePtr(cache_.ReadCopy()); + return utils::SharedReadablePtr(cache_.ReadCopy()); } template void CachingComponentBase::Set(std::unique_ptr value_ptr) { - const std::shared_ptr new_value = - TransformNewValue(std::move(value_ptr)); + const std::shared_ptr new_value = TransformNewValue(std::move(value_ptr)); - if (HasPreAssignCheck()) { - auto old_value = cache_.Read(); - PreAssignCheck(old_value->get(), new_value.get()); - } + if (HasPreAssignCheck()) { + auto old_value = cache_.Read(); + PreAssignCheck(old_value->get(), new_value.get()); + } - cache_.Assign(new_value); - event_channel_.SendEvent(new_value); - OnCacheModified(); + cache_.Assign(new_value); + event_channel_.SendEvent(new_value); + OnCacheModified(); } template void CachingComponentBase::Set(T&& value) { - Emplace(std::move(value)); + Emplace(std::move(value)); } template template void CachingComponentBase::Emplace(Args&&... args) { - Set(std::make_unique(std::forward(args)...)); + Set(std::make_unique(std::forward(args)...)); } template void CachingComponentBase::Clear() { - cache_.Assign(std::make_unique()); + cache_.Assign(std::make_unique()); } template bool CachingComponentBase::MayReturnNull() const { - return false; + return false; } template void CachingComponentBase::GetAndWrite(dump::Writer& writer) const { - const auto contents = GetUnsafe(); - if (!contents) throw cache::EmptyCacheError(Name()); - WriteContents(writer, *contents); + const auto contents = GetUnsafe(); + if (!contents) throw cache::EmptyCacheError(Name()); + WriteContents(writer, *contents); } template void CachingComponentBase::ReadAndSet(dump::Reader& reader) { - auto data = ReadContents(reader); - if constexpr (meta::kIsSizable) { - if (data) { - SetDataSizeStatistic(std::size(*data)); + auto data = ReadContents(reader); + if constexpr (meta::kIsSizable) { + if (data) { + SetDataSizeStatistic(std::size(*data)); + } } - } - Set(std::move(data)); + Set(std::move(data)); } template -void CachingComponentBase::WriteContents(dump::Writer& writer, - const T& contents) const { - if constexpr (dump::kIsDumpable) { - writer.Write(contents); - } else { - dump::ThrowDumpUnimplemented(Name()); - } +void CachingComponentBase::WriteContents(dump::Writer& writer, const T& contents) const { + if constexpr (dump::kIsDumpable) { + writer.Write(contents); + } else { + dump::ThrowDumpUnimplemented(Name()); + } } template -std::unique_ptr CachingComponentBase::ReadContents( - dump::Reader& reader) const { - if constexpr (dump::kIsDumpable) { - // To avoid an extra move and avoid including common_containers.hpp - return std::unique_ptr{new T(reader.Read())}; - } else { - dump::ThrowDumpUnimplemented(Name()); - } +std::unique_ptr CachingComponentBase::ReadContents(dump::Reader& reader) const { + if constexpr (dump::kIsDumpable) { + // To avoid an extra move and avoid including common_containers.hpp + return std::unique_ptr{new T(reader.Read())}; + } else { + dump::ThrowDumpUnimplemented(Name()); + } } template void CachingComponentBase::OnAllComponentsLoaded() { - AssertPeriodicUpdateStarted(); + AssertPeriodicUpdateStarted(); } template void CachingComponentBase::Cleanup() { - cache_.Cleanup(); + cache_.Cleanup(); } template void CachingComponentBase::MarkAsExpired() { - Set(std::unique_ptr{}); + Set(std::unique_ptr{}); } namespace impl { @@ -384,61 +375,56 @@ yaml_config::Schema GetCachingComponentBaseSchema(); template auto MakeAsyncDeleter(engine::TaskProcessor& task_processor, Deleter deleter) { - return [&task_processor, - deleter = std::move(deleter)](const T* raw_ptr) mutable { - std::unique_ptr ptr(raw_ptr, std::move(deleter)); - - engine::CriticalAsyncNoSpan(task_processor, [ptr = - std::move(ptr)]() mutable { - }).Detach(); - }; + return [&task_processor, deleter = std::move(deleter)](const T* raw_ptr) mutable { + std::unique_ptr ptr(raw_ptr, std::move(deleter)); + + engine::CriticalAsyncNoSpan(task_processor, [ptr = std::move(ptr)]() mutable {}).Detach(); + }; } } // namespace impl template yaml_config::Schema CachingComponentBase::GetStaticConfigSchema() { - return impl::GetCachingComponentBaseSchema(); + return impl::GetCachingComponentBaseSchema(); } template -void CachingComponentBase::PreAssignCheck( - const T*, [[maybe_unused]] const T* new_value_ptr) const { - UINVARIANT( - meta::kIsSizable, - fmt::format("{} type does not support std::size(), add implementation of " - "the method size() for this type or " - "override cache::CachingComponentBase::PreAssignCheck.", - compiler::GetTypeName())); - - if constexpr (meta::kIsSizable) { - if (!new_value_ptr || std::size(*new_value_ptr) == 0) { - throw cache::EmptyDataError(Name()); +void CachingComponentBase::PreAssignCheck(const T*, [[maybe_unused]] const T* new_value_ptr) const { + UINVARIANT( + meta::kIsSizable, + fmt::format( + "{} type does not support std::size(), add implementation of " + "the method size() for this type or " + "override cache::CachingComponentBase::PreAssignCheck.", + compiler::GetTypeName() + ) + ); + + if constexpr (meta::kIsSizable) { + if (!new_value_ptr || std::size(*new_value_ptr) == 0) { + throw cache::EmptyDataError(Name()); + } } - } } template -std::shared_ptr CachingComponentBase::TransformNewValue( - std::unique_ptr new_value) { - // Kill garbage asynchronously as T::~T() might be very slow - if (IsSafeDataLifetime()) { - // Use token only if `safe-data-lifetime` is true - auto deleter_with_token = - [token = wait_token_storage_.GetToken()](const T* raw_ptr) { - // Make sure *raw_ptr is deleted before token is destroyed - std::default_delete{}(raw_ptr); +std::shared_ptr CachingComponentBase::TransformNewValue(std::unique_ptr new_value) { + // Kill garbage asynchronously as T::~T() might be very slow + if (IsSafeDataLifetime()) { + // Use token only if `safe-data-lifetime` is true + auto deleter_with_token = [token = wait_token_storage_.GetToken()](const T* raw_ptr) { + // Make sure *raw_ptr is deleted before token is destroyed + std::default_delete{}(raw_ptr); }; - return std::shared_ptr( - new_value.release(), - impl::MakeAsyncDeleter(GetCacheTaskProcessor(), - std::move(deleter_with_token))); - } else { - return std::shared_ptr( - new_value.release(), - impl::MakeAsyncDeleter(GetCacheTaskProcessor(), - std::default_delete{})); - } + return std::shared_ptr( + new_value.release(), impl::MakeAsyncDeleter(GetCacheTaskProcessor(), std::move(deleter_with_token)) + ); + } else { + return std::shared_ptr( + new_value.release(), impl::MakeAsyncDeleter(GetCacheTaskProcessor(), std::default_delete{}) + ); + } } } // namespace components diff --git a/core/include/userver/cache/exceptions.hpp b/core/include/userver/cache/exceptions.hpp index 428f03e909d9..da5ef4b3306e 100644 --- a/core/include/userver/cache/exceptions.hpp +++ b/core/include/userver/cache/exceptions.hpp @@ -14,19 +14,19 @@ namespace cache { /// Thrown by components::CachingComponentBase::Get if the cache is empty and /// `MayReturnNull` returns `false` (as by default). class EmptyCacheError final : public std::runtime_error { - public: - explicit EmptyCacheError(std::string_view cache_name); +public: + explicit EmptyCacheError(std::string_view cache_name); }; /// Thrown by components::CachingComponentBase::PreAssignCheck when the new /// value does not pass the check. class DataError : public std::runtime_error { - using std::runtime_error::runtime_error; + using std::runtime_error::runtime_error; }; class EmptyDataError final : public DataError { - public: - explicit EmptyDataError(std::string_view cache_name); +public: + explicit EmptyDataError(std::string_view cache_name); }; } // namespace cache diff --git a/core/include/userver/cache/expirable_lru_cache.hpp b/core/include/userver/cache/expirable_lru_cache.hpp index 507cfd9e6421..7ba099edabb1 100644 --- a/core/include/userver/cache/expirable_lru_cache.hpp +++ b/core/include/userver/cache/expirable_lru_cache.hpp @@ -26,25 +26,23 @@ namespace impl { template struct ExpirableValue final { - Value value; - std::chrono::steady_clock::time_point update_time; + Value value; + std::chrono::steady_clock::time_point update_time; }; template void Write(dump::Writer& writer, const impl::ExpirableValue& value) { - const auto [now, steady_now] = utils::impl::GetGlobalTime(); - writer.Write(value.value); - writer.Write(value.update_time - steady_now + now); + const auto [now, steady_now] = utils::impl::GetGlobalTime(); + writer.Write(value.value); + writer.Write(value.update_time - steady_now + now); } template -impl::ExpirableValue Read(dump::Reader& reader, - dump::To>) { - const auto [now, steady_now] = utils::impl::GetGlobalTime(); - // Evaluation order of arguments is guaranteed in brace-initialization. - return impl::ExpirableValue{ - reader.Read(), - reader.Read() - now + steady_now}; +impl::ExpirableValue Read(dump::Reader& reader, dump::To>) { + const auto [now, steady_now] = utils::impl::GetGlobalTime(); + // Evaluation order of arguments is guaranteed in brace-initialization. + return impl::ExpirableValue{ + reader.Read(), reader.Read() - now + steady_now}; } } // namespace impl @@ -56,392 +54,371 @@ impl::ExpirableValue Read(dump::Reader& reader, /// Example usage: /// /// @snippet cache/expirable_lru_cache_test.cpp Sample ExpirableLruCache -template , - typename Equal = std::equal_to> +template , typename Equal = std::equal_to> class ExpirableLruCache final { - public: - using UpdateValueFunc = std::function; +public: + using UpdateValueFunc = std::function; - /// Cache read mode - enum class ReadMode { - kSkipCache, ///< Do not cache value got from update function - kUseCache, ///< Cache value got from update function - }; - - /// For the description of `ways` and `way_size`, - /// see the cache::NWayLRU::NWayLRU constructor. - ExpirableLruCache(size_t ways, size_t way_size, const Hash& hash = Hash(), - const Equal& equal = Equal()); - - ~ExpirableLruCache(); - - /// For the description of `way_size`, - /// see the cache::NWayLRU::NWayLRU constructor. - void SetWaySize(size_t way_size); - - std::chrono::milliseconds GetMaxLifetime() const noexcept; - - void SetMaxLifetime(std::chrono::milliseconds max_lifetime); - - /** - * Sets background update mode. If "background_update" mode is kDisabled, - * expiring values are not updated in background (asynchronously) or are - * updated if "background_update" is kEnabled. - */ - void SetBackgroundUpdate(BackgroundUpdateMode background_update); - - /** - * @returns GetOptional("key", update_func) if it is not std::nullopt. - * Otherwise the result of update_func(key) is returned, and additionally - * stored in cache if "read_mode" is kUseCache. - */ - Value Get(const Key& key, const UpdateValueFunc& update_func, - ReadMode read_mode = ReadMode::kUseCache); - - /** - * Update value in cache by "update_func" if background update mode is - * kEnabled and "key" is in cache and not expired but its lifetime ends soon. - * @returns value by key if key is in cache and not expired, or std::nullopt - * otherwise - */ - std::optional GetOptional(const Key& key, - const UpdateValueFunc& update_func); - - /** - * GetOptional, but without expiry checks and value updates. - * - * Used during fallback in FallbackELruCache. - */ - std::optional GetOptionalUnexpirable(const Key& key); - - /** - * GetOptional, but without expiry check. - * - * Used during fallback in FallbackELruCache. - */ - std::optional GetOptionalUnexpirableWithUpdate( - const Key& key, const UpdateValueFunc& update_func); - - /** - * GetOptional, but without value updates. - */ - std::optional GetOptionalNoUpdate(const Key& key); - - void Put(const Key& key, const Value& value); - - void Put(const Key& key, Value&& value); - - const impl::ExpirableLruCacheStatistics& GetStatistics() const; - - size_t GetSizeApproximate() const; - - /// Clear cache - void Invalidate(); - - /// Erase key from cache - void InvalidateByKey(const Key& key); - - /// Add async task for updating value by update_func(key) - void UpdateInBackground(const Key& key, UpdateValueFunc update_func); - - void Write(dump::Writer& writer) const; - - void Read(dump::Reader& reader); - - /// The dump::Dumper will be notified of any cache updates. This method is not - /// thread-safe. - void SetDumper(std::shared_ptr dumper); - - private: - bool IsExpired(std::chrono::steady_clock::time_point update_time, - std::chrono::steady_clock::time_point now) const; - - bool ShouldUpdate(std::chrono::steady_clock::time_point update_time, - std::chrono::steady_clock::time_point now) const; - - cache::NWayLRU, Hash, Equal> lru_; - std::atomic max_lifetime_{ - std::chrono::milliseconds(0)}; - std::atomic background_update_mode_{ - BackgroundUpdateMode::kDisabled}; - impl::ExpirableLruCacheStatistics stats_; - concurrent::MutexSet mutex_set_; - utils::impl::WaitTokenStorage wait_token_storage_; + /// Cache read mode + enum class ReadMode { + kSkipCache, ///< Do not cache value got from update function + kUseCache, ///< Cache value got from update function + }; + + /// For the description of `ways` and `way_size`, + /// see the cache::NWayLRU::NWayLRU constructor. + ExpirableLruCache(size_t ways, size_t way_size, const Hash& hash = Hash(), const Equal& equal = Equal()); + + ~ExpirableLruCache(); + + /// For the description of `way_size`, + /// see the cache::NWayLRU::NWayLRU constructor. + void SetWaySize(size_t way_size); + + std::chrono::milliseconds GetMaxLifetime() const noexcept; + + void SetMaxLifetime(std::chrono::milliseconds max_lifetime); + + /** + * Sets background update mode. If "background_update" mode is kDisabled, + * expiring values are not updated in background (asynchronously) or are + * updated if "background_update" is kEnabled. + */ + void SetBackgroundUpdate(BackgroundUpdateMode background_update); + + /** + * @returns GetOptional("key", update_func) if it is not std::nullopt. + * Otherwise the result of update_func(key) is returned, and additionally + * stored in cache if "read_mode" is kUseCache. + */ + Value Get(const Key& key, const UpdateValueFunc& update_func, ReadMode read_mode = ReadMode::kUseCache); + + /** + * Update value in cache by "update_func" if background update mode is + * kEnabled and "key" is in cache and not expired but its lifetime ends soon. + * @returns value by key if key is in cache and not expired, or std::nullopt + * otherwise + */ + std::optional GetOptional(const Key& key, const UpdateValueFunc& update_func); + + /** + * GetOptional, but without expiry checks and value updates. + * + * Used during fallback in FallbackELruCache. + */ + std::optional GetOptionalUnexpirable(const Key& key); + + /** + * GetOptional, but without expiry check. + * + * Used during fallback in FallbackELruCache. + */ + std::optional GetOptionalUnexpirableWithUpdate(const Key& key, const UpdateValueFunc& update_func); + + /** + * GetOptional, but without value updates. + */ + std::optional GetOptionalNoUpdate(const Key& key); + + void Put(const Key& key, const Value& value); + + void Put(const Key& key, Value&& value); + + const impl::ExpirableLruCacheStatistics& GetStatistics() const; + + size_t GetSizeApproximate() const; + + /// Clear cache + void Invalidate(); + + /// Erase key from cache + void InvalidateByKey(const Key& key); + + /// Add async task for updating value by update_func(key) + void UpdateInBackground(const Key& key, UpdateValueFunc update_func); + + void Write(dump::Writer& writer) const; + + void Read(dump::Reader& reader); + + /// The dump::Dumper will be notified of any cache updates. This method is not + /// thread-safe. + void SetDumper(std::shared_ptr dumper); + +private: + bool IsExpired(std::chrono::steady_clock::time_point update_time, std::chrono::steady_clock::time_point now) const; + + bool ShouldUpdate(std::chrono::steady_clock::time_point update_time, std::chrono::steady_clock::time_point now) + const; + + cache::NWayLRU, Hash, Equal> lru_; + std::atomic max_lifetime_{std::chrono::milliseconds(0)}; + std::atomic background_update_mode_{BackgroundUpdateMode::kDisabled}; + impl::ExpirableLruCacheStatistics stats_; + concurrent::MutexSet mutex_set_; + utils::impl::WaitTokenStorage wait_token_storage_; }; template ExpirableLruCache::ExpirableLruCache( - size_t ways, size_t way_size, const Hash& hash, const Equal& equal) - : lru_(ways, way_size, hash, equal), - mutex_set_{ways, way_size, hash, equal} {} + size_t ways, + size_t way_size, + const Hash& hash, + const Equal& equal +) + : lru_(ways, way_size, hash, equal), mutex_set_{ways, way_size, hash, equal} {} template ExpirableLruCache::~ExpirableLruCache() { - wait_token_storage_.WaitForAllTokens(); + wait_token_storage_.WaitForAllTokens(); } template void ExpirableLruCache::SetWaySize(size_t way_size) { - lru_.UpdateWaySize(way_size); + lru_.UpdateWaySize(way_size); } template -std::chrono::milliseconds -ExpirableLruCache::GetMaxLifetime() const noexcept { - return max_lifetime_.load(); +std::chrono::milliseconds ExpirableLruCache::GetMaxLifetime() const noexcept { + return max_lifetime_.load(); } template -void ExpirableLruCache::SetMaxLifetime( - std::chrono::milliseconds max_lifetime) { - max_lifetime_ = max_lifetime; +void ExpirableLruCache::SetMaxLifetime(std::chrono::milliseconds max_lifetime) { + max_lifetime_ = max_lifetime; } template -void ExpirableLruCache::SetBackgroundUpdate( - BackgroundUpdateMode background_update) { - background_update_mode_ = background_update; +void ExpirableLruCache::SetBackgroundUpdate(BackgroundUpdateMode background_update) { + background_update_mode_ = background_update; } template Value ExpirableLruCache::Get( - const Key& key, const UpdateValueFunc& update_func, ReadMode read_mode) { - auto now = utils::datetime::SteadyNow(); - auto opt_old_value = GetOptional(key, update_func); - if (opt_old_value) { - return std::move(*opt_old_value); - } - - auto mutex = mutex_set_.GetMutexForKey(key); - std::lock_guard lock(mutex); - // Test one more time - concurrent ExpirableLruCache::Get() - // might have put the value - auto old_value = lru_.Get(key); - if (old_value && !IsExpired(old_value->update_time, now)) { - return std::move(old_value->value); - } - - auto value = update_func(key); - if (read_mode == ReadMode::kUseCache) { - lru_.Put(key, {value, now}); - } - return value; + const Key& key, + const UpdateValueFunc& update_func, + ReadMode read_mode +) { + auto now = utils::datetime::SteadyNow(); + auto opt_old_value = GetOptional(key, update_func); + if (opt_old_value) { + return std::move(*opt_old_value); + } + + auto mutex = mutex_set_.GetMutexForKey(key); + std::lock_guard lock(mutex); + // Test one more time - concurrent ExpirableLruCache::Get() + // might have put the value + auto old_value = lru_.Get(key); + if (old_value && !IsExpired(old_value->update_time, now)) { + return std::move(old_value->value); + } + + auto value = update_func(key); + if (read_mode == ReadMode::kUseCache) { + lru_.Put(key, {value, now}); + } + return value; } template -std::optional ExpirableLruCache::GetOptional( - const Key& key, const UpdateValueFunc& update_func) { - auto now = utils::datetime::SteadyNow(); - auto old_value = lru_.Get(key); - - if (old_value) { - if (!IsExpired(old_value->update_time, now)) { - impl::CacheHit(stats_); - - if (ShouldUpdate(old_value->update_time, now)) { - UpdateInBackground(key, update_func); - } - - return std::move(old_value->value); - } else { - impl::CacheStale(stats_); +std::optional +ExpirableLruCache::GetOptional(const Key& key, const UpdateValueFunc& update_func) { + auto now = utils::datetime::SteadyNow(); + auto old_value = lru_.Get(key); + + if (old_value) { + if (!IsExpired(old_value->update_time, now)) { + impl::CacheHit(stats_); + + if (ShouldUpdate(old_value->update_time, now)) { + UpdateInBackground(key, update_func); + } + + return std::move(old_value->value); + } else { + impl::CacheStale(stats_); + } } - } - impl::CacheMiss(stats_); + impl::CacheMiss(stats_); - return std::nullopt; + return std::nullopt; } template -std::optional -ExpirableLruCache::GetOptionalUnexpirable( - const Key& key) { - auto old_value = lru_.Get(key); +std::optional ExpirableLruCache::GetOptionalUnexpirable(const Key& key) { + auto old_value = lru_.Get(key); - if (old_value) { - impl::CacheHit(stats_); - return old_value->value; - } - impl::CacheMiss(stats_); + if (old_value) { + impl::CacheHit(stats_); + return old_value->value; + } + impl::CacheMiss(stats_); - return std::nullopt; + return std::nullopt; } template -std::optional -ExpirableLruCache::GetOptionalUnexpirableWithUpdate( - const Key& key, const UpdateValueFunc& update_func) { - auto now = utils::datetime::SteadyNow(); - auto old_value = lru_.Get(key); +std::optional ExpirableLruCache::GetOptionalUnexpirableWithUpdate( + const Key& key, + const UpdateValueFunc& update_func +) { + auto now = utils::datetime::SteadyNow(); + auto old_value = lru_.Get(key); - if (old_value) { - impl::CacheHit(stats_); + if (old_value) { + impl::CacheHit(stats_); - if (ShouldUpdate(old_value->update_time, now)) { - UpdateInBackground(key, update_func); - } + if (ShouldUpdate(old_value->update_time, now)) { + UpdateInBackground(key, update_func); + } - return old_value->value; - } - impl::CacheMiss(stats_); + return old_value->value; + } + impl::CacheMiss(stats_); - return std::nullopt; + return std::nullopt; } template -std::optional -ExpirableLruCache::GetOptionalNoUpdate( - const Key& key) { - auto now = utils::datetime::SteadyNow(); - auto old_value = lru_.Get(key); - - if (old_value) { - if (!IsExpired(old_value->update_time, now)) { - impl::CacheHit(stats_); - - return old_value->value; - } else { - impl::CacheStale(stats_); +std::optional ExpirableLruCache::GetOptionalNoUpdate(const Key& key) { + auto now = utils::datetime::SteadyNow(); + auto old_value = lru_.Get(key); + + if (old_value) { + if (!IsExpired(old_value->update_time, now)) { + impl::CacheHit(stats_); + + return old_value->value; + } else { + impl::CacheStale(stats_); + } } - } - impl::CacheMiss(stats_); + impl::CacheMiss(stats_); - return std::nullopt; + return std::nullopt; } template -void ExpirableLruCache::Put(const Key& key, - const Value& value) { - lru_.Put(key, {value, utils::datetime::SteadyNow()}); +void ExpirableLruCache::Put(const Key& key, const Value& value) { + lru_.Put(key, {value, utils::datetime::SteadyNow()}); } template -void ExpirableLruCache::Put(const Key& key, - Value&& value) { - lru_.Put(key, {std::move(value), utils::datetime::SteadyNow()}); +void ExpirableLruCache::Put(const Key& key, Value&& value) { + lru_.Put(key, {std::move(value), utils::datetime::SteadyNow()}); } template -const impl::ExpirableLruCacheStatistics& -ExpirableLruCache::GetStatistics() const { - return stats_; +const impl::ExpirableLruCacheStatistics& ExpirableLruCache::GetStatistics() const { + return stats_; } template size_t ExpirableLruCache::GetSizeApproximate() const { - return lru_.GetSize(); + return lru_.GetSize(); } template void ExpirableLruCache::Invalidate() { - lru_.Invalidate(); + lru_.Invalidate(); } template -void ExpirableLruCache::InvalidateByKey( - const Key& key) { - lru_.InvalidateByKey(key); +void ExpirableLruCache::InvalidateByKey(const Key& key) { + lru_.InvalidateByKey(key); } template -void ExpirableLruCache::UpdateInBackground( - const Key& key, UpdateValueFunc update_func) { - stats_.total.background_updates++; - stats_.recent.GetCurrentCounter().background_updates++; - - // cache will wait for all detached tasks in ~ExpirableLruCache() - engine::AsyncNoSpan([token = wait_token_storage_.GetToken(), this, key, - update_func = std::move(update_func)] { - auto mutex = mutex_set_.GetMutexForKey(key); - std::unique_lock lock(mutex, std::try_to_lock); - if (!lock) { - // someone is updating the key right now - return; - } - - auto now = utils::datetime::SteadyNow(); - auto value = update_func(key); - lru_.Put(key, {value, now}); - }).Detach(); +void ExpirableLruCache::UpdateInBackground(const Key& key, UpdateValueFunc update_func) { + stats_.total.background_updates++; + stats_.recent.GetCurrentCounter().background_updates++; + + // cache will wait for all detached tasks in ~ExpirableLruCache() + engine::AsyncNoSpan([token = wait_token_storage_.GetToken(), this, key, update_func = std::move(update_func)] { + auto mutex = mutex_set_.GetMutexForKey(key); + std::unique_lock lock(mutex, std::try_to_lock); + if (!lock) { + // someone is updating the key right now + return; + } + + auto now = utils::datetime::SteadyNow(); + auto value = update_func(key); + lru_.Put(key, {value, now}); + }).Detach(); } template bool ExpirableLruCache::IsExpired( std::chrono::steady_clock::time_point update_time, - std::chrono::steady_clock::time_point now) const { - auto max_lifetime = max_lifetime_.load(); - return max_lifetime.count() != 0 && update_time + max_lifetime < now; + std::chrono::steady_clock::time_point now +) const { + auto max_lifetime = max_lifetime_.load(); + return max_lifetime.count() != 0 && update_time + max_lifetime < now; } template bool ExpirableLruCache::ShouldUpdate( std::chrono::steady_clock::time_point update_time, - std::chrono::steady_clock::time_point now) const { - auto max_lifetime = max_lifetime_.load(); - return (background_update_mode_.load() == BackgroundUpdateMode::kEnabled) && - max_lifetime.count() != 0 && update_time + max_lifetime / 2 < now; + std::chrono::steady_clock::time_point now +) const { + auto max_lifetime = max_lifetime_.load(); + return (background_update_mode_.load() == BackgroundUpdateMode::kEnabled) && max_lifetime.count() != 0 && + update_time + max_lifetime / 2 < now; } -template , - typename Equal = std::equal_to> +template , typename Equal = std::equal_to> class LruCacheWrapper final { - public: - using Cache = ExpirableLruCache; - using ReadMode = typename Cache::ReadMode; +public: + using Cache = ExpirableLruCache; + using ReadMode = typename Cache::ReadMode; - LruCacheWrapper(std::shared_ptr cache, - typename Cache::UpdateValueFunc update_func) - : cache_(std::move(cache)), update_func_(std::move(update_func)) {} + LruCacheWrapper(std::shared_ptr cache, typename Cache::UpdateValueFunc update_func) + : cache_(std::move(cache)), update_func_(std::move(update_func)) {} - /// Get cached value or evaluates if "key" is missing in cache - Value Get(const Key& key, ReadMode read_mode = ReadMode::kUseCache) { - return cache_->Get(key, update_func_, read_mode); - } + /// Get cached value or evaluates if "key" is missing in cache + Value Get(const Key& key, ReadMode read_mode = ReadMode::kUseCache) { + return cache_->Get(key, update_func_, read_mode); + } - /// Get cached value or "nullopt" if "key" is missing in cache - std::optional GetOptional(const Key& key) { - return cache_->GetOptional(key, update_func_); - } + /// Get cached value or "nullopt" if "key" is missing in cache + std::optional GetOptional(const Key& key) { return cache_->GetOptional(key, update_func_); } - void InvalidateByKey(const Key& key) { cache_->InvalidateByKey(key); } + void InvalidateByKey(const Key& key) { cache_->InvalidateByKey(key); } - /// Update cached value in background - void UpdateInBackground(const Key& key) { - cache_->UpdateInBackground(key, update_func_); - } + /// Update cached value in background + void UpdateInBackground(const Key& key) { cache_->UpdateInBackground(key, update_func_); } - /// Get raw cache. For internal use. - std::shared_ptr GetCache() { return cache_; } + /// Get raw cache. For internal use. + std::shared_ptr GetCache() { return cache_; } - private: - std::shared_ptr cache_; - typename Cache::UpdateValueFunc update_func_; +private: + std::shared_ptr cache_; + typename Cache::UpdateValueFunc update_func_; }; template -void ExpirableLruCache::Write( - dump::Writer& writer) const { - utils::impl::UpdateGlobalTime(); - lru_.Write(writer); +void ExpirableLruCache::Write(dump::Writer& writer) const { + utils::impl::UpdateGlobalTime(); + lru_.Write(writer); } template void ExpirableLruCache::Read(dump::Reader& reader) { - utils::impl::UpdateGlobalTime(); - lru_.Read(reader); + utils::impl::UpdateGlobalTime(); + lru_.Read(reader); } template -void ExpirableLruCache::SetDumper( - std::shared_ptr dumper) { - lru_.SetDumper(std::move(dumper)); +void ExpirableLruCache::SetDumper(std::shared_ptr dumper) { + lru_.SetDumper(std::move(dumper)); } template -void DumpMetric(utils::statistics::Writer& writer, - const ExpirableLruCache& cache) { - writer["current-documents-count"] = cache.GetSizeApproximate(); - writer = cache.GetStatistics(); +void DumpMetric(utils::statistics::Writer& writer, const ExpirableLruCache& cache) { + writer["current-documents-count"] = cache.GetSizeApproximate(); + writer = cache.GetStatistics(); } } // namespace cache diff --git a/core/include/userver/cache/lru_cache_component_base.hpp b/core/include/userver/cache/lru_cache_component_base.hpp index 279d1ba693b5..36d68424c33c 100644 --- a/core/include/userver/cache/lru_cache_component_base.hpp +++ b/core/include/userver/cache/lru_cache_component_base.hpp @@ -25,11 +25,12 @@ namespace cache { namespace impl { utils::statistics::Entry RegisterOnStatisticsStorage( - const components::ComponentContext& context, const std::string& name, - std::function func); + const components::ComponentContext& context, + const std::string& name, + std::function func +); -dynamic_config::Source FindDynamicConfigSource( - const components::ComponentContext& context); +dynamic_config::Source FindDynamicConfigSource(const components::ComponentContext& context); bool IsDumpSupportEnabled(const components::ComponentConfig& config); @@ -71,167 +72,156 @@ yaml_config::Schema GetLruCacheComponentBaseSchema(); /// @snippet cache/lru_cache_component_base_test.cpp Sample lru cache component config // clang-format on -template , - typename Equal = std::equal_to> +template , typename Equal = std::equal_to> // NOLINTNEXTLINE(fuchsia-multiple-inheritance) -class LruCacheComponent : public components::ComponentBase, - private dump::DumpableEntity { - public: - using Cache = ExpirableLruCache; - using CacheWrapper = LruCacheWrapper; +class LruCacheComponent : public components::ComponentBase, private dump::DumpableEntity { +public: + using Cache = ExpirableLruCache; + using CacheWrapper = LruCacheWrapper; - LruCacheComponent(const components::ComponentConfig&, - const components::ComponentContext&); + LruCacheComponent(const components::ComponentConfig&, const components::ComponentContext&); - ~LruCacheComponent() override; + ~LruCacheComponent() override; - CacheWrapper GetCache(); + CacheWrapper GetCache(); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - protected: - virtual Value DoGetByKey(const Key& key) = 0; +protected: + virtual Value DoGetByKey(const Key& key) = 0; - std::shared_ptr GetCacheRaw() { return cache_; } + std::shared_ptr GetCacheRaw() { return cache_; } - private: - void DropCache(); +private: + void DropCache(); - Value GetByKey(const Key& key); + Value GetByKey(const Key& key); - void OnConfigUpdate(const dynamic_config::Snapshot& cfg); + void OnConfigUpdate(const dynamic_config::Snapshot& cfg); - void UpdateConfig(const LruCacheConfig& config); + void UpdateConfig(const LruCacheConfig& config); - static constexpr bool kCacheIsDumpable = - dump::kIsDumpable && dump::kIsDumpable; + static constexpr bool kCacheIsDumpable = dump::kIsDumpable && dump::kIsDumpable; - void GetAndWrite(dump::Writer& writer) const override; - void ReadAndSet(dump::Reader& reader) override; + void GetAndWrite(dump::Writer& writer) const override; + void ReadAndSet(dump::Reader& reader) override; - const std::string name_; - const LruCacheConfigStatic static_config_; - std::shared_ptr dumper_; - const std::shared_ptr cache_; + const std::string name_; + const LruCacheConfigStatic static_config_; + std::shared_ptr dumper_; + const std::shared_ptr cache_; - // Subscriptions must be the last fields. - concurrent::AsyncEventSubscriberScope config_subscription_; - utils::statistics::Entry statistics_holder_; - testsuite::CacheResetRegistration reset_registration_; - // See the comment above before adding a new field. + // Subscriptions must be the last fields. + concurrent::AsyncEventSubscriberScope config_subscription_; + utils::statistics::Entry statistics_holder_; + testsuite::CacheResetRegistration reset_registration_; + // See the comment above before adding a new field. }; template LruCacheComponent::LruCacheComponent( const components::ComponentConfig& config, - const components::ComponentContext& context) + const components::ComponentContext& context +) : ComponentBase(config, context), name_(components::GetCurrentComponentName(config)), static_config_(config), - cache_(std::make_shared(static_config_.ways, - static_config_.GetWaySize())) { - if (impl::IsDumpSupportEnabled(config)) { - dumper_ = std::make_shared( - config, context, static_cast(*this)); - cache_->SetDumper(dumper_); - dumper_->ReadDump(); - } - - cache_->SetMaxLifetime(static_config_.config.lifetime); - cache_->SetBackgroundUpdate(static_config_.config.background_update); - - if (static_config_.use_dynamic_config) { - LOG_INFO() << "Dynamic LRU cache config is enabled, subscribing on " - "dynamic-config updates, cache=" - << name_; - - config_subscription_ = - impl::FindDynamicConfigSource(context).UpdateAndListen( - this, "cache." + name_, &LruCacheComponent::OnConfigUpdate); - } else { - LOG_INFO() << "Dynamic LRU cache config is disabled, cache=" << name_; - } - - statistics_holder_ = impl::RegisterOnStatisticsStorage( - context, name_, - [this](utils::statistics::Writer& writer) { writer = *cache_; }); - - reset_registration_ = testsuite::RegisterCache(config, context, this, - &LruCacheComponent::DropCache); + cache_(std::make_shared(static_config_.ways, static_config_.GetWaySize())) { + if (impl::IsDumpSupportEnabled(config)) { + dumper_ = std::make_shared(config, context, static_cast(*this)); + cache_->SetDumper(dumper_); + dumper_->ReadDump(); + } + + cache_->SetMaxLifetime(static_config_.config.lifetime); + cache_->SetBackgroundUpdate(static_config_.config.background_update); + + if (static_config_.use_dynamic_config) { + LOG_INFO() << "Dynamic LRU cache config is enabled, subscribing on " + "dynamic-config updates, cache=" + << name_; + + config_subscription_ = impl::FindDynamicConfigSource(context).UpdateAndListen( + this, "cache." + name_, &LruCacheComponent::OnConfigUpdate + ); + } else { + LOG_INFO() << "Dynamic LRU cache config is disabled, cache=" << name_; + } + + statistics_holder_ = impl::RegisterOnStatisticsStorage(context, name_, [this](utils::statistics::Writer& writer) { + writer = *cache_; + }); + + reset_registration_ = testsuite::RegisterCache(config, context, this, &LruCacheComponent::DropCache); } template LruCacheComponent::~LruCacheComponent() { - reset_registration_.Unregister(); - statistics_holder_.Unregister(); - config_subscription_.Unsubscribe(); + reset_registration_.Unregister(); + statistics_holder_.Unregister(); + config_subscription_.Unsubscribe(); - if (dumper_) { - dumper_->CancelWriteTaskAndWait(); - } + if (dumper_) { + dumper_->CancelWriteTaskAndWait(); + } } template -typename LruCacheComponent::CacheWrapper -LruCacheComponent::GetCache() { - return CacheWrapper(cache_, [this](const Key& key) { return GetByKey(key); }); +typename LruCacheComponent::CacheWrapper LruCacheComponent::GetCache( +) { + return CacheWrapper(cache_, [this](const Key& key) { return GetByKey(key); }); } template void LruCacheComponent::DropCache() { - cache_->Invalidate(); + cache_->Invalidate(); } template Value LruCacheComponent::GetByKey(const Key& key) { - return DoGetByKey(key); + return DoGetByKey(key); } template -void LruCacheComponent::OnConfigUpdate( - const dynamic_config::Snapshot& cfg) { - const auto config = GetLruConfig(cfg, name_); - if (config) { - LOG_DEBUG() << "Using dynamic config for LRU cache"; - UpdateConfig(*config); - } else { - LOG_DEBUG() << "Using static config for LRU cache"; - UpdateConfig(static_config_.config); - } +void LruCacheComponent::OnConfigUpdate(const dynamic_config::Snapshot& cfg) { + const auto config = GetLruConfig(cfg, name_); + if (config) { + LOG_DEBUG() << "Using dynamic config for LRU cache"; + UpdateConfig(*config); + } else { + LOG_DEBUG() << "Using static config for LRU cache"; + UpdateConfig(static_config_.config); + } } template -void LruCacheComponent::UpdateConfig( - const LruCacheConfig& config) { - cache_->SetWaySize(config.GetWaySize(static_config_.ways)); - cache_->SetMaxLifetime(config.lifetime); - cache_->SetBackgroundUpdate(config.background_update); +void LruCacheComponent::UpdateConfig(const LruCacheConfig& config) { + cache_->SetWaySize(config.GetWaySize(static_config_.ways)); + cache_->SetMaxLifetime(config.lifetime); + cache_->SetBackgroundUpdate(config.background_update); } template -yaml_config::Schema -LruCacheComponent::GetStaticConfigSchema() { - return impl::GetLruCacheComponentBaseSchema(); +yaml_config::Schema LruCacheComponent::GetStaticConfigSchema() { + return impl::GetLruCacheComponentBaseSchema(); } template -void LruCacheComponent::GetAndWrite( - dump::Writer& writer) const { - if constexpr (kCacheIsDumpable) { - cache_->Write(writer); - } else { - dump::ThrowDumpUnimplemented(name_); - } +void LruCacheComponent::GetAndWrite(dump::Writer& writer) const { + if constexpr (kCacheIsDumpable) { + cache_->Write(writer); + } else { + dump::ThrowDumpUnimplemented(name_); + } } template -void LruCacheComponent::ReadAndSet( - dump::Reader& reader) { - if constexpr (kCacheIsDumpable) { - cache_->Read(reader); - } else { - dump::ThrowDumpUnimplemented(name_); - } +void LruCacheComponent::ReadAndSet(dump::Reader& reader) { + if constexpr (kCacheIsDumpable) { + cache_->Read(reader); + } else { + dump::ThrowDumpUnimplemented(name_); + } } } // namespace cache diff --git a/core/include/userver/cache/lru_cache_config.hpp b/core/include/userver/cache/lru_cache_config.hpp index 77f47c2015cc..108ea5662cfd 100644 --- a/core/include/userver/cache/lru_cache_config.hpp +++ b/core/include/userver/cache/lru_cache_config.hpp @@ -15,43 +15,39 @@ USERVER_NAMESPACE_BEGIN namespace cache { enum class BackgroundUpdateMode { - kEnabled, - kDisabled, + kEnabled, + kDisabled, }; struct LruCacheConfig final { - explicit LruCacheConfig(const yaml_config::YamlConfig& config); - explicit LruCacheConfig(const components::ComponentConfig& config); + explicit LruCacheConfig(const yaml_config::YamlConfig& config); + explicit LruCacheConfig(const components::ComponentConfig& config); - explicit LruCacheConfig(const formats::json::Value& value); + explicit LruCacheConfig(const formats::json::Value& value); - std::size_t GetWaySize(std::size_t ways) const; + std::size_t GetWaySize(std::size_t ways) const; - std::size_t size; - std::chrono::milliseconds lifetime; - BackgroundUpdateMode background_update; + std::size_t size; + std::chrono::milliseconds lifetime; + BackgroundUpdateMode background_update; }; -LruCacheConfig Parse(const formats::json::Value& value, - formats::parse::To); +LruCacheConfig Parse(const formats::json::Value& value, formats::parse::To); struct LruCacheConfigStatic final { - explicit LruCacheConfigStatic(const yaml_config::YamlConfig& config); - explicit LruCacheConfigStatic(const components::ComponentConfig& config); + explicit LruCacheConfigStatic(const yaml_config::YamlConfig& config); + explicit LruCacheConfigStatic(const components::ComponentConfig& config); - std::size_t GetWaySize() const; + std::size_t GetWaySize() const; - LruCacheConfig config; - std::size_t ways; - bool use_dynamic_config; + LruCacheConfig config; + std::size_t ways; + bool use_dynamic_config; }; -extern const dynamic_config::Key< - std::unordered_map> - kLruCacheConfigSet; +extern const dynamic_config::Key> kLruCacheConfigSet; -std::optional GetLruConfig( - const dynamic_config::Snapshot& config, const std::string& cache_name); +std::optional GetLruConfig(const dynamic_config::Snapshot& config, const std::string& cache_name); } // namespace cache diff --git a/core/include/userver/cache/lru_cache_statistics.hpp b/core/include/userver/cache/lru_cache_statistics.hpp index de059df56b95..a1b5d8e68116 100644 --- a/core/include/userver/cache/lru_cache_statistics.hpp +++ b/core/include/userver/cache/lru_cache_statistics.hpp @@ -12,26 +12,25 @@ USERVER_NAMESPACE_BEGIN namespace cache::impl { struct ExpirableLruCacheStatisticsBase final { - std::atomic hits{0}; - std::atomic misses{0}; - std::atomic stale{0}; - std::atomic background_updates{0}; + std::atomic hits{0}; + std::atomic misses{0}; + std::atomic stale{0}; + std::atomic background_updates{0}; - ExpirableLruCacheStatisticsBase(); + ExpirableLruCacheStatisticsBase(); - ExpirableLruCacheStatisticsBase(const ExpirableLruCacheStatisticsBase& other); + ExpirableLruCacheStatisticsBase(const ExpirableLruCacheStatisticsBase& other); - void Reset(); + void Reset(); - ExpirableLruCacheStatisticsBase& operator+=( - const ExpirableLruCacheStatisticsBase& other); + ExpirableLruCacheStatisticsBase& operator+=(const ExpirableLruCacheStatisticsBase& other); }; struct ExpirableLruCacheStatistics final { - ExpirableLruCacheStatisticsBase total; - utils::statistics::RecentPeriod - recent{std::chrono::seconds(5), std::chrono::seconds(60)}; + ExpirableLruCacheStatisticsBase total; + utils::statistics::RecentPeriod recent{ + std::chrono::seconds(5), + std::chrono::seconds(60)}; }; void CacheHit(ExpirableLruCacheStatistics& stats); @@ -40,8 +39,7 @@ void CacheMiss(ExpirableLruCacheStatistics& stats); void CacheStale(ExpirableLruCacheStatistics& stats); -void DumpMetric(utils::statistics::Writer& writer, - const ExpirableLruCacheStatistics& stats); +void DumpMetric(utils::statistics::Writer& writer, const ExpirableLruCacheStatistics& stats); } // namespace cache::impl diff --git a/core/include/userver/cache/nway_lru_cache.hpp b/core/include/userver/cache/nway_lru_cache.hpp index 5dedf5876aef..3d8f1aece063 100644 --- a/core/include/userver/cache/nway_lru_cache.hpp +++ b/core/include/userver/cache/nway_lru_cache.hpp @@ -16,223 +16,217 @@ USERVER_NAMESPACE_BEGIN namespace cache { /// @ingroup userver_containers -template , - typename Equal = std::equal_to> +template , typename Equal = std::equal_to> class NWayLRU final { - public: - /// @param ways is the number of ways (a.k.a. shards, internal hash-maps), - /// into which elements are distributed based on their hash. Each shard is - /// protected by an individual mutex. Larger `ways` means more internal - /// hash-map instances and more memory usage, but less contention. A good - /// starting point is `ways=16`. If you encounter contention, you can increase - /// `ways` to something on the order of `256` or whatever your RAM constraints - /// allow. - /// - /// @param way_size is the maximum allowed amount of elements per way. When - /// the size of a way reaches this number, existing elements are deleted - /// according to the LRU policy. - /// - /// The maximum total number of elements is `ways * way_size`. - NWayLRU(size_t ways, size_t way_size, const Hash& hash = Hash(), - const Equal& equal = Equal()); - - void Put(const T& key, U value); - - template - std::optional Get(const T& key, Validator validator); - - std::optional Get(const T& key) { - return Get(key, [](const U&) { return true; }); - } +public: + /// @param ways is the number of ways (a.k.a. shards, internal hash-maps), + /// into which elements are distributed based on their hash. Each shard is + /// protected by an individual mutex. Larger `ways` means more internal + /// hash-map instances and more memory usage, but less contention. A good + /// starting point is `ways=16`. If you encounter contention, you can increase + /// `ways` to something on the order of `256` or whatever your RAM constraints + /// allow. + /// + /// @param way_size is the maximum allowed amount of elements per way. When + /// the size of a way reaches this number, existing elements are deleted + /// according to the LRU policy. + /// + /// The maximum total number of elements is `ways * way_size`. + NWayLRU(size_t ways, size_t way_size, const Hash& hash = Hash(), const Equal& equal = Equal()); + + void Put(const T& key, U value); + + template + std::optional Get(const T& key, Validator validator); + + std::optional Get(const T& key) { + return Get(key, [](const U&) { return true; }); + } - U GetOr(const T& key, const U& default_value); + U GetOr(const T& key, const U& default_value); - void Invalidate(); + void Invalidate(); - void InvalidateByKey(const T& key); + void InvalidateByKey(const T& key); - /// Iterates over all items. May be slow for big caches. - template - void VisitAll(Function func) const; + /// Iterates over all items. May be slow for big caches. + template + void VisitAll(Function func) const; - size_t GetSize() const; + size_t GetSize() const; - /// For the description of `way_size`, - /// see the cache::NWayLRU::NWayLRU constructor. - void UpdateWaySize(size_t way_size); + /// For the description of `way_size`, + /// see the cache::NWayLRU::NWayLRU constructor. + void UpdateWaySize(size_t way_size); - void Write(dump::Writer& writer) const; - void Read(dump::Reader& reader); + void Write(dump::Writer& writer) const; + void Read(dump::Reader& reader); - /// The dump::Dumper will be notified of any cache updates. This method is not - /// thread-safe. - void SetDumper(std::shared_ptr dumper); + /// The dump::Dumper will be notified of any cache updates. This method is not + /// thread-safe. + void SetDumper(std::shared_ptr dumper); - private: - struct Way { - Way(Way&& other) noexcept : cache(std::move(other.cache)) {} +private: + struct Way { + Way(Way&& other) noexcept : cache(std::move(other.cache)) {} - // max_size is not used, will be reset by Resize() in NWayLRU::NWayLRU - Way(const Hash& hash, const Equal& equal) : cache(1, hash, equal) {} + // max_size is not used, will be reset by Resize() in NWayLRU::NWayLRU + Way(const Hash& hash, const Equal& equal) : cache(1, hash, equal) {} - mutable engine::Mutex mutex; - LruMap cache; - }; + mutable engine::Mutex mutex; + LruMap cache; + }; - Way& GetWay(const T& key); + Way& GetWay(const T& key); - void NotifyDumper(); + void NotifyDumper(); - std::vector caches_; - Hash hash_fn_; - std::shared_ptr dumper_{nullptr}; + std::vector caches_; + Hash hash_fn_; + std::shared_ptr dumper_{nullptr}; }; template -NWayLRU::NWayLRU(size_t ways, size_t way_size, const Hash& hash, - const Eq& equal) +NWayLRU::NWayLRU(size_t ways, size_t way_size, const Hash& hash, const Eq& equal) : caches_(), hash_fn_(hash) { - caches_.reserve(ways); - for (size_t i = 0; i < ways; ++i) caches_.emplace_back(hash, equal); - if (ways == 0) throw std::logic_error("Ways must be positive"); + caches_.reserve(ways); + for (size_t i = 0; i < ways; ++i) caches_.emplace_back(hash, equal); + if (ways == 0) throw std::logic_error("Ways must be positive"); - for (auto& way : caches_) way.cache.SetMaxSize(way_size); + for (auto& way : caches_) way.cache.SetMaxSize(way_size); } template void NWayLRU::Put(const T& key, U value) { - auto& way = GetWay(key); - { - std::unique_lock lock(way.mutex); - way.cache.Put(key, std::move(value)); - } - NotifyDumper(); + auto& way = GetWay(key); + { + std::unique_lock lock(way.mutex); + way.cache.Put(key, std::move(value)); + } + NotifyDumper(); } template template -std::optional NWayLRU::Get(const T& key, - Validator validator) { - auto& way = GetWay(key); - std::unique_lock lock(way.mutex); - auto* value = way.cache.Get(key); - - if (value) { - if (validator(*value)) return *value; - way.cache.Erase(key); - } - - return std::nullopt; +std::optional NWayLRU::Get(const T& key, Validator validator) { + auto& way = GetWay(key); + std::unique_lock lock(way.mutex); + auto* value = way.cache.Get(key); + + if (value) { + if (validator(*value)) return *value; + way.cache.Erase(key); + } + + return std::nullopt; } template void NWayLRU::InvalidateByKey(const T& key) { - auto& way = GetWay(key); - { - std::unique_lock lock(way.mutex); - way.cache.Erase(key); - } - NotifyDumper(); + auto& way = GetWay(key); + { + std::unique_lock lock(way.mutex); + way.cache.Erase(key); + } + NotifyDumper(); } template U NWayLRU::GetOr(const T& key, const U& default_value) { - auto& way = GetWay(key); - std::unique_lock lock(way.mutex); - return way.cache.GetOr(key, default_value); + auto& way = GetWay(key); + std::unique_lock lock(way.mutex); + return way.cache.GetOr(key, default_value); } template void NWayLRU::Invalidate() { - for (auto& way : caches_) { - std::unique_lock lock(way.mutex); - way.cache.Clear(); - } - NotifyDumper(); + for (auto& way : caches_) { + std::unique_lock lock(way.mutex); + way.cache.Clear(); + } + NotifyDumper(); } template template void NWayLRU::VisitAll(Function func) const { - for (const auto& way : caches_) { - std::unique_lock lock(way.mutex); - way.cache.VisitAll(func); - } + for (const auto& way : caches_) { + std::unique_lock lock(way.mutex); + way.cache.VisitAll(func); + } } template size_t NWayLRU::GetSize() const { - size_t size{0}; - for (const auto& way : caches_) { - std::unique_lock lock(way.mutex); - size += way.cache.GetSize(); - } - return size; + size_t size{0}; + for (const auto& way : caches_) { + std::unique_lock lock(way.mutex); + size += way.cache.GetSize(); + } + return size; } template void NWayLRU::UpdateWaySize(size_t way_size) { - for (auto& way : caches_) { - std::unique_lock lock(way.mutex); - way.cache.SetMaxSize(way_size); - } + for (auto& way : caches_) { + std::unique_lock lock(way.mutex); + way.cache.SetMaxSize(way_size); + } } template -typename NWayLRU::Way& NWayLRU::GetWay( - const T& key) { - /// It is needed to twist hash because there is hash map in LruMap. Otherwise - /// nodes will fall into one bucket. According to - /// https://www.boost.org/doc/libs/1_83_0/libs/container_hash/doc/html/hash.html#notes_hash_combine - /// hash_combine can be treated as hash itself - auto seed = hash_fn_(key); - boost::hash_combine(seed, 0); - auto n = seed % caches_.size(); - return caches_[n]; +typename NWayLRU::Way& NWayLRU::GetWay(const T& key) { + /// It is needed to twist hash because there is hash map in LruMap. Otherwise + /// nodes will fall into one bucket. According to + /// https://www.boost.org/doc/libs/1_83_0/libs/container_hash/doc/html/hash.html#notes_hash_combine + /// hash_combine can be treated as hash itself + auto seed = hash_fn_(key); + boost::hash_combine(seed, 0); + auto n = seed % caches_.size(); + return caches_[n]; } template void NWayLRU::Write(dump::Writer& writer) const { - writer.Write(caches_.size()); + writer.Write(caches_.size()); - for (const Way& way : caches_) { - std::unique_lock lock(way.mutex); + for (const Way& way : caches_) { + std::unique_lock lock(way.mutex); - writer.Write(way.cache.GetSize()); + writer.Write(way.cache.GetSize()); - way.cache.VisitAll([&writer](const T& key, const U& value) { - writer.Write(key); - writer.Write(value); - }); - } + way.cache.VisitAll([&writer](const T& key, const U& value) { + writer.Write(key); + writer.Write(value); + }); + } } template void NWayLRU::Read(dump::Reader& reader) { - Invalidate(); - - const auto ways = reader.Read(); - for (std::size_t i = 0; i < ways; ++i) { - const auto elements_in_way = reader.Read(); - for (std::size_t j = 0; j < elements_in_way; ++j) { - auto key = reader.Read(); - auto value = reader.Read(); - Put(std::move(key), std::move(value)); + Invalidate(); + + const auto ways = reader.Read(); + for (std::size_t i = 0; i < ways; ++i) { + const auto elements_in_way = reader.Read(); + for (std::size_t j = 0; j < elements_in_way; ++j) { + auto key = reader.Read(); + auto value = reader.Read(); + Put(std::move(key), std::move(value)); + } } - } } template void NWayLRU::NotifyDumper() { - if (dumper_ != nullptr) { - dumper_->OnUpdateCompleted(); - } + if (dumper_ != nullptr) { + dumper_->OnUpdateCompleted(); + } } template -void NWayLRU::SetDumper( - std::shared_ptr dumper) { - dumper_ = std::move(dumper); +void NWayLRU::SetDumper(std::shared_ptr dumper) { + dumper_ = std::move(dumper); } } // namespace cache diff --git a/core/include/userver/cache/update_type.hpp b/core/include/userver/cache/update_type.hpp index 02f786c40cc0..b570176a6dd2 100644 --- a/core/include/userver/cache/update_type.hpp +++ b/core/include/userver/cache/update_type.hpp @@ -14,24 +14,22 @@ namespace cache { /// Type of `CachingComponentBase` update enum class UpdateType { - kFull, ///< requests all the items, starting from scratch - kIncremental, ///< requests only newly updated items + kFull, ///< requests all the items, starting from scratch + kIncremental, ///< requests only newly updated items }; -UpdateType Parse(const formats::json::Value& value, - formats::parse::To); +UpdateType Parse(const formats::json::Value& value, formats::parse::To); std::string_view ToString(UpdateType update_type); /// Update types allowed for a `CachingComponentBase` instance by static config enum class AllowedUpdateTypes { - kFullAndIncremental, - kOnlyFull, - kOnlyIncremental, + kFullAndIncremental, + kOnlyFull, + kOnlyIncremental, }; -AllowedUpdateTypes Parse(const yaml_config::YamlConfig& value, - formats::parse::To); +AllowedUpdateTypes Parse(const yaml_config::YamlConfig& value, formats::parse::To); std::string_view ToString(AllowedUpdateTypes allowed_update_types); diff --git a/core/include/userver/clients/dns/component.hpp b/core/include/userver/clients/dns/component.hpp index 77509503aa41..673e0005041a 100644 --- a/core/include/userver/clients/dns/component.hpp +++ b/core/include/userver/clients/dns/component.hpp @@ -40,23 +40,22 @@ namespace clients::dns { // clang-format on class Component final : public components::ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of clients::dns::Component component - static constexpr std::string_view kName = "dns-client"; +public: + /// @ingroup userver_component_names + /// @brief The default name of clients::dns::Component component + static constexpr std::string_view kName = "dns-client"; - Component(const components::ComponentConfig&, - const components::ComponentContext&); + Component(const components::ComponentConfig&, const components::ComponentContext&); - Resolver& GetResolver(); + Resolver& GetResolver(); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - void Write(utils::statistics::Writer& writer); +private: + void Write(utils::statistics::Writer& writer); - Resolver resolver_; - utils::statistics::Entry statistics_holder_; + Resolver resolver_; + utils::statistics::Entry statistics_holder_; }; } // namespace clients::dns diff --git a/core/include/userver/clients/dns/config.hpp b/core/include/userver/clients/dns/config.hpp index cf4603677ae6..b97cedfc738c 100644 --- a/core/include/userver/clients/dns/config.hpp +++ b/core/include/userver/clients/dns/config.hpp @@ -13,32 +13,32 @@ namespace clients::dns { /// Caching DNS resolver static configuration. struct ResolverConfig { - /// hosts file path - std::string file_path{"/etc/hosts"}; + /// hosts file path + std::string file_path{"/etc/hosts"}; - /// hosts file update interval - std::chrono::milliseconds file_update_interval{std::chrono::minutes{5}}; + /// hosts file update interval + std::chrono::milliseconds file_update_interval{std::chrono::minutes{5}}; - /// Network query timeout - std::chrono::milliseconds network_timeout{std::chrono::seconds{1}}; + /// Network query timeout + std::chrono::milliseconds network_timeout{std::chrono::seconds{1}}; - /// Network query attempts - int network_attempts{1}; + /// Network query attempts + int network_attempts{1}; - /// Custom name servers list (system-wide resolvers used if empty) - std::vector network_custom_servers; + /// Custom name servers list (system-wide resolvers used if empty) + std::vector network_custom_servers; - /// Network cache ways - size_t cache_ways{16}; + /// Network cache ways + size_t cache_ways{16}; - /// Network cache size per way - size_t cache_size_per_way{256}; + /// Network cache size per way + size_t cache_size_per_way{256}; - /// Network cache upper reply TTL limit - std::chrono::milliseconds cache_max_reply_ttl{std::chrono::minutes{5}}; + /// Network cache upper reply TTL limit + std::chrono::milliseconds cache_max_reply_ttl{std::chrono::minutes{5}}; - /// Network cache failure TTL - std::chrono::milliseconds cache_failure_ttl{std::chrono::seconds{5}}; + /// Network cache failure TTL + std::chrono::milliseconds cache_failure_ttl{std::chrono::seconds{5}}; }; } // namespace clients::dns diff --git a/core/include/userver/clients/dns/exception.hpp b/core/include/userver/clients/dns/exception.hpp index fe4c48c97837..3e75129b5a14 100644 --- a/core/include/userver/clients/dns/exception.hpp +++ b/core/include/userver/clients/dns/exception.hpp @@ -11,26 +11,26 @@ namespace clients::dns { /// Generic resolver error class ResolverException : public std::runtime_error { - public: - using std::runtime_error::runtime_error; +public: + using std::runtime_error::runtime_error; }; /// Unsupported domain error class UnsupportedDomainException : public ResolverException { - public: - using ResolverException::ResolverException; +public: + using ResolverException::ResolverException; }; /// Host resolution error class NotResolvedException : public ResolverException { - public: - using ResolverException::ResolverException; +public: + using ResolverException::ResolverException; }; /// Configuration error class InvalidConfigException : public ResolverException { - public: - using ResolverException::ResolverException; +public: + using ResolverException::ResolverException; }; } // namespace clients::dns diff --git a/core/include/userver/clients/dns/resolver.hpp b/core/include/userver/clients/dns/resolver.hpp index 826d4dba7e3e..bc71f52edc70 100644 --- a/core/include/userver/clients/dns/resolver.hpp +++ b/core/include/userver/clients/dns/resolver.hpp @@ -24,50 +24,49 @@ namespace clients::dns { /// /// Combines file-based (/etc/hosts) name resolution with network-based one. class Resolver { - public: - struct LookupSourceCounters { - utils::statistics::RelaxedCounter file{0}; - utils::statistics::RelaxedCounter cached{0}; - utils::statistics::RelaxedCounter cached_stale{0}; - utils::statistics::RelaxedCounter cached_failure{0}; - utils::statistics::RelaxedCounter network{0}; - utils::statistics::RelaxedCounter network_failure{0}; - }; +public: + struct LookupSourceCounters { + utils::statistics::RelaxedCounter file{0}; + utils::statistics::RelaxedCounter cached{0}; + utils::statistics::RelaxedCounter cached_stale{0}; + utils::statistics::RelaxedCounter cached_failure{0}; + utils::statistics::RelaxedCounter network{0}; + utils::statistics::RelaxedCounter network_failure{0}; + }; - Resolver(engine::TaskProcessor& fs_task_processor, - const ResolverConfig& config); - Resolver(const Resolver&) = delete; - Resolver(Resolver&&) = delete; - ~Resolver(); + Resolver(engine::TaskProcessor& fs_task_processor, const ResolverConfig& config); + Resolver(const Resolver&) = delete; + Resolver(Resolver&&) = delete; + ~Resolver(); - /// Performs a domain name resolution. - /// - /// Sources are tried in the following order: - /// - Cached file lookup table - /// - Cached network resolution results - /// - Network name servers - /// - /// @throws clients::dns::NotResolvedException if none of the sources provide - /// a result within the specified deadline. - AddrVector Resolve(const std::string& name, engine::Deadline deadline); + /// Performs a domain name resolution. + /// + /// Sources are tried in the following order: + /// - Cached file lookup table + /// - Cached network resolution results + /// - Network name servers + /// + /// @throws clients::dns::NotResolvedException if none of the sources provide + /// a result within the specified deadline. + AddrVector Resolve(const std::string& name, engine::Deadline deadline); - /// Returns lookup source counters. - const LookupSourceCounters& GetLookupSourceCounters() const; + /// Returns lookup source counters. + const LookupSourceCounters& GetLookupSourceCounters() const; - /// Forces the reload of lookup table file. Waits until the reload is done. - void ReloadHosts(); + /// Forces the reload of lookup table file. Waits until the reload is done. + void ReloadHosts(); - /// Resets the network results cache. - void FlushNetworkCache(); + /// Resets the network results cache. + void FlushNetworkCache(); - /// Removes the specified domain name from the network results cache. - void FlushNetworkCache(const std::string& name); + /// Removes the specified domain name from the network results cache. + void FlushNetworkCache(const std::string& name); - private: - class Impl; - constexpr static size_t kSize = 1728; - constexpr static size_t kAlignment = 16; - utils::FastPimpl impl_; +private: + class Impl; + constexpr static size_t kSize = 1728; + constexpr static size_t kAlignment = 16; + utils::FastPimpl impl_; }; } // namespace clients::dns diff --git a/core/include/userver/clients/dns/resolver_utils.hpp b/core/include/userver/clients/dns/resolver_utils.hpp index 3f5a7cd50442..e0075520ae4b 100644 --- a/core/include/userver/clients/dns/resolver_utils.hpp +++ b/core/include/userver/clients/dns/resolver_utils.hpp @@ -10,8 +10,8 @@ namespace clients::dns { /// Resolver types used by the components enum class ResolverType { - kGetaddrinfo, ///< resolve hosts using blocking getaddrinfo call - kAsync, ///< use non-blocking resolver + kGetaddrinfo, ///< resolve hosts using blocking getaddrinfo call + kAsync, ///< use non-blocking resolver }; /// Returns pointer to asynchronous resolver interface if required by config @@ -20,7 +20,8 @@ enum class ResolverType { clients::dns::Resolver* GetResolverPtr( const components::ComponentConfig& config, const components::ComponentContext& context, - ResolverType default_type = ResolverType::kAsync); + ResolverType default_type = ResolverType::kAsync +); } // namespace clients::dns diff --git a/core/include/userver/clients/http/client.hpp b/core/include/userver/clients/http/client.hpp index be8b5b259136..eefe720fcdd0 100644 --- a/core/include/userver/clients/http/client.hpp +++ b/core/include/userver/clients/http/client.hpp @@ -61,120 +61,118 @@ class DestinationStatistics; /// /// @snippet clients/http/client_test.cpp Sample HTTP Client usage class Client final { - public: - Client(ClientSettings settings, engine::TaskProcessor& fs_task_processor, - impl::PluginPipeline&& plugin_pipeline); - - ~Client(); +public: + Client(ClientSettings settings, engine::TaskProcessor& fs_task_processor, impl::PluginPipeline&& plugin_pipeline); - /// @brief Returns a HTTP request builder type with preset values of - /// User-Agent, Proxy and some of the Testsuite suff (if any). - /// - /// @note This method is thread-safe despite being non-const. - Request CreateRequest(); + ~Client(); - /// Providing CreateNonSignedRequest() function for the clients::Http alias. - /// - /// @note This method is thread-safe despite being non-const. - Request CreateNotSignedRequest() { return CreateRequest(); } + /// @brief Returns a HTTP request builder type with preset values of + /// User-Agent, Proxy and some of the Testsuite suff (if any). + /// + /// @note This method is thread-safe despite being non-const. + Request CreateRequest(); - /// @cond - // For internal use only. - void SetMultiplexingEnabled(bool enabled); + /// Providing CreateNonSignedRequest() function for the clients::Http alias. + /// + /// @note This method is thread-safe despite being non-const. + Request CreateNotSignedRequest() { return CreateRequest(); } - // For internal use only. - void SetMaxHostConnections(size_t max_host_connections); + /// @cond + // For internal use only. + void SetMultiplexingEnabled(bool enabled); - // For internal use only. - PoolStatistics GetPoolStatistics() const; + // For internal use only. + void SetMaxHostConnections(size_t max_host_connections); - // Set max number of automatically created destination metrics. - // For internal use only. - void SetDestinationMetricsAutoMaxSize(size_t max_size); + // For internal use only. + PoolStatistics GetPoolStatistics() const; - // For internal use only. - const http::DestinationStatistics& GetDestinationStatistics() const; + // Set max number of automatically created destination metrics. + // For internal use only. + void SetDestinationMetricsAutoMaxSize(size_t max_size); - // For internal use only. - void SetTestsuiteConfig(const TestsuiteConfig& config); + // For internal use only. + const http::DestinationStatistics& GetDestinationStatistics() const; - // For internal use only. - void SetAllowedUrlsExtra(std::vector&& urls); + // For internal use only. + void SetTestsuiteConfig(const TestsuiteConfig& config); - // For internal use only. - void SetConfig(const impl::Config&); - /// @endcond + // For internal use only. + void SetAllowedUrlsExtra(std::vector&& urls); - /// @brief Sets User-Agent headers for all the requests or removes that - /// header. - /// - /// By default User-Agent is set by components::HttpClient to the - /// userver identity string. - void ResetUserAgent(std::optional user_agent = std::nullopt); + // For internal use only. + void SetConfig(const impl::Config&); + /// @endcond - /// @brief Returns the current proxy that is automatically used for each - /// request. - /// - /// @warning The value may become immediately obsolete as the proxy could be - /// concurrently changed from runtime config. - std::string GetProxy() const; + /// @brief Sets User-Agent headers for all the requests or removes that + /// header. + /// + /// By default User-Agent is set by components::HttpClient to the + /// userver identity string. + void ResetUserAgent(std::optional user_agent = std::nullopt); - /// @brief Sets the DNS resolver to use. - /// - /// If given nullptr, the default resolver will be used - /// (most likely getaddrinfo). - void SetDnsResolver(clients::dns::Resolver* resolver); + /// @brief Returns the current proxy that is automatically used for each + /// request. + /// + /// @warning The value may become immediately obsolete as the proxy could be + /// concurrently changed from runtime config. + std::string GetProxy() const; - private: - void ReinitEasy(); + /// @brief Sets the DNS resolver to use. + /// + /// If given nullptr, the default resolver will be used + /// (most likely getaddrinfo). + void SetDnsResolver(clients::dns::Resolver* resolver); - InstanceStatistics GetMultiStatistics(size_t n) const; +private: + void ReinitEasy(); - size_t FindMultiIndex(const curl::multi*) const; + InstanceStatistics GetMultiStatistics(size_t n) const; - // Functions for EasyWrapper that must be noexcept, as they are called from - // the EasyWrapper destructor. - friend class impl::EasyWrapper; - void IncPending() noexcept { ++pending_tasks_; } - void DecPending() noexcept { --pending_tasks_; } - void PushIdleEasy(std::shared_ptr&& easy) noexcept; + size_t FindMultiIndex(const curl::multi*) const; - std::shared_ptr TryDequeueIdle() noexcept; + // Functions for EasyWrapper that must be noexcept, as they are called from + // the EasyWrapper destructor. + friend class impl::EasyWrapper; + void IncPending() noexcept { ++pending_tasks_; } + void DecPending() noexcept { --pending_tasks_; } + void PushIdleEasy(std::shared_ptr&& easy) noexcept; - std::atomic pending_tasks_{0}; + std::shared_ptr TryDequeueIdle() noexcept; - const DeadlinePropagationConfig deadline_propagation_config_; - CancellationPolicy cancellation_policy_; + std::atomic pending_tasks_{0}; - std::shared_ptr destination_statistics_; - std::unique_ptr thread_pool_; - std::vector statistics_; - std::vector> multis_; + const DeadlinePropagationConfig deadline_propagation_config_; + CancellationPolicy cancellation_policy_; - static constexpr size_t kIdleQueueSize = 616; - static constexpr size_t kIdleQueueAlignment = 8; - using IdleQueueTraits = moodycamel::ConcurrentQueueDefaultTraits; - using IdleQueueValue = std::shared_ptr; - using IdleQueue = - moodycamel::ConcurrentQueue; - utils::FastPimpl idle_queue_; + std::shared_ptr destination_statistics_; + std::unique_ptr thread_pool_; + std::vector statistics_; + std::vector> multis_; - engine::TaskProcessor& fs_task_processor_; - std::optional user_agent_; - rcu::Variable proxy_; + static constexpr size_t kIdleQueueSize = 616; + static constexpr size_t kIdleQueueAlignment = 8; + using IdleQueueTraits = moodycamel::ConcurrentQueueDefaultTraits; + using IdleQueueValue = std::shared_ptr; + using IdleQueue = moodycamel::ConcurrentQueue; + utils::FastPimpl idle_queue_; - utils::SwappingSmart easy_; - utils::PeriodicTask easy_reinit_task_; + engine::TaskProcessor& fs_task_processor_; + std::optional user_agent_; + rcu::Variable proxy_; - // Testsuite support - std::shared_ptr testsuite_config_; - rcu::Variable> allowed_urls_extra_; + utils::SwappingSmart easy_; + utils::PeriodicTask easy_reinit_task_; - std::shared_ptr connect_rate_limiter_; + // Testsuite support + std::shared_ptr testsuite_config_; + rcu::Variable> allowed_urls_extra_; - clients::dns::Resolver* resolver_{nullptr}; - utils::NotNull tracing_manager_; - impl::PluginPipeline plugin_pipeline_; + std::shared_ptr connect_rate_limiter_; + + clients::dns::Resolver* resolver_{nullptr}; + utils::NotNull tracing_manager_; + impl::PluginPipeline plugin_pipeline_; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/component.hpp b/core/include/userver/clients/http/component.hpp index fd4be2408893..310c41f0e143 100644 --- a/core/include/userver/clients/http/component.hpp +++ b/core/include/userver/clients/http/component.hpp @@ -55,32 +55,31 @@ namespace components { // clang-format on class HttpClient final : public ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::HttpClient component - static constexpr std::string_view kName = "http-client"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::HttpClient component + static constexpr std::string_view kName = "http-client"; - HttpClient(const ComponentConfig&, const ComponentContext&); + HttpClient(const ComponentConfig&, const ComponentContext&); - ~HttpClient() override; + ~HttpClient() override; - clients::http::Client& GetHttpClient(); + clients::http::Client& GetHttpClient(); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - void OnConfigUpdate(const dynamic_config::Snapshot& config); +private: + void OnConfigUpdate(const dynamic_config::Snapshot& config); - void WriteStatistics(utils::statistics::Writer& writer); + void WriteStatistics(utils::statistics::Writer& writer); - static std::vector> FindPlugins( - const std::vector& names, - const components::ComponentContext& context); + static std::vector> + FindPlugins(const std::vector& names, const components::ComponentContext& context); - const bool disable_pool_stats_; - clients::http::Client http_client_; - concurrent::AsyncEventSubscriberScope subscriber_scope_; - utils::statistics::Entry statistics_holder_; + const bool disable_pool_stats_; + clients::http::Client http_client_; + concurrent::AsyncEventSubscriberScope subscriber_scope_; + utils::statistics::Entry statistics_holder_; }; template <> diff --git a/core/include/userver/clients/http/config.hpp b/core/include/userver/clients/http/config.hpp index b0f59ea09e79..7a694179bd1a 100644 --- a/core/include/userver/clients/http/config.hpp +++ b/core/include/userver/clients/http/config.hpp @@ -16,54 +16,51 @@ class TracingManagerBase; namespace clients::http { struct DeadlinePropagationConfig { - bool update_header{true}; + bool update_header{true}; }; enum class CancellationPolicy { - kIgnore, - kCancel, + kIgnore, + kCancel, }; -CancellationPolicy Parse(yaml_config::YamlConfig value, - formats::parse::To); +CancellationPolicy Parse(yaml_config::YamlConfig value, formats::parse::To); // Static config struct ClientSettings final { - std::string thread_name_prefix{}; - size_t io_threads{8}; - DeadlinePropagationConfig deadline_propagation{}; - const tracing::TracingManagerBase* tracing_manager{nullptr}; - CancellationPolicy cancellation_policy{CancellationPolicy::kCancel}; + std::string thread_name_prefix{}; + size_t io_threads{8}; + DeadlinePropagationConfig deadline_propagation{}; + const tracing::TracingManagerBase* tracing_manager{nullptr}; + CancellationPolicy cancellation_policy{CancellationPolicy::kCancel}; }; -ClientSettings Parse(const yaml_config::YamlConfig& value, - formats::parse::To); +ClientSettings Parse(const yaml_config::YamlConfig& value, formats::parse::To); } // namespace clients::http namespace clients::http::impl { struct ThrottleConfig final { - static constexpr size_t kNoLimit = -1; - - std::size_t http_connect_limit{kNoLimit}; - std::chrono::microseconds http_connect_rate{0}; - std::size_t https_connect_limit{kNoLimit}; - std::chrono::microseconds https_connect_rate{0}; - std::size_t per_host_connect_limit{kNoLimit}; - std::chrono::microseconds per_host_connect_rate{0}; + static constexpr size_t kNoLimit = -1; + + std::size_t http_connect_limit{kNoLimit}; + std::chrono::microseconds http_connect_rate{0}; + std::size_t https_connect_limit{kNoLimit}; + std::chrono::microseconds https_connect_rate{0}; + std::size_t per_host_connect_limit{kNoLimit}; + std::chrono::microseconds per_host_connect_rate{0}; }; -ThrottleConfig Parse(const formats::json::Value& value, - formats::parse::To); +ThrottleConfig Parse(const formats::json::Value& value, formats::parse::To); // Dynamic config struct Config final { - static constexpr std::size_t kDefaultConnectionPoolSize = 10000; + static constexpr std::size_t kDefaultConnectionPoolSize = 10000; - std::size_t connection_pool_size{kDefaultConnectionPoolSize}; - std::string proxy; - ThrottleConfig throttle; + std::size_t connection_pool_size{kDefaultConnectionPoolSize}; + std::string proxy; + ThrottleConfig throttle; }; Config ParseConfig(const dynamic_config::DocsMap& docs_map); diff --git a/core/include/userver/clients/http/connect_to.hpp b/core/include/userver/clients/http/connect_to.hpp index efa937a65297..22027f69f748 100644 --- a/core/include/userver/clients/http/connect_to.hpp +++ b/core/include/userver/clients/http/connect_to.hpp @@ -18,23 +18,23 @@ namespace clients::http { /// @warning ConnectTo passed to connect_to() must outlive http's Request as /// it holds curl's slist value. class ConnectTo final { - public: - ConnectTo(ConnectTo&&) noexcept; +public: + ConnectTo(ConnectTo&&) noexcept; - ConnectTo(const ConnectTo&) = delete; + ConnectTo(const ConnectTo&) = delete; - explicit ConnectTo(const std::string& value); + explicit ConnectTo(const std::string& value); - ~ConnectTo(); + ~ConnectTo(); - ConnectTo& operator=(const ConnectTo&) = delete; + ConnectTo& operator=(const ConnectTo&) = delete; - ConnectTo& operator=(ConnectTo&&) noexcept; + ConnectTo& operator=(ConnectTo&&) noexcept; - curl::native::curl_slist* GetUnderlying() const noexcept; + curl::native::curl_slist* GetUnderlying() const noexcept; - private: - curl::native::curl_slist* value_{nullptr}; +private: + curl::native::curl_slist* value_{nullptr}; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/error.hpp b/core/include/userver/clients/http/error.hpp index 37c6977fe83d..f44aff0e521e 100644 --- a/core/include/userver/clients/http/error.hpp +++ b/core/include/userver/clients/http/error.hpp @@ -14,123 +14,117 @@ namespace clients::http { /// Exception with string class BaseException : public std::exception { - public: - BaseException(std::string message, const LocalStats& stats, - ErrorKind error_kind) - : message_(std::move(message)), stats_(stats), error_kind_(error_kind) {} - ~BaseException() override = default; +public: + BaseException(std::string message, const LocalStats& stats, ErrorKind error_kind) + : message_(std::move(message)), stats_(stats), error_kind_(error_kind) {} + ~BaseException() override = default; - const char* what() const noexcept override { return message_.c_str(); } + const char* what() const noexcept override { return message_.c_str(); } - ErrorKind GetErrorKind() const { return error_kind_; } + ErrorKind GetErrorKind() const { return error_kind_; } - const LocalStats& GetStats() const { return stats_; } + const LocalStats& GetStats() const { return stats_; } - private: - std::string message_; - LocalStats stats_; - ErrorKind error_kind_; +private: + std::string message_; + LocalStats stats_; + ErrorKind error_kind_; }; /// Exception with string and error_code class BaseCodeException : public BaseException { - public: - BaseCodeException(std::error_code ec, std::string_view message, - std::string_view url, const LocalStats& stats); - ~BaseCodeException() override = default; +public: + BaseCodeException(std::error_code ec, std::string_view message, std::string_view url, const LocalStats& stats); + ~BaseCodeException() override = default; - const std::error_code& error_code() const noexcept { return ec_; } + const std::error_code& error_code() const noexcept { return ec_; } - private: - std::error_code ec_; +private: + std::error_code ec_; }; class TimeoutException : public BaseException { - public: - TimeoutException(std::string_view message, const LocalStats& stats); - ~TimeoutException() override = default; +public: + TimeoutException(std::string_view message, const LocalStats& stats); + ~TimeoutException() override = default; }; class CancelException : public BaseException { - public: - using BaseException::BaseException; - ~CancelException() override = default; +public: + using BaseException::BaseException; + ~CancelException() override = default; }; class SSLException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~SSLException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~SSLException() override = default; }; class TechnicalError : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~TechnicalError() override = default; +public: + using BaseCodeException::BaseCodeException; + ~TechnicalError() override = default; }; class BadArgumentException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~BadArgumentException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~BadArgumentException() override = default; }; class TooManyRedirectsException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~TooManyRedirectsException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~TooManyRedirectsException() override = default; }; class NetworkProblemException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~NetworkProblemException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~NetworkProblemException() override = default; }; class DNSProblemException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~DNSProblemException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~DNSProblemException() override = default; }; class AuthFailedException : public BaseCodeException { - public: - using BaseCodeException::BaseCodeException; - ~AuthFailedException() override = default; +public: + using BaseCodeException::BaseCodeException; + ~AuthFailedException() override = default; }; /// Base class for HttpClientException and HttpServerException class HttpException : public BaseException { - public: - HttpException(int code, const LocalStats& stats, std::string_view message, - ErrorKind error_kind); - ~HttpException() override = default; +public: + HttpException(int code, const LocalStats& stats, std::string_view message, ErrorKind error_kind); + ~HttpException() override = default; - int code() const { return code_; } + int code() const { return code_; } - private: - int code_; +private: + int code_; }; class HttpClientException : public HttpException { - public: - HttpClientException(int code, const LocalStats& stats); - HttpClientException(int code, const LocalStats& stats, - std::string_view message); - ~HttpClientException() override = default; +public: + HttpClientException(int code, const LocalStats& stats); + HttpClientException(int code, const LocalStats& stats, std::string_view message); + ~HttpClientException() override = default; }; class HttpServerException : public HttpException { - public: - HttpServerException(int code, const LocalStats& stats); - HttpServerException(int code, const LocalStats& stats, - std::string_view message); - ~HttpServerException() override = default; +public: + HttpServerException(int code, const LocalStats& stats); + HttpServerException(int code, const LocalStats& stats, std::string_view message); + ~HttpServerException() override = default; }; /// map error_code to exceptions -std::exception_ptr PrepareException(std::error_code ec, std::string_view url, - const LocalStats& stats); +std::exception_ptr PrepareException(std::error_code ec, std::string_view url, const LocalStats& stats); } // namespace clients::http diff --git a/core/include/userver/clients/http/error_kind.hpp b/core/include/userver/clients/http/error_kind.hpp index 971c82804725..636d5cd2d962 100644 --- a/core/include/userver/clients/http/error_kind.hpp +++ b/core/include/userver/clients/http/error_kind.hpp @@ -9,12 +9,12 @@ namespace clients::http { /// Additional tag to the exception. enum class ErrorKind { - kNetwork, // error during transportation - kDeadlinePropagation, // our own deadline exceeded - kTimeout, // timeout reached - kCancel, // task or request cancelled - kClient, // request was called with a bad parameter - kServer, // error on server side + kNetwork, // error during transportation + kDeadlinePropagation, // our own deadline exceeded + kTimeout, // timeout reached + kCancel, // task or request cancelled + kClient, // request was called with a bad parameter + kServer, // error on server side }; } // namespace clients::http diff --git a/core/include/userver/clients/http/form.hpp b/core/include/userver/clients/http/form.hpp index 35c4be55207d..8ebc08491800 100644 --- a/core/include/userver/clients/http/form.hpp +++ b/core/include/userver/clients/http/form.hpp @@ -12,32 +12,33 @@ class form; namespace clients::http { class Form final { - public: - Form(); - ~Form(); - - Form(const Form&) = delete; - Form(Form&&) noexcept; - Form& operator=(const Form&) = delete; - Form& operator=(Form&&) noexcept; - - void AddContent(std::string_view key, std::string_view content); - void AddContent(std::string_view key, std::string_view content, - const std::string& content_type); - - void AddBuffer(const std::string& key, const std::string& file_name, - const std::shared_ptr& buffer); - void AddBuffer(const std::string& key, const std::string& file_name, - const std::shared_ptr& buffer, - const std::string& content_type); - - /// @cond - // Call of this method will invalidate the form - std::unique_ptr GetNative() &&; - /// @endcond - - private: - std::unique_ptr impl_; +public: + Form(); + ~Form(); + + Form(const Form&) = delete; + Form(Form&&) noexcept; + Form& operator=(const Form&) = delete; + Form& operator=(Form&&) noexcept; + + void AddContent(std::string_view key, std::string_view content); + void AddContent(std::string_view key, std::string_view content, const std::string& content_type); + + void AddBuffer(const std::string& key, const std::string& file_name, const std::shared_ptr& buffer); + void AddBuffer( + const std::string& key, + const std::string& file_name, + const std::shared_ptr& buffer, + const std::string& content_type + ); + + /// @cond + // Call of this method will invalidate the form + std::unique_ptr GetNative() &&; + /// @endcond + +private: + std::unique_ptr impl_; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/local_stats.hpp b/core/include/userver/clients/http/local_stats.hpp index 7aaf2b689c5a..3db592f40919 100644 --- a/core/include/userver/clients/http/local_stats.hpp +++ b/core/include/userver/clients/http/local_stats.hpp @@ -9,22 +9,22 @@ namespace clients::http { /// Represents all the local timings and statistics struct LocalStats final { - using duration = std::chrono::steady_clock::time_point::duration; + using duration = std::chrono::steady_clock::time_point::duration; - duration time_to_connect{}; + duration time_to_connect{}; - /// total time - duration time_to_process{}; + /// total time + duration time_to_process{}; - size_t open_socket_count = 0; + size_t open_socket_count = 0; - /// returns 0 based retires count. In other words: - /// 0 - the very first request succeeded - /// 1 - made 1 retry - /// 2 - made 2 retries - /// ... - /// - size_t retries_count = 0; + /// returns 0 based retires count. In other words: + /// 0 - the very first request succeeded + /// 1 - made 1 retry + /// 2 - made 2 retries + /// ... + /// + size_t retries_count = 0; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/plugin.hpp b/core/include/userver/clients/http/plugin.hpp index b3e303fe9b64..6de4df3720d8 100644 --- a/core/include/userver/clients/http/plugin.hpp +++ b/core/include/userver/clients/http/plugin.hpp @@ -19,65 +19,65 @@ class Response; /// @brief Auxiliary entity that allows editing request to a client /// from plugins class PluginRequest final { - public: - /// @cond - explicit PluginRequest(RequestState& state); - /// @endcond +public: + /// @cond + explicit PluginRequest(RequestState& state); + /// @endcond - void SetHeader(std::string_view name, std::string_view value); + void SetHeader(std::string_view name, std::string_view value); - void AddQueryParams(std::string_view params); + void AddQueryParams(std::string_view params); - void SetTimeout(std::chrono::milliseconds ms); + void SetTimeout(std::chrono::milliseconds ms); - private: - RequestState& state_; +private: + RequestState& state_; }; /// @brief Base class for HTTP Client plugins class Plugin { - public: - explicit Plugin(std::string name); +public: + explicit Plugin(std::string name); - virtual ~Plugin() = default; + virtual ~Plugin() = default; - /// @brief Get plugin name - const std::string& GetName() const; + /// @brief Get plugin name + const std::string& GetName() const; - /// @brief The hook is called before actual HTTP request sending and before - /// DNS name resolution. You might want to use the hook for most of the - /// hook job. - virtual void HookPerformRequest(PluginRequest& request) = 0; + /// @brief The hook is called before actual HTTP request sending and before + /// DNS name resolution. You might want to use the hook for most of the + /// hook job. + virtual void HookPerformRequest(PluginRequest& request) = 0; - /// @brief The hook is called just after the "external" Span is created. - /// You might want to add custom tags from the hook. - virtual void HookCreateSpan(PluginRequest& request) = 0; + /// @brief The hook is called just after the "external" Span is created. + /// You might want to add custom tags from the hook. + virtual void HookCreateSpan(PluginRequest& request) = 0; - /// @brief The hook is called after the HTTP response is received or the - /// timeout is passed. - /// - /// @warning The hook is called in libev thread, not in coroutine context! Do - /// not do any heavy work here, offload it to other hooks. - virtual void HookOnCompleted(PluginRequest& request, Response& response) = 0; + /// @brief The hook is called after the HTTP response is received or the + /// timeout is passed. + /// + /// @warning The hook is called in libev thread, not in coroutine context! Do + /// not do any heavy work here, offload it to other hooks. + virtual void HookOnCompleted(PluginRequest& request, Response& response) = 0; - private: - const std::string name_; +private: + const std::string name_; }; namespace impl { class PluginPipeline final { - public: - PluginPipeline(const std::vector>& plugins); +public: + PluginPipeline(const std::vector>& plugins); - void HookPerformRequest(RequestState& request); + void HookPerformRequest(RequestState& request); - void HookCreateSpan(RequestState& request); + void HookCreateSpan(RequestState& request); - void HookOnCompleted(RequestState& request, Response& response); + void HookOnCompleted(RequestState& request, Response& response); - private: - const std::vector> plugins_; +private: + const std::vector> plugins_; }; } // namespace impl diff --git a/core/include/userver/clients/http/plugin_component.hpp b/core/include/userver/clients/http/plugin_component.hpp index 0180ce47c40c..c137d591f3e6 100644 --- a/core/include/userver/clients/http/plugin_component.hpp +++ b/core/include/userver/clients/http/plugin_component.hpp @@ -8,10 +8,10 @@ USERVER_NAMESPACE_BEGIN namespace clients::http::plugin { class ComponentBase : public components::ComponentBase { - public: - using components::ComponentBase::ComponentBase; +public: + using components::ComponentBase::ComponentBase; - virtual Plugin& GetPlugin() = 0; + virtual Plugin& GetPlugin() = 0; }; } // namespace clients::http::plugin diff --git a/core/include/userver/clients/http/plugins/headers_propagator/component.hpp b/core/include/userver/clients/http/plugins/headers_propagator/component.hpp index 558b725a4805..97b96290ff04 100644 --- a/core/include/userver/clients/http/plugins/headers_propagator/component.hpp +++ b/core/include/userver/clients/http/plugins/headers_propagator/component.hpp @@ -11,28 +11,25 @@ namespace clients::http::plugins::headers_propagator { class Plugin; class Component final : public plugin::ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of - /// clients::http::plugins::headers_propagator::Component component - static constexpr std::string_view kName = - "http-client-plugin-headers-propagator"; +public: + /// @ingroup userver_component_names + /// @brief The default name of + /// clients::http::plugins::headers_propagator::Component component + static constexpr std::string_view kName = "http-client-plugin-headers-propagator"; - Component(const components::ComponentConfig&, - const components::ComponentContext&); + Component(const components::ComponentConfig&, const components::ComponentContext&); - ~Component() override; + ~Component() override; - http::Plugin& GetPlugin() override; + http::Plugin& GetPlugin() override; - private: - std::unique_ptr plugin_; +private: + std::unique_ptr plugin_; }; } // namespace clients::http::plugins::headers_propagator template <> -inline constexpr bool components::kHasValidate< - clients::http::plugins::headers_propagator::Component> = true; +inline constexpr bool components::kHasValidate = true; USERVER_NAMESPACE_END diff --git a/core/include/userver/clients/http/plugins/yandex_tracing/component.hpp b/core/include/userver/clients/http/plugins/yandex_tracing/component.hpp index 5e371b211baa..9cdef3bafc1d 100644 --- a/core/include/userver/clients/http/plugins/yandex_tracing/component.hpp +++ b/core/include/userver/clients/http/plugins/yandex_tracing/component.hpp @@ -11,27 +11,25 @@ namespace clients::http::plugins::yandex_tracing { class Plugin; class Component final : public plugin::ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of - /// clients::http::plugins::yandex_tracing::Component component - static constexpr std::string_view kName = "http-client-plugin-yandex-tracing"; +public: + /// @ingroup userver_component_names + /// @brief The default name of + /// clients::http::plugins::yandex_tracing::Component component + static constexpr std::string_view kName = "http-client-plugin-yandex-tracing"; - Component(const components::ComponentConfig&, - const components::ComponentContext&); + Component(const components::ComponentConfig&, const components::ComponentContext&); - ~Component() override; + ~Component() override; - http::Plugin& GetPlugin() override; + http::Plugin& GetPlugin() override; - private: - std::unique_ptr plugin_; +private: + std::unique_ptr plugin_; }; } // namespace clients::http::plugins::yandex_tracing template <> -inline constexpr bool components::kHasValidate< - clients::http::plugins::yandex_tracing::Component> = true; +inline constexpr bool components::kHasValidate = true; USERVER_NAMESPACE_END diff --git a/core/include/userver/clients/http/request.hpp b/core/include/userver/clients/http/request.hpp index 567b73676dbe..f93d7b5d45a5 100644 --- a/core/include/userver/clients/http/request.hpp +++ b/core/include/userver/clients/http/request.hpp @@ -48,298 +48,282 @@ std::string_view ToStringView(HttpMethod method); using USERVER_NAMESPACE::http::HttpVersion; enum class HttpAuthType { - kBasic, ///< "basic" - kDigest, ///< "digest" - kDigestIE, ///< "digest_ie" - kNegotiate, ///< "negotiate" - kNtlm, ///< "ntlm" - kNtlmWb, ///< "ntlm_wb" - kAny, ///< "any" - kAnySafe, ///< "any_safe" + kBasic, ///< "basic" + kDigest, ///< "digest" + kDigestIE, ///< "digest_ie" + kNegotiate, ///< "negotiate" + kNtlm, ///< "ntlm" + kNtlmWb, ///< "ntlm_wb" + kAny, ///< "any" + kAnySafe, ///< "any_safe" }; enum class ProxyAuthType { - kBasic, ///< "basic" - kDigest, ///< "digest" - kDigestIE, ///< "digest_ie" - kBearer, ///< "bearer" - kNegotiate, ///< "negotiate" - kNtlm, ///< "ntlm" - kNtlmWb, ///< "ntlm_wb" - kAny, ///< "any" - kAnySafe, ///< "any_safe" + kBasic, ///< "basic" + kDigest, ///< "digest" + kDigestIE, ///< "digest_ie" + kBearer, ///< "bearer" + kNegotiate, ///< "negotiate" + kNtlm, ///< "ntlm" + kNtlmWb, ///< "ntlm_wb" + kAny, ///< "any" + kAnySafe, ///< "any_safe" }; ProxyAuthType ProxyAuthTypeFromString(const std::string& auth_name); /// Class for creating and performing new http requests class Request final { - public: - /// Request cookies container type - using Cookies = - std::unordered_map; - - /// @cond - // For internal use only. - explicit Request(impl::EasyWrapper&&, RequestStats&& req_stats, - const std::shared_ptr& dest_stats, - clients::dns::Resolver* resolver, - impl::PluginPipeline& plugin_pipeline, - const tracing::TracingManagerBase& tracing_manager); - /// @endcond - - /// Specifies method - Request& method(HttpMethod method) &; - Request method(HttpMethod method) &&; - /// GET request - Request& get() &; - Request get() &&; - /// GET request with url - Request& get(const std::string& url) &; - Request get(const std::string& url) &&; - /// HEAD request - Request& head() &; - Request head() &&; - /// HEAD request with url - Request& head(const std::string& url) &; - Request head(const std::string& url) &&; - /// POST request - Request& post() &; - Request post() &&; - /// POST request with url and data - Request& post(const std::string& url, std::string data = {}) &; - Request post(const std::string& url, std::string data = {}) &&; - /// POST request with url and multipart/form-data - Request& post(const std::string& url, Form&& form) &; - Request post(const std::string& url, Form&& form) &&; - /// PUT request - Request& put() &; - Request put() &&; - /// PUT request with url and data - Request& put(const std::string& url, std::string data = {}) &; - Request put(const std::string& url, std::string data = {}) &&; - - /// PATCH request - Request& patch() &; - Request patch() &&; - /// PATCH request with url and data - Request& patch(const std::string& url, std::string data = {}) &; - Request patch(const std::string& url, std::string data = {}) &&; - - /// DELETE request - Request& delete_method() &; - Request delete_method() &&; - /// DELETE request with url - Request& delete_method(const std::string& url) &; - Request delete_method(const std::string& url) &&; - /// DELETE request with url and data - Request& delete_method(const std::string& url, std::string data) &; - Request delete_method(const std::string& url, std::string data) &&; - - /// Set custom request method. Only replaces name of the HTTP method - Request& set_custom_http_request_method(std::string method) &; - Request set_custom_http_request_method(std::string method) &&; - - /// url if you don't specify request type with url - Request& url(const std::string& url) &; - Request url(const std::string& url) &&; - /// data for POST request - Request& data(std::string data) &; - Request data(std::string data) &&; - /// form for POST request - Request& form(Form&& form) &; - Request form(Form&& form) &&; - /// Headers for request as map - Request& headers(const Headers& headers) &; - Request headers(const Headers& headers) &&; - /// Headers for request as list - Request& headers(const std::initializer_list< - std::pair>& headers) &; - Request headers(const std::initializer_list< - std::pair>& headers) &&; - /// Sets http auth type to use. - Request& http_auth_type(HttpAuthType value, bool auth_only, - std::string_view user, std::string_view password) &; - Request http_auth_type(HttpAuthType value, bool auth_only, - std::string_view user, std::string_view password) &&; - /// Proxy headers for request as map - Request& proxy_headers(const Headers& headers) &; - Request proxy_headers(const Headers& headers) &&; - /// Proxy headers for request as list - Request& proxy_headers( - const std::initializer_list< - std::pair>& headers) &; - Request proxy_headers( - const std::initializer_list< - std::pair>& headers) &&; - /// Sets the User-Agent header - Request& user_agent(const std::string& value) &; - Request user_agent(const std::string& value) &&; - /// Sets proxy to use. Example: [::1]:1080 - Request& proxy(const std::string& value) &; - Request proxy(const std::string& value) &&; - /// Sets proxy auth type to use. - Request& proxy_auth_type(ProxyAuthType value) &; - Request proxy_auth_type(ProxyAuthType value) &&; - /// Cookies for request as HashDos-safe map - Request& cookies(const Cookies& cookies) &; - Request cookies(const Cookies& cookies) &&; - /// Cookies for request as map - Request& cookies( - const std::unordered_map& cookies) &; - Request cookies( - const std::unordered_map& cookies) &&; - /// Follow redirects or not. Default: follow - Request& follow_redirects(bool follow = true) &; - Request follow_redirects(bool follow = true) &&; - /// Set timeout in ms for request - Request& timeout(long timeout_ms) &; - Request timeout(long timeout_ms) &&; - Request& timeout(std::chrono::milliseconds timeout_ms) & { - return timeout(timeout_ms.count()); - } - Request timeout(std::chrono::milliseconds timeout_ms) && { - return std::move(this->timeout(timeout_ms.count())); - } - /// Verify host and peer or not. Default: verify - Request& verify(bool verify = true) &; - Request verify(bool verify = true) &&; - /// Set file holding one or more certificates to verify the peer with - Request& ca_info(const std::string& file_path) &; - Request ca_info(const std::string& file_path) &&; - /// Set CA - Request& ca(crypto::Certificate cert) &; - Request ca(crypto::Certificate cert) &&; - /// Set CRL-file - Request& crl_file(const std::string& file_path) &; - Request crl_file(const std::string& file_path) &&; - /// Set private client key and certificate for request. - /// - /// @warning Do not use this function on MacOS as it may cause Segmentation - /// Fault on that platform. - Request& client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert) &; - Request client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert) &&; - /// Set HTTP version - Request& http_version(HttpVersion version) &; - Request http_version(HttpVersion version) &&; - - /// Specify number of retries on incorrect status, if on_fails is True - /// retry on network error too. Retries = 3 means that maximum 3 request - /// will be performed. - /// - /// Retries use exponential backoff with jitter - an exponentially increasing - /// randomized delay is added before each retry of this request. - Request& retry(short retries = 3, bool on_fails = true) &; - Request retry(short retries = 3, bool on_fails = true) &&; - - /// Set unix domain socket as connection endpoint and provide path to it - /// When enabled, request will connect to the Unix domain socket instead - /// of establishing a TCP connection to a host. - Request& unix_socket_path(const std::string& path) &; - Request unix_socket_path(const std::string& path) &&; - - /// Set CURL_IPRESOLVE_V4 for ipv4 resolving - Request& use_ipv4() &; - Request use_ipv4() &&; - /// Set CURL_IPRESOLVE_V6 for ipv6 resolving - Request& use_ipv6() &; - Request use_ipv6() &&; - - /// Set CURLOPT_CONNECT_TO option - /// @warning connect_to argument must outlive Request - Request& connect_to(const ConnectTo& connect_to) &; - Request connect_to(const ConnectTo& connect_to) &&; - - template - std::enable_if_t, Request&> connect_to(T&&) { - static_assert( - !sizeof(T), - "ConnectTo argument must not be temporary, it must outlive Request"); - return *this; - } - - /// Override log URL. Useful for "there's a secret in the query". - /// @warning The query might be logged by other intermediate HTTP agents - /// (nginx, L7 balancer, etc.). - Request& SetLoggedUrl(std::string url) &; - Request SetLoggedUrl(std::string url) &&; - - /// Set destination name in metric "httpclient.destinations.". - /// If not set, defaults to HTTP path. Should be called for all requests - /// with parameters in HTTP path. - Request& SetDestinationMetricName(const std::string& destination) &; - Request SetDestinationMetricName(const std::string& destination) &&; - - /// @cond - // Set testsuite related settings. For internal use only. - void SetTestsuiteConfig( - const std::shared_ptr& config) &; - - void SetAllowedUrlsExtra(const std::vector& urls) &; - - // Set deadline propagation settings. For internal use only. - void SetDeadlinePropagationConfig( - const DeadlinePropagationConfig& deadline_propagation_config) &; - /// @endcond - - /// Disable auto-decoding of received replies. - /// Useful to proxy replies 'as is'. - Request& DisableReplyDecoding() &; - Request DisableReplyDecoding() &&; - - void SetCancellationPolicy(CancellationPolicy cp); - - /// Override the default tracing manager from HTTP client for this - /// particular request. - Request& SetTracingManager(const tracing::TracingManagerBase&) &; - Request SetTracingManager(const tracing::TracingManagerBase&) &&; - - /// Perform request asynchronously. - /// - /// Works well with engine::WaitAny, engine::WaitAnyFor, and - /// engine::WaitUntil functions: - /// @snippet src/clients/http/client_wait_test.cpp HTTP Client - waitany - /// - /// Request object could be reused after retrieval of data from - /// ResponseFuture, all the setup holds: - /// @snippet src/clients/http/client_test.cpp HTTP Client - reuse async - [[nodiscard]] ResponseFuture async_perform( - utils::impl::SourceLocation location = - utils::impl::SourceLocation::Current()); - - /// @brief Perform a request with streamed response body. - /// - /// The HTTP client uses queue producer. - /// StreamedResponse uses queue consumer. - [[nodiscard]] StreamedResponse async_perform_stream_body( - const std::shared_ptr& queue, - utils::impl::SourceLocation location = - utils::impl::SourceLocation::Current()); - - /// Calls async_perform and wait for timeout_ms on a future. Default time - /// for waiting will be timeout value if it was set. If error occurred it - /// will be thrown as exception. - /// - /// Request object could be reused after return from perform(), all the - /// setup holds: - /// @snippet src/clients/http/client_test.cpp HTTP Client - request reuse - [[nodiscard]] std::shared_ptr perform( - utils::impl::SourceLocation location = - utils::impl::SourceLocation::Current()); - - /// Returns a reference to the original URL of a request - const std::string& GetUrl() const&; - const std::string& GetUrl() && = delete; - - /// Returns a reference to the HTTP body of a request to send - const std::string& GetData() const&; - const std::string& GetData() && = delete; - - /// Returns HTTP body of a request, leaving it empty - std::string ExtractData(); - - private: - std::shared_ptr pimpl_; +public: + /// Request cookies container type + using Cookies = std::unordered_map; + + /// @cond + // For internal use only. + explicit Request( + impl::EasyWrapper&&, + RequestStats&& req_stats, + const std::shared_ptr& dest_stats, + clients::dns::Resolver* resolver, + impl::PluginPipeline& plugin_pipeline, + const tracing::TracingManagerBase& tracing_manager + ); + /// @endcond + + /// Specifies method + Request& method(HttpMethod method) &; + Request method(HttpMethod method) &&; + /// GET request + Request& get() &; + Request get() &&; + /// GET request with url + Request& get(const std::string& url) &; + Request get(const std::string& url) &&; + /// HEAD request + Request& head() &; + Request head() &&; + /// HEAD request with url + Request& head(const std::string& url) &; + Request head(const std::string& url) &&; + /// POST request + Request& post() &; + Request post() &&; + /// POST request with url and data + Request& post(const std::string& url, std::string data = {}) &; + Request post(const std::string& url, std::string data = {}) &&; + /// POST request with url and multipart/form-data + Request& post(const std::string& url, Form&& form) &; + Request post(const std::string& url, Form&& form) &&; + /// PUT request + Request& put() &; + Request put() &&; + /// PUT request with url and data + Request& put(const std::string& url, std::string data = {}) &; + Request put(const std::string& url, std::string data = {}) &&; + + /// PATCH request + Request& patch() &; + Request patch() &&; + /// PATCH request with url and data + Request& patch(const std::string& url, std::string data = {}) &; + Request patch(const std::string& url, std::string data = {}) &&; + + /// DELETE request + Request& delete_method() &; + Request delete_method() &&; + /// DELETE request with url + Request& delete_method(const std::string& url) &; + Request delete_method(const std::string& url) &&; + /// DELETE request with url and data + Request& delete_method(const std::string& url, std::string data) &; + Request delete_method(const std::string& url, std::string data) &&; + + /// Set custom request method. Only replaces name of the HTTP method + Request& set_custom_http_request_method(std::string method) &; + Request set_custom_http_request_method(std::string method) &&; + + /// url if you don't specify request type with url + Request& url(const std::string& url) &; + Request url(const std::string& url) &&; + /// data for POST request + Request& data(std::string data) &; + Request data(std::string data) &&; + /// form for POST request + Request& form(Form&& form) &; + Request form(Form&& form) &&; + /// Headers for request as map + Request& headers(const Headers& headers) &; + Request headers(const Headers& headers) &&; + /// Headers for request as list + Request& headers(const std::initializer_list>& headers) &; + Request headers(const std::initializer_list>& headers) &&; + /// Sets http auth type to use. + Request& http_auth_type(HttpAuthType value, bool auth_only, std::string_view user, std::string_view password) &; + Request http_auth_type(HttpAuthType value, bool auth_only, std::string_view user, std::string_view password) &&; + /// Proxy headers for request as map + Request& proxy_headers(const Headers& headers) &; + Request proxy_headers(const Headers& headers) &&; + /// Proxy headers for request as list + Request& proxy_headers(const std::initializer_list>& headers) &; + Request proxy_headers(const std::initializer_list>& headers) &&; + /// Sets the User-Agent header + Request& user_agent(const std::string& value) &; + Request user_agent(const std::string& value) &&; + /// Sets proxy to use. Example: [::1]:1080 + Request& proxy(const std::string& value) &; + Request proxy(const std::string& value) &&; + /// Sets proxy auth type to use. + Request& proxy_auth_type(ProxyAuthType value) &; + Request proxy_auth_type(ProxyAuthType value) &&; + /// Cookies for request as HashDos-safe map + Request& cookies(const Cookies& cookies) &; + Request cookies(const Cookies& cookies) &&; + /// Cookies for request as map + Request& cookies(const std::unordered_map& cookies) &; + Request cookies(const std::unordered_map& cookies) &&; + /// Follow redirects or not. Default: follow + Request& follow_redirects(bool follow = true) &; + Request follow_redirects(bool follow = true) &&; + /// Set timeout in ms for request + Request& timeout(long timeout_ms) &; + Request timeout(long timeout_ms) &&; + Request& timeout(std::chrono::milliseconds timeout_ms) & { return timeout(timeout_ms.count()); } + Request timeout(std::chrono::milliseconds timeout_ms) && { return std::move(this->timeout(timeout_ms.count())); } + /// Verify host and peer or not. Default: verify + Request& verify(bool verify = true) &; + Request verify(bool verify = true) &&; + /// Set file holding one or more certificates to verify the peer with + Request& ca_info(const std::string& file_path) &; + Request ca_info(const std::string& file_path) &&; + /// Set CA + Request& ca(crypto::Certificate cert) &; + Request ca(crypto::Certificate cert) &&; + /// Set CRL-file + Request& crl_file(const std::string& file_path) &; + Request crl_file(const std::string& file_path) &&; + /// Set private client key and certificate for request. + /// + /// @warning Do not use this function on MacOS as it may cause Segmentation + /// Fault on that platform. + Request& client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert) &; + Request client_key_cert(crypto::PrivateKey pkey, crypto::Certificate cert) &&; + /// Set HTTP version + Request& http_version(HttpVersion version) &; + Request http_version(HttpVersion version) &&; + + /// Specify number of retries on incorrect status, if on_fails is True + /// retry on network error too. Retries = 3 means that maximum 3 request + /// will be performed. + /// + /// Retries use exponential backoff with jitter - an exponentially increasing + /// randomized delay is added before each retry of this request. + Request& retry(short retries = 3, bool on_fails = true) &; + Request retry(short retries = 3, bool on_fails = true) &&; + + /// Set unix domain socket as connection endpoint and provide path to it + /// When enabled, request will connect to the Unix domain socket instead + /// of establishing a TCP connection to a host. + Request& unix_socket_path(const std::string& path) &; + Request unix_socket_path(const std::string& path) &&; + + /// Set CURL_IPRESOLVE_V4 for ipv4 resolving + Request& use_ipv4() &; + Request use_ipv4() &&; + /// Set CURL_IPRESOLVE_V6 for ipv6 resolving + Request& use_ipv6() &; + Request use_ipv6() &&; + + /// Set CURLOPT_CONNECT_TO option + /// @warning connect_to argument must outlive Request + Request& connect_to(const ConnectTo& connect_to) &; + Request connect_to(const ConnectTo& connect_to) &&; + + template + std::enable_if_t, Request&> connect_to(T&&) { + static_assert(!sizeof(T), "ConnectTo argument must not be temporary, it must outlive Request"); + return *this; + } + + /// Override log URL. Useful for "there's a secret in the query". + /// @warning The query might be logged by other intermediate HTTP agents + /// (nginx, L7 balancer, etc.). + Request& SetLoggedUrl(std::string url) &; + Request SetLoggedUrl(std::string url) &&; + + /// Set destination name in metric "httpclient.destinations.". + /// If not set, defaults to HTTP path. Should be called for all requests + /// with parameters in HTTP path. + Request& SetDestinationMetricName(const std::string& destination) &; + Request SetDestinationMetricName(const std::string& destination) &&; + + /// @cond + // Set testsuite related settings. For internal use only. + void SetTestsuiteConfig(const std::shared_ptr& config) &; + + void SetAllowedUrlsExtra(const std::vector& urls) &; + + // Set deadline propagation settings. For internal use only. + void SetDeadlinePropagationConfig(const DeadlinePropagationConfig& deadline_propagation_config) &; + /// @endcond + + /// Disable auto-decoding of received replies. + /// Useful to proxy replies 'as is'. + Request& DisableReplyDecoding() &; + Request DisableReplyDecoding() &&; + + void SetCancellationPolicy(CancellationPolicy cp); + + /// Override the default tracing manager from HTTP client for this + /// particular request. + Request& SetTracingManager(const tracing::TracingManagerBase&) &; + Request SetTracingManager(const tracing::TracingManagerBase&) &&; + + /// Perform request asynchronously. + /// + /// Works well with engine::WaitAny, engine::WaitAnyFor, and + /// engine::WaitUntil functions: + /// @snippet src/clients/http/client_wait_test.cpp HTTP Client - waitany + /// + /// Request object could be reused after retrieval of data from + /// ResponseFuture, all the setup holds: + /// @snippet src/clients/http/client_test.cpp HTTP Client - reuse async + [[nodiscard]] ResponseFuture async_perform( + utils::impl::SourceLocation location = utils::impl::SourceLocation::Current() + ); + + /// @brief Perform a request with streamed response body. + /// + /// The HTTP client uses queue producer. + /// StreamedResponse uses queue consumer. + [[nodiscard]] StreamedResponse async_perform_stream_body( + const std::shared_ptr& queue, + utils::impl::SourceLocation location = utils::impl::SourceLocation::Current() + ); + + /// Calls async_perform and wait for timeout_ms on a future. Default time + /// for waiting will be timeout value if it was set. If error occurred it + /// will be thrown as exception. + /// + /// Request object could be reused after return from perform(), all the + /// setup holds: + /// @snippet src/clients/http/client_test.cpp HTTP Client - request reuse + [[nodiscard]] std::shared_ptr perform( + utils::impl::SourceLocation location = utils::impl::SourceLocation::Current() + ); + + /// Returns a reference to the original URL of a request + const std::string& GetUrl() const&; + const std::string& GetUrl() && = delete; + + /// Returns a reference to the HTTP body of a request to send + const std::string& GetData() const&; + const std::string& GetData() && = delete; + + /// Returns HTTP body of a request, leaving it empty + std::string ExtractData(); + +private: + std::shared_ptr pimpl_; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/response.hpp b/core/include/userver/clients/http/response.hpp index 8027f22718d2..aade34e7ec02 100644 --- a/core/include/userver/clients/http/response.hpp +++ b/core/include/userver/clients/http/response.hpp @@ -23,50 +23,50 @@ using Headers = USERVER_NAMESPACE::http::headers::HeaderMap; /// Class that will be returned for successful request class Response final { - public: - using CookiesMap = server::http::Cookie::CookiesMap; +public: + using CookiesMap = server::http::Cookie::CookiesMap; - Response() = default; + Response() = default; - /// response string - std::string& sink_string() { return response_; } + /// response string + std::string& sink_string() { return response_; } - /// body as string - std::string body() const& { return response_; } - std::string&& body() && { return std::move(response_); } + /// body as string + std::string body() const& { return response_; } + std::string&& body() && { return std::move(response_); } - /// body as string_view - std::string_view body_view() const { return response_; } + /// body as string_view + std::string_view body_view() const { return response_; } - /// return reference to headers - const Headers& headers() const { return headers_; } - Headers& headers() { return headers_; } - const CookiesMap& cookies() const { return cookies_; } - CookiesMap& cookies() { return cookies_; } + /// return reference to headers + const Headers& headers() const { return headers_; } + Headers& headers() { return headers_; } + const CookiesMap& cookies() const { return cookies_; } + CookiesMap& cookies() { return cookies_; } - /// status_code - Status status_code() const; - /// check status code - bool IsOk() const { return status_code() == Status::OK; } - bool IsError() const { return static_cast(status_code()) >= 400; } + /// status_code + Status status_code() const; + /// check status code + bool IsOk() const { return status_code() == Status::OK; } + bool IsError() const { return static_cast(status_code()) >= 400; } - static void RaiseForStatus(int code, const LocalStats& stats); + static void RaiseForStatus(int code, const LocalStats& stats); - void raise_for_status() const; + void raise_for_status() const; - /// returns statistics on request execution like count of opened sockets, - /// connect time... - LocalStats GetStats() const; + /// returns statistics on request execution like count of opened sockets, + /// connect time... + LocalStats GetStats() const; - void SetStats(const LocalStats& stats) { stats_ = stats; } - void SetStatusCode(Status status_code) { status_code_ = status_code; } + void SetStats(const LocalStats& stats) { stats_ = stats; } + void SetStatusCode(Status status_code) { status_code_ = status_code; } - private: - Headers headers_; - CookiesMap cookies_; - std::string response_; - Status status_code_{Status::Invalid}; - LocalStats stats_; +private: + Headers headers_; + CookiesMap cookies_; + std::string response_; + Status status_code_{Status::Invalid}; + LocalStats stats_; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/response_future.hpp b/core/include/userver/clients/http/response_future.hpp index 3ac8c7bed4f8..d999ab4c7355 100644 --- a/core/include/userver/clients/http/response_future.hpp +++ b/core/include/userver/clients/http/response_future.hpp @@ -27,39 +27,38 @@ class EasyWrapper; /// @brief Allows to perform a request concurrently with other work without /// creating an extra coroutine for waiting. class ResponseFuture final { - public: - ResponseFuture(ResponseFuture&& other) noexcept; - ResponseFuture& operator=(ResponseFuture&&) noexcept; - ResponseFuture(const ResponseFuture&) = delete; - ResponseFuture& operator=(const ResponseFuture&) = delete; - ~ResponseFuture(); +public: + ResponseFuture(ResponseFuture&& other) noexcept; + ResponseFuture& operator=(ResponseFuture&&) noexcept; + ResponseFuture(const ResponseFuture&) = delete; + ResponseFuture& operator=(const ResponseFuture&) = delete; + ~ResponseFuture(); - void Cancel(); + void Cancel(); - void Detach(); + void Detach(); - std::future_status Wait(); + std::future_status Wait(); - std::shared_ptr Get(); + std::shared_ptr Get(); - void SetCancellationPolicy(CancellationPolicy cp); + void SetCancellationPolicy(CancellationPolicy cp); - /// @cond - /// Internal helper for WaitAny/WaitAll - engine::impl::ContextAccessor* TryGetContextAccessor() noexcept; + /// @cond + /// Internal helper for WaitAny/WaitAll + engine::impl::ContextAccessor* TryGetContextAccessor() noexcept; - ResponseFuture(engine::Future>&& future, - std::shared_ptr request); - /// @endcond + ResponseFuture(engine::Future>&& future, std::shared_ptr request); + /// @endcond - private: - void CancelOrDetach(); +private: + void CancelOrDetach(); - engine::Future> future_; - engine::Deadline deadline_; - std::shared_ptr request_state_; - bool was_deadline_propagated_{false}; - CancellationPolicy cancellation_policy_; + engine::Future> future_; + engine::Deadline deadline_; + std::shared_ptr request_state_; + bool was_deadline_propagated_{false}; + CancellationPolicy cancellation_policy_; }; } // namespace clients::http diff --git a/core/include/userver/clients/http/streamed_response.hpp b/core/include/userver/clients/http/streamed_response.hpp index 4115c1d6ff2e..043cd9661026 100644 --- a/core/include/userver/clients/http/streamed_response.hpp +++ b/core/include/userver/clients/http/streamed_response.hpp @@ -22,54 +22,56 @@ class RequestState; /// to get one. You can use it for fast proxying backend response body /// to a remote Application. class StreamedResponse final { - public: - StreamedResponse(StreamedResponse&&) = default; - StreamedResponse(const StreamedResponse&) = delete; - - StreamedResponse& operator=(StreamedResponse&&) = default; - StreamedResponse& operator=(const StreamedResponse&) = delete; - - /// @brief HTTP status code - /// @note may suspend the coroutine if the code is not obtained yet. - Status StatusCode(); - - /// Returns HTTP header value by its name (case-insensitive) - /// A missing key results in empty string - /// @note may suspend the coroutine if headers are not obtained yet. - std::string GetHeader(const std::string& header_name); - - /// Get all HTTP headers as a case-insensitive unordered map - /// @note may suspend the coroutine if headers are not obtained yet. - const Headers& GetHeaders(); - const Response::CookiesMap& GetCookies(); - - using Queue = concurrent::StringStreamQueue; - - /// Read another HTTP response body part into 'output'. - /// Any previous data in 'output' is dropped. - /// @note The chunk size is not guaranteed to be exactly - /// multipart/form-data chunk size or any other HTTP-related size - /// @note may block if the chunk is not obtained yet. - bool ReadChunk(std::string& output, engine::Deadline); - - /// @cond - StreamedResponse(engine::Future&& headers_future, - Queue::Consumer&& queue_consumer, - std::shared_ptr request_state); - /// @endcond - - private: - std::future_status WaitForHeaders(engine::Deadline); - - void WaitForHeadersOrThrow(engine::Deadline); - - std::shared_ptr request_state_; - // re-use sync response's headers & status code storage - std::shared_ptr response_; - engine::Deadline deadline_; - - engine::Future headers_future_; - Queue::Consumer queue_consumer_; +public: + StreamedResponse(StreamedResponse&&) = default; + StreamedResponse(const StreamedResponse&) = delete; + + StreamedResponse& operator=(StreamedResponse&&) = default; + StreamedResponse& operator=(const StreamedResponse&) = delete; + + /// @brief HTTP status code + /// @note may suspend the coroutine if the code is not obtained yet. + Status StatusCode(); + + /// Returns HTTP header value by its name (case-insensitive) + /// A missing key results in empty string + /// @note may suspend the coroutine if headers are not obtained yet. + std::string GetHeader(const std::string& header_name); + + /// Get all HTTP headers as a case-insensitive unordered map + /// @note may suspend the coroutine if headers are not obtained yet. + const Headers& GetHeaders(); + const Response::CookiesMap& GetCookies(); + + using Queue = concurrent::StringStreamQueue; + + /// Read another HTTP response body part into 'output'. + /// Any previous data in 'output' is dropped. + /// @note The chunk size is not guaranteed to be exactly + /// multipart/form-data chunk size or any other HTTP-related size + /// @note may block if the chunk is not obtained yet. + bool ReadChunk(std::string& output, engine::Deadline); + + /// @cond + StreamedResponse( + engine::Future&& headers_future, + Queue::Consumer&& queue_consumer, + std::shared_ptr request_state + ); + /// @endcond + +private: + std::future_status WaitForHeaders(engine::Deadline); + + void WaitForHeadersOrThrow(engine::Deadline); + + std::shared_ptr request_state_; + // re-use sync response's headers & status code storage + std::shared_ptr response_; + engine::Deadline deadline_; + + engine::Future headers_future_; + Queue::Consumer queue_consumer_; }; } // namespace clients::http diff --git a/core/include/userver/components/component_base.hpp b/core/include/userver/components/component_base.hpp index 21a8c2edcb5b..270935377c8e 100644 --- a/core/include/userver/components/component_base.hpp +++ b/core/include/userver/components/component_base.hpp @@ -17,56 +17,54 @@ namespace components { /// @brief Base class for all @ref userver_components "application components", /// it depends on components::Logger and components::Tracer. class ComponentBase : public RawComponentBase { - public: - ComponentBase(const ComponentConfig&, const ComponentContext&); - - ComponentBase(ComponentBase&&) = delete; - ComponentBase(const ComponentBase&) = delete; - - /// It is a good place to stop your work here. - /// All components dependent on the current component were destroyed. - /// All components on which the current component depends are still alive. - ~ComponentBase() override = default; - - /// Override this function to inform the world of the state of your - /// component. - /// - /// @warning The function is called concurrently from multiple threads. - ComponentHealth GetComponentHealth() const override { - return ComponentHealth::kOk; - } - - /// Called once if the creation of any other component failed. - /// If the current component expects some other component to take any action - /// with the current component, this call is a signal that such action may - /// never happen due to components loading was cancelled. - /// Application components might not want to override it. - void OnLoadingCancelled() override {} - - /// Component may use this function to finalize registration of other - /// components that depend on it (for example, handler components register - /// in server component, and the latter uses OnAllComponentsLoaded() to start - /// processing requests). - /// - /// Base components may override it and make `final` to do some work after the - /// derived object constructor is called. Don't use it otherwise. - void OnAllComponentsLoaded() override {} - - /// Component may use this function to stop doing work before the stop of the - /// components that depend on it. - /// - /// Base components may override it and make `final` to do some work before - /// the derived object constructor is called. Don't use it otherwise. - void OnAllComponentsAreStopping() override {} - - /// If the component pulls more options from @ref ComponentConfig than its - /// parent component, then it needs to define `GetStaticConfigSchema` method - /// and add its own options to the parent component's options. - static yaml_config::Schema GetStaticConfigSchema(); - - protected: - /// Legacy alias, use @ref ComponentBase instead. - using LoggableComponentBase = ComponentBase; +public: + ComponentBase(const ComponentConfig&, const ComponentContext&); + + ComponentBase(ComponentBase&&) = delete; + ComponentBase(const ComponentBase&) = delete; + + /// It is a good place to stop your work here. + /// All components dependent on the current component were destroyed. + /// All components on which the current component depends are still alive. + ~ComponentBase() override = default; + + /// Override this function to inform the world of the state of your + /// component. + /// + /// @warning The function is called concurrently from multiple threads. + ComponentHealth GetComponentHealth() const override { return ComponentHealth::kOk; } + + /// Called once if the creation of any other component failed. + /// If the current component expects some other component to take any action + /// with the current component, this call is a signal that such action may + /// never happen due to components loading was cancelled. + /// Application components might not want to override it. + void OnLoadingCancelled() override {} + + /// Component may use this function to finalize registration of other + /// components that depend on it (for example, handler components register + /// in server component, and the latter uses OnAllComponentsLoaded() to start + /// processing requests). + /// + /// Base components may override it and make `final` to do some work after the + /// derived object constructor is called. Don't use it otherwise. + void OnAllComponentsLoaded() override {} + + /// Component may use this function to stop doing work before the stop of the + /// components that depend on it. + /// + /// Base components may override it and make `final` to do some work before + /// the derived object constructor is called. Don't use it otherwise. + void OnAllComponentsAreStopping() override {} + + /// If the component pulls more options from @ref ComponentConfig than its + /// parent component, then it needs to define `GetStaticConfigSchema` method + /// and add its own options to the parent component's options. + static yaml_config::Schema GetStaticConfigSchema(); + +protected: + /// Legacy alias, use @ref ComponentBase instead. + using LoggableComponentBase = ComponentBase; }; /// Deprecated, use @ref ComponentBase instead. diff --git a/core/include/userver/components/component_config.hpp b/core/include/userver/components/component_config.hpp index 251833480cd8..5cac488e5696 100644 --- a/core/include/userver/components/component_config.hpp +++ b/core/include/userver/components/component_config.hpp @@ -11,24 +11,22 @@ USERVER_NAMESPACE_BEGIN namespace components { class ComponentConfig final : public yaml_config::YamlConfig { - public: - /// Creates an empty config - explicit ComponentConfig(std::string name); +public: + /// Creates an empty config + explicit ComponentConfig(std::string name); - ComponentConfig(yaml_config::YamlConfig value); + ComponentConfig(yaml_config::YamlConfig value); - const std::string& Name() const; - void SetName(std::string name); + const std::string& Name() const; + void SetName(std::string name); - private: - std::string name_; +private: + std::string name_; }; -ComponentConfig Parse(const yaml_config::YamlConfig& value, - formats::parse::To); +ComponentConfig Parse(const yaml_config::YamlConfig& value, formats::parse::To); -using ComponentConfigMap = - std::unordered_map; +using ComponentConfigMap = std::unordered_map; } // namespace components diff --git a/core/include/userver/components/component_context.hpp b/core/include/userver/components/component_context.hpp index 93efa472d317..74a2ffa8ab0c 100644 --- a/core/include/userver/components/component_context.hpp +++ b/core/include/userver/components/component_context.hpp @@ -33,22 +33,23 @@ class ComponentInfo; class ComponentContextImpl; using ComponentFactory = - std::function( - const components::ComponentContext&)>; + std::function(const components::ComponentContext&)>; template constexpr auto NameFromComponentType() -> decltype(std::string_view{T::kName}) { - return T::kName; + return T::kName; } template constexpr auto NameFromComponentType(Args...) { - static_assert(!sizeof(T), - "Component does not have a 'kName' member convertible to " - "std::string_view. You have to explicitly specify the name: " - "context.FindComponent(name) or " - "context.FindComponentOptional(name)."); - return std::string_view{}; + static_assert( + !sizeof(T), + "Component does not have a 'kName' member convertible to " + "std::string_view. You have to explicitly specify the name: " + "context.FindComponent(name) or " + "context.FindComponentOptional(name)." + ); + return std::string_view{}; } } // namespace impl @@ -56,9 +57,9 @@ constexpr auto NameFromComponentType(Args...) { /// @brief Exception that is thrown from /// components::ComponentContext::FindComponent() if a component load failed. class ComponentsLoadCancelledException : public std::runtime_error { - public: - ComponentsLoadCancelledException(); - explicit ComponentsLoadCancelledException(const std::string& message); +public: + ComponentsLoadCancelledException(); + explicit ComponentsLoadCancelledException(const std::string& message); }; /// @brief Class to retrieve other components. @@ -71,128 +72,125 @@ class ComponentsLoadCancelledException : public std::runtime_error { /// /// @see @ref userver_components class ComponentContext final { - public: - /// @brief Finds a component of type T with specified name (if any) and - /// returns the component after it was initialized. - /// - /// Can only be called from other component's constructor in a task where - /// that constructor was called. - /// May block and asynchronously wait for the creation of the requested - /// component. - /// @throw ComponentsLoadCancelledException if components loading was - /// cancelled due to errors in the creation of other component. - /// @throw std::runtime_error if component missing in `component_list` was - /// requested. - template - T& FindComponent() const { - return FindComponent(impl::NameFromComponentType()); - } - - /// @overload T& FindComponent() - template - T& FindComponent(std::string_view name) const { - if (!Contains(name)) { - ThrowNonRegisteredComponent(name, compiler::GetTypeName()); +public: + /// @brief Finds a component of type T with specified name (if any) and + /// returns the component after it was initialized. + /// + /// Can only be called from other component's constructor in a task where + /// that constructor was called. + /// May block and asynchronously wait for the creation of the requested + /// component. + /// @throw ComponentsLoadCancelledException if components loading was + /// cancelled due to errors in the creation of other component. + /// @throw std::runtime_error if component missing in `component_list` was + /// requested. + template + T& FindComponent() const { + return FindComponent(impl::NameFromComponentType()); } - auto* component_base = DoFindComponent(name); - T* ptr = dynamic_cast(component_base); - if (!ptr) { - ThrowComponentTypeMismatch(name, compiler::GetTypeName(), - component_base); + /// @overload T& FindComponent() + template + T& FindComponent(std::string_view name) const { + if (!Contains(name)) { + ThrowNonRegisteredComponent(name, compiler::GetTypeName()); + } + + auto* component_base = DoFindComponent(name); + T* ptr = dynamic_cast(component_base); + if (!ptr) { + ThrowComponentTypeMismatch(name, compiler::GetTypeName(), component_base); + } + + return *ptr; + } + + template + T& FindComponent(std::string_view /*name*/ = {}) { + return ReportMisuse(); + } + + /// @brief If there's no component with specified type and name return + /// nullptr; otherwise behaves as FindComponent(). + template + T* FindComponentOptional() const { + return FindComponentOptional(impl::NameFromComponentType()); } - return *ptr; - } - - template - T& FindComponent(std::string_view /*name*/ = {}) { - return ReportMisuse(); - } - - /// @brief If there's no component with specified type and name return - /// nullptr; otherwise behaves as FindComponent(). - template - T* FindComponentOptional() const { - return FindComponentOptional(impl::NameFromComponentType()); - } - - /// @overload T* FindComponentOptional() - template - T* FindComponentOptional(std::string_view name) const { - if (!Contains(name)) { - return nullptr; + /// @overload T* FindComponentOptional() + template + T* FindComponentOptional(std::string_view name) const { + if (!Contains(name)) { + return nullptr; + } + return dynamic_cast(DoFindComponent(name)); } - return dynamic_cast(DoFindComponent(name)); - } - template - T& FindComponentOptional(std::string_view /*name*/ = {}) { - return ReportMisuse(); - } + template + T& FindComponentOptional(std::string_view /*name*/ = {}) { + return ReportMisuse(); + } - /// @brief Returns an engine::TaskProcessor with the specified name. - engine::TaskProcessor& GetTaskProcessor(const std::string& name) const; + /// @brief Returns an engine::TaskProcessor with the specified name. + engine::TaskProcessor& GetTaskProcessor(const std::string& name) const; - template - engine::TaskProcessor& GetTaskProcessor(const T&) { - return ReportMisuse(); - } + template + engine::TaskProcessor& GetTaskProcessor(const T&) { + return ReportMisuse(); + } - const Manager& GetManager() const; + const Manager& GetManager() const; - private: - /// @returns true if there is a component with the specified name and it - /// could be found via FindComponent() - bool Contains(std::string_view name) const noexcept; +private: + /// @returns true if there is a component with the specified name and it + /// could be found via FindComponent() + bool Contains(std::string_view name) const noexcept; - template - bool Contains(const T&) { - return ReportMisuse(); - } + template + bool Contains(const T&) { + return ReportMisuse(); + } - template - decltype(auto) ReportMisuse() { - static_assert(!sizeof(T), - "components::ComponentContext should be accepted by " - "a constant reference, i.e. " - "`MyComponent(const components::ComponentConfig& config, " - "const components::ComponentContext& context)`"); - return 0; - } + template + decltype(auto) ReportMisuse() { + static_assert( + !sizeof(T), + "components::ComponentContext should be accepted by " + "a constant reference, i.e. " + "`MyComponent(const components::ComponentConfig& config, " + "const components::ComponentContext& context)`" + ); + return 0; + } - friend class Manager; - friend class State; + friend class Manager; + friend class State; - ComponentContext() noexcept; + ComponentContext() noexcept; - void Emplace(const Manager& manager, - std::vector&& loading_component_names); + void Emplace(const Manager& manager, std::vector&& loading_component_names); - void Reset() noexcept; + void Reset() noexcept; - ~ComponentContext(); + ~ComponentContext(); - RawComponentBase* AddComponent(std::string_view name, - const impl::ComponentFactory& factory); + RawComponentBase* AddComponent(std::string_view name, const impl::ComponentFactory& factory); - void OnAllComponentsLoaded(); + void OnAllComponentsLoaded(); - void OnAllComponentsAreStopping(); + void OnAllComponentsAreStopping(); - void ClearComponents(); + void ClearComponents(); - void CancelComponentsLoad(); + void CancelComponentsLoad(); - [[noreturn]] void ThrowNonRegisteredComponent(std::string_view name, - std::string_view type) const; - [[noreturn]] void ThrowComponentTypeMismatch( - std::string_view name, std::string_view type, - RawComponentBase* component) const; + [[noreturn]] void ThrowNonRegisteredComponent(std::string_view name, std::string_view type) const; + [[noreturn]] void + ThrowComponentTypeMismatch(std::string_view name, std::string_view type, RawComponentBase* component) const; - RawComponentBase* DoFindComponent(std::string_view name) const; + RawComponentBase* DoFindComponent(std::string_view name) const; - std::unique_ptr impl_; + std::unique_ptr impl_; }; } // namespace components diff --git a/core/include/userver/components/component_list.hpp b/core/include/userver/components/component_list.hpp index aac0773d8019..b809ec771e5d 100644 --- a/core/include/userver/components/component_list.hpp +++ b/core/include/userver/components/component_list.hpp @@ -20,111 +20,107 @@ class Manager; namespace impl { template -auto NameRegistrationFromComponentType() - -> decltype(std::string_view{T::kName}) { - return std::string_view{T::kName}; +auto NameRegistrationFromComponentType() -> decltype(std::string_view{T::kName}) { + return std::string_view{T::kName}; } template auto NameRegistrationFromComponentType(Args...) { - static_assert(!sizeof(T), - "Component does not have a 'kName' member convertible to " - "std::string_view. You have to explicitly specify the name: " - "component_list.Append(name)."); - return std::string_view{}; + static_assert( + !sizeof(T), + "Component does not have a 'kName' member convertible to " + "std::string_view. You have to explicitly specify the name: " + "component_list.Append(name)." + ); + return std::string_view{}; } -using ComponentBaseFactory = - std::function( - const components::ComponentConfig&, - const components::ComponentContext&)>; +using ComponentBaseFactory = std::function(const components::ComponentConfig&, const components::ComponentContext&)>; // Hides manager implementation from header -void AddComponentImpl(Manager& manager, - const components::ComponentConfigMap& config_map, - const std::string& name, ComponentBaseFactory factory); +void AddComponentImpl( + Manager& manager, + const components::ComponentConfigMap& config_map, + const std::string& name, + ComponentBaseFactory factory +); class ComponentAdderBase { - public: - ComponentAdderBase() = delete; - ComponentAdderBase(const ComponentAdderBase&) = delete; - ComponentAdderBase(ComponentAdderBase&&) = delete; - ComponentAdderBase& operator=(const ComponentAdderBase&) = delete; - ComponentAdderBase& operator=(ComponentAdderBase&&) = delete; +public: + ComponentAdderBase() = delete; + ComponentAdderBase(const ComponentAdderBase&) = delete; + ComponentAdderBase(ComponentAdderBase&&) = delete; + ComponentAdderBase& operator=(const ComponentAdderBase&) = delete; + ComponentAdderBase& operator=(ComponentAdderBase&&) = delete; - ComponentAdderBase(std::string name, ConfigFileMode config_file_mode); + ComponentAdderBase(std::string name, ConfigFileMode config_file_mode); - virtual ~ComponentAdderBase(); + virtual ~ComponentAdderBase(); - const std::string& GetComponentName() const noexcept { return name_; } + const std::string& GetComponentName() const noexcept { return name_; } - ConfigFileMode GetConfigFileMode() const { return config_file_mode_; } + ConfigFileMode GetConfigFileMode() const { return config_file_mode_; } - virtual void operator()(Manager&, - const components::ComponentConfigMap&) const = 0; + virtual void operator()(Manager&, const components::ComponentConfigMap&) const = 0; - virtual void ValidateStaticConfig(const ComponentConfig&, - ValidationMode) const = 0; + virtual void ValidateStaticConfig(const ComponentConfig&, ValidationMode) const = 0; - virtual yaml_config::Schema GetStaticConfigSchema() const = 0; + virtual yaml_config::Schema GetStaticConfigSchema() const = 0; - private: - std::string name_; - ConfigFileMode config_file_mode_; +private: + std::string name_; + ConfigFileMode config_file_mode_; }; template class ComponentAdder final : public ComponentAdderBase { - public: - explicit ComponentAdder(std::string name) - : ComponentAdderBase(std::move(name), kConfigFileMode) {} +public: + explicit ComponentAdder(std::string name) : ComponentAdderBase(std::move(name), kConfigFileMode) {} - void operator()(Manager&, - const components::ComponentConfigMap&) const override; + void operator()(Manager&, const components::ComponentConfigMap&) const override; - void ValidateStaticConfig(const ComponentConfig& static_config, - ValidationMode validation_mode) const override { - impl::TryValidateStaticConfig(static_config, validation_mode); - } + void ValidateStaticConfig(const ComponentConfig& static_config, ValidationMode validation_mode) const override { + impl::TryValidateStaticConfig(static_config, validation_mode); + } - yaml_config::Schema GetStaticConfigSchema() const override { - return impl::GetStaticConfigSchema(); - } + yaml_config::Schema GetStaticConfigSchema() const override { return impl::GetStaticConfigSchema(); } }; template -void ComponentAdder::operator()( - Manager& manager, const components::ComponentConfigMap& config_map) const { - // Using std::is_convertible_v because std::is_base_of_v returns true even - // if RawComponentBase is a private, protected, or ambiguous base class. - static_assert( - std::is_convertible_v, - "Component should publicly inherit from components::ComponentBase" - " and the component definition should be visible at its registration"); - impl::AddComponentImpl(manager, config_map, GetComponentName(), - [](const components::ComponentConfig& config, - const components::ComponentContext& context) { - return std::make_unique(config, context); - }); +void ComponentAdder::operator()(Manager& manager, const components::ComponentConfigMap& config_map) const { + // Using std::is_convertible_v because std::is_base_of_v returns true even + // if RawComponentBase is a private, protected, or ambiguous base class. + static_assert( + std::is_convertible_v, + "Component should publicly inherit from components::ComponentBase" + " and the component definition should be visible at its registration" + ); + impl::AddComponentImpl( + manager, + config_map, + GetComponentName(), + [](const components::ComponentConfig& config, const components::ComponentContext& context) { + return std::make_unique(config, context); + } + ); } using ComponentAdderPtr = std::unique_ptr; struct ComponentAdderComparator { - using is_transparent = std::true_type; + using is_transparent = std::true_type; - static std::string_view ToStringView(const ComponentAdderPtr& x) noexcept { - return std::string_view{x->GetComponentName()}; - } + static std::string_view ToStringView(const ComponentAdderPtr& x) noexcept { + return std::string_view{x->GetComponentName()}; + } - static std::string_view ToStringView(std::string_view x) noexcept { - return x; - } + static std::string_view ToStringView(std::string_view x) noexcept { return x; } - template - bool operator()(const T& x, const U& y) const noexcept { - return ToStringView(x) < ToStringView(y); - } + template + bool operator()(const T& x, const U& y) const noexcept { + return ToStringView(x) < ToStringView(y); + } }; } // namespace impl @@ -132,60 +128,58 @@ struct ComponentAdderComparator { /// @brief A list to keep a unique list of components to start with /// components::Run(), utils::DaemonMain() or components::RunOnce(). class ComponentList final { - public: - /// Appends a component with default component name Component::kName. - template - ComponentList& Append() &; +public: + /// Appends a component with default component name Component::kName. + template + ComponentList& Append() &; - /// Appends a component with a provided component name. - template - ComponentList& Append(std::string_view name) &; + /// Appends a component with a provided component name. + template + ComponentList& Append(std::string_view name) &; - /// Merges components from `other` into `*this`. - ComponentList& AppendComponentList(ComponentList&& other) &; + /// Merges components from `other` into `*this`. + ComponentList& AppendComponentList(ComponentList&& other) &; - /// @overload - ComponentList&& AppendComponentList(ComponentList&& other) &&; + /// @overload + ComponentList&& AppendComponentList(ComponentList&& other) &&; - /// @overload - template - ComponentList&& Append(Args&&...) &&; + /// @overload + template + ComponentList&& Append(Args&&...) &&; - /// @return true iff the component with provided name was added to *this. - bool Contains(std::string_view name) const { return adders_.count(name) > 0; } + /// @return true iff the component with provided name was added to *this. + bool Contains(std::string_view name) const { return adders_.count(name) > 0; } - /// @cond - using Adders = - std::set; + /// @cond + using Adders = std::set; - Adders::const_iterator begin() const { return adders_.begin(); } - Adders::const_iterator end() const { return adders_.end(); } + Adders::const_iterator begin() const { return adders_.begin(); } + Adders::const_iterator end() const { return adders_.end(); } - ComponentList& Append(impl::ComponentAdderPtr&& added) &; + ComponentList& Append(impl::ComponentAdderPtr&& added) &; - yaml_config::Schema GetStaticConfigSchema() const; - /// @endcond + yaml_config::Schema GetStaticConfigSchema() const; + /// @endcond - private: - Adders adders_; +private: + Adders adders_; }; template ComponentList& ComponentList::Append() & { - return Append( - impl::NameRegistrationFromComponentType()); + return Append(impl::NameRegistrationFromComponentType()); } template ComponentList& ComponentList::Append(std::string_view name) & { - using Adder = impl::ComponentAdder; - auto adder = std::make_unique(std::string{name}); - return Append(std::move(adder)); + using Adder = impl::ComponentAdder; + auto adder = std::make_unique(std::string{name}); + return Append(std::move(adder)); } template ComponentList&& ComponentList::Append(Args&&... args) && { - return std::move(Append(std::forward(args)...)); + return std::move(Append(std::forward(args)...)); } } // namespace components diff --git a/core/include/userver/components/dump_configurator.hpp b/core/include/userver/components/dump_configurator.hpp index 9b6b22ae0360..954c72115c54 100644 --- a/core/include/userver/components/dump_configurator.hpp +++ b/core/include/userver/components/dump_configurator.hpp @@ -28,20 +28,19 @@ namespace components { // clang-format on class DumpConfigurator final : public ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::DumpConfigurator component - static constexpr std::string_view kName = "dump-configurator"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::DumpConfigurator component + static constexpr std::string_view kName = "dump-configurator"; - DumpConfigurator(const ComponentConfig& config, - const ComponentContext& context); + DumpConfigurator(const ComponentConfig& config, const ComponentContext& context); - const std::string& GetDumpRoot() const; + const std::string& GetDumpRoot() const; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - const std::string dump_root_; +private: + const std::string dump_root_; }; template <> diff --git a/core/include/userver/components/fs_cache.hpp b/core/include/userver/components/fs_cache.hpp index a45ab2560c84..c62dcc23be5a 100644 --- a/core/include/userver/components/fs_cache.hpp +++ b/core/include/userver/components/fs_cache.hpp @@ -28,18 +28,17 @@ namespace components { // clang-format on class FsCache final : public components::ComponentBase { - public: - using Client = fs::FsCacheClient; +public: + using Client = fs::FsCacheClient; - FsCache(const components::ComponentConfig& config, - const components::ComponentContext& context); + FsCache(const components::ComponentConfig& config, const components::ComponentContext& context); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - const Client& GetClient() const; + const Client& GetClient() const; - private: - Client client_; +private: + Client client_; }; template <> diff --git a/core/include/userver/components/logging_configurator.hpp b/core/include/userver/components/logging_configurator.hpp index 7f1851ae0c00..2c631fecd20c 100644 --- a/core/include/userver/components/logging_configurator.hpp +++ b/core/include/userver/components/logging_configurator.hpp @@ -42,23 +42,22 @@ namespace components { // clang-format on class LoggingConfigurator final : public RawComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::LoggingConfigurator component - static constexpr std::string_view kName = "logging-configurator"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::LoggingConfigurator component + static constexpr std::string_view kName = "logging-configurator"; - LoggingConfigurator(const ComponentConfig& config, - const ComponentContext& context); + LoggingConfigurator(const ComponentConfig& config, const ComponentContext& context); - ~LoggingConfigurator() override; + ~LoggingConfigurator() override; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - void OnConfigUpdate(const dynamic_config::Snapshot& config); +private: + void OnConfigUpdate(const dynamic_config::Snapshot& config); - concurrent::AsyncEventSubscriberScope config_subscription_; - rcu::Variable dynamic_debug_; + concurrent::AsyncEventSubscriberScope config_subscription_; + rcu::Variable dynamic_debug_; }; /// }@ diff --git a/core/include/userver/components/manager_controller_component.hpp b/core/include/userver/components/manager_controller_component.hpp index 12c55cb723e9..4534b1aa9040 100644 --- a/core/include/userver/components/manager_controller_component.hpp +++ b/core/include/userver/components/manager_controller_component.hpp @@ -66,29 +66,27 @@ class Manager; // clang-format on class ManagerControllerComponent final : public RawComponentBase { - public: - ManagerControllerComponent(const components::ComponentConfig& config, - const components::ComponentContext& context); +public: + ManagerControllerComponent(const components::ComponentConfig& config, const components::ComponentContext& context); - ~ManagerControllerComponent() override; + ~ManagerControllerComponent() override; - /// @ingroup userver_component_names - /// @brief The default name of components::ManagerControllerComponent - static constexpr std::string_view kName = "manager-controller"; + /// @ingroup userver_component_names + /// @brief The default name of components::ManagerControllerComponent + static constexpr std::string_view kName = "manager-controller"; - private: - void WriteStatistics(utils::statistics::Writer& writer); +private: + void WriteStatistics(utils::statistics::Writer& writer); - void OnConfigUpdate(const dynamic_config::Snapshot& cfg); + void OnConfigUpdate(const dynamic_config::Snapshot& cfg); - const components::Manager& components_manager_; - utils::statistics::Entry statistics_holder_; - concurrent::AsyncEventSubscriberScope config_subscription_; + const components::Manager& components_manager_; + utils::statistics::Entry statistics_holder_; + concurrent::AsyncEventSubscriberScope config_subscription_; }; template <> -inline constexpr auto kConfigFileMode = - ConfigFileMode::kNotRequired; +inline constexpr auto kConfigFileMode = ConfigFileMode::kNotRequired; } // namespace components diff --git a/core/include/userver/components/process_starter.hpp b/core/include/userver/components/process_starter.hpp index 741ae51ccab7..31076c9b65be 100644 --- a/core/include/userver/components/process_starter.hpp +++ b/core/include/userver/components/process_starter.hpp @@ -24,20 +24,19 @@ namespace components { // clang-format on class ProcessStarter final : public ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::ProcessStarter component - static constexpr std::string_view kName = "process-starter"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::ProcessStarter component + static constexpr std::string_view kName = "process-starter"; - ProcessStarter(const ComponentConfig& config, - const ComponentContext& context); + ProcessStarter(const ComponentConfig& config, const ComponentContext& context); - engine::subprocess::ProcessStarter& Get() { return process_starter_; } + engine::subprocess::ProcessStarter& Get() { return process_starter_; } - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - engine::subprocess::ProcessStarter process_starter_; +private: + engine::subprocess::ProcessStarter process_starter_; }; template <> diff --git a/core/include/userver/components/raw_component_base.hpp b/core/include/userver/components/raw_component_base.hpp index b6df1755740f..c3f01a267135 100644 --- a/core/include/userver/components/raw_component_base.hpp +++ b/core/include/userver/components/raw_component_base.hpp @@ -15,21 +15,21 @@ namespace components { /// State of the component enum class ComponentHealth { - /// component is alive and fine - kOk, - /// component in fallback state, but the service keeps working - kFallback, - /// component is sick, service can not work without it - kFatal, + /// component is alive and fine + kOk, + /// component in fallback state, but the service keeps working + kFallback, + /// component is sick, service can not work without it + kFatal, }; /// Whether the static config for the component must always be present, or can /// be missing enum class ConfigFileMode { - /// component must be setup in config - kRequired, - /// component must be not setup in config - kNotRequired + /// component must be setup in config + kRequired, + /// component must be not setup in config + kNotRequired }; /// @brief The base class for all components. Don't use it for application @@ -37,26 +37,24 @@ enum class ConfigFileMode { /// /// Only inherited directly by some of the built-in userver components. class RawComponentBase { - public: - RawComponentBase() = default; +public: + RawComponentBase() = default; - RawComponentBase(RawComponentBase&&) = delete; + RawComponentBase(RawComponentBase&&) = delete; - RawComponentBase(const RawComponentBase&) = delete; + RawComponentBase(const RawComponentBase&) = delete; - virtual ~RawComponentBase(); + virtual ~RawComponentBase(); - virtual ComponentHealth GetComponentHealth() const { - return ComponentHealth::kOk; - } + virtual ComponentHealth GetComponentHealth() const { return ComponentHealth::kOk; } - virtual void OnLoadingCancelled() {} + virtual void OnLoadingCancelled() {} - virtual void OnAllComponentsLoaded() {} + virtual void OnAllComponentsLoaded() {} - virtual void OnAllComponentsAreStopping() {} + virtual void OnAllComponentsAreStopping() {} - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); }; /// Specialize it for typename Component to validate static config against diff --git a/core/include/userver/components/run.hpp b/core/include/userver/components/run.hpp index 3895b36af661..9ecd2620eeee 100644 --- a/core/include/userver/components/run.hpp +++ b/core/include/userver/components/run.hpp @@ -17,17 +17,19 @@ namespace components { /// Data type to distinguish config path and in-memory config values in /// components::Run() and components::RunOnce() functions. struct InMemoryConfig : utils::StrongTypedef { - using StrongTypedef::StrongTypedef; + using StrongTypedef::StrongTypedef; }; /// Starts a server with the provided component list and config loaded from /// file. Reopens the logging files on SIGUSR1. /// /// @see utils::DaemonMain -void Run(const std::string& config_path, - const std::optional& config_vars_path, - const std::optional& config_vars_override_path, - const ComponentList& component_list); +void Run( + const std::string& config_path, + const std::optional& config_vars_path, + const std::optional& config_vars_override_path, + const ComponentList& component_list +); /// Starts a server with the provided component list and config. /// Reopens the logging files on SIGUSR1. @@ -38,10 +40,12 @@ void Run(const InMemoryConfig& config, const ComponentList& component_list); /// Runs the component list once with the config loaded from file. /// /// @see utils::DaemonMain -void RunOnce(const std::string& config_path, - const std::optional& config_vars_path, - const std::optional& config_vars_override_path, - const ComponentList& component_list); +void RunOnce( + const std::string& config_path, + const std::optional& config_vars_path, + const std::optional& config_vars_override_path, + const ComponentList& component_list +); /// Runs the component list once with the config. /// diff --git a/core/include/userver/components/single_threaded_task_processors.hpp b/core/include/userver/components/single_threaded_task_processors.hpp index a4e0825b7b87..664433156714 100644 --- a/core/include/userver/components/single_threaded_task_processors.hpp +++ b/core/include/userver/components/single_threaded_task_processors.hpp @@ -30,22 +30,21 @@ namespace components { /// components::ManagerControllerComponent for options description and /// sample. class SingleThreadedTaskProcessors final : public ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::SingleThreadedTaskProcessors - static constexpr std::string_view kName = "single-threaded-task-processors"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::SingleThreadedTaskProcessors + static constexpr std::string_view kName = "single-threaded-task-processors"; - SingleThreadedTaskProcessors(const ComponentConfig& config, - const ComponentContext&); + SingleThreadedTaskProcessors(const ComponentConfig& config, const ComponentContext&); - ~SingleThreadedTaskProcessors() override; + ~SingleThreadedTaskProcessors() override; - engine::SingleThreadedTaskProcessorsPool& GetPool() { return pool_; } + engine::SingleThreadedTaskProcessorsPool& GetPool() { return pool_; } - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - engine::SingleThreadedTaskProcessorsPool pool_; +private: + engine::SingleThreadedTaskProcessorsPool pool_; }; template <> diff --git a/core/include/userver/components/state.hpp b/core/include/userver/components/state.hpp index 97f46b50de58..cbb2642bcf05 100644 --- a/core/include/userver/components/state.hpp +++ b/core/include/userver/components/state.hpp @@ -22,39 +22,37 @@ class ComponentContextImpl; /// /// @see components::ComponentContext class State final { - public: - explicit State(const ComponentContext& cc) noexcept; - - /// @returns true if one of the components is in fatal state and can not - /// work. A component is in fatal state if the - /// components::ComponentHealth::kFatal value is returned from the overridden - /// components::ComponentBase::GetComponentHealth(). - bool IsAnyComponentInFatalState() const; - - /// @returns true if component with name `component_name` depends - /// (directly or transitively) on a component with name `dependency`. - /// - /// Component with name `component_name` should be loaded. - /// Components construction should finish before any call to this function - /// is made. - /// - /// Note that GetAllDependencies usually is more effective, if you are - /// planning multiple calls for the same component name. - bool HasDependencyOn(std::string_view component_name, - std::string_view dependency) const; - - /// @returns all the components that `component_name` depends on directly or - /// transitively. - /// - /// Component with name `component_name` should be loaded. - /// Components construction should finish before any call to this function - /// is made. The result should now outlive the all the components - /// destruction. - std::unordered_set GetAllDependencies( - std::string_view component_name) const; - - private: - const impl::ComponentContextImpl& impl_; +public: + explicit State(const ComponentContext& cc) noexcept; + + /// @returns true if one of the components is in fatal state and can not + /// work. A component is in fatal state if the + /// components::ComponentHealth::kFatal value is returned from the overridden + /// components::ComponentBase::GetComponentHealth(). + bool IsAnyComponentInFatalState() const; + + /// @returns true if component with name `component_name` depends + /// (directly or transitively) on a component with name `dependency`. + /// + /// Component with name `component_name` should be loaded. + /// Components construction should finish before any call to this function + /// is made. + /// + /// Note that GetAllDependencies usually is more effective, if you are + /// planning multiple calls for the same component name. + bool HasDependencyOn(std::string_view component_name, std::string_view dependency) const; + + /// @returns all the components that `component_name` depends on directly or + /// transitively. + /// + /// Component with name `component_name` should be loaded. + /// Components construction should finish before any call to this function + /// is made. The result should now outlive the all the components + /// destruction. + std::unordered_set GetAllDependencies(std::string_view component_name) const; + +private: + const impl::ComponentContextImpl& impl_; }; } // namespace components diff --git a/core/include/userver/components/static_config_validator.hpp b/core/include/userver/components/static_config_validator.hpp index 75c71316f947..4a6b60be0bc8 100644 --- a/core/include/userver/components/static_config_validator.hpp +++ b/core/include/userver/components/static_config_validator.hpp @@ -10,29 +10,26 @@ USERVER_NAMESPACE_BEGIN namespace components { enum class ValidationMode { - kOnlyTurnedOn, - kAll, + kOnlyTurnedOn, + kAll, }; -ValidationMode Parse(const yaml_config::YamlConfig& value, - formats::parse::To); +ValidationMode Parse(const yaml_config::YamlConfig& value, formats::parse::To); namespace impl { template -void TryValidateStaticConfig(const components::ComponentConfig& static_config, - ValidationMode validation_condition) { - if (components::kHasValidate || - validation_condition == ValidationMode::kAll) { - yaml_config::Schema schema = Component::GetStaticConfigSchema(); - - yaml_config::impl::Validate(static_config, schema); - } +void TryValidateStaticConfig(const components::ComponentConfig& static_config, ValidationMode validation_condition) { + if (components::kHasValidate || validation_condition == ValidationMode::kAll) { + yaml_config::Schema schema = Component::GetStaticConfigSchema(); + + yaml_config::impl::Validate(static_config, schema); + } } template yaml_config::Schema GetStaticConfigSchema() { - // TODO: implement for kOnlyTurnedOn - return Component::GetStaticConfigSchema(); + // TODO: implement for kOnlyTurnedOn + return Component::GetStaticConfigSchema(); } } // namespace impl diff --git a/core/include/userver/components/statistics_storage.hpp b/core/include/userver/components/statistics_storage.hpp index 5ae5f95546de..526588693e7c 100644 --- a/core/include/userver/components/statistics_storage.hpp +++ b/core/include/userver/components/statistics_storage.hpp @@ -30,40 +30,36 @@ namespace components { // clang-format on class StatisticsStorage final : public RawComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::StatisticsStorage component - static constexpr std::string_view kName = "statistics-storage"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::StatisticsStorage component + static constexpr std::string_view kName = "statistics-storage"; - StatisticsStorage(const ComponentConfig& config, - const ComponentContext& context); + StatisticsStorage(const ComponentConfig& config, const ComponentContext& context); - ~StatisticsStorage() override; + ~StatisticsStorage() override; - void OnAllComponentsLoaded() override; + void OnAllComponentsLoaded() override; - utils::statistics::Storage& GetStorage() { return storage_; } + utils::statistics::Storage& GetStorage() { return storage_; } - const utils::statistics::Storage& GetStorage() const { return storage_; } + const utils::statistics::Storage& GetStorage() const { return storage_; } - utils::statistics::MetricsStoragePtr GetMetricsStorage() { - return metrics_storage_; - } + utils::statistics::MetricsStoragePtr GetMetricsStorage() { return metrics_storage_; } - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - utils::statistics::Storage storage_; - utils::statistics::MetricsStoragePtr metrics_storage_; - std::vector metrics_storage_registration_; +private: + utils::statistics::Storage storage_; + utils::statistics::MetricsStoragePtr metrics_storage_; + std::vector metrics_storage_registration_; }; template <> inline constexpr bool kHasValidate = true; template <> -inline constexpr auto kConfigFileMode = - ConfigFileMode::kNotRequired; +inline constexpr auto kConfigFileMode = ConfigFileMode::kNotRequired; } // namespace components diff --git a/core/include/userver/components/tcp_acceptor_base.hpp b/core/include/userver/components/tcp_acceptor_base.hpp index 0ae1db6d7d24..d024c1a0832c 100644 --- a/core/include/userver/components/tcp_acceptor_base.hpp +++ b/core/include/userver/components/tcp_acceptor_base.hpp @@ -39,35 +39,37 @@ namespace components { // clang-format on class TcpAcceptorBase : public ComponentBase { - public: - TcpAcceptorBase(const ComponentConfig&, const ComponentContext&); - ~TcpAcceptorBase() override; - - static yaml_config::Schema GetStaticConfigSchema(); - - protected: - /// Override this function to process incoming sockets. - /// - /// @warning The function is called concurrently from multiple threads on - /// each new socket. - virtual void ProcessSocket(engine::io::Socket&& sock) = 0; - - private: - TcpAcceptorBase(const ComponentConfig& config, - const ComponentContext& context, - const server::net::ListenerConfig& acceptor_config); - - void KeepAccepting(); - - void OnAllComponentsLoaded() final; - void OnAllComponentsAreStopping() final; - - const bool no_delay_; - engine::TaskProcessor& acceptor_task_processor_; - engine::TaskProcessor& sockets_task_processor_; - concurrent::BackgroundTaskStorageCore tasks_; - engine::io::Socket listen_sock_; - engine::Task acceptor_; +public: + TcpAcceptorBase(const ComponentConfig&, const ComponentContext&); + ~TcpAcceptorBase() override; + + static yaml_config::Schema GetStaticConfigSchema(); + +protected: + /// Override this function to process incoming sockets. + /// + /// @warning The function is called concurrently from multiple threads on + /// each new socket. + virtual void ProcessSocket(engine::io::Socket&& sock) = 0; + +private: + TcpAcceptorBase( + const ComponentConfig& config, + const ComponentContext& context, + const server::net::ListenerConfig& acceptor_config + ); + + void KeepAccepting(); + + void OnAllComponentsLoaded() final; + void OnAllComponentsAreStopping() final; + + const bool no_delay_; + engine::TaskProcessor& acceptor_task_processor_; + engine::TaskProcessor& sockets_task_processor_; + concurrent::BackgroundTaskStorageCore tasks_; + engine::io::Socket listen_sock_; + engine::Task acceptor_; }; } // namespace components diff --git a/core/include/userver/concurrent/async_event_channel.hpp b/core/include/userver/concurrent/async_event_channel.hpp index 7097c962204d..5081b9f743e0 100644 --- a/core/include/userver/concurrent/async_event_channel.hpp +++ b/core/include/userver/concurrent/async_event_channel.hpp @@ -27,17 +27,17 @@ namespace impl { void WaitForTask(std::string_view name, engine::TaskWithResult& task); -[[noreturn]] void ReportAlreadySubscribed(std::string_view channel_name, - std::string_view listener_name); +[[noreturn]] void ReportAlreadySubscribed(std::string_view channel_name, std::string_view listener_name); void ReportNotSubscribed(std::string_view channel_name) noexcept; -void ReportUnsubscribingAutomatically(std::string_view channel_name, - std::string_view listener_name) noexcept; +void ReportUnsubscribingAutomatically(std::string_view channel_name, std::string_view listener_name) noexcept; -void ReportErrorWhileUnsubscribing(std::string_view channel_name, - std::string_view listener_name, - std::string_view error) noexcept; +void ReportErrorWhileUnsubscribing( + std::string_view channel_name, + std::string_view listener_name, + std::string_view error +) noexcept; std::string MakeAsyncChannelName(std::string_view base, std::string_view name); @@ -50,14 +50,17 @@ inline constexpr bool kCheckSubscriptionUB = utils::impl::kEnableAssert; // struct fields. template void CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing( - std::function& on_listener_removal, Func& listener_func, - std::string_view channel_name, std::string_view listener_name) noexcept { - if (!on_listener_removal) return; - try { - on_listener_removal(listener_func); - } catch (const std::exception& e) { - ReportErrorWhileUnsubscribing(channel_name, listener_name, e.what()); - } + std::function& on_listener_removal, + Func& listener_func, + std::string_view channel_name, + std::string_view listener_name +) noexcept { + if (!on_listener_removal) return; + try { + on_listener_removal(listener_func); + } catch (const std::exception& e) { + ReportErrorWhileUnsubscribing(channel_name, listener_name, e.what()); + } } } // namespace impl @@ -72,143 +75,139 @@ void CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing( /// @snippet concurrent/async_event_channel_test.cpp AsyncEventChannel sample template class AsyncEventChannel : public AsyncEventSource { - public: - using Function = typename AsyncEventSource::Function; - using OnRemoveCallback = std::function; - - /// @brief The primary constructor - /// @param name used for diagnostic purposes and is also accessible with Name - explicit AsyncEventChannel(std::string_view name) - : name_(name), data_(ListenersData{{}, {}}) {} - - /// @brief The constructor with `AsyncEventSubscriberScope` usage checking. - /// - /// The constructor with a callback that is called on listener removal. The - /// callback takes a reference to `Function' as input. This is useful for - /// checking the lifetime of data captured by the listener update function. - /// - /// @note Works only in debug mode. - /// - /// @warning Data captured by `on_listener_removal` function must be valid - /// until the `AsyncEventChannel` object is completely destroyed. - /// - /// Example usage: - /// @snippet concurrent/async_event_channel_test.cpp OnListenerRemoval sample - /// - /// @param name used for diagnostic purposes and is also accessible with Name - /// @param on_listener_removal the callback used for check - /// - /// @see impl::CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing - AsyncEventChannel(std::string_view name, OnRemoveCallback on_listener_removal) - : name_(name), data_(ListenersData{{}, std::move(on_listener_removal)}) {} - - /// @brief For use in `UpdateAndListen` of specific event channels - /// - /// Atomically calls `updater`, which should invoke `func` with the previously - /// sent event, and subscribes to new events as if using AddListener. - /// - /// @see AsyncEventSource::AddListener - template - AsyncEventSubscriberScope DoUpdateAndListen(FunctionId id, - std::string_view name, - Function&& func, - UpdaterFunc&& updater) { - std::lock_guard lock(event_mutex_); - std::forward(updater)(); - return DoAddListener(id, name, std::move(func)); - } - - /// @overload - template - AsyncEventSubscriberScope DoUpdateAndListen(Class* obj, std::string_view name, - void (Class::*func)(Args...), - UpdaterFunc&& updater) { - return DoUpdateAndListen( - FunctionId(obj), name, - [obj, func](Args... args) { (obj->*func)(args...); }, - std::forward(updater)); - } - - /// Send the next event and wait until all the listeners process it. - /// - /// Strict FIFO serialization is guaranteed, i.e. only after this event is - /// processed a new event may be delivered for the subscribers, same - /// listener/subscriber is never called concurrently. - void SendEvent(Args... args) const { - std::lock_guard lock(event_mutex_); - auto data = data_.Lock(); - auto& listeners = data->listeners; - - std::vector> tasks; - tasks.reserve(listeners.size()); - - for (const auto& [_, listener] : listeners) { - tasks.push_back(utils::Async( - listener.task_name, - [&, &callback = listener.callback] { callback(args...); })); +public: + using Function = typename AsyncEventSource::Function; + using OnRemoveCallback = std::function; + + /// @brief The primary constructor + /// @param name used for diagnostic purposes and is also accessible with Name + explicit AsyncEventChannel(std::string_view name) : name_(name), data_(ListenersData{{}, {}}) {} + + /// @brief The constructor with `AsyncEventSubscriberScope` usage checking. + /// + /// The constructor with a callback that is called on listener removal. The + /// callback takes a reference to `Function' as input. This is useful for + /// checking the lifetime of data captured by the listener update function. + /// + /// @note Works only in debug mode. + /// + /// @warning Data captured by `on_listener_removal` function must be valid + /// until the `AsyncEventChannel` object is completely destroyed. + /// + /// Example usage: + /// @snippet concurrent/async_event_channel_test.cpp OnListenerRemoval sample + /// + /// @param name used for diagnostic purposes and is also accessible with Name + /// @param on_listener_removal the callback used for check + /// + /// @see impl::CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing + AsyncEventChannel(std::string_view name, OnRemoveCallback on_listener_removal) + : name_(name), data_(ListenersData{{}, std::move(on_listener_removal)}) {} + + /// @brief For use in `UpdateAndListen` of specific event channels + /// + /// Atomically calls `updater`, which should invoke `func` with the previously + /// sent event, and subscribes to new events as if using AddListener. + /// + /// @see AsyncEventSource::AddListener + template + AsyncEventSubscriberScope + DoUpdateAndListen(FunctionId id, std::string_view name, Function&& func, UpdaterFunc&& updater) { + std::lock_guard lock(event_mutex_); + std::forward(updater)(); + return DoAddListener(id, name, std::move(func)); } - std::size_t i = 0; - for (const auto& [_, listener] : listeners) { - impl::WaitForTask(listener.name, tasks[i++]); + /// @overload + template + AsyncEventSubscriberScope + DoUpdateAndListen(Class* obj, std::string_view name, void (Class::*func)(Args...), UpdaterFunc&& updater) { + return DoUpdateAndListen( + FunctionId(obj), + name, + [obj, func](Args... args) { (obj->*func)(args...); }, + std::forward(updater) + ); } - } - - /// @returns the name of this event channel - const std::string& Name() const noexcept { return name_; } - - private: - struct Listener final { - std::string name; - Function callback; - std::string task_name; - }; - - struct ListenersData final { - std::unordered_map listeners; - OnRemoveCallback on_listener_removal; - }; - - void RemoveListener(FunctionId id, UnsubscribingKind kind) noexcept final { - engine::TaskCancellationBlocker blocker; - auto data = data_.Lock(); - auto& listeners = data->listeners; - const auto iter = listeners.find(id); - - if (iter == listeners.end()) { - impl::ReportNotSubscribed(Name()); - return; + + /// Send the next event and wait until all the listeners process it. + /// + /// Strict FIFO serialization is guaranteed, i.e. only after this event is + /// processed a new event may be delivered for the subscribers, same + /// listener/subscriber is never called concurrently. + void SendEvent(Args... args) const { + std::lock_guard lock(event_mutex_); + auto data = data_.Lock(); + auto& listeners = data->listeners; + + std::vector> tasks; + tasks.reserve(listeners.size()); + + for (const auto& [_, listener] : listeners) { + tasks.push_back(utils::Async(listener.task_name, [&, &callback = listener.callback] { callback(args...); }) + ); + } + + std::size_t i = 0; + for (const auto& [_, listener] : listeners) { + impl::WaitForTask(listener.name, tasks[i++]); + } } - if (kind == UnsubscribingKind::kAutomatic) { - if (!data->on_listener_removal) { - impl::ReportUnsubscribingAutomatically(name_, iter->second.name); - } - - if constexpr (impl::kCheckSubscriptionUB) { - // Fake listener call to check - impl::CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing( - data->on_listener_removal, iter->second.callback, name_, - iter->second.name); - } + /// @returns the name of this event channel + const std::string& Name() const noexcept { return name_; } + +private: + struct Listener final { + std::string name; + Function callback; + std::string task_name; + }; + + struct ListenersData final { + std::unordered_map listeners; + OnRemoveCallback on_listener_removal; + }; + + void RemoveListener(FunctionId id, UnsubscribingKind kind) noexcept final { + engine::TaskCancellationBlocker blocker; + auto data = data_.Lock(); + auto& listeners = data->listeners; + const auto iter = listeners.find(id); + + if (iter == listeners.end()) { + impl::ReportNotSubscribed(Name()); + return; + } + + if (kind == UnsubscribingKind::kAutomatic) { + if (!data->on_listener_removal) { + impl::ReportUnsubscribingAutomatically(name_, iter->second.name); + } + + if constexpr (impl::kCheckSubscriptionUB) { + // Fake listener call to check + impl::CheckDataUsedByCallbackHasNotBeenDestroyedBeforeUnsubscribing( + data->on_listener_removal, iter->second.callback, name_, iter->second.name + ); + } + } + listeners.erase(iter); } - listeners.erase(iter); - } - - AsyncEventSubscriberScope DoAddListener(FunctionId id, std::string_view name, - Function&& func) final { - auto data = data_.Lock(); - auto& listeners = data->listeners; - auto task_name = impl::MakeAsyncChannelName(name_, name); - const auto [iterator, success] = listeners.emplace( - id, Listener{std::string{name}, std::move(func), std::move(task_name)}); - if (!success) impl::ReportAlreadySubscribed(Name(), name); - return AsyncEventSubscriberScope(*this, id); - } - - const std::string name_; - concurrent::Variable data_; - mutable engine::Mutex event_mutex_; + + AsyncEventSubscriberScope DoAddListener(FunctionId id, std::string_view name, Function&& func) final { + auto data = data_.Lock(); + auto& listeners = data->listeners; + auto task_name = impl::MakeAsyncChannelName(name_, name); + const auto [iterator, success] = + listeners.emplace(id, Listener{std::string{name}, std::move(func), std::move(task_name)}); + if (!success) impl::ReportAlreadySubscribed(Name(), name); + return AsyncEventSubscriberScope(*this, id); + } + + const std::string name_; + concurrent::Variable data_; + mutable engine::Mutex event_mutex_; }; } // namespace concurrent diff --git a/core/include/userver/concurrent/async_event_source.hpp b/core/include/userver/concurrent/async_event_source.hpp index a29f84e7af81..99b5712a681d 100644 --- a/core/include/userver/concurrent/async_event_source.hpp +++ b/core/include/userver/concurrent/async_event_source.hpp @@ -22,12 +22,12 @@ class AsyncEventSource; namespace impl { class AsyncEventSourceBase { - public: - virtual void RemoveListener(FunctionId, UnsubscribingKind) noexcept = 0; +public: + virtual void RemoveListener(FunctionId, UnsubscribingKind) noexcept = 0; - protected: - // disallow deletion via pointer to base - ~AsyncEventSourceBase(); +protected: + // disallow deletion via pointer to base + ~AsyncEventSourceBase(); }; } // namespace impl @@ -35,25 +35,25 @@ class AsyncEventSourceBase { /// Uniquely identifies a subscription (usually the callback method owner) for /// AsyncEventSource class FunctionId final { - public: - constexpr FunctionId() = default; +public: + constexpr FunctionId() = default; - template - explicit FunctionId(Class* obj) : FunctionId(obj, typeid(Class)) {} + template + explicit FunctionId(Class* obj) : FunctionId(obj, typeid(Class)) {} - explicit operator bool() const; + explicit operator bool() const; - bool operator==(const FunctionId& other) const; + bool operator==(const FunctionId& other) const; - struct Hash final { - std::size_t operator()(FunctionId id) const noexcept; - }; + struct Hash final { + std::size_t operator()(FunctionId id) const noexcept; + }; - private: - FunctionId(void* ptr, const std::type_info& type); +private: + FunctionId(void* ptr, const std::type_info& type); - void* ptr_{nullptr}; - const std::type_info* type_{nullptr}; + void* ptr_{nullptr}; + const std::type_info* type_{nullptr}; }; enum class UnsubscribingKind { kManual, kAutomatic }; @@ -66,30 +66,28 @@ enum class UnsubscribingKind { kManual, kAutomatic }; /// `Unsubscribe` should be called manually in the objects destructor, before /// anything that the callback needs is destroyed. class [[nodiscard]] AsyncEventSubscriberScope final { - public: - AsyncEventSubscriberScope() = default; +public: + AsyncEventSubscriberScope() = default; - template - AsyncEventSubscriberScope(AsyncEventSource& channel, FunctionId id) - : AsyncEventSubscriberScope( - static_cast(channel), id) {} + template + AsyncEventSubscriberScope(AsyncEventSource& channel, FunctionId id) + : AsyncEventSubscriberScope(static_cast(channel), id) {} - AsyncEventSubscriberScope(AsyncEventSubscriberScope&& scope) noexcept; + AsyncEventSubscriberScope(AsyncEventSubscriberScope&& scope) noexcept; - AsyncEventSubscriberScope& operator=( - AsyncEventSubscriberScope&& other) noexcept; + AsyncEventSubscriberScope& operator=(AsyncEventSubscriberScope&& other) noexcept; - ~AsyncEventSubscriberScope(); + ~AsyncEventSubscriberScope(); - /// Unsubscribes manually. The subscription should be cancelled before - /// anything that the callback needs is destroyed. - void Unsubscribe() noexcept; + /// Unsubscribes manually. The subscription should be cancelled before + /// anything that the callback needs is destroyed. + void Unsubscribe() noexcept; - private: - AsyncEventSubscriberScope(impl::AsyncEventSourceBase& channel, FunctionId id); +private: + AsyncEventSubscriberScope(impl::AsyncEventSourceBase& channel, FunctionId id); - impl::AsyncEventSourceBase* channel_{nullptr}; - FunctionId id_; + impl::AsyncEventSourceBase* channel_{nullptr}; + FunctionId id_; }; /// @ingroup userver_concurrency @@ -100,55 +98,50 @@ class [[nodiscard]] AsyncEventSubscriberScope final { /// concurrently. template class AsyncEventSource : public impl::AsyncEventSourceBase { - public: - using Function = std::function; - - virtual ~AsyncEventSource() = default; - - /// @brief Subscribes to updates from this event source - /// - /// The listener won't be called immediately. To process the current value and - /// then listen to updates, use `UpdateAndListen` of specific event channels. - /// - /// @warning Listeners should not be added or removed while processing the - /// event inside another listener. - /// - /// Example usage: - /// @snippet concurrent/async_event_channel_test.cpp AddListener sample - /// - /// @param obj the subscriber, which is the owner of the listener method, and - /// is also used as the unique identifier of the subscription for this - /// AsyncEventSource - /// @param name the name of the subscriber, for diagnostic purposes - /// @param func the listener method, usually called `OnUpdate`, e.g. - /// `OnConfigUpdate` or `OnCacheUpdate` - /// @returns a AsyncEventSubscriberScope controlling the subscription, which - /// should be stored as a member in the subscriber; `Unsubscribe` should be - /// called explicitly - template - AsyncEventSubscriberScope AddListener(Class* obj, std::string_view name, - void (Class::*func)(Args...)) { - return AddListener(FunctionId(obj), name, - [obj, func](Args... args) { (obj->*func)(args...); }); - } - - /// @brief A type-erased version of AddListener - /// - /// @param id the unique identifier of the subscription - /// @param name the name of the subscriber, for diagnostic purposes - /// @param func the callback used for event notifications - AsyncEventSubscriberScope AddListener(FunctionId id, std::string_view name, - Function&& func) { - return DoAddListener(id, name, std::move(func)); - } - - /// Used by AsyncEventSubscriberScope to cancel an event subscription - void RemoveListener(FunctionId, UnsubscribingKind) noexcept override = 0; - - protected: - virtual AsyncEventSubscriberScope DoAddListener(FunctionId id, - std::string_view name, - Function&& func) = 0; +public: + using Function = std::function; + + virtual ~AsyncEventSource() = default; + + /// @brief Subscribes to updates from this event source + /// + /// The listener won't be called immediately. To process the current value and + /// then listen to updates, use `UpdateAndListen` of specific event channels. + /// + /// @warning Listeners should not be added or removed while processing the + /// event inside another listener. + /// + /// Example usage: + /// @snippet concurrent/async_event_channel_test.cpp AddListener sample + /// + /// @param obj the subscriber, which is the owner of the listener method, and + /// is also used as the unique identifier of the subscription for this + /// AsyncEventSource + /// @param name the name of the subscriber, for diagnostic purposes + /// @param func the listener method, usually called `OnUpdate`, e.g. + /// `OnConfigUpdate` or `OnCacheUpdate` + /// @returns a AsyncEventSubscriberScope controlling the subscription, which + /// should be stored as a member in the subscriber; `Unsubscribe` should be + /// called explicitly + template + AsyncEventSubscriberScope AddListener(Class* obj, std::string_view name, void (Class::*func)(Args...)) { + return AddListener(FunctionId(obj), name, [obj, func](Args... args) { (obj->*func)(args...); }); + } + + /// @brief A type-erased version of AddListener + /// + /// @param id the unique identifier of the subscription + /// @param name the name of the subscriber, for diagnostic purposes + /// @param func the callback used for event notifications + AsyncEventSubscriberScope AddListener(FunctionId id, std::string_view name, Function&& func) { + return DoAddListener(id, name, std::move(func)); + } + + /// Used by AsyncEventSubscriberScope to cancel an event subscription + void RemoveListener(FunctionId, UnsubscribingKind) noexcept override = 0; + +protected: + virtual AsyncEventSubscriberScope DoAddListener(FunctionId id, std::string_view name, Function&& func) = 0; }; } // namespace concurrent diff --git a/core/include/userver/concurrent/background_task_storage.hpp b/core/include/userver/concurrent/background_task_storage.hpp index 01c390de1e74..53da1a5ebbea 100644 --- a/core/include/userver/concurrent/background_task_storage.hpp +++ b/core/include/userver/concurrent/background_task_storage.hpp @@ -19,32 +19,32 @@ namespace concurrent { /// A version of concurrent::BackgroundTaskStorage for advanced use cases (e.g. /// driver internals) that can take the ownership of any kind of task. class BackgroundTaskStorageCore final { - public: - /// Creates an empty BTS. - BackgroundTaskStorageCore(); +public: + /// Creates an empty BTS. + BackgroundTaskStorageCore(); - BackgroundTaskStorageCore(BackgroundTaskStorageCore&&) = delete; - BackgroundTaskStorageCore& operator=(BackgroundTaskStorageCore&&) = delete; - ~BackgroundTaskStorageCore(); + BackgroundTaskStorageCore(BackgroundTaskStorageCore&&) = delete; + BackgroundTaskStorageCore& operator=(BackgroundTaskStorageCore&&) = delete; + ~BackgroundTaskStorageCore(); - /// Explicitly cancel and wait for the tasks. New tasks must not be launched - /// after this call returns. Should be called no more than once. - void CancelAndWait() noexcept; + /// Explicitly cancel and wait for the tasks. New tasks must not be launched + /// after this call returns. Should be called no more than once. + void CancelAndWait() noexcept; - /// Explicitly wait for execution tasks in the store. - /// Should be called no more than once. - void CloseAndWaitDebug() noexcept; + /// Explicitly wait for execution tasks in the store. + /// Should be called no more than once. + void CloseAndWaitDebug() noexcept; - /// @brief Detaches task, allowing it to continue execution out of scope. It - /// will be cancelled and waited for on BTS destruction. - /// @note After detach, Task becomes invalid - void Detach(engine::Task&& task); + /// @brief Detaches task, allowing it to continue execution out of scope. It + /// will be cancelled and waited for on BTS destruction. + /// @note After detach, Task becomes invalid + void Detach(engine::Task&& task); - /// Approximate number of currently active tasks - std::int64_t ActiveTasksApprox() const noexcept; + /// Approximate number of currently active tasks + std::int64_t ActiveTasksApprox() const noexcept; - private: - std::optional sync_block_; +private: + std::optional sync_block_; }; /// @ingroup userver_concurrency userver_containers @@ -125,58 +125,56 @@ class BackgroundTaskStorageCore final { /// safely use the fields declared before the BTS field, as well as everything /// from the components, on which the current component depends. class BackgroundTaskStorage final { - public: - /// Creates a BTS that launches tasks in the engine::TaskProcessor used at the - /// BTS creation. - BackgroundTaskStorage(); - - /// Creates a BTS that launches tasks in the specified engine::TaskProcessor. - explicit BackgroundTaskStorage(engine::TaskProcessor& task_processor); - - BackgroundTaskStorage(const BackgroundTaskStorage&) = delete; - BackgroundTaskStorage& operator=(const BackgroundTaskStorage&) = delete; - - /// Explicitly cancel and wait for the tasks. New tasks must not be launched - /// after this call returns. Should be called no more than once. - void CancelAndWait() noexcept; - - /// Explicitly stop accepting new tasks and wait for execution tasks in the - /// store. Should be called no more than once. - void CloseAndWaitDebug() noexcept; - - /// @brief Launch a task that will be cancelled and waited for in the BTS - /// destructor. - /// - /// The task is started as non-Critical, it may be cancelled due to - /// `TaskProcessor` overload. engine::TaskInheritedVariable instances are not - /// inherited from the caller except baggage::Baggage. See - /// utils::AsyncBackground for details. - template - void AsyncDetach(std::string name, Args&&... args) { - core_.Detach(utils::AsyncBackground(std::move(name), task_processor_, - std::forward(args)...)); - } - - /// @brief Launch a task that will be cancelled and waited for in the BTS - /// destructor. - /// - /// Execution of function is guaranteed to start regardless - /// of engine::TaskProcessor load limits. - /// engine::TaskInheritedVariable instances are not - /// inherited from the caller except baggage::Baggage. See - /// utils::CriticalAsyncBackground for details. - template - void CriticalAsyncDetach(std::string name, Args&&... args) { - core_.Detach(utils::CriticalAsyncBackground( - std::move(name), task_processor_, std::forward(args)...)); - } - - /// Approximate number of currently active tasks - std::int64_t ActiveTasksApprox() const noexcept; - - private: - BackgroundTaskStorageCore core_; - engine::TaskProcessor& task_processor_; +public: + /// Creates a BTS that launches tasks in the engine::TaskProcessor used at the + /// BTS creation. + BackgroundTaskStorage(); + + /// Creates a BTS that launches tasks in the specified engine::TaskProcessor. + explicit BackgroundTaskStorage(engine::TaskProcessor& task_processor); + + BackgroundTaskStorage(const BackgroundTaskStorage&) = delete; + BackgroundTaskStorage& operator=(const BackgroundTaskStorage&) = delete; + + /// Explicitly cancel and wait for the tasks. New tasks must not be launched + /// after this call returns. Should be called no more than once. + void CancelAndWait() noexcept; + + /// Explicitly stop accepting new tasks and wait for execution tasks in the + /// store. Should be called no more than once. + void CloseAndWaitDebug() noexcept; + + /// @brief Launch a task that will be cancelled and waited for in the BTS + /// destructor. + /// + /// The task is started as non-Critical, it may be cancelled due to + /// `TaskProcessor` overload. engine::TaskInheritedVariable instances are not + /// inherited from the caller except baggage::Baggage. See + /// utils::AsyncBackground for details. + template + void AsyncDetach(std::string name, Args&&... args) { + core_.Detach(utils::AsyncBackground(std::move(name), task_processor_, std::forward(args)...)); + } + + /// @brief Launch a task that will be cancelled and waited for in the BTS + /// destructor. + /// + /// Execution of function is guaranteed to start regardless + /// of engine::TaskProcessor load limits. + /// engine::TaskInheritedVariable instances are not + /// inherited from the caller except baggage::Baggage. See + /// utils::CriticalAsyncBackground for details. + template + void CriticalAsyncDetach(std::string name, Args&&... args) { + core_.Detach(utils::CriticalAsyncBackground(std::move(name), task_processor_, std::forward(args)...)); + } + + /// Approximate number of currently active tasks + std::int64_t ActiveTasksApprox() const noexcept; + +private: + BackgroundTaskStorageCore core_; + engine::TaskProcessor& task_processor_; }; } // namespace concurrent diff --git a/core/include/userver/concurrent/background_task_storage_fwd.hpp b/core/include/userver/concurrent/background_task_storage_fwd.hpp index 5306fd853c11..f3fed3526856 100644 --- a/core/include/userver/concurrent/background_task_storage_fwd.hpp +++ b/core/include/userver/concurrent/background_task_storage_fwd.hpp @@ -9,8 +9,7 @@ namespace concurrent { class BackgroundTaskStorageCore; class BackgroundTaskStorage; -using BackgroundTaskStorageFastPimpl = - utils::FastPimpl; +using BackgroundTaskStorageFastPimpl = utils::FastPimpl; } // namespace concurrent diff --git a/core/include/userver/concurrent/conflated_event_channel.hpp b/core/include/userver/concurrent/conflated_event_channel.hpp index 09338d6105c5..f20d23f81e9d 100644 --- a/core/include/userver/concurrent/conflated_event_channel.hpp +++ b/core/include/userver/concurrent/conflated_event_channel.hpp @@ -22,52 +22,47 @@ namespace concurrent { /// instead of 'AsyncEventChannel' when we've got a "heavy" subscriber and we /// don't want to slow down the pipeline. class ConflatedEventChannel : private AsyncEventChannel<> { - public: - explicit ConflatedEventChannel(std::string name, - OnRemoveCallback on_listener_removal = {}); - ~ConflatedEventChannel() override; - - /// For convenient forwarding of events from other channels - template - void AddChannel(concurrent::AsyncEventSource& channel); - - using AsyncEventChannel<>::AddListener; - - /// Subscribes to updates using a member function. Also immediately invokes - /// the function with the current config snapshot. - template - concurrent::AsyncEventSubscriberScope UpdateAndListen(Class* obj, - std::string_view name, - void (Class::*func)()); - - void SendEvent(); - - private: - template - void OnChannelEvent(Args...); - - std::atomic stop_flag_; - engine::TaskWithResult task_; - std::vector subscriptions_; - engine::SingleConsumerEvent event_; +public: + explicit ConflatedEventChannel(std::string name, OnRemoveCallback on_listener_removal = {}); + ~ConflatedEventChannel() override; + + /// For convenient forwarding of events from other channels + template + void AddChannel(concurrent::AsyncEventSource& channel); + + using AsyncEventChannel<>::AddListener; + + /// Subscribes to updates using a member function. Also immediately invokes + /// the function with the current config snapshot. + template + concurrent::AsyncEventSubscriberScope UpdateAndListen(Class* obj, std::string_view name, void (Class::*func)()); + + void SendEvent(); + +private: + template + void OnChannelEvent(Args...); + + std::atomic stop_flag_; + engine::TaskWithResult task_; + std::vector subscriptions_; + engine::SingleConsumerEvent event_; }; template -void ConflatedEventChannel::AddChannel( - concurrent::AsyncEventSource& channel) { - subscriptions_.push_back(channel.AddListener( - this, Name(), &ConflatedEventChannel::OnChannelEvent)); +void ConflatedEventChannel::AddChannel(concurrent::AsyncEventSource& channel) { + subscriptions_.push_back(channel.AddListener(this, Name(), &ConflatedEventChannel::OnChannelEvent)); } template -concurrent::AsyncEventSubscriberScope ConflatedEventChannel::UpdateAndListen( - Class* obj, std::string_view name, void (Class::*func)()) { - return DoUpdateAndListen(obj, name, func, [&] { (obj->*func)(); }); +concurrent::AsyncEventSubscriberScope +ConflatedEventChannel::UpdateAndListen(Class* obj, std::string_view name, void (Class::*func)()) { + return DoUpdateAndListen(obj, name, func, [&] { (obj->*func)(); }); } template void ConflatedEventChannel::OnChannelEvent(Args...) { - SendEvent(); + SendEvent(); } } // namespace concurrent diff --git a/core/include/userver/concurrent/impl/intrusive_hooks.hpp b/core/include/userver/concurrent/impl/intrusive_hooks.hpp index 6ab712e2eb31..8b0cd9146e53 100644 --- a/core/include/userver/concurrent/impl/intrusive_hooks.hpp +++ b/core/include/userver/concurrent/impl/intrusive_hooks.hpp @@ -9,47 +9,47 @@ namespace concurrent::impl { template struct MemberHook final { - template - auto& operator()(T& node) const noexcept { - return node.*Member; - } + template + auto& operator()(T& node) const noexcept { + return node.*Member; + } }; template struct CombinedHook final { - static_assert(std::is_empty_v); - static_assert(std::is_empty_v); + static_assert(std::is_empty_v); + static_assert(std::is_empty_v); - template - auto& operator()(T& node) const noexcept { - return HookExtractor2{}(HookExtractor1{}(node)); - } + template + auto& operator()(T& node) const noexcept { + return HookExtractor2{}(HookExtractor1{}(node)); + } }; template class SinglyLinkedHook final { - public: - SinglyLinkedHook() = default; +public: + SinglyLinkedHook() = default; - private: - template - friend class IntrusiveStack; +private: + template + friend class IntrusiveStack; - friend class IntrusiveMpscQueueImpl; + friend class IntrusiveMpscQueueImpl; - std::atomic next_{nullptr}; + std::atomic next_{nullptr}; }; template struct IntrusiveWalkablePoolHook final { - SinglyLinkedHook permanent_list_hook; - SinglyLinkedHook free_list_hook; + SinglyLinkedHook permanent_list_hook; + SinglyLinkedHook free_list_hook; }; // IntrusiveMpscQueue element types must inherit from this. class SinglyLinkedBaseHook { - public: - SinglyLinkedHook singly_linked_hook; +public: + SinglyLinkedHook singly_linked_hook; }; } // namespace concurrent::impl diff --git a/core/include/userver/concurrent/impl/intrusive_stack.hpp b/core/include/userver/concurrent/impl/intrusive_stack.hpp index dff9277b5580..69cf6fe4b8da 100644 --- a/core/include/userver/concurrent/impl/intrusive_stack.hpp +++ b/core/include/userver/concurrent/impl/intrusive_stack.hpp @@ -26,90 +26,90 @@ namespace concurrent::impl { /// Treiber, R.K., 1986. Systems programming: Coping with parallelism. template class IntrusiveStack final { - static_assert(std::is_empty_v); + static_assert(std::is_empty_v); + +public: + constexpr IntrusiveStack() = default; + + IntrusiveStack(IntrusiveStack&&) = delete; + IntrusiveStack& operator=(IntrusiveStack&&) = delete; + + void Push(T& node) noexcept { + UASSERT_MSG( + GetNext(node).load(std::memory_order_relaxed) == nullptr, + "This node is already contained in an IntrusiveStack" + ); + + NodeTaggedPtr expected = stack_head_.load(); + while (true) { + GetNext(node).store(expected.GetDataPtr()); + const NodeTaggedPtr desired(&node, expected.GetTag()); + if (stack_head_.compare_exchange_weak(expected, desired)) { + break; + } + } + } - public: - constexpr IntrusiveStack() = default; + T* TryPop() noexcept { + NodeTaggedPtr expected = stack_head_.load(); + while (true) { + T* const expected_ptr = expected.GetDataPtr(); + if (!expected_ptr) return nullptr; + const NodeTaggedPtr desired(GetNext(*expected_ptr).load(), expected.GetNextTag()); + if (stack_head_.compare_exchange_weak(expected, desired)) { + // 'relaxed' is OK, because popping a node must happen-before pushing it + GetNext(*expected_ptr).store(nullptr, std::memory_order_relaxed); + return expected_ptr; + } + } + } - IntrusiveStack(IntrusiveStack&&) = delete; - IntrusiveStack& operator=(IntrusiveStack&&) = delete; + template + void WalkUnsafe(const Func& func) { + DoWalk(func); + } - void Push(T& node) noexcept { - UASSERT_MSG(GetNext(node).load(std::memory_order_relaxed) == nullptr, - "This node is already contained in an IntrusiveStack"); + template + void WalkUnsafe(const Func& func) const { + DoWalk(func); + } - NodeTaggedPtr expected = stack_head_.load(); - while (true) { - GetNext(node).store(expected.GetDataPtr()); - const NodeTaggedPtr desired(&node, expected.GetTag()); - if (stack_head_.compare_exchange_weak(expected, desired)) { - break; - } + template + void DisposeUnsafe(const DisposerFunc& disposer) noexcept { + T* iter = stack_head_.load().GetDataPtr(); + stack_head_.store(nullptr); + while (iter) { + T* const old_iter = iter; + iter = GetNext(*iter).load(); + disposer(*old_iter); + } } - } - - T* TryPop() noexcept { - NodeTaggedPtr expected = stack_head_.load(); - while (true) { - T* const expected_ptr = expected.GetDataPtr(); - if (!expected_ptr) return nullptr; - const NodeTaggedPtr desired(GetNext(*expected_ptr).load(), - expected.GetNextTag()); - if (stack_head_.compare_exchange_weak(expected, desired)) { - // 'relaxed' is OK, because popping a node must happen-before pushing it - GetNext(*expected_ptr).store(nullptr, std::memory_order_relaxed); - return expected_ptr; - } + + std::size_t GetSizeUnsafe() const noexcept { + std::size_t size = 0; + WalkUnsafe([&](auto& /*item*/) { ++size; }); + return size; } - } - - template - void WalkUnsafe(const Func& func) { - DoWalk(func); - } - - template - void WalkUnsafe(const Func& func) const { - DoWalk(func); - } - - template - void DisposeUnsafe(const DisposerFunc& disposer) noexcept { - T* iter = stack_head_.load().GetDataPtr(); - stack_head_.store(nullptr); - while (iter) { - T* const old_iter = iter; - iter = GetNext(*iter).load(); - disposer(*old_iter); + +private: + using NodeTaggedPtr = TaggedPtr; + + static_assert(std::atomic::is_always_lock_free); + static_assert(std::has_unique_object_representations_v); + + static std::atomic& GetNext(T& node) noexcept { + SinglyLinkedHook& hook = HookExtractor{}(node); + return hook.next_; } - } - - std::size_t GetSizeUnsafe() const noexcept { - std::size_t size = 0; - WalkUnsafe([&](auto& /*item*/) { ++size; }); - return size; - } - - private: - using NodeTaggedPtr = TaggedPtr; - - static_assert(std::atomic::is_always_lock_free); - static_assert(std::has_unique_object_representations_v); - - static std::atomic& GetNext(T& node) noexcept { - SinglyLinkedHook& hook = HookExtractor{}(node); - return hook.next_; - } - - template - void DoWalk(const Func& func) const { - for (auto* iter = stack_head_.load().GetDataPtr(); iter; - iter = GetNext(*iter).load()) { - func(static_cast(*iter)); + + template + void DoWalk(const Func& func) const { + for (auto* iter = stack_head_.load().GetDataPtr(); iter; iter = GetNext(*iter).load()) { + func(static_cast(*iter)); + } } - } - std::atomic stack_head_{nullptr}; + std::atomic stack_head_{nullptr}; }; } // namespace concurrent::impl diff --git a/core/include/userver/concurrent/impl/semaphore_capacity_control.hpp b/core/include/userver/concurrent/impl/semaphore_capacity_control.hpp index 721e603e1526..c6f274753940 100644 --- a/core/include/userver/concurrent/impl/semaphore_capacity_control.hpp +++ b/core/include/userver/concurrent/impl/semaphore_capacity_control.hpp @@ -18,27 +18,27 @@ namespace concurrent::impl { // - such an update must not be missed and must take effect after the queue // is "unblocked" class SemaphoreCapacityControl final { - public: - using Counter = engine::Semaphore::Counter; - static constexpr Counter kOverrideDisabled = -1; +public: + using Counter = engine::Semaphore::Counter; + static constexpr Counter kOverrideDisabled = -1; - explicit SemaphoreCapacityControl(engine::CancellableSemaphore& semaphore); + explicit SemaphoreCapacityControl(engine::CancellableSemaphore& semaphore); - // These methods may be called concurrently from N threads. - void SetCapacity(Counter capacity); - Counter GetCapacity() const noexcept; + // These methods may be called concurrently from N threads. + void SetCapacity(Counter capacity); + Counter GetCapacity() const noexcept; - // These methods may be called from 1 thread at a time, potentially - // concurrently with *Capacity. - void SetCapacityOverride(Counter capacity); - void RemoveCapacityOverride(); + // These methods may be called from 1 thread at a time, potentially + // concurrently with *Capacity. + void SetCapacityOverride(Counter capacity); + void RemoveCapacityOverride(); - private: - void UpdateSemaphoreCapacity() const; +private: + void UpdateSemaphoreCapacity() const; - engine::CancellableSemaphore& semaphore_; - std::atomic capacity_requested_; - std::atomic capacity_override_{kOverrideDisabled}; + engine::CancellableSemaphore& semaphore_; + std::atomic capacity_requested_; + std::atomic capacity_override_{kOverrideDisabled}; }; } // namespace concurrent::impl diff --git a/core/include/userver/concurrent/impl/striped_read_indicator.hpp b/core/include/userver/concurrent/impl/striped_read_indicator.hpp index f3a606da3162..c1bf387b1cfa 100644 --- a/core/include/userver/concurrent/impl/striped_read_indicator.hpp +++ b/core/include/userver/concurrent/impl/striped_read_indicator.hpp @@ -29,95 +29,94 @@ class StripedReadIndicatorLock; /// /// @see Based on ideas from https://youtu.be/FtaD0maxwec class StripedReadIndicator final { - public: - /// @brief Create a new unused instance of `ReadIndicator`. - StripedReadIndicator(); - - StripedReadIndicator(StripedReadIndicator&&) = delete; - StripedReadIndicator& operator=(StripedReadIndicator&&) = delete; - ~StripedReadIndicator(); - - /// @brief Mark the indicator as "used" as long as the returned lock is alive. - /// @note The lock should not outlive the `StripedReadIndicator`. - /// @note The data may still be retired in parallel with a `Lock()` call. - /// After calling `Lock`, the reader must check whether the data has been - /// retired in the meantime. - /// @note `Lock` uses `std::memory_order_relaxed`, and unlock uses - /// `std::memory_order_release` to ensure that unlocks don't run ahead - /// of locks from `IsFree`'s point of view. - /// @warning Readers must ensure that `Lock` is visible by `IsFree` checks - /// in other threads when necessary - /// (which may require `std::atomic_thread_fence(std::memory_order_seq_cst)`. - /// `Lock` and `IsFree` use weak memory orders, which may lead to `Lock` - /// unexpectedly not being visible to `IsFree`. - StripedReadIndicatorLock Lock() noexcept; - - /// @returns `true` if there are no locks held on the `StripedReadIndicator`. - /// @note `IsFree` should only be called after direct access to this - /// StripedReadIndicator is closed for readers. Locks acquired during - /// the `IsFree` call may or may not be accounted for. - /// @note May sometimes falsely return `false` when the `StripedReadIndicator` - /// has just become free. Never falsely returns `true`. - /// @note Uses effectively `std::memory_order_acquire`. - bool IsFree() const noexcept; - - /// @returns `true` if there are no locks held on any of the `indicators`. - /// @see IsFree - template - static bool AreAllFree(StripedReadIndicatorRange&& indicators) { - // See GetActiveCountApprox for implementation strategy explanation. - std::uintptr_t released = 0; - for (const auto& indicator : indicators) { - released += indicator.released_count_.Read(); +public: + /// @brief Create a new unused instance of `ReadIndicator`. + StripedReadIndicator(); + + StripedReadIndicator(StripedReadIndicator&&) = delete; + StripedReadIndicator& operator=(StripedReadIndicator&&) = delete; + ~StripedReadIndicator(); + + /// @brief Mark the indicator as "used" as long as the returned lock is alive. + /// @note The lock should not outlive the `StripedReadIndicator`. + /// @note The data may still be retired in parallel with a `Lock()` call. + /// After calling `Lock`, the reader must check whether the data has been + /// retired in the meantime. + /// @note `Lock` uses `std::memory_order_relaxed`, and unlock uses + /// `std::memory_order_release` to ensure that unlocks don't run ahead + /// of locks from `IsFree`'s point of view. + /// @warning Readers must ensure that `Lock` is visible by `IsFree` checks + /// in other threads when necessary + /// (which may require `std::atomic_thread_fence(std::memory_order_seq_cst)`. + /// `Lock` and `IsFree` use weak memory orders, which may lead to `Lock` + /// unexpectedly not being visible to `IsFree`. + StripedReadIndicatorLock Lock() noexcept; + + /// @returns `true` if there are no locks held on the `StripedReadIndicator`. + /// @note `IsFree` should only be called after direct access to this + /// StripedReadIndicator is closed for readers. Locks acquired during + /// the `IsFree` call may or may not be accounted for. + /// @note May sometimes falsely return `false` when the `StripedReadIndicator` + /// has just become free. Never falsely returns `true`. + /// @note Uses effectively `std::memory_order_acquire`. + bool IsFree() const noexcept; + + /// @returns `true` if there are no locks held on any of the `indicators`. + /// @see IsFree + template + static bool AreAllFree(StripedReadIndicatorRange&& indicators) { + // See GetActiveCountApprox for implementation strategy explanation. + std::uintptr_t released = 0; + for (const auto& indicator : indicators) { + released += indicator.released_count_.Read(); + } + + std::uintptr_t acquired = 0; + for (const auto& indicator : indicators) { + acquired += indicator.acquired_count_.Read(); + } + + UASSERT(acquired - released <= std::numeric_limits::max() / 2); + return acquired == released; } - std::uintptr_t acquired = 0; - for (const auto& indicator : indicators) { - acquired += indicator.acquired_count_.Read(); - } - - UASSERT(acquired - released <= - std::numeric_limits::max() / 2); - return acquired == released; - } - - /// Get the total amount of `Lock` calls, useful for metrics. - std::uintptr_t GetAcquireCountApprox() const noexcept; + /// Get the total amount of `Lock` calls, useful for metrics. + std::uintptr_t GetAcquireCountApprox() const noexcept; - /// Get the total amount of `Lock` drops, useful for metrics. - std::uintptr_t GetReleaseCountApprox() const noexcept; + /// Get the total amount of `Lock` drops, useful for metrics. + std::uintptr_t GetReleaseCountApprox() const noexcept; - /// Get the approximate amount of locks held, useful for metrics. - std::uintptr_t GetActiveCountApprox() const noexcept; + /// Get the approximate amount of locks held, useful for metrics. + std::uintptr_t GetActiveCountApprox() const noexcept; - private: - friend class StripedReadIndicatorLock; +private: + friend class StripedReadIndicatorLock; - void DoLock() noexcept; - void DoUnlock() noexcept; + void DoLock() noexcept; + void DoUnlock() noexcept; - StripedCounter acquired_count_; - StripedCounter released_count_; + StripedCounter acquired_count_; + StripedCounter released_count_; }; /// @brief Keeps the data protected by a StripedReadIndicator from being retired class [[nodiscard]] StripedReadIndicatorLock final { - public: - /// @brief Produces a `null` instance - StripedReadIndicatorLock() noexcept = default; +public: + /// @brief Produces a `null` instance + StripedReadIndicatorLock() noexcept = default; - StripedReadIndicatorLock(StripedReadIndicatorLock&&) noexcept; - StripedReadIndicatorLock(const StripedReadIndicatorLock&) noexcept; - StripedReadIndicatorLock& operator=(StripedReadIndicatorLock&&) noexcept; - StripedReadIndicatorLock& operator=(const StripedReadIndicatorLock&) noexcept; - ~StripedReadIndicatorLock(); + StripedReadIndicatorLock(StripedReadIndicatorLock&&) noexcept; + StripedReadIndicatorLock(const StripedReadIndicatorLock&) noexcept; + StripedReadIndicatorLock& operator=(StripedReadIndicatorLock&&) noexcept; + StripedReadIndicatorLock& operator=(const StripedReadIndicatorLock&) noexcept; + ~StripedReadIndicatorLock(); - private: - explicit StripedReadIndicatorLock(StripedReadIndicator& indicator) noexcept; +private: + explicit StripedReadIndicatorLock(StripedReadIndicator& indicator) noexcept; - friend class StripedReadIndicator; + friend class StripedReadIndicator; - StripedReadIndicator* indicator_{nullptr}; + StripedReadIndicator* indicator_{nullptr}; }; } // namespace concurrent::impl diff --git a/core/include/userver/concurrent/impl/tagged_ptr.hpp b/core/include/userver/concurrent/impl/tagged_ptr.hpp index ad25d528aaf7..360b4771e835 100644 --- a/core/include/userver/concurrent/impl/tagged_ptr.hpp +++ b/core/include/userver/concurrent/impl/tagged_ptr.hpp @@ -11,31 +11,28 @@ namespace concurrent::impl { template class TaggedPtr final { - static_assert(sizeof(std::uintptr_t) <= sizeof(std::uint64_t)); - static constexpr std::uint64_t kTagShift = 48; + static_assert(sizeof(std::uintptr_t) <= sizeof(std::uint64_t)); + static constexpr std::uint64_t kTagShift = 48; - public: - using Tag = std::uint16_t; +public: + using Tag = std::uint16_t; - constexpr /*implicit*/ TaggedPtr(std::nullptr_t) noexcept : impl_(0) {} + constexpr /*implicit*/ TaggedPtr(std::nullptr_t) noexcept : impl_(0) {} - TaggedPtr(T* ptr, Tag tag) - : impl_(reinterpret_cast(ptr) | - (std::uint64_t{tag} << kTagShift)) { - UASSERT(!(reinterpret_cast(ptr) & 0xffff'0000'0000'0000)); - } + TaggedPtr(T* ptr, Tag tag) : impl_(reinterpret_cast(ptr) | (std::uint64_t{tag} << kTagShift)) { + UASSERT(!(reinterpret_cast(ptr) & 0xffff'0000'0000'0000)); + } - T* GetDataPtr() const noexcept { - return reinterpret_cast(static_cast( - impl_ & ((std::uint64_t{1} << kTagShift) - 1))); - } + T* GetDataPtr() const noexcept { + return reinterpret_cast(static_cast(impl_ & ((std::uint64_t{1} << kTagShift) - 1))); + } - Tag GetTag() const noexcept { return static_cast(impl_ >> kTagShift); } + Tag GetTag() const noexcept { return static_cast(impl_ >> kTagShift); } - Tag GetNextTag() const noexcept { return static_cast(GetTag() + 1); } + Tag GetNextTag() const noexcept { return static_cast(GetTag() + 1); } - private: - std::uint64_t impl_; +private: + std::uint64_t impl_; }; } // namespace concurrent::impl diff --git a/core/include/userver/concurrent/lazy_value.hpp b/core/include/userver/concurrent/lazy_value.hpp index d5cb60e6eae9..d504353c49d4 100644 --- a/core/include/userver/concurrent/lazy_value.hpp +++ b/core/include/userver/concurrent/lazy_value.hpp @@ -20,54 +20,52 @@ namespace concurrent { /// @brief lazy value computation with multiple users template class LazyValue final { - public: - explicit LazyValue(std::function f) : f_(std::move(f)) { UASSERT(f_); } - - /// @brief Get an already calculated result or calculate it. - /// It is guaranteed that `f` is called exactly once. - /// Can be called concurrently from multiple coroutines. - /// @throws anything `f` throws. - const T& operator()(); - - private: - std::function f_; - std::atomic started_{false}; - utils::ResultStore result_; - - engine::ConditionVariable cv_finished_; - engine::Mutex m_finished_; - std::atomic finished_{false}; +public: + explicit LazyValue(std::function f) : f_(std::move(f)) { UASSERT(f_); } + + /// @brief Get an already calculated result or calculate it. + /// It is guaranteed that `f` is called exactly once. + /// Can be called concurrently from multiple coroutines. + /// @throws anything `f` throws. + const T& operator()(); + +private: + std::function f_; + std::atomic started_{false}; + utils::ResultStore result_; + + engine::ConditionVariable cv_finished_; + engine::Mutex m_finished_; + std::atomic finished_{false}; }; template const T& LazyValue::operator()() { - if (finished_) return result_.Get(); - - auto old = started_.exchange(true); - if (!old) { - try { - result_.SetValue(f_()); - - std::lock_guard lock(m_finished_); - finished_ = true; - cv_finished_.NotifyAll(); - } catch (...) { - result_.SetException(std::current_exception()); - - std::lock_guard lock(m_finished_); - finished_ = true; - cv_finished_.NotifyAll(); - throw; + if (finished_) return result_.Get(); + + auto old = started_.exchange(true); + if (!old) { + try { + result_.SetValue(f_()); + + std::lock_guard lock(m_finished_); + finished_ = true; + cv_finished_.NotifyAll(); + } catch (...) { + result_.SetException(std::current_exception()); + + std::lock_guard lock(m_finished_); + finished_ = true; + cv_finished_.NotifyAll(); + throw; + } + } else { + std::unique_lock lock(m_finished_); + auto rc = cv_finished_.Wait(lock, [this]() { return finished_.load(); }); + if (!rc) throw engine::WaitInterruptedException(engine::current_task::CancellationReason()); } - } else { - std::unique_lock lock(m_finished_); - auto rc = cv_finished_.Wait(lock, [this]() { return finished_.load(); }); - if (!rc) - throw engine::WaitInterruptedException( - engine::current_task::CancellationReason()); - } - - return result_.Get(); + + return result_.Get(); } } // namespace concurrent diff --git a/core/include/userver/concurrent/mpsc_queue.hpp b/core/include/userver/concurrent/mpsc_queue.hpp index 52dfdc235cd5..ffede41b89d6 100644 --- a/core/include/userver/concurrent/mpsc_queue.hpp +++ b/core/include/userver/concurrent/mpsc_queue.hpp @@ -26,38 +26,37 @@ namespace impl { /// Helper template. Default implementation is straightforward. template struct QueueHelper { - using LockFreeQueue = boost::lockfree::queue; + using LockFreeQueue = boost::lockfree::queue; - static void Push(LockFreeQueue& queue, T&& value) { - [[maybe_unused]] bool push_result = queue.push(std::move(value)); - UASSERT(push_result); - } + static void Push(LockFreeQueue& queue, T&& value) { + [[maybe_unused]] bool push_result = queue.push(std::move(value)); + UASSERT(push_result); + } - [[nodiscard]] static bool Pop(LockFreeQueue& queue, T& value) { - return queue.pop(value); - } + [[nodiscard]] static bool Pop(LockFreeQueue& queue, T& value) { return queue.pop(value); } - static_assert(std::is_trivially_destructible_v, - "T has non-trivial destructor. Use " - "MpscQueue> instead of MpscQueue"); + static_assert( + std::is_trivially_destructible_v, + "T has non-trivial destructor. Use " + "MpscQueue> instead of MpscQueue" + ); }; /// This partial specialization allows to use std::unique_ptr with Queue. template struct QueueHelper> { - using LockFreeQueue = boost::lockfree::queue; + using LockFreeQueue = boost::lockfree::queue; - static void Push(LockFreeQueue& queue, std::unique_ptr&& value) { - QueueHelper::Push(queue, value.release()); - } + static void Push(LockFreeQueue& queue, std::unique_ptr&& value) { + QueueHelper::Push(queue, value.release()); + } - [[nodiscard]] static bool Pop(LockFreeQueue& queue, - std::unique_ptr& value) { - T* ptr{nullptr}; - if (!QueueHelper::Pop(queue, ptr)) return false; - value.reset(ptr); - return true; - } + [[nodiscard]] static bool Pop(LockFreeQueue& queue, std::unique_ptr& value) { + T* ptr{nullptr}; + if (!QueueHelper::Pop(queue, ptr)) return false; + value.reset(ptr); + return true; + } }; } // namespace impl @@ -73,225 +72,214 @@ struct QueueHelper> { /// @see @ref scripts/docs/en/userver/synchronization.md template class MpscQueue final : public std::enable_shared_from_this> { - struct EmplaceEnabler final { - // Disable {}-initialization in Queue's constructor - explicit EmplaceEnabler() = default; - }; - - using QueueHelper = impl::QueueHelper; - - using ProducerToken = impl::NoToken; - using ConsumerToken = impl::NoToken; - - friend class Producer; - friend class Consumer; - - public: - static constexpr std::size_t kUnbounded = - std::numeric_limits::max(); - - using ValueType = T; - - using Producer = - concurrent::Producer; - using Consumer = - concurrent::Consumer; - using MultiProducer = - concurrent::Producer; - - /// @cond - // For internal use only - explicit MpscQueue(std::size_t max_size, EmplaceEnabler /*unused*/) - : remaining_capacity_(max_size), - remaining_capacity_control_(remaining_capacity_) {} - - MpscQueue(MpscQueue&&) = delete; - MpscQueue(const MpscQueue&) = delete; - MpscQueue& operator=(MpscQueue&&) = delete; - MpscQueue& operator=(const MpscQueue&) = delete; - ~MpscQueue(); - /// @endcond - - /// Create a new queue - static std::shared_ptr Create(std::size_t max_size = kUnbounded) { - return std::make_shared(max_size, EmplaceEnabler{}); - } - - /// Get a `Producer` which makes it possible to push items into the queue. - /// Can be called multiple times. The resulting `Producer` is not thread-safe, - /// so you have to use multiple Producers of the same queue to simultaneously - /// write from multiple coroutines/threads. - /// - /// @note `Producer` may outlive the queue and the `Consumer`. - Producer GetProducer(); - - /// Get a `MultiProducer` which makes it possible to push items into the - /// queue. Can be called multiple times. The resulting `MultiProducer` is - /// thread-safe, so it can be used simultaneously from multiple - /// coroutines/threads. - /// - /// @note `MultiProducer` may outlive the queue and the `Consumer`. - MultiProducer GetMultiProducer(); - - /// Get a `Consumer` which makes it possible to read items from the queue. - /// Can be called only once. You may not use the `Consumer` simultaneously - /// from multiple coroutines/threads. - /// - /// @note `Consumer` may outlive the queue and producers. - Consumer GetConsumer(); - - /// @brief Sets the limit on the queue size, pushes over this limit will block - /// @note This is a soft limit and may be slightly overrun under load. - void SetSoftMaxSize(size_t size); - - /// @brief Gets the limit on the queue size - [[nodiscard]] size_t GetSoftMaxSize() const; - - /// @brief Gets the approximate size of queue - [[nodiscard]] size_t GetSizeApproximate() const; - - private: - bool Push(ProducerToken&, T&&, engine::Deadline); - bool PushNoblock(ProducerToken&, T&&); - bool DoPush(ProducerToken&, T&&); - - bool Pop(ConsumerToken&, T&, engine::Deadline); - bool PopNoblock(ConsumerToken&, T&); - bool DoPop(ConsumerToken&, T&); - - void MarkConsumerIsDead(); - void MarkProducerIsDead(); - - // Resolves to boost::lockfree::queue except for std::unique_ptr - // specialization. In that case, resolves to boost::lockfree::queue - typename QueueHelper::LockFreeQueue queue_{1}; - engine::SingleConsumerEvent nonempty_event_; - engine::CancellableSemaphore remaining_capacity_; - concurrent::impl::SemaphoreCapacityControl remaining_capacity_control_; - std::atomic consumer_is_created_{false}; - std::atomic consumer_is_created_and_dead_{false}; - std::atomic producer_is_created_and_dead_{false}; - std::atomic producers_count_{0}; - std::atomic size_{0}; + struct EmplaceEnabler final { + // Disable {}-initialization in Queue's constructor + explicit EmplaceEnabler() = default; + }; + + using QueueHelper = impl::QueueHelper; + + using ProducerToken = impl::NoToken; + using ConsumerToken = impl::NoToken; + + friend class Producer; + friend class Consumer; + +public: + static constexpr std::size_t kUnbounded = std::numeric_limits::max(); + + using ValueType = T; + + using Producer = concurrent::Producer; + using Consumer = concurrent::Consumer; + using MultiProducer = concurrent::Producer; + + /// @cond + // For internal use only + explicit MpscQueue(std::size_t max_size, EmplaceEnabler /*unused*/) + : remaining_capacity_(max_size), remaining_capacity_control_(remaining_capacity_) {} + + MpscQueue(MpscQueue&&) = delete; + MpscQueue(const MpscQueue&) = delete; + MpscQueue& operator=(MpscQueue&&) = delete; + MpscQueue& operator=(const MpscQueue&) = delete; + ~MpscQueue(); + /// @endcond + + /// Create a new queue + static std::shared_ptr Create(std::size_t max_size = kUnbounded) { + return std::make_shared(max_size, EmplaceEnabler{}); + } + + /// Get a `Producer` which makes it possible to push items into the queue. + /// Can be called multiple times. The resulting `Producer` is not thread-safe, + /// so you have to use multiple Producers of the same queue to simultaneously + /// write from multiple coroutines/threads. + /// + /// @note `Producer` may outlive the queue and the `Consumer`. + Producer GetProducer(); + + /// Get a `MultiProducer` which makes it possible to push items into the + /// queue. Can be called multiple times. The resulting `MultiProducer` is + /// thread-safe, so it can be used simultaneously from multiple + /// coroutines/threads. + /// + /// @note `MultiProducer` may outlive the queue and the `Consumer`. + MultiProducer GetMultiProducer(); + + /// Get a `Consumer` which makes it possible to read items from the queue. + /// Can be called only once. You may not use the `Consumer` simultaneously + /// from multiple coroutines/threads. + /// + /// @note `Consumer` may outlive the queue and producers. + Consumer GetConsumer(); + + /// @brief Sets the limit on the queue size, pushes over this limit will block + /// @note This is a soft limit and may be slightly overrun under load. + void SetSoftMaxSize(size_t size); + + /// @brief Gets the limit on the queue size + [[nodiscard]] size_t GetSoftMaxSize() const; + + /// @brief Gets the approximate size of queue + [[nodiscard]] size_t GetSizeApproximate() const; + +private: + bool Push(ProducerToken&, T&&, engine::Deadline); + bool PushNoblock(ProducerToken&, T&&); + bool DoPush(ProducerToken&, T&&); + + bool Pop(ConsumerToken&, T&, engine::Deadline); + bool PopNoblock(ConsumerToken&, T&); + bool DoPop(ConsumerToken&, T&); + + void MarkConsumerIsDead(); + void MarkProducerIsDead(); + + // Resolves to boost::lockfree::queue except for std::unique_ptr + // specialization. In that case, resolves to boost::lockfree::queue + typename QueueHelper::LockFreeQueue queue_{1}; + engine::SingleConsumerEvent nonempty_event_; + engine::CancellableSemaphore remaining_capacity_; + concurrent::impl::SemaphoreCapacityControl remaining_capacity_control_; + std::atomic consumer_is_created_{false}; + std::atomic consumer_is_created_and_dead_{false}; + std::atomic producer_is_created_and_dead_{false}; + std::atomic producers_count_{0}; + std::atomic size_{0}; }; template MpscQueue::~MpscQueue() { - UASSERT(consumer_is_created_and_dead_ || !consumer_is_created_); - UASSERT(!producers_count_); - // Clear remaining items in queue. This will work for unique_ptr as well. - T value; - ConsumerToken temp_token{queue_}; - while (PopNoblock(temp_token, value)) { - } + UASSERT(consumer_is_created_and_dead_ || !consumer_is_created_); + UASSERT(!producers_count_); + // Clear remaining items in queue. This will work for unique_ptr as well. + T value; + ConsumerToken temp_token{queue_}; + while (PopNoblock(temp_token, value)) { + } } template typename MpscQueue::Producer MpscQueue::GetProducer() { - producers_count_++; - producer_is_created_and_dead_ = false; - nonempty_event_.Send(); - return Producer(this->shared_from_this(), EmplaceEnabler{}); + producers_count_++; + producer_is_created_and_dead_ = false; + nonempty_event_.Send(); + return Producer(this->shared_from_this(), EmplaceEnabler{}); } template typename MpscQueue::MultiProducer MpscQueue::GetMultiProducer() { - // MultiProducer and Producer are actually the same for MpscQueue, which is an - // implementation detail. - return GetProducer(); + // MultiProducer and Producer are actually the same for MpscQueue, which is an + // implementation detail. + return GetProducer(); } template typename MpscQueue::Consumer MpscQueue::GetConsumer() { - UINVARIANT(!consumer_is_created_, - "MpscQueue::Consumer must only be obtained a single time"); - consumer_is_created_ = true; - return Consumer(this->shared_from_this(), EmplaceEnabler{}); + UINVARIANT(!consumer_is_created_, "MpscQueue::Consumer must only be obtained a single time"); + consumer_is_created_ = true; + return Consumer(this->shared_from_this(), EmplaceEnabler{}); } template void MpscQueue::SetSoftMaxSize(size_t max_size) { - remaining_capacity_control_.SetCapacity(max_size); + remaining_capacity_control_.SetCapacity(max_size); } template size_t MpscQueue::GetSoftMaxSize() const { - return remaining_capacity_control_.GetCapacity(); + return remaining_capacity_control_.GetCapacity(); } template size_t MpscQueue::GetSizeApproximate() const { - return size_; + return size_; } template -bool MpscQueue::Push(ProducerToken& token, T&& value, - engine::Deadline deadline) { - return remaining_capacity_.try_lock_shared_until(deadline) && - DoPush(token, std::move(value)); +bool MpscQueue::Push(ProducerToken& token, T&& value, engine::Deadline deadline) { + return remaining_capacity_.try_lock_shared_until(deadline) && DoPush(token, std::move(value)); } template bool MpscQueue::PushNoblock(ProducerToken& token, T&& value) { - return remaining_capacity_.try_lock_shared() && - DoPush(token, std::move(value)); + return remaining_capacity_.try_lock_shared() && DoPush(token, std::move(value)); } template bool MpscQueue::DoPush(ProducerToken& /*unused*/, T&& value) { - if (consumer_is_created_and_dead_) { - remaining_capacity_.unlock_shared(); - return false; - } + if (consumer_is_created_and_dead_) { + remaining_capacity_.unlock_shared(); + return false; + } - QueueHelper::Push(queue_, std::move(value)); - ++size_; - nonempty_event_.Send(); + QueueHelper::Push(queue_, std::move(value)); + ++size_; + nonempty_event_.Send(); - return true; + return true; } template -bool MpscQueue::Pop(ConsumerToken& token, T& value, - engine::Deadline deadline) { - while (!DoPop(token, value)) { - if (producer_is_created_and_dead_ || - !nonempty_event_.WaitForEventUntil(deadline)) { - // Producer might have pushed something in queue between .pop() - // and !producer_is_created_and_dead_ check. Check twice to avoid - // TOCTOU. - return DoPop(token, value); +bool MpscQueue::Pop(ConsumerToken& token, T& value, engine::Deadline deadline) { + while (!DoPop(token, value)) { + if (producer_is_created_and_dead_ || !nonempty_event_.WaitForEventUntil(deadline)) { + // Producer might have pushed something in queue between .pop() + // and !producer_is_created_and_dead_ check. Check twice to avoid + // TOCTOU. + return DoPop(token, value); + } } - } - return true; + return true; } template bool MpscQueue::PopNoblock(ConsumerToken& token, T& value) { - return DoPop(token, value); + return DoPop(token, value); } template bool MpscQueue::DoPop(ConsumerToken& /*unused*/, T& value) { - if (QueueHelper::Pop(queue_, value)) { - --size_; - remaining_capacity_.unlock_shared(); - nonempty_event_.Reset(); - return true; - } - return false; + if (QueueHelper::Pop(queue_, value)) { + --size_; + remaining_capacity_.unlock_shared(); + nonempty_event_.Reset(); + return true; + } + return false; } template void MpscQueue::MarkConsumerIsDead() { - consumer_is_created_and_dead_ = true; - remaining_capacity_control_.SetCapacityOverride(0); + consumer_is_created_and_dead_ = true; + remaining_capacity_control_.SetCapacityOverride(0); } template void MpscQueue::MarkProducerIsDead() { - producer_is_created_and_dead_ = (--producers_count_ == 0); - nonempty_event_.Send(); + producer_is_created_and_dead_ = (--producers_count_ == 0); + nonempty_event_.Send(); } } // namespace concurrent diff --git a/core/include/userver/concurrent/mutex_set.hpp b/core/include/userver/concurrent/mutex_set.hpp index 5df9f12736c1..00af522dec20 100644 --- a/core/include/userver/concurrent/mutex_set.hpp +++ b/core/include/userver/concurrent/mutex_set.hpp @@ -23,17 +23,13 @@ namespace impl { template struct MutexDatum final { - explicit MutexDatum(size_t way_size, const Equal& equal = Equal{}) - : set(way_size, {}, equal) {} + explicit MutexDatum(size_t way_size, const Equal& equal = Equal{}) : set(way_size, {}, equal) {} - ~MutexDatum() { - UASSERT_MSG(set.empty(), - "MutexDatum is destroyed while someone is holding the lock"); - } + ~MutexDatum() { UASSERT_MSG(set.empty(), "MutexDatum is destroyed while someone is holding the lock"); } - engine::Mutex mutex; - engine::ConditionVariable cv; - std::unordered_set, Equal> set; + engine::Mutex mutex; + engine::ConditionVariable cv; + std::unordered_set, Equal> set; }; } // namespace impl @@ -48,31 +44,30 @@ struct MutexDatum final { /// @note can be used only from coroutines. template class ItemMutex final { - public: - using HashAndKey = utils::CachedHash; +public: + using HashAndKey = utils::CachedHash; - using MutexDatum = - impl::MutexDatum>; + using MutexDatum = impl::MutexDatum>; - ItemMutex(MutexDatum& md, HashAndKey&& key); + ItemMutex(MutexDatum& md, HashAndKey&& key); - void lock(); + void lock(); - void unlock(); + void unlock(); - bool try_lock(); + bool try_lock(); - template - bool try_lock_for(std::chrono::duration); + template + bool try_lock_for(std::chrono::duration); - template - bool try_lock_until(std::chrono::time_point); + template + bool try_lock_until(std::chrono::time_point); - private: - bool TryFinishLocking(); +private: + bool TryFinishLocking(); - MutexDatum& md_; - const HashAndKey key_; + MutexDatum& md_; + const HashAndKey key_; }; /// @ingroup userver_concurrency userver_containers @@ -85,105 +80,96 @@ class ItemMutex final { /// /// Example: /// @snippet src/concurrent/mutex_set_test.cpp Sample mutex set usage -template , - typename Equal = std::equal_to> +template , typename Equal = std::equal_to> class MutexSet final : Hash { - public: - explicit MutexSet(size_t ways = 1, size_t way_size = 1, - const Hash& hash = Hash{}, const Equal& equal = Equal{}); - - /// Get the mutex-like object for a key. Coroutine-safe. - /// @note the returned object holds a reference to MutexSet, so make sure - /// that MutexSet is alive while you're working with ItemMutex. - ItemMutex GetMutexForKey(Key key); - - private: - using MutexDatum = typename ItemMutex::MutexDatum; - utils::FixedArray mutex_data_; +public: + explicit MutexSet(size_t ways = 1, size_t way_size = 1, const Hash& hash = Hash{}, const Equal& equal = Equal{}); + + /// Get the mutex-like object for a key. Coroutine-safe. + /// @note the returned object holds a reference to MutexSet, so make sure + /// that MutexSet is alive while you're working with ItemMutex. + ItemMutex GetMutexForKey(Key key); + +private: + using MutexDatum = typename ItemMutex::MutexDatum; + utils::FixedArray mutex_data_; }; template -MutexSet::MutexSet(size_t ways, size_t way_size, - const Hash& hash, const Equal& equal) - : Hash(hash), - mutex_data_(ways, way_size, utils::CachedHashKeyEqual{equal}) {} +MutexSet::MutexSet(size_t ways, size_t way_size, const Hash& hash, const Equal& equal) + : Hash(hash), mutex_data_(ways, way_size, utils::CachedHashKeyEqual{equal}) {} template ItemMutex MutexSet::GetMutexForKey(Key key) { - const auto hash_value = Hash::operator()(key); - const auto size = mutex_data_.size(); + const auto hash_value = Hash::operator()(key); + const auto size = mutex_data_.size(); - // Compilers optimize a % b and a / b to a single div operation - const auto way = hash_value % size; - const auto new_hash = hash_value / size; + // Compilers optimize a % b and a / b to a single div operation + const auto way = hash_value % size; + const auto new_hash = hash_value / size; - return ItemMutex(mutex_data_[way], {new_hash, std::move(key)}); + return ItemMutex(mutex_data_[way], {new_hash, std::move(key)}); } template -ItemMutex::ItemMutex(MutexDatum& md, HashAndKey&& key) - : md_(md), key_(std::move(key)) {} +ItemMutex::ItemMutex(MutexDatum& md, HashAndKey&& key) : md_(md), key_(std::move(key)) {} template void ItemMutex::lock() { - engine::TaskCancellationBlocker blocker; - std::unique_lock lock(md_.mutex); + engine::TaskCancellationBlocker blocker; + std::unique_lock lock(md_.mutex); - [[maybe_unused]] auto is_locked = - md_.cv.Wait(lock, [this] { return TryFinishLocking(); }); - UASSERT(is_locked); + [[maybe_unused]] auto is_locked = md_.cv.Wait(lock, [this] { return TryFinishLocking(); }); + UASSERT(is_locked); } template void ItemMutex::unlock() { - std::unique_lock lock(md_.mutex); - - // Forcing the destructor of the node to run outside of the critical section - [[maybe_unused]] auto node = md_.set.extract(key_); - - // We must wakeup all the waiters, because otherwise we can wake up the wrong - // one and loose the wakeup: - // - // Task #1 waits for mutex A, task #2 waits for mutex B - // Task #3 - // * unlocks mutex A - // * does NotifyOne - // * wakeups thread #2 - // * mutex B is still locked, task #2 goes to sleep - // * we lost the wakeup :( - md_.cv.NotifyAll(); - - lock.unlock(); - - // Destructor of node is run here + std::unique_lock lock(md_.mutex); + + // Forcing the destructor of the node to run outside of the critical section + [[maybe_unused]] auto node = md_.set.extract(key_); + + // We must wakeup all the waiters, because otherwise we can wake up the wrong + // one and loose the wakeup: + // + // Task #1 waits for mutex A, task #2 waits for mutex B + // Task #3 + // * unlocks mutex A + // * does NotifyOne + // * wakeups thread #2 + // * mutex B is still locked, task #2 goes to sleep + // * we lost the wakeup :( + md_.cv.NotifyAll(); + + lock.unlock(); + + // Destructor of node is run here } template bool ItemMutex::try_lock() { - std::unique_lock lock(md_.mutex); - return TryFinishLocking(); + std::unique_lock lock(md_.mutex); + return TryFinishLocking(); } template template -bool ItemMutex::try_lock_for( - std::chrono::duration duration) { - std::unique_lock lock(md_.mutex); - return md_.cv.WaitFor(lock, duration, [this] { return TryFinishLocking(); }); +bool ItemMutex::try_lock_for(std::chrono::duration duration) { + std::unique_lock lock(md_.mutex); + return md_.cv.WaitFor(lock, duration, [this] { return TryFinishLocking(); }); } template template -bool ItemMutex::try_lock_until( - std::chrono::time_point time_point) { - std::unique_lock lock(md_.mutex); - return md_.cv.WaitUntil(lock, time_point, - [this] { return TryFinishLocking(); }); +bool ItemMutex::try_lock_until(std::chrono::time_point time_point) { + std::unique_lock lock(md_.mutex); + return md_.cv.WaitUntil(lock, time_point, [this] { return TryFinishLocking(); }); } template bool ItemMutex::TryFinishLocking() { - return md_.set.insert(key_).second; + return md_.set.insert(key_).second; } } // namespace concurrent diff --git a/core/include/userver/concurrent/queue.hpp b/core/include/userver/concurrent/queue.hpp index 4bd8be8b0b6c..c2dd60d4a2e6 100644 --- a/core/include/userver/concurrent/queue.hpp +++ b/core/include/userver/concurrent/queue.hpp @@ -23,24 +23,24 @@ namespace impl { template struct SimpleQueuePolicy { - template - static constexpr std::size_t GetElementSize(const T&) { - return 1; - } + template + static constexpr std::size_t GetElementSize(const T&) { + return 1; + } - static constexpr bool kIsMultipleProducer{MultipleProducer}; - static constexpr bool kIsMultipleConsumer{MultipleConsumer}; + static constexpr bool kIsMultipleProducer{MultipleProducer}; + static constexpr bool kIsMultipleConsumer{MultipleConsumer}; }; template struct ContainerQueuePolicy { - template - static std::size_t GetElementSize(const T& value) { - return std::size(value); - } + template + static std::size_t GetElementSize(const T& value) { + return std::size(value); + } - static constexpr bool kIsMultipleProducer{MultipleProducer}; - static constexpr bool kIsMultipleConsumer{MultipleConsumer}; + static constexpr bool kIsMultipleProducer{MultipleProducer}; + static constexpr bool kIsMultipleConsumer{MultipleConsumer}; }; } // namespace impl @@ -62,571 +62,511 @@ struct ContainerQueuePolicy { /// /// @see @ref scripts/docs/en/userver/synchronization.md template -class GenericQueue final - : public std::enable_shared_from_this> { - struct EmplaceEnabler final { - // Disable {}-initialization in Queue's constructor - explicit EmplaceEnabler() = default; - }; - - using ProducerToken = - std::conditional_t; - using ConsumerToken = - std::conditional_t; - using MultiProducerToken = impl::MultiToken; - using MultiConsumerToken = - std::conditional_t; - - using SingleProducerToken = - std::conditional_t; - - friend class Producer; - friend class Producer; - friend class Consumer; - friend class Consumer; - - public: - using ValueType = T; - - using Producer = - concurrent::Producer; - using Consumer = - concurrent::Consumer; - using MultiProducer = - concurrent::Producer; - using MultiConsumer = - concurrent::Consumer; - - static constexpr std::size_t kUnbounded = - std::numeric_limits::max() / 4; - - /// @cond - // For internal use only - explicit GenericQueue(std::size_t max_size, EmplaceEnabler /*unused*/) - : queue_(), - single_producer_token_(queue_), - producer_side_(*this, std::min(max_size, kUnbounded)), - consumer_side_(*this) {} - - ~GenericQueue() { - UASSERT(consumers_count_ == kCreatedAndDead || !consumers_count_); - UASSERT(producers_count_ == kCreatedAndDead || !producers_count_); - - if (producers_count_ == kCreatedAndDead) { - // To allow reading the remaining items - consumer_side_.ResumeBlockingOnPop(); - } - - // Clear remaining items in queue - T value; - ConsumerToken token{queue_}; - while (consumer_side_.PopNoblock(token, value)) { - } - } - - GenericQueue(GenericQueue&&) = delete; - GenericQueue(const GenericQueue&) = delete; - GenericQueue& operator=(GenericQueue&&) = delete; - GenericQueue& operator=(const GenericQueue&) = delete; - /// @endcond - - /// Create a new queue - static std::shared_ptr Create( - std::size_t max_size = kUnbounded) { - return std::make_shared(max_size, EmplaceEnabler{}); - } - - /// Get a `Producer` which makes it possible to push items into the queue. - /// Can be called multiple times. The resulting `Producer` is not thread-safe, - /// so you have to use multiple Producers of the same queue to simultaneously - /// write from multiple coroutines/threads. - /// - /// @note `Producer` may outlive the queue and consumers. - Producer GetProducer() { - PrepareProducer(); - return Producer(this->shared_from_this(), EmplaceEnabler{}); - } - - /// Get a `MultiProducer` which makes it possible to push items into the - /// queue. Can be called multiple times. The resulting `MultiProducer` is - /// thread-safe, so it can be used simultaneously from multiple - /// coroutines/threads. - /// - /// @note `MultiProducer` may outlive the queue and consumers. - /// - /// @note Prefer `Producer` tokens when possible, because `MultiProducer` - /// token incurs some overhead. - MultiProducer GetMultiProducer() { - static_assert(QueuePolicy::kIsMultipleProducer, - "Trying to obtain MultiProducer for a single-producer queue"); - PrepareProducer(); - return MultiProducer(this->shared_from_this(), EmplaceEnabler{}); - } - - /// Get a `Consumer` which makes it possible to read items from the queue. - /// Can be called multiple times. The resulting `Consumer` is not thread-safe, - /// so you have to use multiple `Consumer`s of the same queue to - /// simultaneously write from multiple coroutines/threads. - /// - /// @note `Consumer` may outlive the queue and producers. - Consumer GetConsumer() { - PrepareConsumer(); - return Consumer(this->shared_from_this(), EmplaceEnabler{}); - } - - /// Get a `MultiConsumer` which makes it possible to read items from the - /// queue. Can be called multiple times. The resulting `MultiConsumer` is - /// thread-safe, so it can be used simultaneously from multiple - /// coroutines/threads. - /// - /// @note `MultiConsumer` may outlive the queue and producers. - /// - /// @note Prefer `Consumer` tokens when possible, because `MultiConsumer` - /// token incurs some overhead. - MultiConsumer GetMultiConsumer() { - static_assert(QueuePolicy::kIsMultipleConsumer, - "Trying to obtain MultiConsumer for a single-consumer queue"); - PrepareConsumer(); - return MultiConsumer(this->shared_from_this(), EmplaceEnabler{}); - } - - /// @brief Sets the limit on the queue size, pushes over this limit will block - /// @note This is a soft limit and may be slightly overrun under load. - void SetSoftMaxSize(std::size_t max_size) { - producer_side_.SetSoftMaxSize(std::min(max_size, kUnbounded)); - } - - /// @brief Gets the limit on the queue size - std::size_t GetSoftMaxSize() const { return producer_side_.GetSoftMaxSize(); } - - /// @brief Gets the approximate size of queue - std::size_t GetSizeApproximate() const { - return producer_side_.GetSizeApproximate(); - } - - private: - class SingleProducerSide; - class MultiProducerSide; - class SingleConsumerSide; - class MultiConsumerSide; - - /// Proxy-class makes synchronization of Push operations in multi or single - /// producer cases - using ProducerSide = - std::conditional_t; - - /// Proxy-class makes synchronization of Pop operations in multi or single - /// consumer cases - using ConsumerSide = - std::conditional_t; - - template - [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline) { - const std::size_t value_size = QueuePolicy::GetElementSize(value); - UASSERT(value_size > 0); - return producer_side_.Push(token, std::move(value), deadline, value_size); - } - - template - [[nodiscard]] bool PushNoblock(Token& token, T&& value) { - const std::size_t value_size = QueuePolicy::GetElementSize(value); - UASSERT(value_size > 0); - return producer_side_.PushNoblock(token, std::move(value), value_size); - } - - template - [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { - return consumer_side_.Pop(token, value, deadline); - } - - template - [[nodiscard]] bool PopNoblock(Token& token, T& value) { - return consumer_side_.PopNoblock(token, value); - } - - void PrepareProducer() { - std::size_t old_producers_count{}; - utils::AtomicUpdate(producers_count_, [&](auto old_value) { - UINVARIANT(QueuePolicy::kIsMultipleProducer || old_value != 1, - "Incorrect usage of queue producers"); - old_producers_count = old_value; - return old_value == kCreatedAndDead ? 1 : old_value + 1; - }); - - if (old_producers_count == kCreatedAndDead) { - consumer_side_.ResumeBlockingOnPop(); - } - } - - void PrepareConsumer() { - std::size_t old_consumers_count{}; - utils::AtomicUpdate(consumers_count_, [&](auto old_value) { - UINVARIANT(QueuePolicy::kIsMultipleConsumer || old_value != 1, - "Incorrect usage of queue consumers"); - old_consumers_count = old_value; - return old_value == kCreatedAndDead ? 1 : old_value + 1; - }); - - if (old_consumers_count == kCreatedAndDead) { - producer_side_.ResumeBlockingOnPush(); - } - } - - void MarkConsumerIsDead() { - const auto new_consumers_count = - utils::AtomicUpdate(consumers_count_, [](auto old_value) { - return old_value == 1 ? kCreatedAndDead : old_value - 1; - }); - if (new_consumers_count == kCreatedAndDead) { - producer_side_.StopBlockingOnPush(); +class GenericQueue final : public std::enable_shared_from_this> { + struct EmplaceEnabler final { + // Disable {}-initialization in Queue's constructor + explicit EmplaceEnabler() = default; + }; + + using ProducerToken = + std::conditional_t; + using ConsumerToken = + std::conditional_t; + using MultiProducerToken = impl::MultiToken; + using MultiConsumerToken = std::conditional_t; + + using SingleProducerToken = + std::conditional_t; + + friend class Producer; + friend class Producer; + friend class Consumer; + friend class Consumer; + +public: + using ValueType = T; + + using Producer = concurrent::Producer; + using Consumer = concurrent::Consumer; + using MultiProducer = concurrent::Producer; + using MultiConsumer = concurrent::Consumer; + + static constexpr std::size_t kUnbounded = std::numeric_limits::max() / 4; + + /// @cond + // For internal use only + explicit GenericQueue(std::size_t max_size, EmplaceEnabler /*unused*/) + : queue_(), + single_producer_token_(queue_), + producer_side_(*this, std::min(max_size, kUnbounded)), + consumer_side_(*this) {} + + ~GenericQueue() { + UASSERT(consumers_count_ == kCreatedAndDead || !consumers_count_); + UASSERT(producers_count_ == kCreatedAndDead || !producers_count_); + + if (producers_count_ == kCreatedAndDead) { + // To allow reading the remaining items + consumer_side_.ResumeBlockingOnPop(); + } + + // Clear remaining items in queue + T value; + ConsumerToken token{queue_}; + while (consumer_side_.PopNoblock(token, value)) { + } } - } - void MarkProducerIsDead() { - const auto new_producers_count = - utils::AtomicUpdate(producers_count_, [](auto old_value) { - return old_value == 1 ? kCreatedAndDead : old_value - 1; - }); - if (new_producers_count == kCreatedAndDead) { - consumer_side_.StopBlockingOnPop(); + GenericQueue(GenericQueue&&) = delete; + GenericQueue(const GenericQueue&) = delete; + GenericQueue& operator=(GenericQueue&&) = delete; + GenericQueue& operator=(const GenericQueue&) = delete; + /// @endcond + + /// Create a new queue + static std::shared_ptr Create(std::size_t max_size = kUnbounded) { + return std::make_shared(max_size, EmplaceEnabler{}); + } + + /// Get a `Producer` which makes it possible to push items into the queue. + /// Can be called multiple times. The resulting `Producer` is not thread-safe, + /// so you have to use multiple Producers of the same queue to simultaneously + /// write from multiple coroutines/threads. + /// + /// @note `Producer` may outlive the queue and consumers. + Producer GetProducer() { + PrepareProducer(); + return Producer(this->shared_from_this(), EmplaceEnabler{}); + } + + /// Get a `MultiProducer` which makes it possible to push items into the + /// queue. Can be called multiple times. The resulting `MultiProducer` is + /// thread-safe, so it can be used simultaneously from multiple + /// coroutines/threads. + /// + /// @note `MultiProducer` may outlive the queue and consumers. + /// + /// @note Prefer `Producer` tokens when possible, because `MultiProducer` + /// token incurs some overhead. + MultiProducer GetMultiProducer() { + static_assert(QueuePolicy::kIsMultipleProducer, "Trying to obtain MultiProducer for a single-producer queue"); + PrepareProducer(); + return MultiProducer(this->shared_from_this(), EmplaceEnabler{}); + } + + /// Get a `Consumer` which makes it possible to read items from the queue. + /// Can be called multiple times. The resulting `Consumer` is not thread-safe, + /// so you have to use multiple `Consumer`s of the same queue to + /// simultaneously write from multiple coroutines/threads. + /// + /// @note `Consumer` may outlive the queue and producers. + Consumer GetConsumer() { + PrepareConsumer(); + return Consumer(this->shared_from_this(), EmplaceEnabler{}); + } + + /// Get a `MultiConsumer` which makes it possible to read items from the + /// queue. Can be called multiple times. The resulting `MultiConsumer` is + /// thread-safe, so it can be used simultaneously from multiple + /// coroutines/threads. + /// + /// @note `MultiConsumer` may outlive the queue and producers. + /// + /// @note Prefer `Consumer` tokens when possible, because `MultiConsumer` + /// token incurs some overhead. + MultiConsumer GetMultiConsumer() { + static_assert(QueuePolicy::kIsMultipleConsumer, "Trying to obtain MultiConsumer for a single-consumer queue"); + PrepareConsumer(); + return MultiConsumer(this->shared_from_this(), EmplaceEnabler{}); + } + + /// @brief Sets the limit on the queue size, pushes over this limit will block + /// @note This is a soft limit and may be slightly overrun under load. + void SetSoftMaxSize(std::size_t max_size) { producer_side_.SetSoftMaxSize(std::min(max_size, kUnbounded)); } + + /// @brief Gets the limit on the queue size + std::size_t GetSoftMaxSize() const { return producer_side_.GetSoftMaxSize(); } + + /// @brief Gets the approximate size of queue + std::size_t GetSizeApproximate() const { return producer_side_.GetSizeApproximate(); } + +private: + class SingleProducerSide; + class MultiProducerSide; + class SingleConsumerSide; + class MultiConsumerSide; + + /// Proxy-class makes synchronization of Push operations in multi or single + /// producer cases + using ProducerSide = std::conditional_t; + + /// Proxy-class makes synchronization of Pop operations in multi or single + /// consumer cases + using ConsumerSide = std::conditional_t; + + template + [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline) { + const std::size_t value_size = QueuePolicy::GetElementSize(value); + UASSERT(value_size > 0); + return producer_side_.Push(token, std::move(value), deadline, value_size); + } + + template + [[nodiscard]] bool PushNoblock(Token& token, T&& value) { + const std::size_t value_size = QueuePolicy::GetElementSize(value); + UASSERT(value_size > 0); + return producer_side_.PushNoblock(token, std::move(value), value_size); + } + + template + [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { + return consumer_side_.Pop(token, value, deadline); } - } - public: // TODO - /// @cond - bool NoMoreConsumers() const { return consumers_count_ == kCreatedAndDead; } + template + [[nodiscard]] bool PopNoblock(Token& token, T& value) { + return consumer_side_.PopNoblock(token, value); + } - bool NoMoreProducers() const { return producers_count_ == kCreatedAndDead; } - /// @endcond + void PrepareProducer() { + std::size_t old_producers_count{}; + utils::AtomicUpdate(producers_count_, [&](auto old_value) { + UINVARIANT(QueuePolicy::kIsMultipleProducer || old_value != 1, "Incorrect usage of queue producers"); + old_producers_count = old_value; + return old_value == kCreatedAndDead ? 1 : old_value + 1; + }); - private: - template - void DoPush(Token& token, T&& value) { - if constexpr (std::is_same_v) { - static_assert(QueuePolicy::kIsMultipleProducer); - queue_.enqueue(token, std::move(value)); - } else if constexpr (std::is_same_v) { - static_assert(QueuePolicy::kIsMultipleProducer); - queue_.enqueue(std::move(value)); - } else { - static_assert(std::is_same_v); - static_assert(!QueuePolicy::kIsMultipleProducer); - queue_.enqueue(single_producer_token_, std::move(value)); + if (old_producers_count == kCreatedAndDead) { + consumer_side_.ResumeBlockingOnPop(); + } } - consumer_side_.OnElementPushed(); - } + void PrepareConsumer() { + std::size_t old_consumers_count{}; + utils::AtomicUpdate(consumers_count_, [&](auto old_value) { + UINVARIANT(QueuePolicy::kIsMultipleConsumer || old_value != 1, "Incorrect usage of queue consumers"); + old_consumers_count = old_value; + return old_value == kCreatedAndDead ? 1 : old_value + 1; + }); + + if (old_consumers_count == kCreatedAndDead) { + producer_side_.ResumeBlockingOnPush(); + } + } - template - [[nodiscard]] bool DoPop(Token& token, T& value) { - bool success{}; + void MarkConsumerIsDead() { + const auto new_consumers_count = utils::AtomicUpdate(consumers_count_, [](auto old_value) { + return old_value == 1 ? kCreatedAndDead : old_value - 1; + }); + if (new_consumers_count == kCreatedAndDead) { + producer_side_.StopBlockingOnPush(); + } + } - if constexpr (std::is_same_v) { - static_assert(QueuePolicy::kIsMultipleProducer); - success = queue_.try_dequeue(token, value); - } else if constexpr (std::is_same_v) { - static_assert(QueuePolicy::kIsMultipleProducer); - success = queue_.try_dequeue(value); - } else { - static_assert(std::is_same_v); - static_assert(!QueuePolicy::kIsMultipleProducer); - success = queue_.try_dequeue_from_producer(single_producer_token_, value); + void MarkProducerIsDead() { + const auto new_producers_count = utils::AtomicUpdate(producers_count_, [](auto old_value) { + return old_value == 1 ? kCreatedAndDead : old_value - 1; + }); + if (new_producers_count == kCreatedAndDead) { + consumer_side_.StopBlockingOnPop(); + } } - if (success) { - producer_side_.OnElementPopped(QueuePolicy::GetElementSize(value)); - return true; +public: // TODO + /// @cond + bool NoMoreConsumers() const { return consumers_count_ == kCreatedAndDead; } + + bool NoMoreProducers() const { return producers_count_ == kCreatedAndDead; } + /// @endcond + +private: + template + void DoPush(Token& token, T&& value) { + if constexpr (std::is_same_v) { + static_assert(QueuePolicy::kIsMultipleProducer); + queue_.enqueue(token, std::move(value)); + } else if constexpr (std::is_same_v) { + static_assert(QueuePolicy::kIsMultipleProducer); + queue_.enqueue(std::move(value)); + } else { + static_assert(std::is_same_v); + static_assert(!QueuePolicy::kIsMultipleProducer); + queue_.enqueue(single_producer_token_, std::move(value)); + } + + consumer_side_.OnElementPushed(); } - return false; - } + template + [[nodiscard]] bool DoPop(Token& token, T& value) { + bool success{}; + + if constexpr (std::is_same_v) { + static_assert(QueuePolicy::kIsMultipleProducer); + success = queue_.try_dequeue(token, value); + } else if constexpr (std::is_same_v) { + static_assert(QueuePolicy::kIsMultipleProducer); + success = queue_.try_dequeue(value); + } else { + static_assert(std::is_same_v); + static_assert(!QueuePolicy::kIsMultipleProducer); + success = queue_.try_dequeue_from_producer(single_producer_token_, value); + } - moodycamel::ConcurrentQueue queue_{1}; - std::atomic consumers_count_{0}; - std::atomic producers_count_{0}; + if (success) { + producer_side_.OnElementPopped(QueuePolicy::GetElementSize(value)); + return true; + } - SingleProducerToken single_producer_token_; + return false; + } - ProducerSide producer_side_; - ConsumerSide consumer_side_; + moodycamel::ConcurrentQueue queue_{1}; + std::atomic consumers_count_{0}; + std::atomic producers_count_{0}; - static constexpr std::size_t kCreatedAndDead = - std::numeric_limits::max(); - static constexpr std::size_t kSemaphoreUnlockValue = - std::numeric_limits::max() / 2; + SingleProducerToken single_producer_token_; + + ProducerSide producer_side_; + ConsumerSide consumer_side_; + + static constexpr std::size_t kCreatedAndDead = std::numeric_limits::max(); + static constexpr std::size_t kSemaphoreUnlockValue = std::numeric_limits::max() / 2; }; // Single-producer ProducerSide implementation template class GenericQueue::SingleProducerSide final { - public: - explicit SingleProducerSide(GenericQueue& queue, std::size_t capacity) - : queue_(queue), used_capacity_(0), total_capacity_(capacity) {} - - // Blocks if there is a consumer to Pop the current value and task - // shouldn't cancel and queue if full - template - [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline, - std::size_t value_size) { - bool no_more_consumers = false; - const bool success = non_full_event_.WaitUntil(deadline, [&] { - if (queue_.NoMoreConsumers()) { - no_more_consumers = true; - return true; - } - if (DoPush(token, std::move(value), value_size)) { +public: + explicit SingleProducerSide(GenericQueue& queue, std::size_t capacity) + : queue_(queue), used_capacity_(0), total_capacity_(capacity) {} + + // Blocks if there is a consumer to Pop the current value and task + // shouldn't cancel and queue if full + template + [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline, std::size_t value_size) { + bool no_more_consumers = false; + const bool success = non_full_event_.WaitUntil(deadline, [&] { + if (queue_.NoMoreConsumers()) { + no_more_consumers = true; + return true; + } + if (DoPush(token, std::move(value), value_size)) { + return true; + } + return false; + }); + return success && !no_more_consumers; + } + + template + [[nodiscard]] bool PushNoblock(Token& token, T&& value, std::size_t value_size) { + return !queue_.NoMoreConsumers() && DoPush(token, std::move(value), value_size); + } + + void OnElementPopped(std::size_t released_capacity) { + used_capacity_.fetch_sub(released_capacity); + non_full_event_.Send(); + } + + void StopBlockingOnPush() { non_full_event_.Send(); } + + void ResumeBlockingOnPush() {} + + void SetSoftMaxSize(std::size_t new_capacity) { + const auto old_capacity = total_capacity_.exchange(new_capacity); + if (new_capacity > old_capacity) non_full_event_.Send(); + } + + std::size_t GetSoftMaxSize() const noexcept { return total_capacity_.load(); } + + std::size_t GetSizeApproximate() const noexcept { return used_capacity_.load(); } + +private: + template + [[nodiscard]] bool DoPush(Token& token, T&& value, std::size_t value_size) { + if (used_capacity_.load() + value_size > total_capacity_.load()) { + return false; + } + + used_capacity_.fetch_add(value_size); + queue_.DoPush(token, std::move(value)); return true; - } - return false; - }); - return success && !no_more_consumers; - } - - template - [[nodiscard]] bool PushNoblock(Token& token, T&& value, - std::size_t value_size) { - return !queue_.NoMoreConsumers() && - DoPush(token, std::move(value), value_size); - } - - void OnElementPopped(std::size_t released_capacity) { - used_capacity_.fetch_sub(released_capacity); - non_full_event_.Send(); - } - - void StopBlockingOnPush() { non_full_event_.Send(); } - - void ResumeBlockingOnPush() {} - - void SetSoftMaxSize(std::size_t new_capacity) { - const auto old_capacity = total_capacity_.exchange(new_capacity); - if (new_capacity > old_capacity) non_full_event_.Send(); - } - - std::size_t GetSoftMaxSize() const noexcept { return total_capacity_.load(); } - - std::size_t GetSizeApproximate() const noexcept { - return used_capacity_.load(); - } - - private: - template - [[nodiscard]] bool DoPush(Token& token, T&& value, std::size_t value_size) { - if (used_capacity_.load() + value_size > total_capacity_.load()) { - return false; - } - - used_capacity_.fetch_add(value_size); - queue_.DoPush(token, std::move(value)); - return true; - } - - GenericQueue& queue_; - engine::SingleConsumerEvent non_full_event_; - std::atomic used_capacity_; - std::atomic total_capacity_; + } + + GenericQueue& queue_; + engine::SingleConsumerEvent non_full_event_; + std::atomic used_capacity_; + std::atomic total_capacity_; }; // Multi producer ProducerSide implementation template class GenericQueue::MultiProducerSide final { - public: - explicit MultiProducerSide(GenericQueue& queue, std::size_t capacity) - : queue_(queue), - remaining_capacity_(capacity), - remaining_capacity_control_(remaining_capacity_) {} - - // Blocks if there is a consumer to Pop the current value and task - // shouldn't cancel and queue if full - template - [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline, - std::size_t value_size) { - return remaining_capacity_.try_lock_shared_until_count(deadline, - value_size) && - DoPush(token, std::move(value), value_size); - } - - template - [[nodiscard]] bool PushNoblock(Token& token, T&& value, - std::size_t value_size) { - return remaining_capacity_.try_lock_shared_count(value_size) && - DoPush(token, std::move(value), value_size); - } - - void OnElementPopped(std::size_t value_size) { - remaining_capacity_.unlock_shared_count(value_size); - } - - void StopBlockingOnPush() { - remaining_capacity_control_.SetCapacityOverride(0); - } - - void ResumeBlockingOnPush() { - remaining_capacity_control_.RemoveCapacityOverride(); - } - - void SetSoftMaxSize(std::size_t count) { - remaining_capacity_control_.SetCapacity(count); - } - - std::size_t GetSizeApproximate() const noexcept { - return remaining_capacity_.UsedApprox(); - } - - std::size_t GetSoftMaxSize() const noexcept { - return remaining_capacity_control_.GetCapacity(); - } - - private: - template - [[nodiscard]] bool DoPush(Token& token, T&& value, std::size_t value_size) { - if (queue_.NoMoreConsumers()) { - remaining_capacity_.unlock_shared_count(value_size); - return false; - } - - queue_.DoPush(token, std::move(value)); - return true; - } - - GenericQueue& queue_; - engine::CancellableSemaphore remaining_capacity_; - concurrent::impl::SemaphoreCapacityControl remaining_capacity_control_; +public: + explicit MultiProducerSide(GenericQueue& queue, std::size_t capacity) + : queue_(queue), remaining_capacity_(capacity), remaining_capacity_control_(remaining_capacity_) {} + + // Blocks if there is a consumer to Pop the current value and task + // shouldn't cancel and queue if full + template + [[nodiscard]] bool Push(Token& token, T&& value, engine::Deadline deadline, std::size_t value_size) { + return remaining_capacity_.try_lock_shared_until_count(deadline, value_size) && + DoPush(token, std::move(value), value_size); + } + + template + [[nodiscard]] bool PushNoblock(Token& token, T&& value, std::size_t value_size) { + return remaining_capacity_.try_lock_shared_count(value_size) && DoPush(token, std::move(value), value_size); + } + + void OnElementPopped(std::size_t value_size) { remaining_capacity_.unlock_shared_count(value_size); } + + void StopBlockingOnPush() { remaining_capacity_control_.SetCapacityOverride(0); } + + void ResumeBlockingOnPush() { remaining_capacity_control_.RemoveCapacityOverride(); } + + void SetSoftMaxSize(std::size_t count) { remaining_capacity_control_.SetCapacity(count); } + + std::size_t GetSizeApproximate() const noexcept { return remaining_capacity_.UsedApprox(); } + + std::size_t GetSoftMaxSize() const noexcept { return remaining_capacity_control_.GetCapacity(); } + +private: + template + [[nodiscard]] bool DoPush(Token& token, T&& value, std::size_t value_size) { + if (queue_.NoMoreConsumers()) { + remaining_capacity_.unlock_shared_count(value_size); + return false; + } + + queue_.DoPush(token, std::move(value)); + return true; + } + + GenericQueue& queue_; + engine::CancellableSemaphore remaining_capacity_; + concurrent::impl::SemaphoreCapacityControl remaining_capacity_control_; }; // Single consumer ConsumerSide implementation template class GenericQueue::SingleConsumerSide final { - public: - explicit SingleConsumerSide(GenericQueue& queue) - : queue_(queue), element_count_(0) {} - - // Blocks only if queue is empty - template - [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { - bool no_more_producers = false; - const bool success = nonempty_event_.WaitUntil(deadline, [&] { - if (DoPop(token, value)) { - return true; - } - if (queue_.NoMoreProducers()) { - // Producer might have pushed something in queue between .pop() - // and !producer_is_created_and_dead_ check. Check twice to avoid - // TOCTOU. - if (!DoPop(token, value)) { - no_more_producers = true; +public: + explicit SingleConsumerSide(GenericQueue& queue) : queue_(queue), element_count_(0) {} + + // Blocks only if queue is empty + template + [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { + bool no_more_producers = false; + const bool success = nonempty_event_.WaitUntil(deadline, [&] { + if (DoPop(token, value)) { + return true; + } + if (queue_.NoMoreProducers()) { + // Producer might have pushed something in queue between .pop() + // and !producer_is_created_and_dead_ check. Check twice to avoid + // TOCTOU. + if (!DoPop(token, value)) { + no_more_producers = true; + } + return true; + } + return false; + }); + return success && !no_more_producers; + } + + template + [[nodiscard]] bool PopNoblock(Token& token, T& value) { + return DoPop(token, value); + } + + void OnElementPushed() { + ++element_count_; + nonempty_event_.Send(); + } + + void StopBlockingOnPop() { nonempty_event_.Send(); } + + void ResumeBlockingOnPop() {} + + std::size_t GetElementCount() const { return element_count_; } + +private: + template + [[nodiscard]] bool DoPop(Token& token, T& value) { + if (queue_.DoPop(token, value)) { + --element_count_; + nonempty_event_.Reset(); + return true; } - return true; - } - return false; - }); - return success && !no_more_producers; - } - - template - [[nodiscard]] bool PopNoblock(Token& token, T& value) { - return DoPop(token, value); - } - - void OnElementPushed() { - ++element_count_; - nonempty_event_.Send(); - } - - void StopBlockingOnPop() { nonempty_event_.Send(); } - - void ResumeBlockingOnPop() {} - - std::size_t GetElementCount() const { return element_count_; } - - private: - template - [[nodiscard]] bool DoPop(Token& token, T& value) { - if (queue_.DoPop(token, value)) { - --element_count_; - nonempty_event_.Reset(); - return true; - } - return false; - } - - GenericQueue& queue_; - engine::SingleConsumerEvent nonempty_event_; - std::atomic element_count_; + return false; + } + + GenericQueue& queue_; + engine::SingleConsumerEvent nonempty_event_; + std::atomic element_count_; }; // Multi consumer ConsumerSide implementation template class GenericQueue::MultiConsumerSide final { - public: - explicit MultiConsumerSide(GenericQueue& queue) - : queue_(queue), - element_count_(kUnbounded), - element_count_control_(element_count_) { - const bool success = element_count_.try_lock_shared_count(kUnbounded); - UASSERT(success); - } - - ~MultiConsumerSide() { element_count_.unlock_shared_count(kUnbounded); } - - // Blocks only if queue is empty - template - [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { - return element_count_.try_lock_shared_until(deadline) && - DoPop(token, value); - } - - template - [[nodiscard]] bool PopNoblock(Token& token, T& value) { - return element_count_.try_lock_shared() && DoPop(token, value); - } - - void OnElementPushed() { element_count_.unlock_shared(); } - - void StopBlockingOnPop() { - element_count_control_.SetCapacityOverride(kUnbounded + - kSemaphoreUnlockValue); - } - - void ResumeBlockingOnPop() { - element_count_control_.RemoveCapacityOverride(); - } - - std::size_t GetElementCount() const { - const std::size_t cur_element_count = element_count_.RemainingApprox(); - if (cur_element_count < kUnbounded) { - return cur_element_count; - } else if (cur_element_count <= kSemaphoreUnlockValue) { - return 0; - } - return cur_element_count - kSemaphoreUnlockValue; - } - - private: - template - [[nodiscard]] bool DoPop(Token& token, T& value) { - while (true) { - if (queue_.DoPop(token, value)) { - return true; - } - if (queue_.NoMoreProducers()) { - element_count_.unlock_shared(); - return false; - } - // We can get here if another consumer steals our element, leaving another - // element in a Moodycamel sub-queue that we have already passed. +public: + explicit MultiConsumerSide(GenericQueue& queue) + : queue_(queue), element_count_(kUnbounded), element_count_control_(element_count_) { + const bool success = element_count_.try_lock_shared_count(kUnbounded); + UASSERT(success); + } + + ~MultiConsumerSide() { element_count_.unlock_shared_count(kUnbounded); } + + // Blocks only if queue is empty + template + [[nodiscard]] bool Pop(Token& token, T& value, engine::Deadline deadline) { + return element_count_.try_lock_shared_until(deadline) && DoPop(token, value); + } + + template + [[nodiscard]] bool PopNoblock(Token& token, T& value) { + return element_count_.try_lock_shared() && DoPop(token, value); + } + + void OnElementPushed() { element_count_.unlock_shared(); } + + void StopBlockingOnPop() { element_count_control_.SetCapacityOverride(kUnbounded + kSemaphoreUnlockValue); } + + void ResumeBlockingOnPop() { element_count_control_.RemoveCapacityOverride(); } + + std::size_t GetElementCount() const { + const std::size_t cur_element_count = element_count_.RemainingApprox(); + if (cur_element_count < kUnbounded) { + return cur_element_count; + } else if (cur_element_count <= kSemaphoreUnlockValue) { + return 0; + } + return cur_element_count - kSemaphoreUnlockValue; + } + +private: + template + [[nodiscard]] bool DoPop(Token& token, T& value) { + while (true) { + if (queue_.DoPop(token, value)) { + return true; + } + if (queue_.NoMoreProducers()) { + element_count_.unlock_shared(); + return false; + } + // We can get here if another consumer steals our element, leaving another + // element in a Moodycamel sub-queue that we have already passed. + } } - } - GenericQueue& queue_; - engine::CancellableSemaphore element_count_; - concurrent::impl::SemaphoreCapacityControl element_count_control_; + GenericQueue& queue_; + engine::CancellableSemaphore element_count_; + concurrent::impl::SemaphoreCapacityControl element_count_control_; }; /// @ingroup userver_concurrency @@ -677,8 +617,7 @@ using SpscQueue = GenericQueue>; /// bytes inside. /// /// @see @ref scripts/docs/en/userver/synchronization.md -using StringStreamQueue = - GenericQueue>; +using StringStreamQueue = GenericQueue>; } // namespace concurrent diff --git a/core/include/userver/concurrent/queue_helpers.hpp b/core/include/userver/concurrent/queue_helpers.hpp index 9540ccfdcc3d..3b225c1b0983 100644 --- a/core/include/userver/concurrent/queue_helpers.hpp +++ b/core/include/userver/concurrent/queue_helpers.hpp @@ -11,151 +11,143 @@ namespace concurrent { namespace impl { struct NoToken final { - template - explicit NoToken(LockFreeQueue& /*unused*/) {} + template + explicit NoToken(LockFreeQueue& /*unused*/) {} }; struct MultiToken final { - template - explicit MultiToken(LockFreeQueue& /*unused*/) {} + template + explicit MultiToken(LockFreeQueue& /*unused*/) {} }; } // namespace impl /// @warning A single Producer must not be used from multiple threads /// concurrently -template +template class Producer final { - static_assert( - std::is_same_v, - "Do not instantiate Producer on your own. Use Producer type alias " - "from queue"); - - using ValueType = typename QueueType::ValueType; - - public: - Producer(const Producer&) = delete; - Producer(Producer&&) noexcept = default; - Producer& operator=(const Producer&) = delete; - Producer& operator=(Producer&& other) noexcept { - queue_.swap(other.queue_); - std::swap(token_, other.token_); - return *this; - } - - ~Producer() { - if (queue_) queue_->MarkProducerIsDead(); - } - - /// Push element into queue. May wait asynchronously if the queue is full. - /// Leaves the `value` unmodified if the operation does not succeed. - /// @returns whether push succeeded before the deadline and before the task - /// was canceled. - [[nodiscard]] bool Push(ValueType&& value, - engine::Deadline deadline = {}) const { - UASSERT(queue_); - return queue_->Push(token_, std::move(value), deadline); - } - - /// Try to push element into queue without blocking. May be used in - /// non-coroutine environment. Leaves the `value` unmodified if the operation - /// does not succeed. - /// @returns whether push succeeded. - [[nodiscard]] bool PushNoblock(ValueType&& value) const { - UASSERT(queue_); - return queue_->PushNoblock(token_, std::move(value)); - } - - void Reset() && { - if (queue_) queue_->MarkProducerIsDead(); - queue_.reset(); - [[maybe_unused]] ProducerToken for_destruction = std::move(token_); - } - - /// Const access to source queue. - [[nodiscard]] std::shared_ptr Queue() const { - return {queue_}; - } - - /// @cond - // For internal use only - Producer(std::shared_ptr queue, EmplaceEnablerType /*unused*/) - : queue_(std::move(queue)), token_(queue_->queue_) {} - /// @endcond - - private: - std::shared_ptr queue_; - mutable ProducerToken token_; + static_assert( + std::is_same_v, + "Do not instantiate Producer on your own. Use Producer type alias " + "from queue" + ); + + using ValueType = typename QueueType::ValueType; + +public: + Producer(const Producer&) = delete; + Producer(Producer&&) noexcept = default; + Producer& operator=(const Producer&) = delete; + Producer& operator=(Producer&& other) noexcept { + queue_.swap(other.queue_); + std::swap(token_, other.token_); + return *this; + } + + ~Producer() { + if (queue_) queue_->MarkProducerIsDead(); + } + + /// Push element into queue. May wait asynchronously if the queue is full. + /// Leaves the `value` unmodified if the operation does not succeed. + /// @returns whether push succeeded before the deadline and before the task + /// was canceled. + [[nodiscard]] bool Push(ValueType&& value, engine::Deadline deadline = {}) const { + UASSERT(queue_); + return queue_->Push(token_, std::move(value), deadline); + } + + /// Try to push element into queue without blocking. May be used in + /// non-coroutine environment. Leaves the `value` unmodified if the operation + /// does not succeed. + /// @returns whether push succeeded. + [[nodiscard]] bool PushNoblock(ValueType&& value) const { + UASSERT(queue_); + return queue_->PushNoblock(token_, std::move(value)); + } + + void Reset() && { + if (queue_) queue_->MarkProducerIsDead(); + queue_.reset(); + [[maybe_unused]] ProducerToken for_destruction = std::move(token_); + } + + /// Const access to source queue. + [[nodiscard]] std::shared_ptr Queue() const { return {queue_}; } + + /// @cond + // For internal use only + Producer(std::shared_ptr queue, EmplaceEnablerType /*unused*/) + : queue_(std::move(queue)), token_(queue_->queue_) {} + /// @endcond + +private: + std::shared_ptr queue_; + mutable ProducerToken token_; }; /// @warning A single Consumer must not be used from multiple threads /// concurrently -template +template class Consumer final { - static_assert( - std::is_same_v, - "Do not instantiate Consumer on your own. Use Consumer type alias " - "from queue"); - - using ValueType = typename QueueType::ValueType; - - public: - Consumer(const Consumer&) = delete; - Consumer(Consumer&&) noexcept = default; - Consumer& operator=(const Consumer&) = delete; - Consumer& operator=(Consumer&& other) noexcept { - queue_.swap(other.queue_); - std::swap(token_, other.token_); - return *this; - } - - ~Consumer() { - if (queue_) queue_->MarkConsumerIsDead(); - } - - /// Pop element from queue. May wait asynchronously if the queue is empty, - /// but the producer is alive. - /// @returns whether something was popped before the deadline. - /// @note `false` can be returned before the deadline when the producer is no - /// longer alive. - /// @warning Be careful when using a method in a loop. The - /// `engine::Deadline` is a wrapper over `std::chrono::time_point`, not - /// `duration`! If you need a timeout, you must reconstruct the deadline in - /// the loop. - [[nodiscard]] bool Pop(ValueType& value, - engine::Deadline deadline = {}) const { - return queue_->Pop(token_, value, deadline); - } - - /// Try to pop element from queue without blocking. May be used in - /// non-coroutine environment - /// @return whether something was popped. - [[nodiscard]] bool PopNoblock(ValueType& value) const { - return queue_->PopNoblock(token_, value); - } - - void Reset() && { - if (queue_) queue_->MarkConsumerIsDead(); - queue_.reset(); - [[maybe_unused]] ConsumerToken for_destruction = std::move(token_); - } - - /// Const access to source queue. - [[nodiscard]] std::shared_ptr Queue() const { - return {queue_}; - } - - /// @cond - // For internal use only - Consumer(std::shared_ptr queue, EmplaceEnablerType /*unused*/) - : queue_(std::move(queue)), token_(queue_->queue_) {} - /// @endcond - - private: - std::shared_ptr queue_{}; - mutable ConsumerToken token_; + static_assert( + std::is_same_v, + "Do not instantiate Consumer on your own. Use Consumer type alias " + "from queue" + ); + + using ValueType = typename QueueType::ValueType; + +public: + Consumer(const Consumer&) = delete; + Consumer(Consumer&&) noexcept = default; + Consumer& operator=(const Consumer&) = delete; + Consumer& operator=(Consumer&& other) noexcept { + queue_.swap(other.queue_); + std::swap(token_, other.token_); + return *this; + } + + ~Consumer() { + if (queue_) queue_->MarkConsumerIsDead(); + } + + /// Pop element from queue. May wait asynchronously if the queue is empty, + /// but the producer is alive. + /// @returns whether something was popped before the deadline. + /// @note `false` can be returned before the deadline when the producer is no + /// longer alive. + /// @warning Be careful when using a method in a loop. The + /// `engine::Deadline` is a wrapper over `std::chrono::time_point`, not + /// `duration`! If you need a timeout, you must reconstruct the deadline in + /// the loop. + [[nodiscard]] bool Pop(ValueType& value, engine::Deadline deadline = {}) const { + return queue_->Pop(token_, value, deadline); + } + + /// Try to pop element from queue without blocking. May be used in + /// non-coroutine environment + /// @return whether something was popped. + [[nodiscard]] bool PopNoblock(ValueType& value) const { return queue_->PopNoblock(token_, value); } + + void Reset() && { + if (queue_) queue_->MarkConsumerIsDead(); + queue_.reset(); + [[maybe_unused]] ConsumerToken for_destruction = std::move(token_); + } + + /// Const access to source queue. + [[nodiscard]] std::shared_ptr Queue() const { return {queue_}; } + + /// @cond + // For internal use only + Consumer(std::shared_ptr queue, EmplaceEnablerType /*unused*/) + : queue_(std::move(queue)), token_(queue_->queue_) {} + /// @endcond + +private: + std::shared_ptr queue_{}; + mutable ConsumerToken token_; }; } // namespace concurrent diff --git a/core/include/userver/concurrent/striped_counter.hpp b/core/include/userver/concurrent/striped_counter.hpp index d716106d1135..c745778bcaf3 100644 --- a/core/include/userver/concurrent/striped_counter.hpp +++ b/core/include/userver/concurrent/striped_counter.hpp @@ -23,51 +23,51 @@ namespace concurrent { /// per-CPU counters. /// In the second case, read is approx. `nproc` times slower than write. class StripedCounter final { - public: - /// @brief Constructs a zero-initialized counter. - /// Might allocate up to kDestructiveInterferenceSize (64 bytes for x86_64) * - /// number of available CPUs bytes. - StripedCounter(); - ~StripedCounter(); +public: + /// @brief Constructs a zero-initialized counter. + /// Might allocate up to kDestructiveInterferenceSize (64 bytes for x86_64) * + /// number of available CPUs bytes. + StripedCounter(); + ~StripedCounter(); - StripedCounter(const StripedCounter&) = delete; - StripedCounter& operator=(const StripedCounter&) = delete; + StripedCounter(const StripedCounter&) = delete; + StripedCounter& operator=(const StripedCounter&) = delete; - StripedCounter(StripedCounter&&) = delete; - StripedCounter& operator=(StripedCounter&&) = delete; + StripedCounter(StripedCounter&&) = delete; + StripedCounter& operator=(StripedCounter&&) = delete; - /// @brief The addition is done with a relaxed memory order. - void Add(std::uintptr_t value) noexcept; + /// @brief The addition is done with a relaxed memory order. + void Add(std::uintptr_t value) noexcept; - /// @brief The subtraction is done with a relaxed memory order. - void Subtract(std::uintptr_t value) noexcept { - // Perfectly defined unsigned wrapping - Add(-value); - } + /// @brief The subtraction is done with a relaxed memory order. + void Subtract(std::uintptr_t value) noexcept { + // Perfectly defined unsigned wrapping + Add(-value); + } - /// @brief Read the the total counter value. The counter uses the full range - /// of `std::uintptr_t`, using wrap-around when necessary. - /// @note The read is done with `std::memory_order_acquire`. - /// - /// Due to the underlying implementation being an array of counters, this - /// function may return logically impossible values if `Subtract` is in play. - /// For example, doing Add(1) and Subtract(1) may lead to this - /// function returning -1 (wrapped). - /// With `Subtract`, consider using `NonNegativeRead` instead. - std::uintptr_t Read() const noexcept; + /// @brief Read the the total counter value. The counter uses the full range + /// of `std::uintptr_t`, using wrap-around when necessary. + /// @note The read is done with `std::memory_order_acquire`. + /// + /// Due to the underlying implementation being an array of counters, this + /// function may return logically impossible values if `Subtract` is in play. + /// For example, doing Add(1) and Subtract(1) may lead to this + /// function returning -1 (wrapped). + /// With `Subtract`, consider using `NonNegativeRead` instead. + std::uintptr_t Read() const noexcept; - /// @brief Read the non-negative total counter value. - /// @note The read is done with `std::memory_order_acquire`. - /// - /// This is almost exactly like `Read`, but for an `Add-Subtract` race, - /// instead of returning a negative value, this function returns `0`. Consider - /// this a convenient shortcut to avoid seeing logically impossible negative - /// values. - std::uintptr_t NonNegativeRead() const noexcept; + /// @brief Read the non-negative total counter value. + /// @note The read is done with `std::memory_order_acquire`. + /// + /// This is almost exactly like `Read`, but for an `Add-Subtract` race, + /// instead of returning a negative value, this function returns `0`. Consider + /// this a convenient shortcut to avoid seeing logically impossible negative + /// values. + std::uintptr_t NonNegativeRead() const noexcept; - private: - struct Impl; - utils::FastPimpl impl_; +private: + struct Impl; + utils::FastPimpl impl_; }; } // namespace concurrent diff --git a/core/include/userver/concurrent/variable.hpp b/core/include/userver/concurrent/variable.hpp index 24c9d7b1966d..e78c79f533b2 100644 --- a/core/include/userver/concurrent/variable.hpp +++ b/core/include/userver/concurrent/variable.hpp @@ -15,35 +15,34 @@ namespace concurrent { /// Proxy class for locked access to data protected with locking::SharedLock template class LockedPtr final { - public: - using Mutex = typename Lock::mutex_type; +public: + using Mutex = typename Lock::mutex_type; - LockedPtr(Mutex& mutex, Data& data) : lock_(mutex), data_(data) {} - LockedPtr(Lock&& lock, Data& data) : lock_(std::move(lock)), data_(data) {} + LockedPtr(Mutex& mutex, Data& data) : lock_(mutex), data_(data) {} + LockedPtr(Lock&& lock, Data& data) : lock_(std::move(lock)), data_(data) {} - Data& operator*() & { return data_; } - const Data& operator*() const& { return data_; } + Data& operator*() & { return data_; } + const Data& operator*() const& { return data_; } - /// Don't use *tmp for temporary value, store it to variable. - Data& operator*() && { return *GetOnRvalue(); } + /// Don't use *tmp for temporary value, store it to variable. + Data& operator*() && { return *GetOnRvalue(); } - Data* operator->() & { return &data_; } - const Data* operator->() const& { return &data_; } + Data* operator->() & { return &data_; } + const Data* operator->() const& { return &data_; } - /// Don't use tmp-> for temporary value, store it to variable. - Data* operator->() && { return GetOnRvalue(); } + /// Don't use tmp-> for temporary value, store it to variable. + Data* operator->() && { return GetOnRvalue(); } - Lock& GetLock() { return lock_; } + Lock& GetLock() { return lock_; } - private: - const Data* GetOnRvalue() { - static_assert(!sizeof(Data), - "Don't use temporary LockedPtr, store it to a variable"); - std::abort(); - } +private: + const Data* GetOnRvalue() { + static_assert(!sizeof(Data), "Don't use temporary LockedPtr, store it to a variable"); + std::abort(); + } - Lock lock_; - Data& data_; + Lock lock_; + Data& data_; }; /// @ingroup userver_concurrency userver_containers @@ -57,83 +56,66 @@ class LockedPtr final { /// @see @ref scripts/docs/en/userver/synchronization.md template class Variable final { - public: - template - Variable(Arg&&... arg) : data_(std::forward(arg)...) {} - - LockedPtr, Data> UniqueLock() { - return {mutex_, data_}; - } - - LockedPtr, const Data> UniqueLock() const { - return {mutex_, data_}; - } - - std::optional, const Data>> UniqueLock( - std::try_to_lock_t) const { - return DoUniqueLock(*this, std::try_to_lock); - } - - std::optional, Data>> UniqueLock( - std::try_to_lock_t) { - return DoUniqueLock(*this, std::try_to_lock); - } - - std::optional, const Data>> UniqueLock( - std::chrono::milliseconds try_duration) const { - return DoUniqueLock(*this, try_duration); - } - - std::optional, Data>> UniqueLock( - std::chrono::milliseconds try_duration) { - return DoUniqueLock(*this, try_duration); - } - - LockedPtr, const Data> SharedLock() const { - return {mutex_, data_}; - } - - /// Useful for grabbing a reference to an object in a node-based container, - /// e.g. `std::unordered_map`. Values must support concurrent modification. - LockedPtr, Data> SharedMutableLockUnsafe() { - return {mutex_, data_}; - } - - LockedPtr, Data> Lock() { return {mutex_, data_}; } - - LockedPtr, const Data> Lock() const { - return {mutex_, data_}; - } - - /// Get raw mutex. Use with caution. For simple use cases call Lock(), - /// UniqueLock(), SharedLock() instead. - Mutex& GetMutexUnsafe() const { return mutex_; } - - /// Get raw data. Use with extreme caution, only for cases where it is - /// impossible to access data with safe methods (e.g. std::scoped_lock with - /// multiple mutexes). For simple use cases call Lock(), UniqueLock(), - /// SharedLock() instead. - Data& GetDataUnsafe() { return data_; } - - const Data& GetDataUnsafe() const { return data_; } - - private: - mutable Mutex mutex_; - Data data_; - - /// We need this function to work around const/non-const methods. This - /// helper accepts concurrent variables as template parameter and thus - /// will accept both const and non-const vars. And Data typename will - /// resolve to const/non-const accordingly. - template - static auto DoUniqueLock(VariableType& concurrent_variable, - StdUniqueLockArgs&&... args) { - std::unique_lock lock(concurrent_variable.mutex_, - std::forward(args)...); - return lock ? std::optional{LockedPtr{std::move(lock), - concurrent_variable.data_}} - : std::nullopt; - } +public: + template + Variable(Arg&&... arg) : data_(std::forward(arg)...) {} + + LockedPtr, Data> UniqueLock() { return {mutex_, data_}; } + + LockedPtr, const Data> UniqueLock() const { return {mutex_, data_}; } + + std::optional, const Data>> UniqueLock(std::try_to_lock_t) const { + return DoUniqueLock(*this, std::try_to_lock); + } + + std::optional, Data>> UniqueLock(std::try_to_lock_t) { + return DoUniqueLock(*this, std::try_to_lock); + } + + std::optional, const Data>> UniqueLock(std::chrono::milliseconds try_duration + ) const { + return DoUniqueLock(*this, try_duration); + } + + std::optional, Data>> UniqueLock(std::chrono::milliseconds try_duration) { + return DoUniqueLock(*this, try_duration); + } + + LockedPtr, const Data> SharedLock() const { return {mutex_, data_}; } + + /// Useful for grabbing a reference to an object in a node-based container, + /// e.g. `std::unordered_map`. Values must support concurrent modification. + LockedPtr, Data> SharedMutableLockUnsafe() { return {mutex_, data_}; } + + LockedPtr, Data> Lock() { return {mutex_, data_}; } + + LockedPtr, const Data> Lock() const { return {mutex_, data_}; } + + /// Get raw mutex. Use with caution. For simple use cases call Lock(), + /// UniqueLock(), SharedLock() instead. + Mutex& GetMutexUnsafe() const { return mutex_; } + + /// Get raw data. Use with extreme caution, only for cases where it is + /// impossible to access data with safe methods (e.g. std::scoped_lock with + /// multiple mutexes). For simple use cases call Lock(), UniqueLock(), + /// SharedLock() instead. + Data& GetDataUnsafe() { return data_; } + + const Data& GetDataUnsafe() const { return data_; } + +private: + mutable Mutex mutex_; + Data data_; + + /// We need this function to work around const/non-const methods. This + /// helper accepts concurrent variables as template parameter and thus + /// will accept both const and non-const vars. And Data typename will + /// resolve to const/non-const accordingly. + template + static auto DoUniqueLock(VariableType& concurrent_variable, StdUniqueLockArgs&&... args) { + std::unique_lock lock(concurrent_variable.mutex_, std::forward(args)...); + return lock ? std::optional{LockedPtr{std::move(lock), concurrent_variable.data_}} : std::nullopt; + } }; } // namespace concurrent diff --git a/core/include/userver/congestion_control/component.hpp b/core/include/userver/congestion_control/component.hpp index aa6502b4c8f5..79a859956089 100644 --- a/core/include/userver/congestion_control/component.hpp +++ b/core/include/userver/congestion_control/component.hpp @@ -39,38 +39,36 @@ namespace congestion_control { // clang-format on class Component final : public components::ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of congestion_control::Component component - static constexpr std::string_view kName = "congestion-control"; +public: + /// @ingroup userver_component_names + /// @brief The default name of congestion_control::Component component + static constexpr std::string_view kName = "congestion-control"; - Component(const components::ComponentConfig&, - const components::ComponentContext&); + Component(const components::ComponentConfig&, const components::ComponentContext&); - ~Component() override; + ~Component() override; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - server::congestion_control::Limiter& GetServerLimiter(); - server::congestion_control::Sensor& GetServerSensor(); + server::congestion_control::Limiter& GetServerLimiter(); + server::congestion_control::Sensor& GetServerSensor(); - private: - void OnConfigUpdate(const dynamic_config::Snapshot& cfg); +private: + void OnConfigUpdate(const dynamic_config::Snapshot& cfg); - void OnAllComponentsLoaded() override; + void OnAllComponentsLoaded() override; - void OnAllComponentsAreStopping() override; + void OnAllComponentsAreStopping() override; - void ExtendWriter(utils::statistics::Writer& writer); + void ExtendWriter(utils::statistics::Writer& writer); - struct Impl; - utils::FastPimpl pimpl_; + struct Impl; + utils::FastPimpl pimpl_; }; } // namespace congestion_control template <> -inline constexpr bool components::kHasValidate = - true; +inline constexpr bool components::kHasValidate = true; USERVER_NAMESPACE_END diff --git a/core/include/userver/congestion_control/config.hpp b/core/include/userver/congestion_control/config.hpp index cd7721b1c2f5..3646ffa3b830 100644 --- a/core/include/userver/congestion_control/config.hpp +++ b/core/include/userver/congestion_control/config.hpp @@ -13,21 +13,21 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control { struct Policy { - size_t min_limit{2}; - double up_rate_percent{2}; - double down_rate_percent{5}; + size_t min_limit{2}; + double up_rate_percent{2}; + double down_rate_percent{5}; - size_t overload_on{10}; - size_t overload_off{3}; + size_t overload_on{10}; + size_t overload_off{3}; - size_t up_count{3}; - size_t down_count{3}; - size_t no_limit_count{1000}; + size_t up_count{3}; + size_t down_count{3}; + size_t no_limit_count{1000}; - size_t load_limit_percent{0}; - size_t load_limit_crit_percent{0}; + size_t load_limit_percent{0}; + size_t load_limit_crit_percent{0}; - double start_limit_factor{0.75}; + double start_limit_factor{0.75}; }; Policy Parse(const formats::json::Value& policy, formats::parse::To); @@ -35,9 +35,9 @@ Policy Parse(const formats::json::Value& policy, formats::parse::To); namespace impl { struct RpsCcConfig { - Policy policy; - bool is_enabled{}; - int activate_factor{0}; + Policy policy; + bool is_enabled{}; + int activate_factor{0}; }; extern const dynamic_config::Key kRpsCcConfig; diff --git a/core/include/userver/congestion_control/controller.hpp b/core/include/userver/congestion_control/controller.hpp index 2543995f63ea..83f19f356f4b 100644 --- a/core/include/userver/congestion_control/controller.hpp +++ b/core/include/userver/congestion_control/controller.hpp @@ -18,65 +18,64 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control { struct PolicyState { - size_t times_with_overload{0}; - size_t times_wo_overload{0}; + size_t times_with_overload{0}; + size_t times_wo_overload{0}; - bool is_overloaded{false}; - std::optional current_limit; + bool is_overloaded{false}; + std::optional current_limit; - size_t max_up_delta{1}; + size_t max_up_delta{1}; }; struct Stats final { - std::atomic no_limit{0}; - std::atomic not_overload_no_pressure{0}; - std::atomic not_overload_pressure{0}; - std::atomic overload_no_pressure{0}; - std::atomic overload_pressure{0}; - - std::atomic current_state{0}; - std::atomic last_overload_pressure{ - std::chrono::duration_cast( - std::chrono::steady_clock::now().time_since_epoch()) - - std::chrono::hours(1)}; + std::atomic no_limit{0}; + std::atomic not_overload_no_pressure{0}; + std::atomic not_overload_pressure{0}; + std::atomic overload_no_pressure{0}; + std::atomic overload_pressure{0}; + + std::atomic current_state{0}; + std::atomic last_overload_pressure{ + std::chrono::duration_cast(std::chrono::steady_clock::now().time_since_epoch()) - + std::chrono::hours(1)}; }; class Controller final { - public: - Controller(std::string name, dynamic_config::Source config_source); +public: + Controller(std::string name, dynamic_config::Source config_source); - void Feed(const Sensor::Data&); + void Feed(const Sensor::Data&); - Limit GetLimit() const; + Limit GetLimit() const; - Limit GetLimitRaw() const; + Limit GetLimitRaw() const; - void SetEnabled(bool enabled); + void SetEnabled(bool enabled); - bool IsEnabled() const; + bool IsEnabled() const; - const Stats& GetStats() const; + const Stats& GetStats() const; - private: - bool IsOverloadedNow(const Sensor::Data& data, const Policy& policy) const; +private: + bool IsOverloadedNow(const Sensor::Data& data, const Policy& policy) const; - size_t CalcNewLimit(const Sensor::Data& data, const Policy& policy) const; + size_t CalcNewLimit(const Sensor::Data& data, const Policy& policy) const; - static bool IsThresholdReached(const Sensor::Data& data, int percent); + static bool IsThresholdReached(const Sensor::Data& data, int percent); - const std::string name_; - Limit limit_; - dynamic_config::Source config_source_; - PolicyState state_; - std::atomic is_enabled_; + const std::string name_; + Limit limit_; + dynamic_config::Source config_source_; + PolicyState state_; + std::atomic is_enabled_; - Stats stats_; + Stats stats_; }; struct ControllerInfo { - Sensor& sensor; - Limiter& limiter; - Controller& controller; + Sensor& sensor; + Limiter& limiter; + Controller& controller; }; } // namespace congestion_control diff --git a/core/include/userver/congestion_control/controllers/linear.hpp b/core/include/userver/congestion_control/controllers/linear.hpp index bda3ca3e69f4..863ab76102f5 100644 --- a/core/include/userver/congestion_control/controllers/linear.hpp +++ b/core/include/userver/congestion_control/controllers/linear.hpp @@ -15,32 +15,35 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control::v2 { class LinearController final : public Controller { - public: - using StaticConfig = Controller::Config; - - LinearController( - const std::string& name, v2::Sensor& sensor, Limiter& limiter, - Stats& stats, const StaticConfig& config, - dynamic_config::Source config_source, - std::function config_getter); - - Limit Update(const Sensor::Data& current) override; - - private: - StaticConfig config_; - utils::SlidingInterval current_load_; - utils::SlidingInterval long_timings_; - utils::SlidingInterval short_timings_; - std::optional current_limit_; - std::size_t epochs_passed_{0}; - - dynamic_config::Source config_source_; - std::function config_getter_; +public: + using StaticConfig = Controller::Config; + + LinearController( + const std::string& name, + v2::Sensor& sensor, + Limiter& limiter, + Stats& stats, + const StaticConfig& config, + dynamic_config::Source config_source, + std::function config_getter + ); + + Limit Update(const Sensor::Data& current) override; + +private: + StaticConfig config_; + utils::SlidingInterval current_load_; + utils::SlidingInterval long_timings_; + utils::SlidingInterval short_timings_; + std::optional current_limit_; + std::size_t epochs_passed_{0}; + + dynamic_config::Source config_source_; + std::function config_getter_; }; -LinearController::StaticConfig Parse( - const yaml_config::YamlConfig& value, - formats::parse::To); +LinearController::StaticConfig +Parse(const yaml_config::YamlConfig& value, formats::parse::To); } // namespace congestion_control::v2 diff --git a/core/include/userver/congestion_control/controllers/linear_config.hpp b/core/include/userver/congestion_control/controllers/linear_config.hpp index 80bfd2675870..49327e55e2d4 100644 --- a/core/include/userver/congestion_control/controllers/linear_config.hpp +++ b/core/include/userver/congestion_control/controllers/linear_config.hpp @@ -10,12 +10,12 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control::v2 { struct Config { - double errors_threshold_percent{5.0}; // 5% - std::size_t safe_delta_limit{10}; - std::size_t timings_burst_threshold{5}; - std::chrono::milliseconds min_timings{20}; - std::size_t min_limit{10}; - std::size_t min_qps{10}; + double errors_threshold_percent{5.0}; // 5% + std::size_t safe_delta_limit{10}; + std::size_t timings_burst_threshold{5}; + std::chrono::milliseconds min_timings{20}; + std::size_t min_limit{10}; + std::size_t min_qps{10}; }; Config Parse(const formats::json::Value& value, formats::parse::To); diff --git a/core/include/userver/congestion_control/controllers/v2.hpp b/core/include/userver/congestion_control/controllers/v2.hpp index 7bfec59d74d4..f9f75c732721 100644 --- a/core/include/userver/congestion_control/controllers/v2.hpp +++ b/core/include/userver/congestion_control/controllers/v2.hpp @@ -13,51 +13,50 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control::v2 { struct Stats { - std::atomic is_enabled{false}; - std::atomic is_fake_mode{false}; - std::atomic current_limit{0}; - std::atomic enabled_epochs{0}; + std::atomic is_enabled{false}; + std::atomic is_fake_mode{false}; + std::atomic current_limit{0}; + std::atomic enabled_epochs{0}; }; void DumpMetric(utils::statistics::Writer& writer, const Stats& stats); class Controller { - public: - struct Config { - bool fake_mode{false}; - bool enabled{true}; - }; +public: + struct Config { + bool fake_mode{false}; + bool enabled{true}; + }; - Controller(const std::string& name, v2::Sensor& sensor, Limiter& limiter, - Stats& stats, const Config& config); + Controller(const std::string& name, v2::Sensor& sensor, Limiter& limiter, Stats& stats, const Config& config); - virtual ~Controller() = default; + virtual ~Controller() = default; - void Start(); - void Stop(); + void Start(); + void Stop(); - void Step(); + void Step(); - const std::string& GetName() const; + const std::string& GetName() const; - void SetEnabled(bool enabled); + void SetEnabled(bool enabled); - protected: - virtual Limit Update(const v2::Sensor::Data& data) = 0; +protected: + virtual Limit Update(const v2::Sensor::Data& data) = 0; - // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) - std::optional current_limit_; + // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) + std::optional current_limit_; - private: - std::string_view LogFakeMode() const; +private: + std::string_view LogFakeMode() const; - const std::string name_; - Sensor& sensor_; - congestion_control::Limiter& limiter_; - Stats& stats_; - const Config config_; - USERVER_NAMESPACE::utils::PeriodicTask periodic_; - std::atomic enabled_{true}; + const std::string name_; + Sensor& sensor_; + congestion_control::Limiter& limiter_; + Stats& stats_; + const Config config_; + USERVER_NAMESPACE::utils::PeriodicTask periodic_; + std::atomic enabled_{true}; }; } // namespace congestion_control::v2 diff --git a/core/include/userver/congestion_control/limiter.hpp b/core/include/userver/congestion_control/limiter.hpp index 5689f2abe31b..d7de3ada30ba 100644 --- a/core/include/userver/congestion_control/limiter.hpp +++ b/core/include/userver/congestion_control/limiter.hpp @@ -8,21 +8,18 @@ USERVER_NAMESPACE_BEGIN namespace congestion_control { struct Limit { - std::optional load_limit; - size_t current_load{0}; + std::optional load_limit; + size_t current_load{0}; - std::string ToLogString() { - return "limit=" + - (load_limit ? std::to_string(*load_limit) : std::string("(none)")); - } + std::string ToLogString() { return "limit=" + (load_limit ? std::to_string(*load_limit) : std::string("(none)")); } }; class Limiter { - public: - virtual void SetLimit(const Limit& new_limit) = 0; +public: + virtual void SetLimit(const Limit& new_limit) = 0; - protected: - ~Limiter() = default; +protected: + ~Limiter() = default; }; } // namespace congestion_control diff --git a/core/include/userver/congestion_control/sensor.hpp b/core/include/userver/congestion_control/sensor.hpp index a48d1780a18e..b9656388f5bf 100644 --- a/core/include/userver/congestion_control/sensor.hpp +++ b/core/include/userver/congestion_control/sensor.hpp @@ -11,45 +11,43 @@ namespace congestion_control { /// Abstract sensor that fetches counters. These counters will be used /// to forecast saturation levels and limit current load. class Sensor { - public: - struct Data { - std::uint64_t current_load{0}; - std::uint64_t overload_events_count{0}; - std::uint64_t no_overload_events_count{0}; - std::chrono::steady_clock::time_point tp; +public: + struct Data { + std::uint64_t current_load{0}; + std::uint64_t overload_events_count{0}; + std::uint64_t no_overload_events_count{0}; + std::chrono::steady_clock::time_point tp; - double GetLoadPercent() const; - }; + double GetLoadPercent() const; + }; - virtual ~Sensor() = default; + virtual ~Sensor() = default; - /// @brief Fetch current counters - /// @note Can be called both from coroutine and non-coroutine context - virtual Data FetchCurrent() = 0; + /// @brief Fetch current counters + /// @note Can be called both from coroutine and non-coroutine context + virtual Data FetchCurrent() = 0; }; namespace v2 { class Sensor { - public: - struct Data { - std::size_t total{0}; - std::size_t timeouts{0}; +public: + struct Data { + std::size_t total{0}; + std::size_t timeouts{0}; - std::size_t timings_avg_ms{0}; + std::size_t timings_avg_ms{0}; - std::size_t current_load{0}; + std::size_t current_load{0}; - double GetRate() const { - return static_cast(timeouts) / (total ? total : 1); - } + double GetRate() const { return static_cast(timeouts) / (total ? total : 1); } - std::string ToLogString() const; - }; + std::string ToLogString() const; + }; - virtual ~Sensor() = default; + virtual ~Sensor() = default; - virtual Data GetCurrent() = 0; + virtual Data GetCurrent() = 0; }; } // namespace v2 diff --git a/core/include/userver/dist_lock/dist_lock_settings.hpp b/core/include/userver/dist_lock/dist_lock_settings.hpp index e0fa86d554ff..592e62c406ca 100644 --- a/core/include/userver/dist_lock/dist_lock_settings.hpp +++ b/core/include/userver/dist_lock/dist_lock_settings.hpp @@ -12,33 +12,33 @@ namespace dist_lock { /// Distributed lock settings struct DistLockSettings { - /// How often to try to acquire the lock. - std::chrono::milliseconds acquire_interval{100}; + /// How often to try to acquire the lock. + std::chrono::milliseconds acquire_interval{100}; - /// How often to try to prolong the lock while holding the lock. - std::chrono::milliseconds prolong_interval{100}; + /// How often to try to prolong the lock while holding the lock. + std::chrono::milliseconds prolong_interval{100}; - /// For how long to acquire/prolong the lock. - std::chrono::milliseconds lock_ttl{1000}; + /// For how long to acquire/prolong the lock. + std::chrono::milliseconds lock_ttl{1000}; - /// How much time we allow for the worker to stop when we're unable to prolong - /// the lock. - std::chrono::milliseconds forced_stop_margin{50}; + /// How much time we allow for the worker to stop when we're unable to prolong + /// the lock. + std::chrono::milliseconds forced_stop_margin{50}; - /// Delay before failed worker_func restart - std::chrono::milliseconds worker_func_restart_delay{100}; + /// Delay before failed worker_func restart + std::chrono::milliseconds worker_func_restart_delay{100}; }; /// Distributed lock waiting mode enum class DistLockWaitingMode { - kWait, ///< waits until distlock becomes free - kNoWait, ///< doesn't wait for distlock if it is occupied + kWait, ///< waits until distlock becomes free + kNoWait, ///< doesn't wait for distlock if it is occupied }; /// Distributed lock retry strategy enum class DistLockRetryMode { - kRetry, ///< Retry on user exception/lock drop - kSingleAttempt, ///< Don't retry on user exception/lock drop + kRetry, ///< Retry on user exception/lock drop + kSingleAttempt, ///< Don't retry on user exception/lock drop }; } // namespace dist_lock diff --git a/core/include/userver/dist_lock/dist_lock_strategy.hpp b/core/include/userver/dist_lock/dist_lock_strategy.hpp index d4e839441477..c9cedfc7414a 100644 --- a/core/include/userver/dist_lock/dist_lock_strategy.hpp +++ b/core/include/userver/dist_lock/dist_lock_strategy.hpp @@ -22,25 +22,24 @@ class LockIsAcquiredByAnotherHostException : public std::exception {}; /// /// @snippet core/src/dist_lock/dist_lock_test.cpp Sample distlock strategy class DistLockStrategyBase { - public: - virtual ~DistLockStrategyBase() = default; - - /// Acquires the distributed lock. - /// - /// @param lock_ttl The duration for which the lock must be held. - /// @param locker_id Globally unique ID of the locking entity. - /// @throws LockIsAcquiredByAnotherHostError when the lock is busy - /// @throws anything else when the locking fails, strategy is responsible for - /// cleanup, Release won't be invoked. - virtual void Acquire(std::chrono::milliseconds lock_ttl, - const std::string& locker_id) = 0; - - /// Releases the lock. - /// - /// @param locker_id Globally unique ID of the locking entity, must be the - /// same as in Acquire(). - /// @note Exceptions are ignored. - virtual void Release(const std::string& locker_id) = 0; +public: + virtual ~DistLockStrategyBase() = default; + + /// Acquires the distributed lock. + /// + /// @param lock_ttl The duration for which the lock must be held. + /// @param locker_id Globally unique ID of the locking entity. + /// @throws LockIsAcquiredByAnotherHostError when the lock is busy + /// @throws anything else when the locking fails, strategy is responsible for + /// cleanup, Release won't be invoked. + virtual void Acquire(std::chrono::milliseconds lock_ttl, const std::string& locker_id) = 0; + + /// Releases the lock. + /// + /// @param locker_id Globally unique ID of the locking entity, must be the + /// same as in Acquire(). + /// @note Exceptions are ignored. + virtual void Release(const std::string& locker_id) = 0; }; } // namespace dist_lock diff --git a/core/include/userver/dist_lock/dist_locked_task.hpp b/core/include/userver/dist_lock/dist_locked_task.hpp index df3d7482f1f3..1a203ca2a1d7 100644 --- a/core/include/userver/dist_lock/dist_locked_task.hpp +++ b/core/include/userver/dist_lock/dist_locked_task.hpp @@ -46,56 +46,61 @@ class Locker; // clang-format on class DistLockedTask final : public engine::TaskBase { - public: - using WorkerFunc = std::function; - - /// Default constructor. - /// Creates an invalid task. - DistLockedTask() = default; - - DistLockedTask(DistLockedTask&&) = delete; - DistLockedTask& operator=(DistLockedTask&&) = delete; - - DistLockedTask(const DistLockedTask&) = delete; - DistLockedTask& operator=(const DistLockedTask&&) = delete; - - ~DistLockedTask(); - - /// Creates a DistLockedTask. - /// @param name name of the task - /// @param worker_func a callback that is started once we've acquired the lock - /// and is cancelled when the lock is lost. - /// @param settings distributed lock settings - /// @param strategy distributed locking strategy - /// @param mode distributed lock waiting mode - /// @note `worker_func` must honour task cancellation and stop ASAP when - /// it is cancelled, otherwise brain split is possible (IOW, two different - /// users do work assuming both of them hold the lock, which is not true). - DistLockedTask(std::string name, WorkerFunc worker_func, - std::shared_ptr strategy, - const DistLockSettings& settings = {}, - DistLockWaitingMode mode = DistLockWaitingMode::kWait, - DistLockRetryMode retry_mode = DistLockRetryMode::kRetry); - - /// Creates a DistLockedTask to be run in a specific engine::TaskProcessor - DistLockedTask(engine::TaskProcessor& task_processor, std::string name, - WorkerFunc worker_func, - std::shared_ptr strategy, - const DistLockSettings& settings = {}, - DistLockWaitingMode mode = DistLockWaitingMode::kWait, - DistLockRetryMode retry_mode = DistLockRetryMode::kRetry); - - /// Returns for how long the lock is held (if held at all). Returned value - /// may be less than the real duration. - std::optional GetLockedDuration() const; - - void Get() noexcept(false); - - private: - DistLockedTask(engine::TaskProcessor&, std::shared_ptr, - DistLockWaitingMode); - - std::shared_ptr locker_ptr_; +public: + using WorkerFunc = std::function; + + /// Default constructor. + /// Creates an invalid task. + DistLockedTask() = default; + + DistLockedTask(DistLockedTask&&) = delete; + DistLockedTask& operator=(DistLockedTask&&) = delete; + + DistLockedTask(const DistLockedTask&) = delete; + DistLockedTask& operator=(const DistLockedTask&&) = delete; + + ~DistLockedTask(); + + /// Creates a DistLockedTask. + /// @param name name of the task + /// @param worker_func a callback that is started once we've acquired the lock + /// and is cancelled when the lock is lost. + /// @param settings distributed lock settings + /// @param strategy distributed locking strategy + /// @param mode distributed lock waiting mode + /// @note `worker_func` must honour task cancellation and stop ASAP when + /// it is cancelled, otherwise brain split is possible (IOW, two different + /// users do work assuming both of them hold the lock, which is not true). + DistLockedTask( + std::string name, + WorkerFunc worker_func, + std::shared_ptr strategy, + const DistLockSettings& settings = {}, + DistLockWaitingMode mode = DistLockWaitingMode::kWait, + DistLockRetryMode retry_mode = DistLockRetryMode::kRetry + ); + + /// Creates a DistLockedTask to be run in a specific engine::TaskProcessor + DistLockedTask( + engine::TaskProcessor& task_processor, + std::string name, + WorkerFunc worker_func, + std::shared_ptr strategy, + const DistLockSettings& settings = {}, + DistLockWaitingMode mode = DistLockWaitingMode::kWait, + DistLockRetryMode retry_mode = DistLockRetryMode::kRetry + ); + + /// Returns for how long the lock is held (if held at all). Returned value + /// may be less than the real duration. + std::optional GetLockedDuration() const; + + void Get() noexcept(false); + +private: + DistLockedTask(engine::TaskProcessor&, std::shared_ptr, DistLockWaitingMode); + + std::shared_ptr locker_ptr_; }; } // namespace dist_lock diff --git a/core/include/userver/dist_lock/dist_locked_worker.hpp b/core/include/userver/dist_lock/dist_locked_worker.hpp index 2416f0826b13..f1cd1dfac714 100644 --- a/core/include/userver/dist_lock/dist_locked_worker.hpp +++ b/core/include/userver/dist_lock/dist_locked_worker.hpp @@ -26,77 +26,79 @@ class Locker; /// and runs user callback in a separate task while the lock is held. /// Cancels the task when the lock is lost. class DistLockedWorker final { - public: - using WorkerFunc = std::function; - - /// Creates a DistLockedWorker. - /// @param name name of the worker - /// @param worker_func a callback that's started each time we acquire the lock - /// and is cancelled when the lock is lost. - /// @param settings distributed lock settings - /// @param strategy distributed locking strategy - /// @param task_processor TaskProcessor for running `worker_func`, - /// using current TaskProcessor if `nullptr` - /// @param locker_log_level Log level for Locker (default is info) - /// @note `worker_func` must honour task cancellation and stop ASAP when - /// it is cancelled, otherwise brain split is possible (IOW, two different - /// users do work assuming both of them hold the lock, which is not true). - DistLockedWorker(std::string name, WorkerFunc worker_func, - std::shared_ptr strategy, - const DistLockSettings& settings = {}, - engine::TaskProcessor* task_processor = nullptr, - logging::Level locker_log_level = logging::Level::kInfo); - - ~DistLockedWorker(); - - /// Name of the worker. - const std::string& Name() const; - - /// Retrieves settings in a thread-safe way. - DistLockSettings GetSettings() const; - - /// Update settings in a thread-safe way. - void UpdateSettings(const DistLockSettings&); - - /// Starts acquiring the lock. Please note that it's possible that the lock is - /// acquired and the WorkerFunc is entered *before* Start() returns. - /// @see DistLockedTask::DistLockedTask - void Start(); - - /// Stops acquiring the lock. It is guaranteed that the lock is not held after - /// Stop() return and WorkerFunc is stopped (if was started). - void Stop(); - - /// Run task once acquiring the lock. - /// @throws std::exception rethrows exception from `worker_func`. - void RunOnce(); - - /// @returns whether the DistLockedTask is started. - bool IsRunning() const; - - /// @returns is current worker owns the lock - bool OwnsLock() const noexcept; - - /// Returns for how long the lock is held (if held at all). Returned value - /// may be less than the real duration. - std::optional GetLockedDuration() const; - - /// Returns lock acquisition statistics. - const Statistics& GetStatistics() const; - - private: - engine::TaskProcessor& GetTaskProcessor() const noexcept; - - std::shared_ptr locker_ptr_; - - mutable engine::Mutex locker_task_mutex_; - engine::TaskWithResult locker_task_; - - engine::TaskProcessor* const task_processor_; +public: + using WorkerFunc = std::function; + + /// Creates a DistLockedWorker. + /// @param name name of the worker + /// @param worker_func a callback that's started each time we acquire the lock + /// and is cancelled when the lock is lost. + /// @param settings distributed lock settings + /// @param strategy distributed locking strategy + /// @param task_processor TaskProcessor for running `worker_func`, + /// using current TaskProcessor if `nullptr` + /// @param locker_log_level Log level for Locker (default is info) + /// @note `worker_func` must honour task cancellation and stop ASAP when + /// it is cancelled, otherwise brain split is possible (IOW, two different + /// users do work assuming both of them hold the lock, which is not true). + DistLockedWorker( + std::string name, + WorkerFunc worker_func, + std::shared_ptr strategy, + const DistLockSettings& settings = {}, + engine::TaskProcessor* task_processor = nullptr, + logging::Level locker_log_level = logging::Level::kInfo + ); + + ~DistLockedWorker(); + + /// Name of the worker. + const std::string& Name() const; + + /// Retrieves settings in a thread-safe way. + DistLockSettings GetSettings() const; + + /// Update settings in a thread-safe way. + void UpdateSettings(const DistLockSettings&); + + /// Starts acquiring the lock. Please note that it's possible that the lock is + /// acquired and the WorkerFunc is entered *before* Start() returns. + /// @see DistLockedTask::DistLockedTask + void Start(); + + /// Stops acquiring the lock. It is guaranteed that the lock is not held after + /// Stop() return and WorkerFunc is stopped (if was started). + void Stop(); + + /// Run task once acquiring the lock. + /// @throws std::exception rethrows exception from `worker_func`. + void RunOnce(); + + /// @returns whether the DistLockedTask is started. + bool IsRunning() const; + + /// @returns is current worker owns the lock + bool OwnsLock() const noexcept; + + /// Returns for how long the lock is held (if held at all). Returned value + /// may be less than the real duration. + std::optional GetLockedDuration() const; + + /// Returns lock acquisition statistics. + const Statistics& GetStatistics() const; + +private: + engine::TaskProcessor& GetTaskProcessor() const noexcept; + + std::shared_ptr locker_ptr_; + + mutable engine::Mutex locker_task_mutex_; + engine::TaskWithResult locker_task_; + + engine::TaskProcessor* const task_processor_; }; -void DumpMetric(utils::statistics::Writer& writer, - const DistLockedWorker& worker); +void DumpMetric(utils::statistics::Writer& writer, const DistLockedWorker& worker); } // namespace dist_lock diff --git a/core/include/userver/dist_lock/statistics.hpp b/core/include/userver/dist_lock/statistics.hpp index 4d8ea5e8ae24..c9ae31d396c8 100644 --- a/core/include/userver/dist_lock/statistics.hpp +++ b/core/include/userver/dist_lock/statistics.hpp @@ -9,11 +9,11 @@ USERVER_NAMESPACE_BEGIN namespace dist_lock { struct Statistics { - utils::statistics::RelaxedCounter lock_successes{0}; - utils::statistics::RelaxedCounter lock_failures{0}; - utils::statistics::RelaxedCounter watchdog_triggers{0}; - utils::statistics::RelaxedCounter brain_splits{0}; - utils::statistics::RelaxedCounter task_failures{0}; + utils::statistics::RelaxedCounter lock_successes{0}; + utils::statistics::RelaxedCounter lock_failures{0}; + utils::statistics::RelaxedCounter watchdog_triggers{0}; + utils::statistics::RelaxedCounter brain_splits{0}; + utils::statistics::RelaxedCounter task_failures{0}; }; } // namespace dist_lock diff --git a/core/include/userver/drivers/impl/connection_pool_base.hpp b/core/include/userver/drivers/impl/connection_pool_base.hpp index 89f625608967..34e1d7f0847b 100644 --- a/core/include/userver/drivers/impl/connection_pool_base.hpp +++ b/core/include/userver/drivers/impl/connection_pool_base.hpp @@ -26,8 +26,8 @@ namespace drivers::impl { /// @brief Thrown when no connection could be acquired from the pool within /// specified timeout. class PoolWaitLimitExceededError : public std::runtime_error { - public: - PoolWaitLimitExceededError(); +public: + PoolWaitLimitExceededError(); }; /// @brief Base connection pool implementation to be derived in different @@ -35,329 +35,325 @@ class PoolWaitLimitExceededError : public std::runtime_error { /// connecting etc.) and provides hooks for metrics. template class ConnectionPoolBase : public std::enable_shared_from_this { - public: - protected: - using ConnectionRawPtr = Connection*; - using ConnectionUniquePtr = std::unique_ptr; - - struct ConnectionHolder final { - std::shared_ptr pool_ptr; - ConnectionUniquePtr connection_ptr; - }; - - /// @brief Constructor, doesn't create any connections, one should call `Init` - /// to initialize the pool. - ConnectionPoolBase(std::size_t max_pool_size, - std::size_t max_simultaneously_connecting_clients); - /// @brief Destructor. One should call `Reset` before the destructor is - /// invoked. - ~ConnectionPoolBase(); - - /// @brief Initializes the pool with given limits. - /// Uses some methods that must or may be overridden in derived class, hence - /// a separate method and not called from base class constructor. - /// Derived class constructor is a good place to call this. - void Init(std::size_t initial_size, - std::chrono::milliseconds connection_setup_timeout); - /// @brief Resets the pool, destroying all managed connections. - /// Uses some methods that may be overridden in derived class, hence - /// a separate function and not called from base class constructor. - /// Derived class destructor is a good place to call this. - void Reset(); - - /// @brief Acquires a connection from the pool. - ConnectionHolder AcquireConnection(engine::Deadline deadline); - /// @brief Returns the connection to the pool. - /// If `connection_ptr->IsBroken()` is true, the connection is destroyed. - void ReleaseConnection(ConnectionUniquePtr connection_ptr); - - /// @brief Pops a connection from the pool, might create a new connection if - /// there are no ready connections. - ConnectionUniquePtr Pop(engine::Deadline deadline); - /// @brief Tries to pop a ready connection from the pool, - /// may return `nullptr`. - ConnectionUniquePtr TryPop(); - - /// @brief Returns the connection to the pool, internal. - /// If `connection_ptr->IsBroken()` is true, the connection is destroyed. - /// Doesn't affect pool limits, so you shouldn't call this directly, - /// unless the connection is acquired from `TryPop` - then it's the only - /// correct way to return it back. - void DoRelease(ConnectionUniquePtr connection_ptr); - - /// @brief Creates a new connection and tries to push it into the ready - /// queue. If the queue is full, the connection is dropped immediately. - void PushConnection(engine::Deadline deadline); - /// @brief Drops the connections - destroys the object and accounts for that. - void Drop(ConnectionRawPtr connection_ptr) noexcept; - - /// @brief Returns the approximate count of alive connections (given away and - /// ready to use). - std::size_t AliveConnectionsCountApprox() const; - - /// @brief Call this method if for some reason a connection previously - /// acquired from the pool won't be returned into it. - /// If one fails to do so pool limits might shrink until pool becomes - /// unusable. - void NotifyConnectionWontBeReleased(); - - private: - Derived& AsDerived() noexcept; - const Derived& AsDerived() const noexcept; - - ConnectionUniquePtr CreateConnection( - const engine::SemaphoreLock& connecting_lock, engine::Deadline deadline); - - void CleanupQueue(); - - void EnsureInitialized() const; - void EnsureReset() const; - - engine::Semaphore given_away_semaphore_; - engine::Semaphore connecting_semaphore_; - - boost::lockfree::queue queue_; - std::atomic alive_connections_{0}; - - bool initialized_{false}; - bool reset_{false}; +public: +protected: + using ConnectionRawPtr = Connection*; + using ConnectionUniquePtr = std::unique_ptr; + + struct ConnectionHolder final { + std::shared_ptr pool_ptr; + ConnectionUniquePtr connection_ptr; + }; + + /// @brief Constructor, doesn't create any connections, one should call `Init` + /// to initialize the pool. + ConnectionPoolBase(std::size_t max_pool_size, std::size_t max_simultaneously_connecting_clients); + /// @brief Destructor. One should call `Reset` before the destructor is + /// invoked. + ~ConnectionPoolBase(); + + /// @brief Initializes the pool with given limits. + /// Uses some methods that must or may be overridden in derived class, hence + /// a separate method and not called from base class constructor. + /// Derived class constructor is a good place to call this. + void Init(std::size_t initial_size, std::chrono::milliseconds connection_setup_timeout); + /// @brief Resets the pool, destroying all managed connections. + /// Uses some methods that may be overridden in derived class, hence + /// a separate function and not called from base class constructor. + /// Derived class destructor is a good place to call this. + void Reset(); + + /// @brief Acquires a connection from the pool. + ConnectionHolder AcquireConnection(engine::Deadline deadline); + /// @brief Returns the connection to the pool. + /// If `connection_ptr->IsBroken()` is true, the connection is destroyed. + void ReleaseConnection(ConnectionUniquePtr connection_ptr); + + /// @brief Pops a connection from the pool, might create a new connection if + /// there are no ready connections. + ConnectionUniquePtr Pop(engine::Deadline deadline); + /// @brief Tries to pop a ready connection from the pool, + /// may return `nullptr`. + ConnectionUniquePtr TryPop(); + + /// @brief Returns the connection to the pool, internal. + /// If `connection_ptr->IsBroken()` is true, the connection is destroyed. + /// Doesn't affect pool limits, so you shouldn't call this directly, + /// unless the connection is acquired from `TryPop` - then it's the only + /// correct way to return it back. + void DoRelease(ConnectionUniquePtr connection_ptr); + + /// @brief Creates a new connection and tries to push it into the ready + /// queue. If the queue is full, the connection is dropped immediately. + void PushConnection(engine::Deadline deadline); + /// @brief Drops the connections - destroys the object and accounts for that. + void Drop(ConnectionRawPtr connection_ptr) noexcept; + + /// @brief Returns the approximate count of alive connections (given away and + /// ready to use). + std::size_t AliveConnectionsCountApprox() const; + + /// @brief Call this method if for some reason a connection previously + /// acquired from the pool won't be returned into it. + /// If one fails to do so pool limits might shrink until pool becomes + /// unusable. + void NotifyConnectionWontBeReleased(); + +private: + Derived& AsDerived() noexcept; + const Derived& AsDerived() const noexcept; + + ConnectionUniquePtr CreateConnection(const engine::SemaphoreLock& connecting_lock, engine::Deadline deadline); + + void CleanupQueue(); + + void EnsureInitialized() const; + void EnsureReset() const; + + engine::Semaphore given_away_semaphore_; + engine::Semaphore connecting_semaphore_; + + boost::lockfree::queue queue_; + std::atomic alive_connections_{0}; + + bool initialized_{false}; + bool reset_{false}; }; template ConnectionPoolBase::ConnectionPoolBase( std::size_t max_pool_size, - std::size_t max_simultaneously_connecting_clients) + std::size_t max_simultaneously_connecting_clients +) : given_away_semaphore_{max_pool_size}, connecting_semaphore_{max_simultaneously_connecting_clients}, queue_{max_pool_size} {} template ConnectionPoolBase::~ConnectionPoolBase() { - if (initialized_) { - // We don't call Reset here, because dropping a connection (when cleaning - // up the queue) might invoke virtual methods, and the derived class is - // already destroyed, so unexpected things could happen. - // However, we assert that derived class performed a cleanup itself. - EnsureReset(); - } + if (initialized_) { + // We don't call Reset here, because dropping a connection (when cleaning + // up the queue) might invoke virtual methods, and the derived class is + // already destroyed, so unexpected things could happen. + // However, we assert that derived class performed a cleanup itself. + EnsureReset(); + } } template void ConnectionPoolBase::Init( std::size_t initial_size, - std::chrono::milliseconds connection_setup_timeout) { - UASSERT_MSG(!initialized_, "Calling Init multiple times is a API misuse"); - // We mark the pool as initialized even if this method throws, because - // this `initialized_` field is here just to ensure correct API usage, - // doesn't have much meaning aside from that. - initialized_ = true; - - std::vector> init_tasks{}; - init_tasks.reserve(initial_size); - - for (std::size_t i = 0; i < initial_size; ++i) { - init_tasks.push_back(engine::AsyncNoSpan([this, connection_setup_timeout] { - PushConnection(engine::Deadline::FromDuration(connection_setup_timeout)); - })); - } - - try { - engine::GetAll(init_tasks); - } catch (const std::exception& ex) { - LOG_WARNING() << "Failed to properly setup connection pool: " << ex; - throw; - } + std::chrono::milliseconds connection_setup_timeout +) { + UASSERT_MSG(!initialized_, "Calling Init multiple times is a API misuse"); + // We mark the pool as initialized even if this method throws, because + // this `initialized_` field is here just to ensure correct API usage, + // doesn't have much meaning aside from that. + initialized_ = true; + + std::vector> init_tasks{}; + init_tasks.reserve(initial_size); + + for (std::size_t i = 0; i < initial_size; ++i) { + init_tasks.push_back(engine::AsyncNoSpan([this, connection_setup_timeout] { + PushConnection(engine::Deadline::FromDuration(connection_setup_timeout)); + })); + } + + try { + engine::GetAll(init_tasks); + } catch (const std::exception& ex) { + LOG_WARNING() << "Failed to properly setup connection pool: " << ex; + throw; + } } template void ConnectionPoolBase::Reset() { - UASSERT_MSG(!reset_, "Calling Reset multiple times is a API misuse"); - reset_ = true; + UASSERT_MSG(!reset_, "Calling Reset multiple times is a API misuse"); + reset_ = true; - CleanupQueue(); + CleanupQueue(); } template typename ConnectionPoolBase::ConnectionHolder -ConnectionPoolBase::AcquireConnection( - engine::Deadline deadline) { - EnsureInitialized(); +ConnectionPoolBase::AcquireConnection(engine::Deadline deadline) { + EnsureInitialized(); - auto connection_ptr = Pop(deadline); - return {this->shared_from_this(), std::move(connection_ptr)}; + auto connection_ptr = Pop(deadline); + return {this->shared_from_this(), std::move(connection_ptr)}; } template -void ConnectionPoolBase::ReleaseConnection( - ConnectionUniquePtr connection_ptr) { - EnsureInitialized(); - UASSERT(connection_ptr); +void ConnectionPoolBase::ReleaseConnection(ConnectionUniquePtr connection_ptr) { + EnsureInitialized(); + UASSERT(connection_ptr); - DoRelease(std::move(connection_ptr)); + DoRelease(std::move(connection_ptr)); - given_away_semaphore_.unlock_shared(); - AsDerived().AccountConnectionReleased(); + given_away_semaphore_.unlock_shared(); + AsDerived().AccountConnectionReleased(); } template Derived& ConnectionPoolBase::AsDerived() noexcept { - return *static_cast(this); + return *static_cast(this); } template -const Derived& ConnectionPoolBase::AsDerived() const - noexcept { - return *static_cast(this); +const Derived& ConnectionPoolBase::AsDerived() const noexcept { + return *static_cast(this); } template typename ConnectionPoolBase::ConnectionUniquePtr ConnectionPoolBase::CreateConnection( - const engine::SemaphoreLock& connecting_lock, engine::Deadline deadline) { - EnsureInitialized(); + const engine::SemaphoreLock& connecting_lock, + engine::Deadline deadline +) { + EnsureInitialized(); - UASSERT(connecting_lock.OwnsLock()); - auto connection_ptr = AsDerived().DoCreateConnection(deadline); + UASSERT(connecting_lock.OwnsLock()); + auto connection_ptr = AsDerived().DoCreateConnection(deadline); - alive_connections_.fetch_add(1); - AsDerived().AccountConnectionCreated(); + alive_connections_.fetch_add(1); + AsDerived().AccountConnectionCreated(); - return connection_ptr; + return connection_ptr; } template -typename ConnectionPoolBase::ConnectionUniquePtr -ConnectionPoolBase::Pop(engine::Deadline deadline) { - EnsureInitialized(); - - engine::SemaphoreLock given_away_lock{given_away_semaphore_, deadline}; - if (!given_away_lock.OwnsLock()) { - AsDerived().AccountOverload(); - throw PoolWaitLimitExceededError{}; - } +typename ConnectionPoolBase::ConnectionUniquePtr ConnectionPoolBase::Pop( + engine::Deadline deadline +) { + EnsureInitialized(); - auto connection_ptr = TryPop(); - if (!connection_ptr) { - engine::SemaphoreLock connecting_lock{connecting_semaphore_, deadline}; - - connection_ptr = TryPop(); - if (!connection_ptr) { - if (!connecting_lock.OwnsLock()) { + engine::SemaphoreLock given_away_lock{given_away_semaphore_, deadline}; + if (!given_away_lock.OwnsLock()) { AsDerived().AccountOverload(); throw PoolWaitLimitExceededError{}; - } - connection_ptr = CreateConnection(connecting_lock, deadline); } - } - UASSERT(connection_ptr); + auto connection_ptr = TryPop(); + if (!connection_ptr) { + engine::SemaphoreLock connecting_lock{connecting_semaphore_, deadline}; + + connection_ptr = TryPop(); + if (!connection_ptr) { + if (!connecting_lock.OwnsLock()) { + AsDerived().AccountOverload(); + throw PoolWaitLimitExceededError{}; + } + connection_ptr = CreateConnection(connecting_lock, deadline); + } + } + + UASSERT(connection_ptr); - given_away_lock.Release(); - AsDerived().AccountConnectionAcquired(); + given_away_lock.Release(); + AsDerived().AccountConnectionAcquired(); - return connection_ptr; + return connection_ptr; } template -typename ConnectionPoolBase::ConnectionUniquePtr -ConnectionPoolBase::TryPop() { - EnsureInitialized(); +typename ConnectionPoolBase::ConnectionUniquePtr ConnectionPoolBase::TryPop( +) { + EnsureInitialized(); - ConnectionRawPtr connection_ptr{nullptr}; - if (!queue_.pop(connection_ptr)) { - return nullptr; - } + ConnectionRawPtr connection_ptr{nullptr}; + if (!queue_.pop(connection_ptr)) { + return nullptr; + } - return ConnectionUniquePtr{connection_ptr}; + return ConnectionUniquePtr{connection_ptr}; } template -void ConnectionPoolBase::DoRelease( - ConnectionUniquePtr connection_ptr) { - EnsureInitialized(); - UASSERT(connection_ptr); - - const auto is_broken = connection_ptr->IsBroken(); - ConnectionRawPtr connection_raw_ptr = connection_ptr.release(); - if (is_broken || !queue_.bounded_push(connection_raw_ptr)) { - Drop(connection_raw_ptr); - } +void ConnectionPoolBase::DoRelease(ConnectionUniquePtr connection_ptr) { + EnsureInitialized(); + UASSERT(connection_ptr); + + const auto is_broken = connection_ptr->IsBroken(); + ConnectionRawPtr connection_raw_ptr = connection_ptr.release(); + if (is_broken || !queue_.bounded_push(connection_raw_ptr)) { + Drop(connection_raw_ptr); + } } template -void ConnectionPoolBase::PushConnection( - engine::Deadline deadline) { - EnsureInitialized(); - - engine::SemaphoreLock connecting_lock{connecting_semaphore_, deadline}; - if (!connecting_lock.OwnsLock()) { - throw PoolWaitLimitExceededError{}; - } - - ConnectionUniquePtr connection_ptr = - CreateConnection(connecting_lock, deadline); - connecting_lock.Unlock(); - - ConnectionRawPtr connection_raw_ptr = connection_ptr.release(); - if (!queue_.bounded_push(connection_raw_ptr)) { - Drop(connection_raw_ptr); - } +void ConnectionPoolBase::PushConnection(engine::Deadline deadline) { + EnsureInitialized(); + + engine::SemaphoreLock connecting_lock{connecting_semaphore_, deadline}; + if (!connecting_lock.OwnsLock()) { + throw PoolWaitLimitExceededError{}; + } + + ConnectionUniquePtr connection_ptr = CreateConnection(connecting_lock, deadline); + connecting_lock.Unlock(); + + ConnectionRawPtr connection_raw_ptr = connection_ptr.release(); + if (!queue_.bounded_push(connection_raw_ptr)) { + Drop(connection_raw_ptr); + } } template -void ConnectionPoolBase::Drop( - ConnectionRawPtr connection_ptr) noexcept { - EnsureInitialized(); - std::default_delete{}(connection_ptr); - - alive_connections_.fetch_sub(1); - - static_assert(noexcept(AsDerived().AccountConnectionDestroyed()), - "Please make AccountConnectionDestroyed() noexcept, " - "because it might get called in pool destructor and is " - "expected to be noexcept"); - AsDerived().AccountConnectionDestroyed(); +void ConnectionPoolBase::Drop(ConnectionRawPtr connection_ptr) noexcept { + EnsureInitialized(); + std::default_delete{}(connection_ptr); + + alive_connections_.fetch_sub(1); + + static_assert( + noexcept(AsDerived().AccountConnectionDestroyed()), + "Please make AccountConnectionDestroyed() noexcept, " + "because it might get called in pool destructor and is " + "expected to be noexcept" + ); + AsDerived().AccountConnectionDestroyed(); } template -std::size_t -ConnectionPoolBase::AliveConnectionsCountApprox() const { - EnsureInitialized(); +std::size_t ConnectionPoolBase::AliveConnectionsCountApprox() const { + EnsureInitialized(); - return alive_connections_.load(); + return alive_connections_.load(); } template void ConnectionPoolBase::NotifyConnectionWontBeReleased() { - EnsureInitialized(); + EnsureInitialized(); - given_away_semaphore_.unlock_shared(); - alive_connections_.fetch_sub(1); + given_away_semaphore_.unlock_shared(); + alive_connections_.fetch_sub(1); } template void ConnectionPoolBase::CleanupQueue() { - EnsureInitialized(); + EnsureInitialized(); - ConnectionRawPtr connection_ptr{nullptr}; + ConnectionRawPtr connection_ptr{nullptr}; - while (queue_.pop(connection_ptr)) { - Drop(connection_ptr); - } + while (queue_.pop(connection_ptr)) { + Drop(connection_ptr); + } } template void ConnectionPoolBase::EnsureInitialized() const { - UASSERT_MSG( - initialized_, - "Please call Init before invoking any other methods on connection pool."); + UASSERT_MSG(initialized_, "Please call Init before invoking any other methods on connection pool."); } template void ConnectionPoolBase::EnsureReset() const { - UASSERT_MSG(reset_, - "Please call Reset before base class is destroyed, otherwise no " - "cleanup is performed."); + UASSERT_MSG( + reset_, + "Please call Reset before base class is destroyed, otherwise no " + "cleanup is performed." + ); } } // namespace drivers::impl diff --git a/core/include/userver/drivers/subscribable_futures.hpp b/core/include/userver/drivers/subscribable_futures.hpp index e800b9e0f2c4..4b508facdef2 100644 --- a/core/include/userver/drivers/subscribable_futures.hpp +++ b/core/include/userver/drivers/subscribable_futures.hpp @@ -20,7 +20,7 @@ namespace drivers { namespace impl { struct EventHolder final : boost::intrusive_ref_counter { - engine::SingleConsumerEvent event{engine::SingleConsumerEvent::NoAutoReset{}}; + engine::SingleConsumerEvent event{engine::SingleConsumerEvent::NoAutoReset{}}; }; } // namespace impl @@ -39,42 +39,38 @@ struct EventHolder final : boost::intrusive_ref_counter { /// @see drivers::TryWaitForSubscribableFuture template class SubscribableFutureWrapper final { - public: - explicit SubscribableFutureWrapper(SubscribableFuture&& future) - : original_future_(static_cast(future)), - event_holder_(utils::make_intrusive_ptr()) { - original_future_.Subscribe( - [event_holder = event_holder_](auto&) { event_holder->event.Send(); }); - } - - /// @returns the original future - SubscribableFuture& GetFuture() { return original_future_; } - - /// @brief Wait for the future. The result can be retrieved from the original - /// future using GetFuture once ready. - /// @throws engine::WaitInterruptedException on task cancellation - void Wait() { - if (TryWaitUntil(engine::Deadline{}) != engine::FutureStatus::kReady) { - throw engine::WaitInterruptedException( - engine::current_task::CancellationReason()); +public: + explicit SubscribableFutureWrapper(SubscribableFuture&& future) + : original_future_(static_cast(future)), + event_holder_(utils::make_intrusive_ptr()) { + original_future_.Subscribe([event_holder = event_holder_](auto&) { event_holder->event.Send(); }); } - } - - /// @brief Wait for the future. The result can be retrieved from the original - /// future using GetFuture once ready. - /// @returns an error code if deadline is exceeded or task is cancelled - [[nodiscard]] engine::FutureStatus TryWaitUntil(engine::Deadline deadline) { - if (event_holder_->event.WaitForEventUntil(deadline)) { - return engine::FutureStatus::kReady; + + /// @returns the original future + SubscribableFuture& GetFuture() { return original_future_; } + + /// @brief Wait for the future. The result can be retrieved from the original + /// future using GetFuture once ready. + /// @throws engine::WaitInterruptedException on task cancellation + void Wait() { + if (TryWaitUntil(engine::Deadline{}) != engine::FutureStatus::kReady) { + throw engine::WaitInterruptedException(engine::current_task::CancellationReason()); + } } - return engine::current_task::ShouldCancel() - ? engine::FutureStatus::kCancelled - : engine::FutureStatus::kTimeout; - } - - private: - SubscribableFuture original_future_; - boost::intrusive_ptr event_holder_; + + /// @brief Wait for the future. The result can be retrieved from the original + /// future using GetFuture once ready. + /// @returns an error code if deadline is exceeded or task is cancelled + [[nodiscard]] engine::FutureStatus TryWaitUntil(engine::Deadline deadline) { + if (event_holder_->event.WaitForEventUntil(deadline)) { + return engine::FutureStatus::kReady; + } + return engine::current_task::ShouldCancel() ? engine::FutureStatus::kCancelled : engine::FutureStatus::kTimeout; + } + +private: + SubscribableFuture original_future_; + boost::intrusive_ptr event_holder_; }; /// @ingroup userver_concurrency @@ -87,7 +83,7 @@ class SubscribableFutureWrapper final { /// @throws engine::WaitInterruptedException on task cancellation template void WaitForSubscribableFuture(SubscribableFuture&& future) { - SubscribableFutureWrapper{future}.Wait(); + SubscribableFutureWrapper{future}.Wait(); } /// @ingroup userver_concurrency @@ -97,10 +93,9 @@ void WaitForSubscribableFuture(SubscribableFuture&& future) { /// @warning Repeatedly waiting again after `deadline` expiration leads to a /// memory leak, use drivers::SubscribableFutureWrapper instead. template -[[nodiscard]] engine::FutureStatus TryWaitForSubscribableFuture( - SubscribableFuture&& future, engine::Deadline deadline) { - return SubscribableFutureWrapper{future}.TryWaitUntil( - deadline); +[[nodiscard]] engine::FutureStatus +TryWaitForSubscribableFuture(SubscribableFuture&& future, engine::Deadline deadline) { + return SubscribableFutureWrapper{future}.TryWaitUntil(deadline); } } // namespace drivers diff --git a/core/include/userver/dump/aggregates.hpp b/core/include/userver/dump/aggregates.hpp index 84a18f4f0bf6..c22c4b86a89e 100644 --- a/core/include/userver/dump/aggregates.hpp +++ b/core/include/userver/dump/aggregates.hpp @@ -28,31 +28,31 @@ using IsNotDumpedAggregate = decltype(sizeof(IsDumpedAggregate)); template constexpr bool AreAllDumpable(std::index_sequence) { - return (kIsDumpable> && ...); + return (kIsDumpable> && ...); } template constexpr bool IsDumpableAggregate() { - if constexpr (std::is_aggregate_v && - !meta::kIsDetected) { - constexpr auto kSize = boost::pfr::tuple_size_v; - static_assert( - AreAllDumpable(std::make_index_sequence{}), - "One of the member of an aggregate that was marked as dumpable " - "with dump::IsDumpedAggregate is not dumpable. Did you forget " - "to include , " - " or some other header with " - "Read and Write functions declarations?"); - return true; - } else { - return false; - } + if constexpr (std::is_aggregate_v && !meta::kIsDetected) { + constexpr auto kSize = boost::pfr::tuple_size_v; + static_assert( + AreAllDumpable(std::make_index_sequence{}), + "One of the member of an aggregate that was marked as dumpable " + "with dump::IsDumpedAggregate is not dumpable. Did you forget " + "to include , " + " or some other header with " + "Read and Write functions declarations?" + ); + return true; + } else { + return false; + } } template T ReadAggregate(Reader& reader, std::index_sequence) { - // `Read`s are guaranteed to occur left-to-right in brace-init - return T{reader.Read>()...}; + // `Read`s are guaranteed to occur left-to-right in brace-init + return T{reader.Read>()...}; } } // namespace impl @@ -68,10 +68,8 @@ T ReadAggregate(Reader& reader, std::index_sequence) { /// /// @warning Don't forget to increment format-version if data layout changes template -std::enable_if_t()> Write(Writer& writer, - const T& value) { - boost::pfr::for_each_field( - value, [&writer](const auto& field) { writer.Write(field); }); +std::enable_if_t()> Write(Writer& writer, const T& value) { + boost::pfr::for_each_field(value, [&writer](const auto& field) { writer.Write(field); }); } /// @brief Aggregates deserialization from dump support @@ -85,10 +83,9 @@ std::enable_if_t()> Write(Writer& writer, /// /// @warning Don't forget to increment format-version if data layout changes template -std::enable_if_t(), T> Read(Reader& reader, - To) { - constexpr auto kSize = boost::pfr::tuple_size_v; - return impl::ReadAggregate(reader, std::make_index_sequence{}); +std::enable_if_t(), T> Read(Reader& reader, To) { + constexpr auto kSize = boost::pfr::tuple_size_v; + return impl::ReadAggregate(reader, std::make_index_sequence{}); } } // namespace dump diff --git a/core/include/userver/dump/common.hpp b/core/include/userver/dump/common.hpp index b25555045086..2490e44948c4 100644 --- a/core/include/userver/dump/common.hpp +++ b/core/include/userver/dump/common.hpp @@ -43,22 +43,19 @@ namespace impl { /// @brief Helpers for serialization of trivially-copyable types template void WriteTrivial(Writer& writer, T value) { - static_assert(std::is_trivially_copyable_v); - // TODO: endianness - WriteStringViewUnsafe( - writer, - std::string_view{reinterpret_cast(&value), sizeof(value)}); + static_assert(std::is_trivially_copyable_v); + // TODO: endianness + WriteStringViewUnsafe(writer, std::string_view{reinterpret_cast(&value), sizeof(value)}); } /// @brief Helpers for deserialization trivially-copyable types template T ReadTrivial(Reader& reader) { - static_assert(std::is_trivially_copyable_v); - T value{}; - // TODO: endianness - ReadStringViewUnsafe(reader, sizeof(T)) - .copy(reinterpret_cast(&value), sizeof(T)); - return value; + static_assert(std::is_trivially_copyable_v); + T value{}; + // TODO: endianness + ReadStringViewUnsafe(reader, sizeof(T)).copy(reinterpret_cast(&value), sizeof(T)); + return value; } void WriteInteger(Writer& writer, std::uint64_t value); @@ -67,10 +64,8 @@ std::uint64_t ReadInteger(Reader& reader); template inline constexpr bool kIsDumpedAsNanoseconds = - std::is_integral_v && - (Duration::period::num == 1) && - (Duration{1} <= std::chrono::milliseconds{1}) && - (1'000'000'000 % Duration::period::den == 0); + std::is_integral_v && (Duration::period::num == 1) && + (Duration{1} <= std::chrono::milliseconds{1}) && (1'000'000'000 % Duration::period::den == 0); } // namespace impl @@ -90,39 +85,39 @@ void Write(Writer& writer, const char* value); /// @brief Integral types serialization support template std::enable_if_t> Write(Writer& writer, T value) { - if constexpr (sizeof(T) == 1) { - impl::WriteTrivial(writer, value); - } else { - impl::WriteInteger(writer, static_cast(value)); - } + if constexpr (sizeof(T) == 1) { + impl::WriteTrivial(writer, value); + } else { + impl::WriteInteger(writer, static_cast(value)); + } } /// @brief Integral types deserialization support template std::enable_if_t, T> Read(Reader& reader, To) { - if constexpr (sizeof(T) == 1) { - return impl::ReadTrivial(reader); - } + if constexpr (sizeof(T) == 1) { + return impl::ReadTrivial(reader); + } - const auto raw = impl::ReadInteger(reader); + const auto raw = impl::ReadInteger(reader); - if constexpr (std::is_signed_v) { - return utils::numeric_cast(static_cast(raw)); - } else { - return utils::numeric_cast(raw); - } + if constexpr (std::is_signed_v) { + return utils::numeric_cast(static_cast(raw)); + } else { + return utils::numeric_cast(raw); + } } /// @brief Floating-point serialization support template std::enable_if_t> Write(Writer& writer, T value) { - impl::WriteTrivial(writer, value); + impl::WriteTrivial(writer, value); } /// @brief Floating-point deserialization support template std::enable_if_t, T> Read(Reader& reader, To) { - return impl::ReadTrivial(reader); + return impl::ReadTrivial(reader); } /// @brief bool serialization support @@ -134,70 +129,66 @@ bool Read(Reader& reader, To); /// @brief enum serialization support template std::enable_if_t> Write(Writer& writer, T value) { - writer.Write(static_cast>(value)); + writer.Write(static_cast>(value)); } /// @brief enum deserialization support template std::enable_if_t, T> Read(Reader& reader, To) { - return static_cast(reader.Read>()); + return static_cast(reader.Read>()); } /// @brief `std::chrono::duration` serialization support template void Write(Writer& writer, std::chrono::duration value) { - using std::chrono::duration, std::chrono::nanoseconds; - - // Durations, which on some systems represent - // `std::chrono::*_clock::duration`, are serialized as `std::nanoseconds` - // to avoid system dependency - if constexpr (impl::kIsDumpedAsNanoseconds>) { - const auto count = std::chrono::duration_cast(value).count(); - - if (nanoseconds{count} != value) { - throw std::logic_error( - "Trying to serialize a huge duration, it does not fit into " - "std::chrono::nanoseconds type"); + using std::chrono::duration, std::chrono::nanoseconds; + + // Durations, which on some systems represent + // `std::chrono::*_clock::duration`, are serialized as `std::nanoseconds` + // to avoid system dependency + if constexpr (impl::kIsDumpedAsNanoseconds>) { + const auto count = std::chrono::duration_cast(value).count(); + + if (nanoseconds{count} != value) { + throw std::logic_error( + "Trying to serialize a huge duration, it does not fit into " + "std::chrono::nanoseconds type" + ); + } + impl::WriteTrivial(writer, count); + } else { + impl::WriteTrivial(writer, value.count()); } - impl::WriteTrivial(writer, count); - } else { - impl::WriteTrivial(writer, value.count()); - } } /// @brief `std::chrono::duration` deserialization support template -std::chrono::duration Read( - Reader& reader, To>) { - using std::chrono::duration, std::chrono::nanoseconds; - - if constexpr (impl::kIsDumpedAsNanoseconds>) { - const auto count = impl::ReadTrivial(reader); - return std::chrono::duration_cast>( - nanoseconds{count}); - } else { - const auto count = impl::ReadTrivial(reader); - return duration{count}; - } +std::chrono::duration Read(Reader& reader, To>) { + using std::chrono::duration, std::chrono::nanoseconds; + + if constexpr (impl::kIsDumpedAsNanoseconds>) { + const auto count = impl::ReadTrivial(reader); + return std::chrono::duration_cast>(nanoseconds{count}); + } else { + const auto count = impl::ReadTrivial(reader); + return duration{count}; + } } /// @brief `std::chrono::time_point` serialization support /// @note Only `system_clock` is supported, because `steady_clock` can only /// be used within a single execution template -void Write(Writer& writer, - std::chrono::time_point value) { - writer.Write(value.time_since_epoch()); +void Write(Writer& writer, std::chrono::time_point value) { + writer.Write(value.time_since_epoch()); } /// @brief `std::chrono::time_point` deserialization support /// @note Only `system_clock` is supported, because `steady_clock` can only /// be used within a single execution template -auto Read(Reader& reader, - To>) { - return std::chrono::time_point{ - reader.Read()}; +auto Read(Reader& reader, To>) { + return std::chrono::time_point{reader.Read()}; } /// @brief `boost::uuids::uuid` serialization support @@ -208,16 +199,14 @@ boost::uuids::uuid Read(Reader& reader, To); /// @brief decimal64::Decimal serialization support template -inline void Write(Writer& writer, - const decimal64::Decimal& dec) { - writer.Write(dec.AsUnbiased()); +inline void Write(Writer& writer, const decimal64::Decimal& dec) { + writer.Write(dec.AsUnbiased()); } /// @brief decimal64::Decimal deserialization support template auto Read(Reader& reader, dump::To>) { - return decimal64::Decimal::FromUnbiased( - reader.Read()); + return decimal64::Decimal::FromUnbiased(reader.Read()); } /// @brief formats::json::Value serialization support diff --git a/core/include/userver/dump/common_containers.hpp b/core/include/userver/dump/common_containers.hpp index 29476db7c56d..099b97df4bea 100644 --- a/core/include/userver/dump/common_containers.hpp +++ b/core/include/userver/dump/common_containers.hpp @@ -74,234 +74,216 @@ using BoostBimapRightKey = typename BoostBimap::right_key_type; template auto ReadLazyPrvalue(Reader& reader) { - return utils::LazyPrvalue([&reader] { return reader.Read(); }); + return utils::LazyPrvalue([&reader] { return reader.Read(); }); } -[[noreturn]] void ThrowInvalidVariantIndex(const std::type_info& type, - std::size_t index); +[[noreturn]] void ThrowInvalidVariantIndex(const std::type_info& type, std::size_t index); template VariantType ReadVariant(Reader& reader, std::size_t index) { - static constexpr auto VariantSize = std::variant_size_v; - std::optional result; - - utils::WithConstexprIndex(index, [&](auto index_constant) { - static constexpr auto kIndex = decltype(index_constant)::value; - using Alternative = std::variant_alternative_t; - // Not using ReadLazyPrvalue because of stdlib issues on some compilers. - result.emplace(std::in_place_index, reader.Read()); - }); + static constexpr auto VariantSize = std::variant_size_v; + std::optional result; + + utils::WithConstexprIndex(index, [&](auto index_constant) { + static constexpr auto kIndex = decltype(index_constant)::value; + using Alternative = std::variant_alternative_t; + // Not using ReadLazyPrvalue because of stdlib issues on some compilers. + result.emplace(std::in_place_index, reader.Read()); + }); - return std::move(*result); + return std::move(*result); } } // namespace impl /// @brief Container serialization support template -std::enable_if_t && kIsWritable>> Write( - Writer& writer, const T& value) { - writer.Write(std::size(value)); - for (const auto& item : value) { - // explicit cast for vector shenanigans - writer.Write(static_cast&>(item)); - } +std::enable_if_t && kIsWritable>> Write(Writer& writer, const T& value) { + writer.Write(std::size(value)); + for (const auto& item : value) { + // explicit cast for vector shenanigans + writer.Write(static_cast&>(item)); + } } /// @brief Container deserialization support template -std::enable_if_t && kIsReadable>, T> -Read(Reader& reader, To) { - const auto size = reader.Read(); - T result{}; - if constexpr (meta::kIsReservable) { - result.reserve(size); - } - for (std::size_t i = 0; i < size; ++i) { - dump::Insert(result, reader.Read>()); - } - return result; +std::enable_if_t && kIsReadable>, T> Read(Reader& reader, To) { + const auto size = reader.Read(); + T result{}; + if constexpr (meta::kIsReservable) { + result.reserve(size); + } + for (std::size_t i = 0; i < size; ++i) { + dump::Insert(result, reader.Read>()); + } + return result; } /// @brief Pair serialization support (for maps) template -std::enable_if_t && kIsWritable, void> Write( - Writer& writer, const std::pair& value) { - writer.Write(value.first); - writer.Write(value.second); +std::enable_if_t && kIsWritable, void> Write(Writer& writer, const std::pair& value) { + writer.Write(value.first); + writer.Write(value.second); } /// @brief Pair deserialization support (for maps) template -std::enable_if_t && kIsReadable, std::pair> Read( - Reader& reader, To>) { - return {reader.Read(), reader.Read()}; +std::enable_if_t && kIsReadable, std::pair> Read(Reader& reader, To>) { + return {reader.Read(), reader.Read()}; } /// @brief `std::optional` serialization support template -std::enable_if_t> Write(Writer& writer, - const std::optional& value) { - writer.Write(value.has_value()); - if (value) writer.Write(*value); +std::enable_if_t> Write(Writer& writer, const std::optional& value) { + writer.Write(value.has_value()); + if (value) writer.Write(*value); } /// @brief `std::optional` deserialization support template -std::enable_if_t, std::optional> Read(Reader& reader, - To>) { - if (!reader.Read()) return std::nullopt; - return impl::ReadLazyPrvalue(reader); +std::enable_if_t, std::optional> Read(Reader& reader, To>) { + if (!reader.Read()) return std::nullopt; + return impl::ReadLazyPrvalue(reader); } /// @brief `std::variant` serialization support template -std::enable_if_t<(true && ... && kIsWritable)> Write( - Writer& writer, const std::variant& value) { - writer.Write(value.index()); - std::visit([&writer](const auto& inner) { writer.Write(inner); }, value); +std::enable_if_t<(true && ... && kIsWritable)> Write(Writer& writer, const std::variant& value) { + writer.Write(value.index()); + std::visit([&writer](const auto& inner) { writer.Write(inner); }, value); } /// @brief `std::variant` deserialization support template -std::enable_if_t<(true && ... && - (std::is_move_constructible_v && kIsReadable)), - std::variant> +std::enable_if_t<(true && ... && (std::is_move_constructible_v && kIsReadable)), std::variant> Read(Reader& reader, To>) { - const auto index = reader.Read(); - if (index >= sizeof...(Args)) { - impl::ThrowInvalidVariantIndex(typeid(std::variant), index); - } - return impl::ReadVariant>(reader, index); + const auto index = reader.Read(); + if (index >= sizeof...(Args)) { + impl::ThrowInvalidVariantIndex(typeid(std::variant), index); + } + return impl::ReadVariant>(reader, index); } /// Allows reading `const T`, which is usually encountered as a member of some /// container template std::enable_if_t, T> Read(Reader& reader, To) { - return Read(reader, To{}); + return Read(reader, To{}); } /// @brief utils::StrongTypedef serialization support template -std::enable_if_t> Write( - Writer& writer, const utils::StrongTypedef& object) { - writer.Write(object.GetUnderlying()); +std::enable_if_t> Write(Writer& writer, const utils::StrongTypedef& object) { + writer.Write(object.GetUnderlying()); } /// @brief utils::StrongTypedef deserialization support template -std::enable_if_t, utils::StrongTypedef> Read( - Reader& reader, To>) { - return utils::StrongTypedef{reader.Read()}; +std::enable_if_t, utils::StrongTypedef> +Read(Reader& reader, To>) { + return utils::StrongTypedef{reader.Read()}; } /// @brief `std::unique_ptr` serialization support template -std::enable_if_t> Write(Writer& writer, - const std::unique_ptr& ptr) { - writer.Write(static_cast(ptr)); - if (ptr) writer.Write(*ptr); +std::enable_if_t> Write(Writer& writer, const std::unique_ptr& ptr) { + writer.Write(static_cast(ptr)); + if (ptr) writer.Write(*ptr); } /// @brief `std::unique_ptr` deserialization support template -std::enable_if_t, std::unique_ptr> Read( - Reader& reader, To>) { - if (!reader.Read()) return {}; - return std::make_unique(impl::ReadLazyPrvalue(reader)); +std::enable_if_t, std::unique_ptr> Read(Reader& reader, To>) { + if (!reader.Read()) return {}; + return std::make_unique(impl::ReadLazyPrvalue(reader)); } /// @brief `std::shared_ptr` serialization support /// @warning If two or more `shared_ptr` within a single dumped entity point to /// the same object, they will point to its distinct copies after loading a dump template -std::enable_if_t> Write(Writer& writer, - const std::shared_ptr& ptr) { - writer.Write(static_cast(ptr)); - if (ptr) writer.Write(*ptr); +std::enable_if_t> Write(Writer& writer, const std::shared_ptr& ptr) { + writer.Write(static_cast(ptr)); + if (ptr) writer.Write(*ptr); } /// @brief `std::shared_ptr` deserialization support /// @warning If two or more `shared_ptr` within a single dumped entity point to /// the same object, they will point to its distinct copies after loading a dump template -std::enable_if_t, std::shared_ptr> Read( - Reader& reader, To>) { - if (!reader.Read()) return {}; - return std::make_shared(impl::ReadLazyPrvalue(reader)); +std::enable_if_t, std::shared_ptr> Read(Reader& reader, To>) { + if (!reader.Read()) return {}; + return std::make_shared(impl::ReadLazyPrvalue(reader)); } /// @brief `boost::bimap` serialization support template -std::enable_if_t> && - kIsWritable>> +std::enable_if_t< + kIsWritable> && kIsWritable>> Write(Writer& writer, const boost::bimap& map) { - writer.Write(map.size()); + writer.Write(map.size()); - for (const auto& [left, right] : map) { - writer.Write(left); - writer.Write(right); - } + for (const auto& [left, right] : map) { + writer.Write(left); + writer.Write(right); + } } /// @brief `boost::bimap` deserialization support template -std::enable_if_t> && - kIsReadable>, - boost::bimap> +std::enable_if_t< + kIsReadable> && kIsReadable>, + boost::bimap> Read(Reader& reader, To>) { - using BoostBimap = impl::BoostBimap; + using BoostBimap = impl::BoostBimap; - using BoostBimapLeftKey = impl::BoostBimapLeftKey; - using BoostBimapRightKey = impl::BoostBimapRightKey; + using BoostBimapLeftKey = impl::BoostBimapLeftKey; + using BoostBimapRightKey = impl::BoostBimapRightKey; - using BoostBimapSizeType = typename BoostBimap::size_type; + using BoostBimapSizeType = typename BoostBimap::size_type; - BoostBimap map; - // bimap doesn't have reserve :( + BoostBimap map; + // bimap doesn't have reserve :( - const auto size = reader.Read(); - for (BoostBimapSizeType i = 0; i < size; ++i) { - // `Read`s are guaranteed to occur left-to-right in brace-init - map.insert({ - reader.Read(), - reader.Read(), - }); - } + const auto size = reader.Read(); + for (BoostBimapSizeType i = 0; i < size; ++i) { + // `Read`s are guaranteed to occur left-to-right in brace-init + map.insert({ + reader.Read(), + reader.Read(), + }); + } - return map; + return map; } /// @brief `boost::multi_index_container` serialization support template -std::enable_if_t> Write( - Writer& writer, - const boost::multi_index_container& container) { - writer.Write(container.template get<0>().size()); - for (auto& item : container.template get<0>()) { - writer.Write(item); - } +std::enable_if_t> Write(Writer& writer, const boost::multi_index_container& container) { + writer.Write(container.template get<0>().size()); + for (auto& item : container.template get<0>()) { + writer.Write(item); + } } /// @brief `boost::multi_index_container` deserialization support template std::enable_if_t, boost::multi_index_container> Read(Reader& reader, To>) { - const auto size = reader.Read(); - boost::multi_index_container container; + const auto size = reader.Read(); + boost::multi_index_container container; - // boost::multi_index_container has reserve() with some, but not all, configs - if constexpr (meta::kIsReservable< - boost::multi_index_container>) { - container.reserve(size); - } + // boost::multi_index_container has reserve() with some, but not all, configs + if constexpr (meta::kIsReservable>) { + container.reserve(size); + } - for (std::size_t i = 0; i < size; ++i) { - container.insert(reader.Read()); - } + for (std::size_t i = 0; i < size; ++i) { + container.insert(reader.Read()); + } - return container; + return container; } } // namespace dump diff --git a/core/include/userver/dump/config.hpp b/core/include/userver/dump/config.hpp index 07bae18eef92..f21fe9159f66 100644 --- a/core/include/userver/dump/config.hpp +++ b/core/include/userver/dump/config.hpp @@ -15,9 +15,8 @@ USERVER_NAMESPACE_BEGIN namespace dump { namespace impl { -std::chrono::milliseconds ParseMs( - const formats::json::Value& value, - std::optional default_value = {}); +std::chrono::milliseconds +ParseMs(const formats::json::Value& value, std::optional default_value = {}); } extern const std::string_view kDump; @@ -25,43 +24,40 @@ extern const std::string_view kMaxDumpAge; extern const std::string_view kMinDumpInterval; struct ConfigPatch final { - std::optional dumps_enabled; - std::optional min_dump_interval; + std::optional dumps_enabled; + std::optional min_dump_interval; }; -ConfigPatch Parse(const formats::json::Value& value, - formats::parse::To); +ConfigPatch Parse(const formats::json::Value& value, formats::parse::To); struct Config final { - Config(std::string name, const yaml_config::YamlConfig& config, - std::string_view dump_root); - - std::string name; - uint64_t dump_format_version; - bool world_readable; - std::string dump_directory; - std::string fs_task_processor; - uint64_t max_dump_count; - std::optional max_dump_age; - bool max_dump_age_set; - bool dump_is_encrypted; - - bool static_dumps_enabled; - std::chrono::milliseconds static_min_dump_interval; + Config(std::string name, const yaml_config::YamlConfig& config, std::string_view dump_root); + + std::string name; + uint64_t dump_format_version; + bool world_readable; + std::string dump_directory; + std::string fs_task_processor; + uint64_t max_dump_count; + std::optional max_dump_age; + bool max_dump_age_set; + bool dump_is_encrypted; + + bool static_dumps_enabled; + std::chrono::milliseconds static_min_dump_interval; }; struct DynamicConfig final { - explicit DynamicConfig(const Config& config, ConfigPatch&& patch); + explicit DynamicConfig(const Config& config, ConfigPatch&& patch); - bool operator==(const DynamicConfig& other) const noexcept; - bool operator!=(const DynamicConfig& other) const noexcept; + bool operator==(const DynamicConfig& other) const noexcept; + bool operator!=(const DynamicConfig& other) const noexcept; - bool dumps_enabled; - std::chrono::milliseconds min_dump_interval; + bool dumps_enabled; + std::chrono::milliseconds min_dump_interval; }; -extern const dynamic_config::Key> - kConfigSet; +extern const dynamic_config::Key> kConfigSet; } // namespace dump diff --git a/core/include/userver/dump/dumper.hpp b/core/include/userver/dump/dumper.hpp index 984fb3f68b3f..e427df573431 100644 --- a/core/include/userver/dump/dumper.hpp +++ b/core/include/userver/dump/dumper.hpp @@ -37,22 +37,22 @@ extern const std::string_view kDump; /// with ADL-found `Write`/`Read`, the methods are guaranteed not to be called /// in parallel. class DumpableEntity { - public: - virtual ~DumpableEntity(); +public: + virtual ~DumpableEntity(); - virtual void GetAndWrite(dump::Writer& writer) const = 0; + virtual void GetAndWrite(dump::Writer& writer) const = 0; - virtual void ReadAndSet(dump::Reader& reader) = 0; + virtual void ReadAndSet(dump::Reader& reader) = 0; }; enum class UpdateType { - /// Some new data has appeared since the last update. `Dumper` will write it - /// on the next `WriteDumpAsync` call, or as specified by the config. - kModified, + /// Some new data has appeared since the last update. `Dumper` will write it + /// on the next `WriteDumpAsync` call, or as specified by the config. + kModified, - /// There is no new data, but we have verified that the old data is - /// up-to-date. `Dumper` will bump the dump modification time to `now`. - kAlreadyUpToDate, + /// There is no new data, but we have verified that the old data is + /// up-to-date. `Dumper` will bump the dump modification time to `now`. + kAlreadyUpToDate, }; // clang-format off @@ -92,81 +92,86 @@ enum class UpdateType { /// @see components::DumpConfigurator // clang-format on class Dumper final { - public: - /// @brief The primary constructor for when `Dumper` is stored in a component - /// @note `dumpable` must outlive this `Dumper` - Dumper(const components::ComponentConfig& config, - const components::ComponentContext& context, DumpableEntity& dumpable); - - /// For internal use only - Dumper(const Config& initial_config, - std::unique_ptr rw_factory, - engine::TaskProcessor& fs_task_processor, - dynamic_config::Source config_source, - utils::statistics::Storage& statistics_storage, - testsuite::DumpControl& dump_control, DumpableEntity& dumpable); - - Dumper(Dumper&&) = delete; - Dumper& operator=(Dumper&&) = delete; - ~Dumper(); - - const std::string& Name() const; - - /// @brief Read data from a dump, if any - /// @note Catches and logs any exceptions related to read operation failure - /// @returns `update_time` of the loaded dump on success, `null` otherwise - std::optional ReadDump(); - - /// @brief Forces the `Dumper` to write a dump synchronously - /// @throws std::exception if the `Dumper` failed to write a dump - void WriteDumpSyncDebug(); - - /// @brief Forces the `Dumper` to read from a dump synchronously - /// @throws std::exception if the `Dumper` failed to read a dump - void ReadDumpDebug(); - - /// @brief Notifies the `Dumper` of an update in the `DumpableEntity` - /// - /// A dump will be written asynchronously as soon as: - /// - /// 1. data update has been reported via `OnUpdateCompleted` since the last - /// written dump, - /// 2. dumps are `enabled` in the dynamic config, and - /// 3. `min-interval` time has passed - /// - /// @note This overload is more performant. The time written on the dump will - /// be taken from the dump writing time. - void OnUpdateCompleted(); - - /// @overload void OnUpdateCompleted() - /// @param update_time The time at which the data has been guaranteed to be - /// up-to-date - /// @param update_type Whether the update modified the data or confirmed its - /// actuality, UpdateType::kModified by default - /// @note This overload locks mutexes and should not be used in tight loops. - /// On the other hand, it allows to exactly control the dump expiration. - void OnUpdateCompleted(TimePoint update_time, UpdateType update_type); - - /// @brief Cancel and wait for the task running background writes. Also - /// disables operations via testsuite dump control. - /// - /// CancelWriteTaskAndWait is automatically called in the destructor. This - /// method must be called explicitly if the `DumpableEntity` may start its - /// destruction before the `Dumper` is destroyed. - /// - /// After calling this method, OnUpdateCompleted calls have no effect. - void CancelWriteTaskAndWait(); - - /// @brief Returns the static config schema for a - /// components::ComponentBase with an added `dump` sub-section. - static yaml_config::Schema GetStaticConfigSchema(); - - private: - Dumper(const Config& initial_config, - const components::ComponentContext& context, DumpableEntity& dumpable); - - class Impl; - utils::FastPimpl impl_; +public: + /// @brief The primary constructor for when `Dumper` is stored in a component + /// @note `dumpable` must outlive this `Dumper` + Dumper( + const components::ComponentConfig& config, + const components::ComponentContext& context, + DumpableEntity& dumpable + ); + + /// For internal use only + Dumper( + const Config& initial_config, + std::unique_ptr rw_factory, + engine::TaskProcessor& fs_task_processor, + dynamic_config::Source config_source, + utils::statistics::Storage& statistics_storage, + testsuite::DumpControl& dump_control, + DumpableEntity& dumpable + ); + + Dumper(Dumper&&) = delete; + Dumper& operator=(Dumper&&) = delete; + ~Dumper(); + + const std::string& Name() const; + + /// @brief Read data from a dump, if any + /// @note Catches and logs any exceptions related to read operation failure + /// @returns `update_time` of the loaded dump on success, `null` otherwise + std::optional ReadDump(); + + /// @brief Forces the `Dumper` to write a dump synchronously + /// @throws std::exception if the `Dumper` failed to write a dump + void WriteDumpSyncDebug(); + + /// @brief Forces the `Dumper` to read from a dump synchronously + /// @throws std::exception if the `Dumper` failed to read a dump + void ReadDumpDebug(); + + /// @brief Notifies the `Dumper` of an update in the `DumpableEntity` + /// + /// A dump will be written asynchronously as soon as: + /// + /// 1. data update has been reported via `OnUpdateCompleted` since the last + /// written dump, + /// 2. dumps are `enabled` in the dynamic config, and + /// 3. `min-interval` time has passed + /// + /// @note This overload is more performant. The time written on the dump will + /// be taken from the dump writing time. + void OnUpdateCompleted(); + + /// @overload void OnUpdateCompleted() + /// @param update_time The time at which the data has been guaranteed to be + /// up-to-date + /// @param update_type Whether the update modified the data or confirmed its + /// actuality, UpdateType::kModified by default + /// @note This overload locks mutexes and should not be used in tight loops. + /// On the other hand, it allows to exactly control the dump expiration. + void OnUpdateCompleted(TimePoint update_time, UpdateType update_type); + + /// @brief Cancel and wait for the task running background writes. Also + /// disables operations via testsuite dump control. + /// + /// CancelWriteTaskAndWait is automatically called in the destructor. This + /// method must be called explicitly if the `DumpableEntity` may start its + /// destruction before the `Dumper` is destroyed. + /// + /// After calling this method, OnUpdateCompleted calls have no effect. + void CancelWriteTaskAndWait(); + + /// @brief Returns the static config schema for a + /// components::ComponentBase with an added `dump` sub-section. + static yaml_config::Schema GetStaticConfigSchema(); + +private: + Dumper(const Config& initial_config, const components::ComponentContext& context, DumpableEntity& dumpable); + + class Impl; + utils::FastPimpl impl_; }; } // namespace dump diff --git a/core/include/userver/dump/factory.hpp b/core/include/userver/dump/factory.hpp index 5c8f7ab4e579..c299a76606de 100644 --- a/core/include/userver/dump/factory.hpp +++ b/core/include/userver/dump/factory.hpp @@ -11,20 +11,18 @@ namespace dump { /// An abstract Reader/Writer factory class OperationsFactory { - public: - virtual ~OperationsFactory() = default; +public: + virtual ~OperationsFactory() = default; - virtual std::unique_ptr CreateReader(std::string full_path) = 0; + virtual std::unique_ptr CreateReader(std::string full_path) = 0; - virtual std::unique_ptr CreateWriter(std::string full_path, - tracing::ScopeTime& scope) = 0; + virtual std::unique_ptr CreateWriter(std::string full_path, tracing::ScopeTime& scope) = 0; }; -std::unique_ptr CreateOperationsFactory( - const Config& config, const components::ComponentContext& context); +std::unique_ptr +CreateOperationsFactory(const Config& config, const components::ComponentContext& context); -std::unique_ptr CreateDefaultOperationsFactory( - const Config& config); +std::unique_ptr CreateDefaultOperationsFactory(const Config& config); } // namespace dump diff --git a/core/include/userver/dump/helpers.hpp b/core/include/userver/dump/helpers.hpp index 4a0ec5052b9a..bcd26590b948 100644 --- a/core/include/userver/dump/helpers.hpp +++ b/core/include/userver/dump/helpers.hpp @@ -10,8 +10,7 @@ USERVER_NAMESPACE_BEGIN namespace dump { -using TimePoint = std::chrono::time_point; +using TimePoint = std::chrono::time_point; [[noreturn]] void ThrowDumpUnimplemented(const std::string& name); diff --git a/core/include/userver/dump/json_helpers.hpp b/core/include/userver/dump/json_helpers.hpp index a0a92fef2e43..9a5de86f238b 100644 --- a/core/include/userver/dump/json_helpers.hpp +++ b/core/include/userver/dump/json_helpers.hpp @@ -26,10 +26,10 @@ namespace dump { /// @see @ref scripts/docs/en/userver/cache_dumps.md template void WriteJson(Writer& writer, const T& contents) { - formats::json::StringBuilder sb; - WriteToStream(contents, sb); - WriteStringViewUnsafe(writer, sb.GetString()); - WriteStringViewUnsafe(writer, "\n"); + formats::json::StringBuilder sb; + WriteToStream(contents, sb); + WriteStringViewUnsafe(writer, sb.GetString()); + WriteStringViewUnsafe(writer, "\n"); } /// @brief Convenience function to use in @@ -39,8 +39,7 @@ void WriteJson(Writer& writer, const T& contents) { /// @see @ref scripts/docs/en/userver/cache_dumps.md template std::unique_ptr ReadJson(Reader& reader) { - return std::make_unique( - formats::json::FromString(ReadEntire(reader)).As()); + return std::make_unique(formats::json::FromString(ReadEntire(reader)).As()); } } // namespace dump diff --git a/core/include/userver/dump/meta.hpp b/core/include/userver/dump/meta.hpp index 85f6ba98b092..e4af0d178b8e 100644 --- a/core/include/userver/dump/meta.hpp +++ b/core/include/userver/dump/meta.hpp @@ -15,8 +15,7 @@ namespace dump { namespace impl { template -using WritableResult = - decltype(Write(std::declval(), std::declval())); +using WritableResult = decltype(Write(std::declval(), std::declval())); template using ReadableResult = decltype(Read(std::declval(), To{})); @@ -25,14 +24,11 @@ using ReadableResult = decltype(Read(std::declval(), To{})); /// Check if `writer.Write(T)` is available template -inline constexpr bool kIsWritable = - std::is_same_v, void>; +inline constexpr bool kIsWritable = std::is_same_v, void>; /// Check if `reader.Read()` is available template -inline constexpr bool kIsReadable = - std::is_same_v, - std::remove_const_t>; +inline constexpr bool kIsReadable = std::is_same_v, std::remove_const_t>; /// Check if `T` is both writable and readable template @@ -40,13 +36,14 @@ inline constexpr bool kIsDumpable = kIsWritable && kIsReadable; template constexpr bool CheckDumpable() { - static_assert( - kIsDumpable, - "Type is not dumpable. Probably you forgot to include " - ", or " - "other headers with Read and Write declarations"); - - return true; + static_assert( + kIsDumpable, + "Type is not dumpable. Probably you forgot to include " + ", or " + "other headers with Read and Write declarations" + ); + + return true; } } // namespace dump diff --git a/core/include/userver/dump/meta_containers.hpp b/core/include/userver/dump/meta_containers.hpp index f5ebabb2084a..0c4b64dc6231 100644 --- a/core/include/userver/dump/meta_containers.hpp +++ b/core/include/userver/dump/meta_containers.hpp @@ -19,44 +19,41 @@ namespace dump { /// Customization point: insert an element into a container template void Insert(std::vector& cont, T&& elem) { - cont.push_back(std::forward(elem)); + cont.push_back(std::forward(elem)); } template void Insert(std::map& cont, std::pair&& elem) { - cont.insert(std::move(elem)); + cont.insert(std::move(elem)); } template -void Insert(std::unordered_map& cont, - std::pair&& elem) { - cont.insert(std::move(elem)); +void Insert(std::unordered_map& cont, std::pair&& elem) { + cont.insert(std::move(elem)); } template void Insert(std::set& cont, T&& elem) { - cont.insert(std::forward(elem)); + cont.insert(std::forward(elem)); } template void Insert(std::unordered_set& cont, T&& elem) { - cont.insert(std::forward(elem)); + cont.insert(std::forward(elem)); } /// @} namespace impl { template -using InsertResult = decltype(dump::Insert( - std::declval(), std::declval&&>())); +using InsertResult = decltype(dump::Insert(std::declval(), std::declval&&>())); } // namespace impl /// Check if a range is a container template -inline constexpr bool kIsContainer = - meta::kIsRange && std::is_default_constructible_v && - meta::kIsSizable && meta::kIsDetected; +inline constexpr bool kIsContainer = meta::kIsRange && std::is_default_constructible_v && meta::kIsSizable && + meta::kIsDetected; } // namespace dump diff --git a/core/include/userver/dump/operations.hpp b/core/include/userver/dump/operations.hpp index c15b2a6fa01b..adb760f69abb 100644 --- a/core/include/userver/dump/operations.hpp +++ b/core/include/userver/dump/operations.hpp @@ -15,123 +15,127 @@ namespace dump { /// Indicates a failure reading or writing a dump. No further operations /// should be performed with a failed dump. class Error final : public std::runtime_error { - public: - explicit Error(std::string message) : std::runtime_error(message) {} +public: + explicit Error(std::string message) : std::runtime_error(message) {} }; /// A general interface for binary data output class Writer { - public: - virtual ~Writer() = default; - - /// @brief Writes binary data - /// @details Calls ADL-found `Write(writer, data)` - /// @throws `Error` and any user-thrown `std::exception` - template - void Write(const T& data); - - /// @brief Must be called once all data has been written - /// @warning This method must not be called from within `Write`/`Read` - /// @throws `Error` on write operation failure - virtual void Finish() = 0; - - protected: - /// @brief Writes binary data - /// @details Unlike `Write`, doesn't write the size of `data` - /// @throws `Error` on write operation failure - virtual void WriteRaw(std::string_view data) = 0; - - friend void WriteStringViewUnsafe(Writer& writer, std::string_view value); +public: + virtual ~Writer() = default; + + /// @brief Writes binary data + /// @details Calls ADL-found `Write(writer, data)` + /// @throws `Error` and any user-thrown `std::exception` + template + void Write(const T& data); + + /// @brief Must be called once all data has been written + /// @warning This method must not be called from within `Write`/`Read` + /// @throws `Error` on write operation failure + virtual void Finish() = 0; + +protected: + /// @brief Writes binary data + /// @details Unlike `Write`, doesn't write the size of `data` + /// @throws `Error` on write operation failure + virtual void WriteRaw(std::string_view data) = 0; + + friend void WriteStringViewUnsafe(Writer& writer, std::string_view value); }; /// A general interface for binary data input class Reader { - public: - virtual ~Reader() = default; - - /// @brief Reads binary data - /// @details Calls ADL-found `Read(reader, To)` - /// @throws `Error` and any user-thrown `std::exception` - template - T Read(); - - /// @brief Must be called once all data has been read - /// @warning This method must not be called from within `Write`/`Read` - /// @throws `Error` on read operation failure or if there is leftover data - virtual void Finish() = 0; - - protected: - /// @brief Reads binary data - /// @note Invalidates the memory returned by the previous call of `ReadRaw` - /// @note Normally, exactly `max_size` bytes is returned. On end-of-file, - /// the amount of bytes returned can be less than `max_size`. - /// @throws `Error` on read operation failure - virtual std::string_view ReadRaw(std::size_t max_size) = 0; - - friend std::string_view ReadUnsafeAtMost(Reader& reader, std::size_t size); +public: + virtual ~Reader() = default; + + /// @brief Reads binary data + /// @details Calls ADL-found `Read(reader, To)` + /// @throws `Error` and any user-thrown `std::exception` + template + T Read(); + + /// @brief Must be called once all data has been read + /// @warning This method must not be called from within `Write`/`Read` + /// @throws `Error` on read operation failure or if there is leftover data + virtual void Finish() = 0; + +protected: + /// @brief Reads binary data + /// @note Invalidates the memory returned by the previous call of `ReadRaw` + /// @note Normally, exactly `max_size` bytes is returned. On end-of-file, + /// the amount of bytes returned can be less than `max_size`. + /// @throws `Error` on read operation failure + virtual std::string_view ReadRaw(std::size_t max_size) = 0; + + friend std::string_view ReadUnsafeAtMost(Reader& reader, std::size_t size); }; namespace impl { template void CallWrite(Writer& writer, const T& data) { - Write(writer, data); + Write(writer, data); } template // NOLINTNEXTLINE(readability-const-return-type) T CallRead(Reader& reader, To to) { - return Read(reader, to); + return Read(reader, to); } } // namespace impl template void Writer::Write(const T& data) { - if constexpr (kIsWritable) { - impl::CallWrite(*this, data); - } else if constexpr (std::is_aggregate_v) { - static_assert( - !sizeof(T), - "Serialization is not implemented for this type. You " - "either forgot to specialize IsDumpedAggregate for your type " - "(see )" - "or you've got a non-standard data type and need to implement " - "`void Write(dump::Writer& writer, const T& data);` and put it " - "in the namespace of `T` or in `dump`."); - } else { - static_assert( - !sizeof(T), - "You either forgot to `#include `, " - "or you've got a non-standard data type and need to implement " - "`void Write(dump::Writer& writer, const T& data);` and put it " - "in the namespace of `T` or in `dump`."); - } + if constexpr (kIsWritable) { + impl::CallWrite(*this, data); + } else if constexpr (std::is_aggregate_v) { + static_assert( + !sizeof(T), + "Serialization is not implemented for this type. You " + "either forgot to specialize IsDumpedAggregate for your type " + "(see )" + "or you've got a non-standard data type and need to implement " + "`void Write(dump::Writer& writer, const T& data);` and put it " + "in the namespace of `T` or in `dump`." + ); + } else { + static_assert( + !sizeof(T), + "You either forgot to `#include `, " + "or you've got a non-standard data type and need to implement " + "`void Write(dump::Writer& writer, const T& data);` and put it " + "in the namespace of `T` or in `dump`." + ); + } } template // NOLINTNEXTLINE(readability-const-return-type) T Reader::Read() { - if constexpr (kIsReadable) { - return impl::CallRead(*this, To{}); - } else if constexpr (std::is_aggregate_v) { - static_assert( - !sizeof(T), - "Serialization is not implemented for this type. You " - "either forgot to specialize IsDumpedAggregate for your type" - "(see ) " - "or you've got a non-standard data type and need to implement " - "`T Read(dump::Reader& reader, dump::To);` and put it " - "in the namespace of `T` or in `dump`."); - } else { - static_assert( - !sizeof(T), - "You either forgot to `#include `, " - "or you've got a non-standard data type and need to implement" - "`T Read(dump::Reader& reader, dump::To);` and put it " - "in the namespace of `T` or in `dump`."); - return T{}; - } + if constexpr (kIsReadable) { + return impl::CallRead(*this, To{}); + } else if constexpr (std::is_aggregate_v) { + static_assert( + !sizeof(T), + "Serialization is not implemented for this type. You " + "either forgot to specialize IsDumpedAggregate for your type" + "(see ) " + "or you've got a non-standard data type and need to implement " + "`T Read(dump::Reader& reader, dump::To);` and put it " + "in the namespace of `T` or in `dump`." + ); + } else { + static_assert( + !sizeof(T), + "You either forgot to `#include `, " + "or you've got a non-standard data type and need to implement" + "`T Read(dump::Reader& reader, dump::To);` and put it " + "in the namespace of `T` or in `dump`." + ); + return T{}; + } } } // namespace dump diff --git a/core/include/userver/dump/operations_encrypted.hpp b/core/include/userver/dump/operations_encrypted.hpp index 02c4fa58bcb7..e88beb72e573 100644 --- a/core/include/userver/dump/operations_encrypted.hpp +++ b/core/include/userver/dump/operations_encrypted.hpp @@ -14,53 +14,55 @@ namespace dump { using SecretKey = utils::NonLoggable; class EncryptedWriter final : public Writer { - public: - /// @brief Creates a new dump file and opens it - /// @throws `Error` on a filesystem error - EncryptedWriter(std::string filename, const SecretKey& secret_key, - boost::filesystem::perms, tracing::ScopeTime& scope); +public: + /// @brief Creates a new dump file and opens it + /// @throws `Error` on a filesystem error + EncryptedWriter( + std::string filename, + const SecretKey& secret_key, + boost::filesystem::perms, + tracing::ScopeTime& scope + ); - ~EncryptedWriter() override; + ~EncryptedWriter() override; - void Finish() override; + void Finish() override; - private: - void WriteRaw(std::string_view data) override; +private: + void WriteRaw(std::string_view data) override; - struct Impl; - utils::FastPimpl impl_; + struct Impl; + utils::FastPimpl impl_; }; class EncryptedReader final : public Reader { - public: - /// @brief Opens an existing dump file - /// @throws `Error` on a filesystem error - EncryptedReader(std::string filename, const SecretKey& key); +public: + /// @brief Opens an existing dump file + /// @throws `Error` on a filesystem error + EncryptedReader(std::string filename, const SecretKey& key); - ~EncryptedReader() override; + ~EncryptedReader() override; - void Finish() override; + void Finish() override; - private: - std::string_view ReadRaw(std::size_t max_size) override; +private: + std::string_view ReadRaw(std::size_t max_size) override; - struct Impl; - utils::FastPimpl impl_; + struct Impl; + utils::FastPimpl impl_; }; class EncryptedOperationsFactory final : public OperationsFactory { - public: - EncryptedOperationsFactory(SecretKey&& secret_key, - boost::filesystem::perms perms); +public: + EncryptedOperationsFactory(SecretKey&& secret_key, boost::filesystem::perms perms); - std::unique_ptr CreateReader(std::string full_path) override; + std::unique_ptr CreateReader(std::string full_path) override; - std::unique_ptr CreateWriter(std::string full_path, - tracing::ScopeTime& scope) override; + std::unique_ptr CreateWriter(std::string full_path, tracing::ScopeTime& scope) override; - private: - const SecretKey secret_key_; - const boost::filesystem::perms perms_; +private: + const SecretKey secret_key_; + const boost::filesystem::perms perms_; }; } // namespace dump diff --git a/core/include/userver/dump/operations_file.hpp b/core/include/userver/dump/operations_file.hpp index b7af03e5d728..bf8c4dca0e2e 100644 --- a/core/include/userver/dump/operations_file.hpp +++ b/core/include/userver/dump/operations_file.hpp @@ -17,52 +17,50 @@ namespace dump { /// A handle to a dump file. File operations block the thread. class FileWriter final : public Writer { - public: - /// @brief Creates a new dump file and opens it - /// @throws `Error` on a filesystem error - explicit FileWriter(std::string path, boost::filesystem::perms perms, - tracing::ScopeTime& scope); - - void Finish() override; - - private: - void WriteRaw(std::string_view data) override; - - fs::blocking::CFile file_; - std::string final_path_; - std::string path_; - boost::filesystem::perms perms_; - utils::StreamingCpuRelax cpu_relax_; +public: + /// @brief Creates a new dump file and opens it + /// @throws `Error` on a filesystem error + explicit FileWriter(std::string path, boost::filesystem::perms perms, tracing::ScopeTime& scope); + + void Finish() override; + +private: + void WriteRaw(std::string_view data) override; + + fs::blocking::CFile file_; + std::string final_path_; + std::string path_; + boost::filesystem::perms perms_; + utils::StreamingCpuRelax cpu_relax_; }; /// A handle to a dump file. File operations block the thread. class FileReader final : public Reader { - public: - /// @brief Opens an existing dump file - /// @throws `Error` on a filesystem error - explicit FileReader(std::string path); +public: + /// @brief Opens an existing dump file + /// @throws `Error` on a filesystem error + explicit FileReader(std::string path); - void Finish() override; + void Finish() override; - private: - std::string_view ReadRaw(std::size_t max_size) override; +private: + std::string_view ReadRaw(std::size_t max_size) override; - fs::blocking::CFile file_; - std::string path_; - std::string curr_chunk_; + fs::blocking::CFile file_; + std::string path_; + std::string curr_chunk_; }; class FileOperationsFactory final : public OperationsFactory { - public: - explicit FileOperationsFactory(boost::filesystem::perms perms); +public: + explicit FileOperationsFactory(boost::filesystem::perms perms); - std::unique_ptr CreateReader(std::string full_path) override; + std::unique_ptr CreateReader(std::string full_path) override; - std::unique_ptr CreateWriter(std::string full_path, - tracing::ScopeTime& scope) override; + std::unique_ptr CreateWriter(std::string full_path, tracing::ScopeTime& scope) override; - private: - const boost::filesystem::perms perms_; +private: + const boost::filesystem::perms perms_; }; } // namespace dump diff --git a/core/include/userver/dynamic_config/client/client.hpp b/core/include/userver/dynamic_config/client/client.hpp index 6143ff60da7f..f057bfc2a825 100644 --- a/core/include/userver/dynamic_config/client/client.hpp +++ b/core/include/userver/dynamic_config/client/client.hpp @@ -17,14 +17,14 @@ class Client; namespace dynamic_config { struct ClientConfig { - std::string service_name; - bool get_configs_overrides_for_service{true}; - std::chrono::milliseconds timeout{0}; - int retries{1}; - std::string config_url; - bool append_path_to_url{true}; - std::string stage_name; - bool fallback_to_no_proxy{true}; + std::string service_name; + bool get_configs_overrides_for_service{true}; + std::chrono::milliseconds timeout{0}; + int retries{1}; + std::string config_url; + bool append_path_to_url{true}; + std::string stage_name; + bool fallback_to_no_proxy{true}; }; /// @ingroup userver_clients @@ -35,43 +35,40 @@ struct ClientConfig { /// It is safe to concurrently invoke members of the same client because this /// client is a thin wrapper around clients::http::Client. class Client final { - public: - Client(clients::http::Client& http_client, const ClientConfig&); +public: + Client(clients::http::Client& http_client, const ClientConfig&); - ~Client(); + ~Client(); - using Timestamp = std::string; + using Timestamp = std::string; - struct Reply { - USERVER_NAMESPACE::dynamic_config::DocsMap docs_map; - std::vector removed; - Timestamp timestamp; + struct Reply { + USERVER_NAMESPACE::dynamic_config::DocsMap docs_map; + std::vector removed; + Timestamp timestamp; - bool IsEmpty() const { return docs_map.Size() == 0 && removed.empty(); } - }; + bool IsEmpty() const { return docs_map.Size() == 0 && removed.empty(); } + }; - struct JsonReply { - formats::json::Value configs; - Timestamp timestamp; - }; + struct JsonReply { + formats::json::Value configs; + Timestamp timestamp; + }; - Reply DownloadFullDocsMap(); + Reply DownloadFullDocsMap(); - Reply FetchDocsMap(const std::optional& last_update, - const std::vector& fields_to_load); + Reply FetchDocsMap(const std::optional& last_update, const std::vector& fields_to_load); - JsonReply FetchJson(const std::optional& last_update, - const std::vector& fields_to_load); + JsonReply FetchJson(const std::optional& last_update, const std::vector& fields_to_load); - private: - formats::json::Value FetchConfigs( - const std::optional& last_update, - const std::vector& fields_to_load); +private: + formats::json::Value + FetchConfigs(const std::optional& last_update, const std::vector& fields_to_load); - std::string FetchConfigsValues(std::string_view body); + std::string FetchConfigsValues(std::string_view body); - const ClientConfig config_; - clients::http::Client& http_client_; + const ClientConfig config_; + clients::http::Client& http_client_; }; } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/client/component.hpp b/core/include/userver/dynamic_config/client/component.hpp index cc2a12c53a71..2a6d06cdb854 100644 --- a/core/include/userver/dynamic_config/client/component.hpp +++ b/core/include/userver/dynamic_config/client/component.hpp @@ -40,20 +40,20 @@ namespace components { // clang-format on class DynamicConfigClient : public ComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::DynamicConfigClient - static constexpr std::string_view kName = "dynamic-config-client"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::DynamicConfigClient + static constexpr std::string_view kName = "dynamic-config-client"; - DynamicConfigClient(const ComponentConfig&, const ComponentContext&); - ~DynamicConfigClient() override = default; + DynamicConfigClient(const ComponentConfig&, const ComponentContext&); + ~DynamicConfigClient() override = default; - [[nodiscard]] dynamic_config::Client& GetClient() const; + [[nodiscard]] dynamic_config::Client& GetClient() const; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - std::unique_ptr config_client_; +private: + std::unique_ptr config_client_; }; template <> diff --git a/core/include/userver/dynamic_config/exception.hpp b/core/include/userver/dynamic_config/exception.hpp index 9e9aa82f12bb..6ae8419d6cc6 100644 --- a/core/include/userver/dynamic_config/exception.hpp +++ b/core/include/userver/dynamic_config/exception.hpp @@ -7,13 +7,13 @@ USERVER_NAMESPACE_BEGIN namespace dynamic_config { class Error : public std::runtime_error { - public: - using std::runtime_error::runtime_error; +public: + using std::runtime_error::runtime_error; }; class ConfigParseError : public Error { - public: - using Error::Error; +public: + using Error::Error; }; } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/impl/snapshot.hpp b/core/include/userver/dynamic_config/impl/snapshot.hpp index 9fffeb6a1e93..32ae56efe648 100644 --- a/core/include/userver/dynamic_config/impl/snapshot.hpp +++ b/core/include/userver/dynamic_config/impl/snapshot.hpp @@ -25,11 +25,10 @@ formats::json::Value DocsMapGet(const DocsMap&, std::string_view key); using ConfigId = std::size_t; -ConfigId Register(std::string&& name, Factory factory, - std::string&& default_docs_map_string); +ConfigId Register(std::string&& name, Factory factory, std::string&& default_docs_map_string); struct InternalTag final { - explicit InternalTag() = default; + explicit InternalTag() = default; }; std::any MakeConfig(ConfigId id, const DocsMap&); @@ -39,41 +38,40 @@ std::string_view GetName(ConfigId id); DocsMap MakeDefaultDocsMap(); struct ConfigIdGetter final { - template - static ConfigId Get(const Key& key) noexcept { - return key.id_; - } + template + static ConfigId Get(const Key& key) noexcept { + return key.id_; + } }; class SnapshotData final { - public: - SnapshotData() = default; +public: + SnapshotData() = default; - explicit SnapshotData(const std::vector& config_variables); + explicit SnapshotData(const std::vector& config_variables); - SnapshotData(const DocsMap& defaults, const std::vector& overrides); + SnapshotData(const DocsMap& defaults, const std::vector& overrides); - SnapshotData(const SnapshotData& defaults, - const std::vector& overrides); + SnapshotData(const SnapshotData& defaults, const std::vector& overrides); - SnapshotData(SnapshotData&&) noexcept = default; - SnapshotData& operator=(SnapshotData&&) noexcept = default; + SnapshotData(SnapshotData&&) noexcept = default; + SnapshotData& operator=(SnapshotData&&) noexcept = default; - template - const T& Get(ConfigId id) const { - try { - return std::any_cast(DoGet(id)); - } catch (const std::exception& ex) { - impl::WrapGetError(ex, typeid(T)); + template + const T& Get(ConfigId id) const { + try { + return std::any_cast(DoGet(id)); + } catch (const std::exception& ex) { + impl::WrapGetError(ex, typeid(T)); + } } - } - bool IsEmpty() const noexcept; + bool IsEmpty() const noexcept; - private: - const std::any& DoGet(ConfigId id) const; +private: + const std::any& DoGet(ConfigId id) const; - std::vector user_configs_; + std::vector user_configs_; }; class StorageData; diff --git a/core/include/userver/dynamic_config/impl/to_json.hpp b/core/include/userver/dynamic_config/impl/to_json.hpp index 1117a42da9f7..e80dfbba31fd 100644 --- a/core/include/userver/dynamic_config/impl/to_json.hpp +++ b/core/include/userver/dynamic_config/impl/to_json.hpp @@ -22,7 +22,7 @@ std::string DoToJsonString(std::string_view value); template struct IdWrapper { - using type = T; + using type = T; }; template @@ -32,30 +32,28 @@ using Id = typename IdWrapper::type; // into frequently-used headers. template std::string ToJsonString(const T& value) { - if constexpr (std::is_same_v) { - return impl::DoToJsonString(static_cast>(value)); - } else if constexpr (std::is_floating_point_v) { - return impl::DoToJsonString(static_cast>(value)); - } else if constexpr (std::is_unsigned_v) { - return impl::DoToJsonString(static_cast>(value)); - } else if constexpr (std::is_integral_v) { - return impl::DoToJsonString(static_cast>(value)); - } else if constexpr (std::is_convertible_v) { - return impl::DoToJsonString(static_cast>(value)); - } else { - return ToString(Serialize(value, formats::serialize::To{})); - } + if constexpr (std::is_same_v) { + return impl::DoToJsonString(static_cast>(value)); + } else if constexpr (std::is_floating_point_v) { + return impl::DoToJsonString(static_cast>(value)); + } else if constexpr (std::is_unsigned_v) { + return impl::DoToJsonString(static_cast>(value)); + } else if constexpr (std::is_integral_v) { + return impl::DoToJsonString(static_cast>(value)); + } else if constexpr (std::is_convertible_v) { + return impl::DoToJsonString(static_cast>(value)); + } else { + return ToString(Serialize(value, formats::serialize::To{})); + } } -std::string SingleToDocsMapString(std::string_view name, - std::string_view value); +std::string SingleToDocsMapString(std::string_view name, std::string_view value); -std::string MultipleToDocsMapString(const ConfigDefault* data, - std::size_t size); +std::string MultipleToDocsMapString(const ConfigDefault* data, std::size_t size); template std::string ValueToDocsMapString(std::string_view name, const T& value) { - return impl::SingleToDocsMapString(name, impl::ToJsonString(value)); + return impl::SingleToDocsMapString(name, impl::ToJsonString(value)); } } // namespace dynamic_config::impl diff --git a/core/include/userver/dynamic_config/snapshot.hpp b/core/include/userver/dynamic_config/snapshot.hpp index f32b65fb3ca3..fe8928b1a202 100644 --- a/core/include/userver/dynamic_config/snapshot.hpp +++ b/core/include/userver/dynamic_config/snapshot.hpp @@ -18,97 +18,96 @@ namespace dynamic_config { /// A strong typedef for usage in dynamic_config::Key constructors. struct DefaultAsJsonString final { - constexpr explicit DefaultAsJsonString(std::string_view json_string); + constexpr explicit DefaultAsJsonString(std::string_view json_string); - std::string_view json_string; + std::string_view json_string; }; /// A config name-value pair for usage in dynamic_config::Key constructors. struct ConfigDefault final { - template - ConfigDefault(std::string_view name, const T& value); + template + ConfigDefault(std::string_view name, const T& value); - ConfigDefault(std::string_view name, DefaultAsJsonString default_json); + ConfigDefault(std::string_view name, DefaultAsJsonString default_json); - std::string_view name; - std::string default_json; + std::string_view name; + std::string default_json; }; /// A tag type for usage in dynamic_config::Key constructors. struct ConstantConfig final { - constexpr explicit ConstantConfig() = default; + constexpr explicit ConstantConfig() = default; }; /// @brief A config key is a unique identifier for a config variable /// @snippet core/src/components/logging_configurator.cpp key template class Key final { - public: - /// The type of the parsed config variable. - using VariableType = Variable; - - using JsonParser = Variable (*)(const formats::json::Value&); - using DocsMapParser = Variable (*)(const DocsMap&); - - /// @brief The constructor for a trivial `VariableType`, e.g. `bool`, integer, - /// `double`, `string`. The default is passed by value. - /// - /// Usage example: - /// @snippet server/handlers/http_server_settings.cpp bool config sample - Key(std::string_view name, const VariableType& default_value); - - /// @brief The constructor for a non-trivial `VariableType`. The default is - /// passed as a JSON string. - /// - /// Uses formats::json::Value `Parse` customization point function to parse - /// `VariableType`. - /// - /// Usage example: - /// @snippet components/logging_configurator.cpp key - Key(std::string_view name, DefaultAsJsonString default_json); - - /// @brief The constructor that provides a special parser from JSON. - /// @warning Prefer the constructors above whenever possible. - /// @details Can be used when generic `Parse` is not applicable. Sometimes - /// used to add validation, e.g. minimum, maximum, string pattern, etc. - Key(std::string_view name, JsonParser parser, - DefaultAsJsonString default_json); - - /// @brief The constructor that parses multiple JSON config items - /// into a single C++ object. - /// @warning Prefer to use a separate `Key` per JSON config item and use the - /// constructors above whenever possible. - /// - /// Usage example: - /// @snippet clients/http/component.cpp docs map config sample - template - Key(DocsMapParser parser, const ConfigDefault (&default_json_map)[N]); - - /// Creates a config that always has the same value. - Key(ConstantConfig, VariableType value); - - /// @cond - Key(impl::InternalTag, std::string_view name); - - Key(impl::InternalTag, DocsMapParser parser); - /// @endcond - - Key(const Key&) noexcept = delete; - Key& operator=(const Key&) noexcept = delete; - - /// @returns the name of the config variable, as passed at the construction. - std::string_view GetName() const noexcept; - - /// Parses the config. Useful only in some very niche scenarios. The config - /// value should be typically be retrieved from dynamic_config::Snapshot, - /// which is obtained from components::DynamicConfig in production or from - /// dynamic_config::StorageMock in unit tests. - VariableType Parse(const DocsMap& docs_map) const; - - private: - friend struct impl::ConfigIdGetter; - - const impl::ConfigId id_; +public: + /// The type of the parsed config variable. + using VariableType = Variable; + + using JsonParser = Variable (*)(const formats::json::Value&); + using DocsMapParser = Variable (*)(const DocsMap&); + + /// @brief The constructor for a trivial `VariableType`, e.g. `bool`, integer, + /// `double`, `string`. The default is passed by value. + /// + /// Usage example: + /// @snippet server/handlers/http_server_settings.cpp bool config sample + Key(std::string_view name, const VariableType& default_value); + + /// @brief The constructor for a non-trivial `VariableType`. The default is + /// passed as a JSON string. + /// + /// Uses formats::json::Value `Parse` customization point function to parse + /// `VariableType`. + /// + /// Usage example: + /// @snippet components/logging_configurator.cpp key + Key(std::string_view name, DefaultAsJsonString default_json); + + /// @brief The constructor that provides a special parser from JSON. + /// @warning Prefer the constructors above whenever possible. + /// @details Can be used when generic `Parse` is not applicable. Sometimes + /// used to add validation, e.g. minimum, maximum, string pattern, etc. + Key(std::string_view name, JsonParser parser, DefaultAsJsonString default_json); + + /// @brief The constructor that parses multiple JSON config items + /// into a single C++ object. + /// @warning Prefer to use a separate `Key` per JSON config item and use the + /// constructors above whenever possible. + /// + /// Usage example: + /// @snippet clients/http/component.cpp docs map config sample + template + Key(DocsMapParser parser, const ConfigDefault (&default_json_map)[N]); + + /// Creates a config that always has the same value. + Key(ConstantConfig, VariableType value); + + /// @cond + Key(impl::InternalTag, std::string_view name); + + Key(impl::InternalTag, DocsMapParser parser); + /// @endcond + + Key(const Key&) noexcept = delete; + Key& operator=(const Key&) noexcept = delete; + + /// @returns the name of the config variable, as passed at the construction. + std::string_view GetName() const noexcept; + + /// Parses the config. Useful only in some very niche scenarios. The config + /// value should be typically be retrieved from dynamic_config::Snapshot, + /// which is obtained from components::DynamicConfig in production or from + /// dynamic_config::StorageMock in unit tests. + VariableType Parse(const DocsMap& docs_map) const; + +private: + friend struct impl::ConfigIdGetter; + + const impl::ConfigId id_; }; // clang-format off @@ -130,50 +129,49 @@ class Key final { // clang-format on class Snapshot final { - public: - Snapshot(const Snapshot&); - Snapshot& operator=(const Snapshot&); +public: + Snapshot(const Snapshot&); + Snapshot& operator=(const Snapshot&); - Snapshot(Snapshot&&) noexcept; - Snapshot& operator=(Snapshot&&) noexcept; + Snapshot(Snapshot&&) noexcept; + Snapshot& operator=(Snapshot&&) noexcept; - ~Snapshot(); + ~Snapshot(); - /// Used to access individual configs in the type-safe config map - template - const VariableType& operator[](const Key& key) const&; + /// Used to access individual configs in the type-safe config map + template + const VariableType& operator[](const Key& key) const&; - /// Used to access individual configs in the type-safe config map - template - const VariableType& operator[](const Key&) &&; + /// Used to access individual configs in the type-safe config map + template + const VariableType& operator[](const Key&) &&; - /// @cond - // No longer supported, use `config[key]` instead - template - const T& Get() const&; + /// @cond + // No longer supported, use `config[key]` instead + template + const T& Get() const&; - // No longer supported, use `config[key]` instead - template - const T& Get() &&; - /// @endcond + // No longer supported, use `config[key]` instead + template + const T& Get() &&; + /// @endcond - private: - // for the constructor - friend class Source; - friend class impl::StorageData; +private: + // for the constructor + friend class Source; + friend class impl::StorageData; - explicit Snapshot(const impl::StorageData& storage); + explicit Snapshot(const impl::StorageData& storage); - const impl::SnapshotData& GetData() const; + const impl::SnapshotData& GetData() const; - struct Impl; - utils::FastPimpl impl_; + struct Impl; + utils::FastPimpl impl_; }; // ========================== Implementation follows ========================== -constexpr DefaultAsJsonString::DefaultAsJsonString(std::string_view json_string) - : json_string(json_string) {} +constexpr DefaultAsJsonString::DefaultAsJsonString(std::string_view json_string) : json_string(json_string) {} template ConfigDefault::ConfigDefault(std::string_view name, const T& value) @@ -184,96 +182,94 @@ Key::Key(std::string_view name, const VariableType& default_value) : id_(impl::Register( std::string{name}, [name = std::string{name}](const auto& docs_map) -> std::any { - return impl::DocsMapGet(docs_map, name).template As(); + return impl::DocsMapGet(docs_map, name).template As(); }, - impl::ValueToDocsMapString(name, default_value))) {} + impl::ValueToDocsMapString(name, default_value) + )) {} template Key::Key(std::string_view name, DefaultAsJsonString default_json) : id_(impl::Register( std::string{name}, [name = std::string{name}](const auto& docs_map) -> std::any { - return impl::DocsMapGet(docs_map, name).template As(); + return impl::DocsMapGet(docs_map, name).template As(); }, - impl::SingleToDocsMapString(name, default_json.json_string))) {} + impl::SingleToDocsMapString(name, default_json.json_string) + )) {} template -Key::Key(std::string_view name, JsonParser parser, - DefaultAsJsonString default_json) +Key::Key(std::string_view name, JsonParser parser, DefaultAsJsonString default_json) : id_(impl::Register( std::string{name}, [name = std::string{name}, parser](const auto& docs_map) -> std::any { - return parser(impl::DocsMapGet(docs_map, name)); + return parser(impl::DocsMapGet(docs_map, name)); }, - impl::SingleToDocsMapString(name, default_json.json_string))) {} + impl::SingleToDocsMapString(name, default_json.json_string) + )) {} template template -Key::Key(DocsMapParser parser, - const ConfigDefault (&default_json_map)[N]) +Key::Key(DocsMapParser parser, const ConfigDefault (&default_json_map)[N]) : id_(impl::Register( std::string{}, - [parser](const DocsMap& docs_map) -> std::any { - return parser(docs_map); - }, - impl::MultipleToDocsMapString(default_json_map, N))) {} + [parser](const DocsMap& docs_map) -> std::any { return parser(docs_map); }, + impl::MultipleToDocsMapString(default_json_map, N) + )) {} template Key::Key(ConstantConfig /*tag*/, VariableType value) : id_(impl::Register( std::string{}, - [value = std::move(value)](const DocsMap& /*unused*/) { - return value; - }, - "{}")) {} + [value = std::move(value)](const DocsMap& /*unused*/) { return value; }, + "{}" + )) {} template Key::Key(impl::InternalTag, std::string_view name) : id_(impl::Register( std::string{name}, [name = std::string{name}](const auto& docs_map) -> std::any { - return impl::DocsMapGet(docs_map, name).template As(); + return impl::DocsMapGet(docs_map, name).template As(); }, - "{}")) {} + "{}" + )) {} template Key::Key(impl::InternalTag, DocsMapParser parser) : id_(impl::Register( std::string{}, - [parser](const DocsMap& docs_map) -> std::any { - return parser(docs_map); - }, - "{}")) {} + [parser](const DocsMap& docs_map) -> std::any { return parser(docs_map); }, + "{}" + )) {} template std::string_view Key::GetName() const noexcept { - return impl::GetName(id_); + return impl::GetName(id_); } template VariableType Key::Parse(const DocsMap& docs_map) const { - return std::any_cast(impl::MakeConfig(id_, docs_map)); + return std::any_cast(impl::MakeConfig(id_, docs_map)); } template const VariableType& Snapshot::operator[](const Key& key) const& { - return GetData().Get(impl::ConfigIdGetter::Get(key)); + return GetData().Get(impl::ConfigIdGetter::Get(key)); } template const VariableType& Snapshot::operator[](const Key&) && { - static_assert(!sizeof(VariableType), - "keep the Snapshot before using, please"); + static_assert(!sizeof(VariableType), "keep the Snapshot before using, please"); } template const T& Snapshot::Get() const& { - return (*this)[T::kDeprecatedKey]; + return (*this)[T::kDeprecatedKey]; } template const T& Snapshot::Get() && { - static_assert(!sizeof(T), "keep the Snapshot before using, please"); + static_assert(!sizeof(T), "keep the Snapshot before using, please"); } } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/source.hpp b/core/include/userver/dynamic_config/source.hpp index de225bb97f87..5106bbd23f6b 100644 --- a/core/include/userver/dynamic_config/source.hpp +++ b/core/include/userver/dynamic_config/source.hpp @@ -19,31 +19,29 @@ namespace dynamic_config { /// to access the config variable. template class VariableSnapshotPtr final { - public: - VariableSnapshotPtr(VariableSnapshotPtr&&) = delete; - VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) = delete; +public: + VariableSnapshotPtr(VariableSnapshotPtr&&) = delete; + VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) = delete; - const VariableType& operator*() const& { return *variable_; } - const VariableType& operator*() && { ReportMisuse(); } + const VariableType& operator*() const& { return *variable_; } + const VariableType& operator*() && { ReportMisuse(); } - const VariableType* operator->() const& { return variable_; } - const VariableType* operator->() && { ReportMisuse(); } + const VariableType* operator->() const& { return variable_; } + const VariableType* operator->() && { ReportMisuse(); } - private: - [[noreturn]] static void ReportMisuse() { - static_assert(!sizeof(VariableType), - "keep the pointer before using, please"); - } +private: + [[noreturn]] static void ReportMisuse() { + static_assert(!sizeof(VariableType), "keep the pointer before using, please"); + } - explicit VariableSnapshotPtr(Snapshot&& snapshot, - const Key& key) - : snapshot_(std::move(snapshot)), variable_(&snapshot_[key]) {} + explicit VariableSnapshotPtr(Snapshot&& snapshot, const Key& key) + : snapshot_(std::move(snapshot)), variable_(&snapshot_[key]) {} - // for the constructor - friend class Source; + // for the constructor + friend class Source; - Snapshot snapshot_; - const VariableType* variable_; + Snapshot snapshot_; + const VariableType* variable_; }; /// @brief Helper class for subscribing to dynamic-config updates with a custom @@ -54,8 +52,8 @@ class VariableSnapshotPtr final { /// @param previous `dynamic_config::Snapshot` of the previous config or /// `std::nullopt` if this update event is the first for the subscriber. struct Diff final { - std::optional previous; - Snapshot current; + std::optional previous; + Snapshot current; }; // clang-format off @@ -74,62 +72,60 @@ struct Diff final { // clang-format on class Source final { - public: - using SnapshotEventSource = concurrent::AsyncEventSource; - using DiffEventSource = concurrent::AsyncEventSource; - - /// For internal use only. Obtain using components::DynamicConfig or - /// dynamic_config::StorageMock instead. - explicit Source(impl::StorageData& storage); - - // trivially copyable - Source(const Source&) = default; - Source(Source&&) = default; - Source& operator=(const Source&) = default; - Source& operator=(Source&&) = default; - - Snapshot GetSnapshot() const; - - template - VariableSnapshotPtr GetSnapshot( - const Key& key) const { - return VariableSnapshotPtr{GetSnapshot(), key}; - } - - template - VariableType GetCopy(const Key& key) const { - const auto snapshot = GetSnapshot(); - return snapshot[key]; - } - - /// Subscribes to dynamic-config updates using a member function. Also - /// immediately invokes the function with the current config snapshot (this - /// invocation will be executed synchronously). - /// - /// @note Callbacks occur in full accordance with - /// `components::DynamicConfigClientUpdater` options. - /// - /// @param obj the subscriber, which is the owner of the listener method, and - /// is also used as the unique identifier of the subscription - /// @param name the name of the subscriber, for diagnostic purposes - /// @param func the listener method, named `OnConfigUpdate` by convention. - /// @returns a `concurrent::AsyncEventSubscriberScope` controlling the - /// subscription, which should be stored as a member in the subscriber; - /// `Unsubscribe` should be called explicitly - /// - /// @see based on concurrent::AsyncEventSource engine - template - concurrent::AsyncEventSubscriberScope UpdateAndListen( - Class* obj, std::string_view name, - void (Class::*func)(const dynamic_config::Snapshot& config)) { - return DoUpdateAndListen( - concurrent::FunctionId(obj), name, - [obj, func](const dynamic_config::Snapshot& config) { - (obj->*func)(config); - }); - } - - // clang-format off +public: + using SnapshotEventSource = concurrent::AsyncEventSource; + using DiffEventSource = concurrent::AsyncEventSource; + + /// For internal use only. Obtain using components::DynamicConfig or + /// dynamic_config::StorageMock instead. + explicit Source(impl::StorageData& storage); + + // trivially copyable + Source(const Source&) = default; + Source(Source&&) = default; + Source& operator=(const Source&) = default; + Source& operator=(Source&&) = default; + + Snapshot GetSnapshot() const; + + template + VariableSnapshotPtr GetSnapshot(const Key& key) const { + return VariableSnapshotPtr{GetSnapshot(), key}; + } + + template + VariableType GetCopy(const Key& key) const { + const auto snapshot = GetSnapshot(); + return snapshot[key]; + } + + /// Subscribes to dynamic-config updates using a member function. Also + /// immediately invokes the function with the current config snapshot (this + /// invocation will be executed synchronously). + /// + /// @note Callbacks occur in full accordance with + /// `components::DynamicConfigClientUpdater` options. + /// + /// @param obj the subscriber, which is the owner of the listener method, and + /// is also used as the unique identifier of the subscription + /// @param name the name of the subscriber, for diagnostic purposes + /// @param func the listener method, named `OnConfigUpdate` by convention. + /// @returns a `concurrent::AsyncEventSubscriberScope` controlling the + /// subscription, which should be stored as a member in the subscriber; + /// `Unsubscribe` should be called explicitly + /// + /// @see based on concurrent::AsyncEventSource engine + template + concurrent::AsyncEventSubscriberScope + UpdateAndListen(Class* obj, std::string_view name, void (Class::*func)(const dynamic_config::Snapshot& config)) { + return DoUpdateAndListen( + concurrent::FunctionId(obj), + name, + [obj, func](const dynamic_config::Snapshot& config) { (obj->*func)(config); } + ); + } + + // clang-format off /// @brief Subscribes to dynamic-config updates with information about the /// current and previous states. @@ -161,78 +157,76 @@ class Source final { /// /// @see dynamic_config::Diff - // clang-format on - template - concurrent::AsyncEventSubscriberScope UpdateAndListen( - Class* obj, std::string_view name, - void (Class::*func)(const dynamic_config::Diff& diff)) { - return DoUpdateAndListen( - concurrent::FunctionId(obj), name, - [obj, func](const dynamic_config::Diff& diff) { (obj->*func)(diff); }); - } - - /// @brief Subscribes to updates of a subset of all configs. - /// - /// Subscribes to dynamic-config updates using a member function, named - /// `OnConfigUpdate` by convention. The function will be invoked if at least - /// one of the configs has been changed since the previous invocation. So at - /// the first time immediately invokes the function with the current config - /// snapshot (this invocation will be executed synchronously). - /// - /// @note Сallbacks occur only if one of the passed config is changed. This is - /// true under any components::DynamicConfigClientUpdater options. - /// - /// @warning To use this function, configs must have the `operator==`. - /// - /// @param obj the subscriber, which is the owner of the listener method, and - /// is also used as the unique identifier of the subscription - /// @param name the name of the subscriber, for diagnostic purposes - /// @param func the listener method, named `OnConfigUpdate` by convention. - /// @param keys config objects, specializations of `dynamic_config::Key`. - /// @returns a `concurrent::AsyncEventSubscriberScope` controlling the - /// subscription, which should be stored as a member in the subscriber; - /// `Unsubscribe` should be called explicitly - /// - /// @see based on concurrent::AsyncEventSource engine - template - concurrent::AsyncEventSubscriberScope UpdateAndListen( - Class* obj, std::string_view name, - void (Class::*func)(const dynamic_config::Snapshot& config), - const Keys&... keys) { - auto wrapper = [obj, func, &keys...](const Diff& diff) { - if (!HasChanged(diff, keys...)) return; - (obj->*func)(diff.current); - }; - return DoUpdateAndListen(concurrent::FunctionId(obj), name, - std::move(wrapper)); - } - - SnapshotEventSource& GetEventChannel(); - - private: - template - static bool HasChanged(const Diff& diff, const Keys&... keys) { - if (!diff.previous) return true; - - const auto& previous = *diff.previous; - const auto& current = diff.current; - - UASSERT(!current.GetData().IsEmpty()); - UASSERT(!previous.GetData().IsEmpty()); - - const bool is_equal = (true && ... && (previous[keys] == current[keys])); - return !is_equal; - } - - concurrent::AsyncEventSubscriberScope DoUpdateAndListen( - concurrent::FunctionId id, std::string_view name, - SnapshotEventSource::Function&& func); - - concurrent::AsyncEventSubscriberScope DoUpdateAndListen( - concurrent::FunctionId id, std::string_view name, - DiffEventSource::Function&& func); - - impl::StorageData* storage_; + // clang-format on + template + concurrent::AsyncEventSubscriberScope + UpdateAndListen(Class* obj, std::string_view name, void (Class::*func)(const dynamic_config::Diff& diff)) { + return DoUpdateAndListen(concurrent::FunctionId(obj), name, [obj, func](const dynamic_config::Diff& diff) { + (obj->*func)(diff); + }); + } + + /// @brief Subscribes to updates of a subset of all configs. + /// + /// Subscribes to dynamic-config updates using a member function, named + /// `OnConfigUpdate` by convention. The function will be invoked if at least + /// one of the configs has been changed since the previous invocation. So at + /// the first time immediately invokes the function with the current config + /// snapshot (this invocation will be executed synchronously). + /// + /// @note Сallbacks occur only if one of the passed config is changed. This is + /// true under any components::DynamicConfigClientUpdater options. + /// + /// @warning To use this function, configs must have the `operator==`. + /// + /// @param obj the subscriber, which is the owner of the listener method, and + /// is also used as the unique identifier of the subscription + /// @param name the name of the subscriber, for diagnostic purposes + /// @param func the listener method, named `OnConfigUpdate` by convention. + /// @param keys config objects, specializations of `dynamic_config::Key`. + /// @returns a `concurrent::AsyncEventSubscriberScope` controlling the + /// subscription, which should be stored as a member in the subscriber; + /// `Unsubscribe` should be called explicitly + /// + /// @see based on concurrent::AsyncEventSource engine + template + concurrent::AsyncEventSubscriberScope UpdateAndListen( + Class* obj, + std::string_view name, + void (Class::*func)(const dynamic_config::Snapshot& config), + const Keys&... keys + ) { + auto wrapper = [obj, func, &keys...](const Diff& diff) { + if (!HasChanged(diff, keys...)) return; + (obj->*func)(diff.current); + }; + return DoUpdateAndListen(concurrent::FunctionId(obj), name, std::move(wrapper)); + } + + SnapshotEventSource& GetEventChannel(); + +private: + template + static bool HasChanged(const Diff& diff, const Keys&... keys) { + if (!diff.previous) return true; + + const auto& previous = *diff.previous; + const auto& current = diff.current; + + UASSERT(!current.GetData().IsEmpty()); + UASSERT(!previous.GetData().IsEmpty()); + + const bool is_equal = (true && ... && (previous[keys] == current[keys])); + return !is_equal; + } + + concurrent::AsyncEventSubscriberScope + DoUpdateAndListen(concurrent::FunctionId id, std::string_view name, SnapshotEventSource::Function&& func); + + concurrent::AsyncEventSubscriberScope + DoUpdateAndListen(concurrent::FunctionId id, std::string_view name, DiffEventSource::Function&& func); + + impl::StorageData* storage_; }; } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/storage/component.hpp b/core/include/userver/dynamic_config/storage/component.hpp index 06c72e0b4ec1..62707eb2d0b5 100644 --- a/core/include/userver/dynamic_config/storage/component.hpp +++ b/core/include/userver/dynamic_config/storage/component.hpp @@ -65,65 +65,60 @@ namespace components { // clang-format on class DynamicConfig final : public DynamicConfigUpdatesSinkBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::DynamicConfig - static constexpr std::string_view kName = "dynamic-config"; +public: + /// @ingroup userver_component_names + /// @brief The default name of components::DynamicConfig + static constexpr std::string_view kName = "dynamic-config"; - class NoblockSubscriber; + class NoblockSubscriber; - DynamicConfig(const ComponentConfig&, const ComponentContext&); - ~DynamicConfig() override; + DynamicConfig(const ComponentConfig&, const ComponentContext&); + ~DynamicConfig() override; - /// Use `dynamic_config::Source` to get up-to-date config values, or to do - /// something special on config updates - dynamic_config::Source GetSource(); + /// Use `dynamic_config::Source` to get up-to-date config values, or to do + /// something special on config updates + dynamic_config::Source GetSource(); - /// Get config defaults with overrides applied. Useful in the implementation - /// of custom config clients. Most code does not need to deal with these - const dynamic_config::DocsMap& GetDefaultDocsMap() const; + /// Get config defaults with overrides applied. Useful in the implementation + /// of custom config clients. Most code does not need to deal with these + const dynamic_config::DocsMap& GetDefaultDocsMap() const; - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - ComponentHealth GetComponentHealth() const override; - void OnLoadingCancelled() override; +private: + ComponentHealth GetComponentHealth() const override; + void OnLoadingCancelled() override; - void SetConfig(std::string_view updater, - dynamic_config::DocsMap&& value) override; + void SetConfig(std::string_view updater, dynamic_config::DocsMap&& value) override; - void SetConfig(std::string_view updater, - const dynamic_config::DocsMap& value) override; + void SetConfig(std::string_view updater, const dynamic_config::DocsMap& value) override; - void NotifyLoadingFailed(std::string_view updater, - std::string_view error) override; + void NotifyLoadingFailed(std::string_view updater, std::string_view error) override; - class Impl; - std::unique_ptr impl_; + class Impl; + std::unique_ptr impl_; }; /// @brief Allows to subscribe to `DynamicConfig` updates without waiting for /// the first update to complete. Primarily intended for internal use. class DynamicConfig::NoblockSubscriber final { - public: - explicit NoblockSubscriber(DynamicConfig& config_component) noexcept; +public: + explicit NoblockSubscriber(DynamicConfig& config_component) noexcept; - NoblockSubscriber(NoblockSubscriber&&) = delete; - NoblockSubscriber& operator=(NoblockSubscriber&&) = delete; + NoblockSubscriber(NoblockSubscriber&&) = delete; + NoblockSubscriber& operator=(NoblockSubscriber&&) = delete; - concurrent::AsyncEventSource& - GetEventSource() noexcept; + concurrent::AsyncEventSource& GetEventSource() noexcept; - private: - DynamicConfig& config_component_; +private: + DynamicConfig& config_component_; }; template <> inline constexpr bool kHasValidate = true; template <> -inline constexpr auto kConfigFileMode = - ConfigFileMode::kNotRequired; +inline constexpr auto kConfigFileMode = ConfigFileMode::kNotRequired; } // namespace components diff --git a/core/include/userver/dynamic_config/storage_mock.hpp b/core/include/userver/dynamic_config/storage_mock.hpp index 51116aedb968..855a5d69419a 100644 --- a/core/include/userver/dynamic_config/storage_mock.hpp +++ b/core/include/userver/dynamic_config/storage_mock.hpp @@ -24,39 +24,38 @@ using IsJson = std::enable_if_t>; /// A type-erased config key-value pair class KeyValue final { - public: - /// Uses the provided value directly. It can also be constructed in-place: - /// @code - /// {kMyConfig, {"foo", 42}} - /// @endcode - /// - /// When passed a formats::json::Value, parses the value from it: - /// @code - /// {kMyConfig, formats::json::FromString(R"({"foo": "what", "bar": 42})")} - /// @endcode - template - KeyValue(const Key& key, Value&& value) - : id_(impl::ConfigIdGetter::Get(key)), - value_(Convert(std::forward(value))) {} - - /// For internal use only - impl::ConfigId GetId() const { return id_; } - - /// For internal use only - std::any GetValue() const { return value_; } - - private: - template - static VariableType Convert(Value&& value) { - if constexpr (std::is_same_v, formats::json::Value>) { - return value.template As(); - } else { - return static_cast(std::forward(value)); +public: + /// Uses the provided value directly. It can also be constructed in-place: + /// @code + /// {kMyConfig, {"foo", 42}} + /// @endcode + /// + /// When passed a formats::json::Value, parses the value from it: + /// @code + /// {kMyConfig, formats::json::FromString(R"({"foo": "what", "bar": 42})")} + /// @endcode + template + KeyValue(const Key& key, Value&& value) + : id_(impl::ConfigIdGetter::Get(key)), value_(Convert(std::forward(value))) {} + + /// For internal use only + impl::ConfigId GetId() const { return id_; } + + /// For internal use only + std::any GetValue() const { return value_; } + +private: + template + static VariableType Convert(Value&& value) { + if constexpr (std::is_same_v, formats::json::Value>) { + return value.template As(); + } else { + return static_cast(std::forward(value)); + } } - } - impl::ConfigId id_; - std::any value_; + impl::ConfigId id_; + std::any value_; }; /// @brief Backing storage for `dynamic_config::Source` in tests and benchmarks @@ -66,38 +65,38 @@ class KeyValue final { /// @see dynamic_config::GetDefaultSource /// @see dynamic_config::MakeDefaultStorage class StorageMock final { - public: - /// Create an empty `StorageMock` - StorageMock(); +public: + /// Create an empty `StorageMock` + StorageMock(); - /// Only store `config_variables` in the `Config`. - /// Use as: `StorageMock{{kVariableKey1, value1}, {kVariableKey2, value2}}` - StorageMock(std::initializer_list config_variables); + /// Only store `config_variables` in the `Config`. + /// Use as: `StorageMock{{kVariableKey1, value1}, {kVariableKey2, value2}}` + StorageMock(std::initializer_list config_variables); - /// Only store `config_variables` in the `Config` - explicit StorageMock(const std::vector& config_variables); + /// Only store `config_variables` in the `Config` + explicit StorageMock(const std::vector& config_variables); - /// @brief Store `overrides` in the `Config`, then parse all the remaining - /// variables from `defaults` - /// @see dynamic_config::MakeDefaultStorage - StorageMock(const DocsMap& defaults, const std::vector& overrides); + /// @brief Store `overrides` in the `Config`, then parse all the remaining + /// variables from `defaults` + /// @see dynamic_config::MakeDefaultStorage + StorageMock(const DocsMap& defaults, const std::vector& overrides); - StorageMock(StorageMock&&) noexcept; - StorageMock& operator=(StorageMock&&) noexcept; - ~StorageMock(); + StorageMock(StorageMock&&) noexcept; + StorageMock& operator=(StorageMock&&) noexcept; + ~StorageMock(); - /// Update some config variables - void Extend(const std::vector& overrides); + /// Update some config variables + void Extend(const std::vector& overrides); - Source GetSource() const&; - Snapshot GetSnapshot() const&; + Source GetSource() const&; + Snapshot GetSnapshot() const&; - // Store the StorageMock in a variable before using - Snapshot GetSource() && = delete; - Snapshot GetSnapshot() && = delete; + // Store the StorageMock in a variable before using + Snapshot GetSource() && = delete; + Snapshot GetSnapshot() && = delete; - private: - std::unique_ptr storage_; +private: + std::unique_ptr storage_; }; } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/test_helpers.hpp b/core/include/userver/dynamic_config/test_helpers.hpp index 70087ac8382b..a17f04fbb15d 100644 --- a/core/include/userver/dynamic_config/test_helpers.hpp +++ b/core/include/userver/dynamic_config/test_helpers.hpp @@ -20,8 +20,7 @@ dynamic_config::Source GetDefaultSource(); const dynamic_config::Snapshot& GetDefaultSnapshot(); /// Make `dynamic_config::StorageMock` with built-in defaults for all configs -dynamic_config::StorageMock MakeDefaultStorage( - const std::vector& overrides); +dynamic_config::StorageMock MakeDefaultStorage(const std::vector& overrides); namespace impl { diff --git a/core/include/userver/dynamic_config/updater/additional_keys_token.hpp b/core/include/userver/dynamic_config/updater/additional_keys_token.hpp index 6521589ce549..01053bd261f1 100644 --- a/core/include/userver/dynamic_config/updater/additional_keys_token.hpp +++ b/core/include/userver/dynamic_config/updater/additional_keys_token.hpp @@ -14,14 +14,14 @@ namespace dynamic_config { /// @brief Defines the scope where DynamicConfigClientUpdater requests /// additional configs. class AdditionalKeysToken { - public: - using KeyList = std::vector; +public: + using KeyList = std::vector; - AdditionalKeysToken(); - explicit AdditionalKeysToken(std::shared_ptr keys); + AdditionalKeysToken(); + explicit AdditionalKeysToken(std::shared_ptr keys); - private: - std::shared_ptr keys_; +private: + std::shared_ptr keys_; }; } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/updater/component.hpp b/core/include/userver/dynamic_config/updater/component.hpp index 77d0372eca76..f23a6f4a9c2a 100644 --- a/core/include/userver/dynamic_config/updater/component.hpp +++ b/core/include/userver/dynamic_config/updater/component.hpp @@ -71,64 +71,58 @@ namespace components { /// @snippet components/common_component_list_test.cpp Sample dynamic config client updater component config // clang-format on -class DynamicConfigClientUpdater final - : public CachingComponentBase { - public: - /// @ingroup userver_component_names - /// @brief The default name of components::DynamicConfigClientUpdater - static constexpr std::string_view kName = "dynamic-config-client-updater"; +class DynamicConfigClientUpdater final : public CachingComponentBase { +public: + /// @ingroup userver_component_names + /// @brief The default name of components::DynamicConfigClientUpdater + static constexpr std::string_view kName = "dynamic-config-client-updater"; - DynamicConfigClientUpdater(const ComponentConfig&, const ComponentContext&); + DynamicConfigClientUpdater(const ComponentConfig&, const ComponentContext&); - ~DynamicConfigClientUpdater() override; + ~DynamicConfigClientUpdater() override; - // After calling this method, `Get()` will return a dynamic_config containing - // the specified keys while the token that this method returned is alive. - dynamic_config::AdditionalKeysToken SetAdditionalKeys( - std::vector keys); + // After calling this method, `Get()` will return a dynamic_config containing + // the specified keys while the token that this method returned is alive. + dynamic_config::AdditionalKeysToken SetAdditionalKeys(std::vector keys); - static yaml_config::Schema GetStaticConfigSchema(); + static yaml_config::Schema GetStaticConfigSchema(); - private: - void Update(cache::UpdateType update_type, - const std::chrono::system_clock::time_point& last_update, - const std::chrono::system_clock::time_point& now, - cache::UpdateStatisticsScope&) override; +private: + void + Update(cache::UpdateType update_type, const std::chrono::system_clock::time_point& last_update, const std::chrono::system_clock::time_point& now, cache::UpdateStatisticsScope&) + override; - void UpdateFull(const std::vector& docs_map_keys, - cache::UpdateStatisticsScope&); + void UpdateFull(const std::vector& docs_map_keys, cache::UpdateStatisticsScope&); - void UpdateIncremental(const std::vector& docs_map_keys, - cache::UpdateStatisticsScope&); + void UpdateIncremental(const std::vector& docs_map_keys, cache::UpdateStatisticsScope&); - dynamic_config::DocsMap MergeDocsMap(const dynamic_config::DocsMap& current, - dynamic_config::DocsMap&& update, - const std::vector& removed); - void StoreIfEnabled(const dynamic_config::DocsMap& value); + dynamic_config::DocsMap MergeDocsMap( + const dynamic_config::DocsMap& current, + dynamic_config::DocsMap&& update, + const std::vector& removed + ); + void StoreIfEnabled(const dynamic_config::DocsMap& value); - using DocsMapKeys = utils::impl::TransparentSet; - using AdditionalDocsMapKeys = - std::unordered_set>>; + using DocsMapKeys = utils::impl::TransparentSet; + using AdditionalDocsMapKeys = std::unordered_set>>; - std::vector GetDocsMapKeysToFetch( - AdditionalDocsMapKeys& additional_docs_map_keys); + std::vector GetDocsMapKeysToFetch(AdditionalDocsMapKeys& additional_docs_map_keys); - void UpdateAdditionalKeys(const std::vector& keys); + void UpdateAdditionalKeys(const std::vector& keys); - bool IsDuplicate(cache::UpdateType update_type, - const dynamic_config::DocsMap& new_value) const; + bool IsDuplicate(cache::UpdateType update_type, const dynamic_config::DocsMap& new_value) const; - DynamicConfigUpdatesSinkBase& updates_sink_; - const bool load_only_my_values_; - const bool store_enabled_; - const std::optional deduplicate_update_types_; - dynamic_config::Client& config_client_; + DynamicConfigUpdatesSinkBase& updates_sink_; + const bool load_only_my_values_; + const bool store_enabled_; + const std::optional deduplicate_update_types_; + dynamic_config::Client& config_client_; - dynamic_config::Client::Timestamp server_timestamp_; - // for atomic updates of cached data - engine::Mutex update_config_mutex_; - DocsMapKeys docs_map_keys_; - concurrent::Variable additional_docs_map_keys_; + dynamic_config::Client::Timestamp server_timestamp_; + // for atomic updates of cached data + engine::Mutex update_config_mutex_; + DocsMapKeys docs_map_keys_; + concurrent::Variable additional_docs_map_keys_; }; template <> diff --git a/core/include/userver/dynamic_config/updates_sink/component.hpp b/core/include/userver/dynamic_config/updates_sink/component.hpp index 08a73f5a2622..8193600b8579 100644 --- a/core/include/userver/dynamic_config/updates_sink/component.hpp +++ b/core/include/userver/dynamic_config/updates_sink/component.hpp @@ -16,9 +16,11 @@ class DynamicConfigUpdatesSinkBase; } // namespace components namespace dynamic_config::impl { -void RegisterUpdater(components::DynamicConfigUpdatesSinkBase& sink, - std::string_view sink_component_name, - std::string_view updater_component_name); +void RegisterUpdater( + components::DynamicConfigUpdatesSinkBase& sink, + std::string_view sink_component_name, + std::string_view updater_component_name +); } // namespace dynamic_config::impl namespace components { @@ -38,48 +40,45 @@ namespace components { /// @warning Unless explicitly stated, descendants of this class expect that /// `SetConfig` method calls are serialized. class DynamicConfigUpdatesSinkBase : public ComponentBase { - public: - DynamicConfigUpdatesSinkBase(const components::ComponentConfig&, - const components::ComponentContext&); - - ~DynamicConfigUpdatesSinkBase() override; - - /// Called by updaters to store new version of dynamic config. - /// @param updater updater name used for logging - /// @param config updated dynamic config - virtual void SetConfig(std::string_view updater, - dynamic_config::DocsMap&& config) = 0; - - /// Called by updaters to store new version of dynamic config. - /// Default implementation creates a copy of `config` and then uses it - /// in the call to `SetConfig` overload with an rvalue `DocsMap` parameter. - /// @param updater updater name used for logging - /// @param config updated dynamic config - virtual void SetConfig(std::string_view updater, - const dynamic_config::DocsMap& config); - - /// Should be called when updater fails to load dynamic config. - /// When the service starts up and dynamic config cache file is not found, - /// components::DynamicConfig expects updater to provide the current version - /// of the dynamic config and blocks all reads until it is received. Updater - /// is expected to call this method if it can't load dynamic config - /// to interrupt the service startup with proper diagnostics. - /// This method should not typically throw any exceptions. - /// If the config is already loaded, calling this method should do nothing. - /// @param updater updater name used for logging - /// @param error error to be outputted to log - virtual void NotifyLoadingFailed(std::string_view updater, - std::string_view error) = 0; - - private: - struct UsedByInfo; - - friend void dynamic_config::impl::RegisterUpdater( - components::DynamicConfigUpdatesSinkBase& sink, - std::string_view sink_component_name, - std::string_view updater_component_name); - - std::unique_ptr used_by_; +public: + DynamicConfigUpdatesSinkBase(const components::ComponentConfig&, const components::ComponentContext&); + + ~DynamicConfigUpdatesSinkBase() override; + + /// Called by updaters to store new version of dynamic config. + /// @param updater updater name used for logging + /// @param config updated dynamic config + virtual void SetConfig(std::string_view updater, dynamic_config::DocsMap&& config) = 0; + + /// Called by updaters to store new version of dynamic config. + /// Default implementation creates a copy of `config` and then uses it + /// in the call to `SetConfig` overload with an rvalue `DocsMap` parameter. + /// @param updater updater name used for logging + /// @param config updated dynamic config + virtual void SetConfig(std::string_view updater, const dynamic_config::DocsMap& config); + + /// Should be called when updater fails to load dynamic config. + /// When the service starts up and dynamic config cache file is not found, + /// components::DynamicConfig expects updater to provide the current version + /// of the dynamic config and blocks all reads until it is received. Updater + /// is expected to call this method if it can't load dynamic config + /// to interrupt the service startup with proper diagnostics. + /// This method should not typically throw any exceptions. + /// If the config is already loaded, calling this method should do nothing. + /// @param updater updater name used for logging + /// @param error error to be outputted to log + virtual void NotifyLoadingFailed(std::string_view updater, std::string_view error) = 0; + +private: + struct UsedByInfo; + + friend void dynamic_config::impl::RegisterUpdater( + components::DynamicConfigUpdatesSinkBase& sink, + std::string_view sink_component_name, + std::string_view updater_component_name + ); + + std::unique_ptr used_by_; }; } // namespace components diff --git a/core/include/userver/dynamic_config/updates_sink/find.hpp b/core/include/userver/dynamic_config/updates_sink/find.hpp index 9fb81059a98c..4a7566205e78 100644 --- a/core/include/userver/dynamic_config/updates_sink/find.hpp +++ b/core/include/userver/dynamic_config/updates_sink/find.hpp @@ -25,9 +25,8 @@ namespace dynamic_config { /// creation of the requested component. /// /// @note It is illegal to use the same updates sink from several components. -components::DynamicConfigUpdatesSinkBase& FindUpdatesSink( - const components::ComponentConfig& config, - const components::ComponentContext& context); +components::DynamicConfigUpdatesSinkBase& +FindUpdatesSink(const components::ComponentConfig& config, const components::ComponentContext& context); } // namespace dynamic_config diff --git a/core/include/userver/dynamic_config/value.hpp b/core/include/userver/dynamic_config/value.hpp index 808b191e5256..79e92a8a28e1 100644 --- a/core/include/userver/dynamic_config/value.hpp +++ b/core/include/userver/dynamic_config/value.hpp @@ -16,40 +16,37 @@ USERVER_NAMESPACE_BEGIN namespace dynamic_config { class DocsMap final { - public: - /* Returns config item or throws an exception if key is missing */ - formats::json::Value Get(std::string_view name) const; - - bool Has(std::string_view name) const; - void Set(std::string name, formats::json::Value); - void Parse(std::string_view json_string, bool empty_ok); - void Parse(formats::json::Value json, bool empty_ok); - void Remove(const std::string& name); - size_t Size() const; - - void MergeOrAssign(DocsMap&& source); - void MergeMissing(const DocsMap& source); - - std::unordered_set GetNames() const; - formats::json::Value AsJson() const; - bool AreContentsEqual(const DocsMap& other) const; - - /// @cond - // For internal use only. - // Set of configs expected to be used is automatically updated when - // configs are retrieved with 'Get' method. - void SetConfigsExpectedToBeUsed( - utils::impl::TransparentSet configs, - utils::impl::InternalTag); - - // For internal use only. - const utils::impl::TransparentSet& GetConfigsExpectedToBeUsed( - utils::impl::InternalTag) const; - /// @endcond - - private: - utils::impl::TransparentMap docs_; - mutable utils::impl::TransparentSet configs_to_be_used_; +public: + /* Returns config item or throws an exception if key is missing */ + formats::json::Value Get(std::string_view name) const; + + bool Has(std::string_view name) const; + void Set(std::string name, formats::json::Value); + void Parse(std::string_view json_string, bool empty_ok); + void Parse(formats::json::Value json, bool empty_ok); + void Remove(const std::string& name); + size_t Size() const; + + void MergeOrAssign(DocsMap&& source); + void MergeMissing(const DocsMap& source); + + std::unordered_set GetNames() const; + formats::json::Value AsJson() const; + bool AreContentsEqual(const DocsMap& other) const; + + /// @cond + // For internal use only. + // Set of configs expected to be used is automatically updated when + // configs are retrieved with 'Get' method. + void SetConfigsExpectedToBeUsed(utils::impl::TransparentSet configs, utils::impl::InternalTag); + + // For internal use only. + const utils::impl::TransparentSet& GetConfigsExpectedToBeUsed(utils::impl::InternalTag) const; + /// @endcond + +private: + utils::impl::TransparentMap docs_; + mutable utils::impl::TransparentSet configs_to_be_used_; }; template diff --git a/core/include/userver/engine/async.hpp b/core/include/userver/engine/async.hpp index 96669f2f0226..6c0c7e878e4e 100644 --- a/core/include/userver/engine/async.hpp +++ b/core/include/userver/engine/async.hpp @@ -16,116 +16,106 @@ namespace engine { namespace impl { -template