From e20a158272edc7d2b603babc7cae4f98704b41d4 Mon Sep 17 00:00:00 2001 From: itrofimow Date: Mon, 28 Nov 2022 02:27:33 +0300 Subject: [PATCH] [C++] Introduce userver (#7617) * introduce userver: + plaintext * + json * + db * fix README * lock userver version * nproc in make -j * some tweaks * Userver -> userver * + march=native * fix paths in README * cr from userver crew fixes * up userver commit * tune coroutine limits a bit * Userver db (#3) * add queries/updates tests * Restructure project (#4) * restructure project * add cached-queries * fix readme (#5) * tune postgres connections pool --- frameworks/C++/userver/README.md | 38 ++++++++ frameworks/C++/userver/benchmark_config.json | 30 +++++++ frameworks/C++/userver/userver.dockerfile | 17 ++++ .../configs/dynamic_config_fallback.json | 53 +++++++++++ .../configs/secure_data.json | 12 +++ .../configs/static_config.yaml | 90 +++++++++++++++++++ .../userver_benchmark/src/CMakeLists.txt | 17 ++++ .../src/common/db_helpers.cpp | 38 ++++++++ .../src/common/db_helpers.hpp | 32 +++++++ .../controllers/cached_queries/handler.cpp | 33 +++++++ .../controllers/cached_queries/handler.hpp | 27 ++++++ .../cached_queries/world_cache_component.cpp | 21 +++++ .../cached_queries/world_cache_component.hpp | 36 ++++++++ .../src/controllers/json/handler.cpp | 12 +++ .../src/controllers/json/handler.hpp | 19 ++++ .../controllers/multiple_queries/handler.cpp | 44 +++++++++ .../controllers/multiple_queries/handler.hpp | 26 ++++++ .../src/controllers/plaintext/handler.cpp | 12 +++ .../src/controllers/plaintext/handler.hpp | 18 ++++ .../src/controllers/single_query/handler.cpp | 31 +++++++ .../src/controllers/single_query/handler.hpp | 25 ++++++ .../src/controllers/updates/handler.cpp | 65 ++++++++++++++ .../src/controllers/updates/handler.hpp | 28 ++++++ .../src/userver_techempower.cpp | 38 ++++++++ 24 files changed, 762 insertions(+) create mode 100755 frameworks/C++/userver/README.md create mode 100755 frameworks/C++/userver/benchmark_config.json create mode 100644 frameworks/C++/userver/userver.dockerfile create mode 100644 frameworks/C++/userver/userver_benchmark/configs/dynamic_config_fallback.json create mode 100644 frameworks/C++/userver/userver_benchmark/configs/secure_data.json create mode 100644 frameworks/C++/userver/userver_benchmark/configs/static_config.yaml create mode 100644 frameworks/C++/userver/userver_benchmark/src/CMakeLists.txt create mode 100644 frameworks/C++/userver/userver_benchmark/src/common/db_helpers.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/common/db_helpers.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.cpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.hpp create mode 100644 frameworks/C++/userver/userver_benchmark/src/userver_techempower.cpp diff --git a/frameworks/C++/userver/README.md b/frameworks/C++/userver/README.md new file mode 100755 index 00000000000..e979806e791 --- /dev/null +++ b/frameworks/C++/userver/README.md @@ -0,0 +1,38 @@ +# userver Benchmarking Test + +This is the [userver](https://github.com/userver-framework/userver) portion of a [benchmarking test suite](https://github.com/TechEmpower/FrameworkBenchmarks) comparing a variety of web development platforms. + +### Test Type Implementation Source Code + +* [PLAINTEXT](userver_benchmark/src/controllers/plaintext/handler.cpp) +* [JSON](userver_benchmark/src/controllers/json/handler.cpp) +* [Single Database Query](userver_benchmark/src/controllers/single_query/handler.cpp) +* [Multiple Database Queries](userver_benchmark/src/controllers/multiple_queries/handler.cpp) +* [Database Updates](userver_benchmark/src/controllers/updates/handler.cpp) +* [Cached Queries](userver_benchmark/src/controllers/cached_queries/handler.cpp) + +## Test URLs +### PLAINTEXT + +http://localhost:8080/plaintext + +### JSON + +http://localhost:8080/json + +### Single Database Query + +http://localhost:8080/db + +### Multiple Database Queries + +http://localhost:8080/queries + +### Database Updates + +http://localhost:8080/updates + +### Cached Queries + +http://localhost:8080/cached-queries + diff --git a/frameworks/C++/userver/benchmark_config.json b/frameworks/C++/userver/benchmark_config.json new file mode 100755 index 00000000000..cef5b264612 --- /dev/null +++ b/frameworks/C++/userver/benchmark_config.json @@ -0,0 +1,30 @@ +{ + "framework": "userver", + "tests": [ + { + "default": { + "json_url": "/json", + "plaintext_url": "/plaintext", + "db_url": "/db", + "query_url": "/queries?queries=", + "update_url": "/updates?queries=", + "cached_query_url": "/cached-queries?count=", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "database": "postgres", + "framework": "userver", + "language": "C++", + "flavor": "None", + "orm": "Raw", + "platform": "None", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "userver", + "notes": "", + "versus": "None" + } + } + ] +} diff --git a/frameworks/C++/userver/userver.dockerfile b/frameworks/C++/userver/userver.dockerfile new file mode 100644 index 00000000000..ce555085453 --- /dev/null +++ b/frameworks/C++/userver/userver.dockerfile @@ -0,0 +1,17 @@ +FROM ghcr.io/userver-framework/docker-userver-build-base:v1a +WORKDIR src +COPY userver_benchmark/src/ ./ +RUN git clone https://github.com/userver-framework/userver.git && \ + cd userver && git checkout 84456123a6a32f68847a791f29ef56d86bb765ad +RUN mkdir build && cd build && \ + cmake -DUSERVER_IS_THE_ROOT_PROJECT=0 -DUSERVER_OPEN_SOURCE_BUILD=1 -DUSERVER_FEATURE_CRYPTOPP_BLAKE2=0 \ + -DUSERVER_FEATURE_REDIS=0 -DUSERVER_FEATURE_CLICKHOUSE=0 -DUSERVER_FEATURE_MONGODB=0 -DUSERVER_FEATURE_RABBITMQ=0 -DUSERVER_FEATURE_GRPC=0 \ + -DUSERVER_FEATURE_UTEST=0 \ + -DUSERVER_FEATURE_POSTGRESQL=1 \ + -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS="-march=native" .. && \ + make -j $(nproc) + +COPY userver_benchmark/configs/* ./ + +EXPOSE 8090 +CMD ./build/userver_techempower -c /src/static_config.yaml diff --git a/frameworks/C++/userver/userver_benchmark/configs/dynamic_config_fallback.json b/frameworks/C++/userver/userver_benchmark/configs/dynamic_config_fallback.json new file mode 100644 index 00000000000..21ab18bf031 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/configs/dynamic_config_fallback.json @@ -0,0 +1,53 @@ +{ + "USERVER_CACHES": {}, + "USERVER_CANCEL_HANDLE_REQUEST_BY_DEADLINE": false, + "USERVER_CHECK_AUTH_IN_HANDLERS": false, + "USERVER_DUMPS": {}, + "USERVER_HTTP_PROXY": "", + "USERVER_LOG_REQUEST": false, + "USERVER_LOG_REQUEST_HEADERS": false, + "USERVER_LRU_CACHES": {}, + "USERVER_RPS_CCONTROL_CUSTOM_STATUS": {}, + "USERVER_TASK_PROCESSOR_PROFILER_DEBUG": {}, + "HTTP_CLIENT_CONNECTION_POOL_SIZE": 1000, + "HTTP_CLIENT_CONNECT_THROTTLE": { + "http-limit": 6000, + "http-per-second": 1500, + "https-limit": 100, + "https-per-second": 25, + "per-host-limit": 3000, + "per-host-per-second": 500 + }, + "HTTP_CLIENT_ENFORCE_TASK_DEADLINE": { + "cancel-request": false, + "update-timeout": false + }, + "USERVER_TASK_PROCESSOR_QOS": { + "default-service": { + "default-task-processor": { + "wait_queue_overload": { + "action": "ignore", + "length_limit": 16385, + "time_limit_us": 30000 + } + } + } + }, + + "POSTGRES_STATEMENT_METRICS_SETTINGS": {}, + "POSTGRES_CONNECTION_PIPELINE_ENABLED": false, + "POSTGRES_CONNECTION_POOL_SETTINGS": { + "hello_world": { + "max_pool_size": 512, + "max_queue_size": 512, + "min_pool_size": 256 + } + }, + "POSTGRES_CONNECTION_SETTINGS": {}, + "POSTGRES_DEFAULT_COMMAND_CONTROL": { + "network_timeout_ms": 1750, + "statement_timeout_ms": 1500 + }, + "POSTGRES_HANDLERS_COMMAND_CONTROL": {}, + "POSTGRES_QUERIES_COMMAND_CONTROL": {} +} diff --git a/frameworks/C++/userver/userver_benchmark/configs/secure_data.json b/frameworks/C++/userver/userver_benchmark/configs/secure_data.json new file mode 100644 index 00000000000..592e5435189 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/configs/secure_data.json @@ -0,0 +1,12 @@ +{ + "postgresql_settings": { + "databases": { + "hello_world": [{ + "shard_number" : 0, + "hosts": [ + "postgresql://benchmarkdbuser:benchmarkdbpass@tfb-database:5432/hello_world" + ] + }] + } + } +} diff --git a/frameworks/C++/userver/userver_benchmark/configs/static_config.yaml b/frameworks/C++/userver/userver_benchmark/configs/static_config.yaml new file mode 100644 index 00000000000..8ba9e5dbbfa --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/configs/static_config.yaml @@ -0,0 +1,90 @@ +# yaml +components_manager: + coro_pool: + initial_size: 10000 # Preallocate 10000 coroutines at startup. + max_size: 65536 # Do not keep more than 65536 preallocated coroutines. + stack_size: 66560 # 64Kb for coroutine stack + + task_processors: # Task processor is an executor for coroutine tasks + + main-task-processor: # Make a task processor for CPU-bound couroutine tasks. + thread_name: main-worker # OS will show the threads of this task processor with 'main-worker' prefix. + worker_threads: 26 + guess-cpu-limit: true + + fs-task-processor: # Make a separate task processor for filesystem bound tasks. + thread_name: fs-worker + worker_threads: 4 + + default_task_processor: main-task-processor + + components: # Configuring components that were registered via component_list + server: + listener: # configuring the main listening socket... + port: 8080 # ...to listen on this port and... + task_processor: main-task-processor # ...process incoming requests on this task processor. + logging: + fs-task-processor: fs-task-processor + loggers: + default: + file_path: '@stderr' + level: ERROR + overflow_behavior: discard # Drop logs if the system is too busy to write them down. + + tracer: # Component that helps to trace execution times and requests in logs. + service-name: userver-techempower # "You know. You all know exactly who I am. Say my name. " (c) + + dynamic-config: # Dynamic config storage options, do nothing + fs-cache-path: '' + dynamic-config-fallbacks: # Load options from file and push them into the dynamic config storage. + fallback-path: /src/dynamic_config_fallback.json + + testsuite-support: + + secdist: # Component that stores configuration of hosts and passwords + config: /src/secure_data.json # Values are supposed to be stored in this file + missing-ok: false # ... but if the file is missing it is still ok + + plaintext-handler: + path: /plaintext + method: GET + task_processor: main-task-processor + + json-handler: + path: /json + method: GET + task_processor: main-task-processor + + hello-world-db: + dbalias: hello_world + blocking_task_processor: fs-task-processor + min_pool_size: 20 + max_pool_size: 520 + max_queue_size: 500 + + single-query-handler: + path: /db + method: GET + task_processor: main-task-processor + + multiple-queries-handler: + path: /queries + method: GET + task_processor: main-task-processor + + updates-handler: + path: /updates + method: GET + task_processor: main-task-processor + + world-pg-cache: + pgcomponent: hello-world-db + update-types: only-full + update-interval: 1s + update-correction: 50ms + + cached-queries-handler: + path: /cached-queries + method: GET + task_processor: main-task-processor + diff --git a/frameworks/C++/userver/userver_benchmark/src/CMakeLists.txt b/frameworks/C++/userver/userver_benchmark/src/CMakeLists.txt new file mode 100644 index 00000000000..ed0f868504a --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/CMakeLists.txt @@ -0,0 +1,17 @@ +cmake_minimum_required(VERSION 3.12) +project(userver_techempower CXX) + +set(CMAKE_CXX_STANDARD 17) + +file(GLOB_RECURSE SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/controllers/*.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/common/*.cpp +) + +include(userver/cmake/SetupEnvironment.cmake) +include(GNUInstallDirs) + +add_subdirectory(userver) + +add_executable(${PROJECT_NAME} ${SOURCES} userver_techempower.cpp) +target_link_libraries(${PROJECT_NAME} PRIVATE userver-core userver-postgresql) diff --git a/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.cpp b/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.cpp new file mode 100644 index 00000000000..50bb41dc0ec --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.cpp @@ -0,0 +1,38 @@ +#include "db_helpers.hpp" + +#include +#include + +namespace userver_techempower::db_helpers { + +int GenerateRandomId() { + return userver::utils::RandRange(1, kMaxWorldRows + 1); +} + +int GenerateRandomValue() { + return userver::utils::RandRange(1, kMaxWorldRows + 1); +} + +userver::formats::json::Value Serialize( + const WorldTableRow& value, + userver::formats::serialize::To) { + return userver::formats::json::MakeObject("id", value.id, "randomNumber", + value.random_number); +} + +int ParseParamFromQuery(const userver::server::http::HttpRequest& request, + const std::string& name) { + const auto& arg_str = request.GetArg(name); + if (arg_str.empty()) { + return 1; + } + + try { + int value = std::stoi(arg_str); + return std::min(500, std::max(1, value)); + } catch (const std::invalid_argument&) { + return 1; + } +} + +} // namespace userver_techempower::db_helpers diff --git a/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.hpp b/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.hpp new file mode 100644 index 00000000000..3e22462a27e --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/common/db_helpers.hpp @@ -0,0 +1,32 @@ +#pragma once + +#include +#include +#include +#include + +namespace userver_techempower::db_helpers { + +constexpr int kMaxWorldRows = 10000; +const userver::storages::postgres::Query kSelectRowQuery{ + "SELECT id, randomNumber FROM World WHERE id = $1"}; +constexpr auto kClusterHostType = + userver::storages::postgres::ClusterHostType::kMaster; +constexpr std::string_view kDbComponentName = "hello-world-db"; + +struct WorldTableRow final { + int id; + int random_number; +}; + +int GenerateRandomId(); +int GenerateRandomValue(); + +userver::formats::json::Value Serialize( + const WorldTableRow& value, + userver::formats::serialize::To); + +int ParseParamFromQuery(const userver::server::http::HttpRequest& request, + const std::string& name); + +} // namespace userver_techempower::db_helpers diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.cpp new file mode 100644 index 00000000000..b11d05e4c66 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.cpp @@ -0,0 +1,33 @@ +#include "handler.hpp" + +#include + +#include + +namespace userver_techempower::cached_queries { + +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : userver::server::handlers::HttpHandlerJsonBase{config, context}, + cache_{context.FindComponent()}, + query_arg_name_{"count"} {} + +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const { + const auto queries_count = + db_helpers::ParseParamFromQuery(request, query_arg_name_); + + boost::container::small_vector result( + queries_count); + + const auto cache_ptr = cache_.Get(); + const auto& cache = *cache_ptr; + std::generate(result.begin(), result.end(), + [&cache] { return cache.at(db_helpers::GenerateRandomId()); }); + + return userver::formats::json::ValueBuilder{result}.ExtractValue(); +} + +} // namespace userver_techempower::cached_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.hpp new file mode 100644 index 00000000000..8f631462f59 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/handler.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#include "world_cache_component.hpp" + +namespace userver_techempower::cached_queries { + +class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + public: + static constexpr std::string_view kName = "cached-queries-handler"; + + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + userver::formats::json::Value HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const final; + + private: + const WorldCacheComponent& cache_; + + const std::string query_arg_name_; +}; + +} // namespace userver_techempower::cached_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.cpp new file mode 100644 index 00000000000..087e4f86a42 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.cpp @@ -0,0 +1,21 @@ +#include "world_cache_component.hpp" + +namespace userver_techempower::cached_queries { + +WorldCache::WorldCache() { data_.reserve(db_helpers::kMaxWorldRows + 1); } + +std::size_t WorldCache::size() const { return data_.size(); } + +void WorldCache::insert_or_assign(int key, db_helpers::WorldTableRow&& row) { + if (size() <= static_cast(key)) { + data_.resize(key + 1); + } + + data_[key] = row; +} + +const db_helpers::WorldTableRow& WorldCache::at(size_t ind) const { + return data_[ind]; +} + +} // namespace userver_techempower::cached_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.hpp new file mode 100644 index 00000000000..aea8e5df2e7 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/cached_queries/world_cache_component.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include + +#include "../../common/db_helpers.hpp" + +#include + +namespace userver_techempower::cached_queries { + +class WorldCache final { + public: + WorldCache(); + + std::size_t size() const; + void insert_or_assign(int key, db_helpers::WorldTableRow&& row); + + const db_helpers::WorldTableRow& at(size_t ind) const; + + private: + std::vector data_; +}; + +struct WorldCachePolicy final { + static constexpr std::string_view kName = "world-pg-cache"; + using ValueType = db_helpers::WorldTableRow; + using CacheContainer = WorldCache; + static constexpr auto kKeyMember = &db_helpers::WorldTableRow::id; + static constexpr const char* kQuery = "SELECT id, randomNumber FROM World"; + static constexpr const char* kUpdatedField = ""; + static constexpr auto kClusterHostType = db_helpers::kClusterHostType; +}; + +using WorldCacheComponent = userver::components::PostgreCache; + +} // namespace userver_techempower::cached_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.cpp new file mode 100644 index 00000000000..ed48b6ea138 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.cpp @@ -0,0 +1,12 @@ +#include "handler.hpp" + +namespace userver_techempower::json { + +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest&, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const { + return userver::formats::json::MakeObject("message", "Hello, World!"); +} + +} // namespace userver_techempower::json diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.hpp new file mode 100644 index 00000000000..706022eb775 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/json/handler.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include + +namespace userver_techempower::json { + +class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + public: + static constexpr std::string_view kName = "json-handler"; + + using HttpHandlerJsonBase::HttpHandlerJsonBase; + + userver::formats::json::Value HandleRequestJsonThrow( + const userver::server::http::HttpRequest&, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const final; +}; + +} // namespace userver_techempower::json diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.cpp new file mode 100644 index 00000000000..c43b0685448 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.cpp @@ -0,0 +1,44 @@ +#include "handler.hpp" + +#include "../../common/db_helpers.hpp" + +#include +#include +#include + +#include + +namespace userver_techempower::multiple_queries { + +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : userver::server::handlers::HttpHandlerJsonBase{config, context}, + pg_{context + .FindComponent( + db_helpers::kDbComponentName) + .GetCluster()}, + query_arg_name_{"queries"} {} + +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const { + const auto queries_count = + db_helpers::ParseParamFromQuery(request, query_arg_name_); + + boost::container::small_vector random_ids(queries_count); + std::generate(random_ids.begin(), random_ids.end(), + db_helpers::GenerateRandomId); + + boost::container::small_vector result{}; + for (auto id : random_ids) { + result.push_back(pg_->Execute(db_helpers::kClusterHostType, + db_helpers::kSelectRowQuery, id) + .AsSingleRow( + userver::storages::postgres::kRowTag)); + } + + return userver::formats::json::ValueBuilder{result}.ExtractValue(); +} + +} // namespace userver_techempower::multiple_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.hpp new file mode 100644 index 00000000000..295e71dbfa1 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/multiple_queries/handler.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include +#include + +namespace userver_techempower::multiple_queries { + +class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + public: + static constexpr std::string_view kName = "multiple-queries-handler"; + + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + userver::formats::json::Value HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const final; + + private: + const userver::storages::postgres::ClusterPtr pg_; + + const std::string query_arg_name_; +}; + +} // namespace userver_techempower::multiple_queries diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.cpp new file mode 100644 index 00000000000..6affae01cc7 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.cpp @@ -0,0 +1,12 @@ +#include "handler.hpp" + +namespace userver_techempower::plaintext { + +std::string Handler::HandleRequestThrow( + const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const { + request.GetHttpResponse().SetContentType("text/plain"); + return "Hello, World!"; +} + +} // namespace userver_techempower::plaintext diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.hpp new file mode 100644 index 00000000000..3539c3808b4 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/plaintext/handler.hpp @@ -0,0 +1,18 @@ +#pragma once + +#include + +namespace userver_techempower::plaintext { + +class Handler final : public userver::server::handlers::HttpHandlerBase { + public: + static constexpr std::string_view kName = "plaintext-handler"; + + using HttpHandlerBase::HttpHandlerBase; + + std::string HandleRequestThrow( + const userver::server::http::HttpRequest& request, + userver::server::request::RequestContext&) const final; +}; + +} // namespace userver_techempower::plaintext diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.cpp new file mode 100644 index 00000000000..b7d5e5264f9 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.cpp @@ -0,0 +1,31 @@ +#include "handler.hpp" + +#include "../../common/db_helpers.hpp" + +#include +#include + +namespace userver_techempower::single_query { + +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : userver::server::handlers::HttpHandlerJsonBase{config, context}, + pg_{context + .FindComponent( + db_helpers::kDbComponentName) + .GetCluster()} {} + +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest&, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const { + const auto row = + pg_->Execute(db_helpers::kClusterHostType, db_helpers::kSelectRowQuery, + db_helpers::GenerateRandomId()) + .AsSingleRow( + userver::storages::postgres::kRowTag); + + return db_helpers::Serialize(row, {}); +} + +} // namespace userver_techempower::single_query diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.hpp new file mode 100644 index 00000000000..9e7812ee9ad --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/single_query/handler.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include + +#include + +namespace userver_techempower::single_query { + +class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + public: + static constexpr std::string_view kName = "single-query-handler"; + + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + userver::formats::json::Value HandleRequestJsonThrow( + const userver::server::http::HttpRequest&, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const final; + + private: + const userver::storages::postgres::ClusterPtr pg_; +}; + +} // namespace userver_techempower::single_query diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.cpp b/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.cpp new file mode 100644 index 00000000000..ef997115d1e --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.cpp @@ -0,0 +1,65 @@ +#include "handler.hpp" + +#include "../../common/db_helpers.hpp" + +#include +#include +#include + +#include + +namespace userver_techempower::updates { + +namespace { + +constexpr const char* kUpdateQueryStr{R"( +UPDATE World w SET + randomNumber = new_numbers.randomNumber +FROM ( SELECT + UNNEST($1) as id, + UNNEST($2) as randomNumber +) new_numbers +WHERE w.id = new_numbers.id +)"}; + +} + +Handler::Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context) + : userver::server::handlers::HttpHandlerJsonBase{config, context}, + pg_{context.FindComponent("hello-world-db") + .GetCluster()}, + query_arg_name_{"queries"}, + update_query_{kUpdateQueryStr} {} + +userver::formats::json::Value Handler::HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const { + const auto queries_count = + db_helpers::ParseParamFromQuery(request, query_arg_name_); + + std::vector random_ids(queries_count); + std::generate(random_ids.begin(), random_ids.end(), + db_helpers::GenerateRandomId); + std::sort(random_ids.begin(), random_ids.end()); + + boost::container::small_vector result{}; + for (auto id : random_ids) { + result.push_back(pg_->Execute(db_helpers::kClusterHostType, + db_helpers::kSelectRowQuery, id) + .AsSingleRow( + userver::storages::postgres::kRowTag)); + } + + std::vector random_numbers(queries_count); + std::generate(random_numbers.begin(), random_numbers.end(), + db_helpers::GenerateRandomValue); + + pg_->Execute(db_helpers::kClusterHostType, update_query_, random_ids, + random_numbers); + + return userver::formats::json::ValueBuilder{result}.ExtractValue(); +} + +} // namespace userver_techempower::updates diff --git a/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.hpp b/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.hpp new file mode 100644 index 00000000000..ec698afbb61 --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/controllers/updates/handler.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +namespace userver_techempower::updates { + +class Handler final : public userver::server::handlers::HttpHandlerJsonBase { + public: + static constexpr std::string_view kName = "updates-handler"; + + Handler(const userver::components::ComponentConfig& config, + const userver::components::ComponentContext& context); + + userver::formats::json::Value HandleRequestJsonThrow( + const userver::server::http::HttpRequest& request, + const userver::formats::json::Value&, + userver::server::request::RequestContext&) const final; + + private: + const userver::storages::postgres::ClusterPtr pg_; + + const std::string query_arg_name_; + const userver::storages::postgres::Query update_query_; +}; + +} // namespace userver_techempower::updates diff --git a/frameworks/C++/userver/userver_benchmark/src/userver_techempower.cpp b/frameworks/C++/userver/userver_benchmark/src/userver_techempower.cpp new file mode 100644 index 00000000000..a977ee9356d --- /dev/null +++ b/frameworks/C++/userver/userver_benchmark/src/userver_techempower.cpp @@ -0,0 +1,38 @@ +#include +#include +#include + +#include +#include + +#include "controllers/cached_queries/handler.hpp" +#include "controllers/json/handler.hpp" +#include "controllers/multiple_queries/handler.hpp" +#include "controllers/plaintext/handler.hpp" +#include "controllers/single_query/handler.hpp" +#include "controllers/updates/handler.hpp" + +namespace userver_techempower { + +int Main(int argc, char* argv[]) { + auto component_list = + userver::components::MinimalServerComponentList() + .Append() + .Append() + .Append("hello-world-db") + .Append() + .Append() + .Append() + .Append() + .Append() + .Append() + .Append(); + + return userver::utils::DaemonMain(argc, argv, component_list); +} + +} // namespace userver_techempower + +int main(int argc, char* argv[]) { + return userver_techempower::Main(argc, argv); +}