userver: userver/storages/clickhouse/cluster.hpp Source File
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
cluster.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/clickhouse/cluster.hpp
4/// @brief @copybrief storages::clickhouse::Cluster
5
6#include <atomic>
7#include <string>
8#include <string_view>
9#include <vector>
10
11#include <userver/clients/dns/resolver_fwd.hpp>
12#include <userver/components/component_fwd.hpp>
13
14#include <userver/storages/clickhouse/fwd.hpp>
15#include <userver/storages/clickhouse/impl/insertion_request.hpp>
16#include <userver/storages/clickhouse/impl/pool.hpp>
17#include <userver/storages/clickhouse/options.hpp>
18#include <userver/storages/clickhouse/query.hpp>
19#include <userver/utils/statistics/writer.hpp>
20
21USERVER_NAMESPACE_BEGIN
22
23namespace storages::clickhouse {
24
25class ExecutionResult;
26
27namespace impl {
28struct ClickhouseSettings;
29}
30
31/// @ingroup userver_clients
32///
33/// @brief Interface for executing queries on a cluster of ClickHouse servers.
34///
35/// Usually retrieved from components::ClickHouse component.
36class Cluster final {
37public:
38 /// Cluster constructor
39 /// @param resolver asynchronous DNS resolver
40 /// @param settings struct with settings fields:
41 /// endpoints - list of endpoints (host + port)
42 /// auth_settings - authentication settings (user, password, database)
43 /// @param config components::ClickHouse component config
45 clients::dns::Resolver& resolver,
46 const impl::ClickhouseSettings& settings,
47 const components::ComponentConfig& config
48 );
49 /// Cluster destructor
51
52 Cluster(const Cluster&) = delete;
53
54 /// @brief Execute a statement at some host of the cluster
55 /// with args as query parameters.
56 template <typename... Args>
57 ExecutionResult Execute(const Query& query, const Args&... args) const;
58
59 /// @brief Execute a statement with specified command control settings
60 /// at some host of the cluster with args as query parameters.
61 template <typename... Args>
62 ExecutionResult Execute(OptionalCommandControl, const Query& query, const Args&... args) const;
63
64 /// @brief Insert data at some host of the cluster;
65 /// `T` is expected to be a struct of vectors of same length.
66 /// @param table_name table to insert into
67 /// @param column_names names of columns of the table
68 /// @param data data to insert
69 /// See @ref clickhouse_io for better understanding of T's requirements.
70 template <typename T>
71 void Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data) const;
72
73 /// @brief Insert data with specified command control settings
74 /// at some host of the cluster;
75 /// `T` is expected to be a struct of vectors of same length.
76 /// @param optional_cc optional request QOS overrides
77 /// @param table_name table to insert into
78 /// @param column_names names of columns of the table
79 /// @param data data to insert
80 /// See @ref clickhouse_io for better understanding of T's requirements.
81 template <typename T>
82 void Insert(
83 OptionalCommandControl optional_cc,
84 const std::string& table_name,
85 const std::vector<std::string_view>& column_names,
86 const T& data
87 ) const;
88
89 /// @brief Insert data at some host of the cluster;
90 /// `Container` is expected to be an iterable of clickhouse-mapped type.
91 /// @param table_name table to insert into
92 /// @param column_names names of columns of the table
93 /// @param data data to insert
94 /// See @ref clickhouse_io for better understanding of
95 /// `Container::value_type`'s requirements.
96 /// @note This version of insert is less performant than `Insert` (it makes 2
97 /// copies of data instead of just 1 copy) due to implementation details, so
98 /// consider using less convenient but more performant analogue if performance
99 /// is a concern.
100 template <typename Container>
101 void InsertRows(
102 const std::string& table_name,
103 const std::vector<std::string_view>& column_names,
104 const Container& data
105 ) const;
106
107 /// @brief Insert data with specified command control settings
108 /// at some host of the cluster;
109 /// `Container` is expected to be an iterable of clickhouse-mapped type.
110 /// @param optional_cc optional request QOS overrides
111 /// @param table_name table to insert into
112 /// @param column_names names of columns of the table
113 /// @param data data to insert
114 /// See @ref clickhouse_io for better understanding of
115 /// `Container::value_type`'s requirements.
116 /// @note This version of insert is less performant than `Insert` (it makes 2
117 /// copies of data instead of just 1 copy) due to implementation details, so
118 /// consider using less convenient but more performant analogue if performance
119 /// is a concern.
120 template <typename Container>
121 void InsertRows(
122 OptionalCommandControl optional_cc,
123 const std::string& table_name,
124 const std::vector<std::string_view>& column_names,
125 const Container& data
126 ) const;
127
128 /// Write cluster statistics
129 void WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const;
130
131 /// Exception that is thrown if all specified endpoints are unavailable
132 class NoAvailablePoolError : public std::runtime_error {
133 using std::runtime_error::runtime_error;
134 };
135
136private:
137 void DoInsert(OptionalCommandControl, const impl::InsertionRequest& request) const;
138
139 ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const;
140
141 const impl::Pool& GetPool() const;
142
143 std::vector<impl::Pool> pools_;
144 mutable std::atomic<std::size_t> current_pool_ind_{0};
145};
146
147template <typename T>
148void Cluster::Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data)
149 const {
150 Insert(OptionalCommandControl{}, table_name, column_names, data);
151}
152
153template <typename T>
154void Cluster::Insert(
155 OptionalCommandControl optional_cc,
156 const std::string& table_name,
157 const std::vector<std::string_view>& column_names,
158 const T& data
159) const {
160 const auto request = impl::InsertionRequest::Create(table_name, column_names, data);
161
162 DoInsert(optional_cc, request);
163}
164
165template <typename Container>
166void Cluster::InsertRows(
167 const std::string& table_name,
168 const std::vector<std::string_view>& column_names,
169 const Container& data
170) const {
171 InsertRows(OptionalCommandControl{}, table_name, column_names, data);
172}
173
174template <typename Container>
175void Cluster::InsertRows(
176 OptionalCommandControl optional_cc,
177 const std::string& table_name,
178 const std::vector<std::string_view>& column_names,
179 const Container& data
180) const {
181 if (data.empty()) return;
182
183 const auto request = impl::InsertionRequest::CreateFromRows(table_name, column_names, data);
184
185 DoInsert(optional_cc, request);
186}
187
188template <typename... Args>
189ExecutionResult Cluster::Execute(const Query& query, const Args&... args) const {
190 return Execute(OptionalCommandControl{}, query, args...);
191}
192
193template <typename... Args>
194ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc, const Query& query, const Args&... args) const {
195 const auto formatted_query = query.WithArgs(args...);
196 return DoExecute(optional_cc, formatted_query);
197}
198
199} // namespace storages::clickhouse
200
201USERVER_NAMESPACE_END