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 ///
57 /// It is convinient to keep SQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
58 /// for more info.
59 template <typename... Args>
60 ExecutionResult Execute(const Query& query, const Args&... args) const;
61
62 /// @brief Execute a statement with specified command control settings
63 /// at some host of the cluster with args as query parameters.
64 ///
65 /// It is convinient to keep SQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
66 /// for more info.
67 template <typename... Args>
68 ExecutionResult Execute(OptionalCommandControl, const Query& query, const Args&... args) const;
69
70 /// @brief Insert data at some host of the cluster;
71 /// `T` is expected to be a struct of vectors of same length.
72 /// @param table_name table to insert into
73 /// @param column_names names of columns of the table
74 /// @param data data to insert
75 /// See @ref clickhouse_io for better understanding of T's requirements.
76 template <typename T>
77 void Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data) const;
78
79 /// @brief Insert data with specified command control settings
80 /// at some host of the cluster;
81 /// `T` is expected to be a struct of vectors of same length.
82 /// @param optional_cc optional request QOS overrides
83 /// @param table_name table to insert into
84 /// @param column_names names of columns of the table
85 /// @param data data to insert
86 /// See @ref clickhouse_io for better understanding of T's requirements.
87 template <typename T>
88 void Insert(
89 OptionalCommandControl optional_cc,
90 const std::string& table_name,
91 const std::vector<std::string_view>& column_names,
92 const T& data
93 ) const;
94
95 /// @brief Insert data at some host of the cluster;
96 /// `Container` is expected to be an iterable of clickhouse-mapped type.
97 /// @param table_name table to insert into
98 /// @param column_names names of columns of the table
99 /// @param data data to insert
100 /// See @ref clickhouse_io for better understanding of
101 /// `Container::value_type`'s requirements.
102 /// @note This version of insert is less performant than `Insert` (it makes 2
103 /// copies of data instead of just 1 copy) due to implementation details, so
104 /// consider using less convenient but more performant analogue if performance
105 /// is a concern.
106 template <typename Container>
107 void InsertRows(
108 const std::string& table_name,
109 const std::vector<std::string_view>& column_names,
110 const Container& data
111 ) const;
112
113 /// @brief Insert data with specified command control settings
114 /// at some host of the cluster;
115 /// `Container` is expected to be an iterable of clickhouse-mapped type.
116 /// @param optional_cc optional request QOS overrides
117 /// @param table_name table to insert into
118 /// @param column_names names of columns of the table
119 /// @param data data to insert
120 /// See @ref clickhouse_io for better understanding of
121 /// `Container::value_type`'s requirements.
122 /// @note This version of insert is less performant than `Insert` (it makes 2
123 /// copies of data instead of just 1 copy) due to implementation details, so
124 /// consider using less convenient but more performant analogue if performance
125 /// is a concern.
126 template <typename Container>
127 void InsertRows(
128 OptionalCommandControl optional_cc,
129 const std::string& table_name,
130 const std::vector<std::string_view>& column_names,
131 const Container& data
132 ) const;
133
134 /// Write cluster statistics
135 void WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const;
136
137 /// Exception that is thrown if all specified endpoints are unavailable
138 class NoAvailablePoolError : public std::runtime_error {
139 using std::runtime_error::runtime_error;
140 };
141
142private:
143 void DoInsert(OptionalCommandControl, const impl::InsertionRequest& request) const;
144
145 ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const;
146
147 const impl::Pool& GetPool() const;
148
149 std::vector<impl::Pool> pools_;
150 mutable std::atomic<std::size_t> current_pool_ind_{0};
151};
152
153template <typename T>
154void Cluster::Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data)
155 const {
156 Insert(OptionalCommandControl{}, table_name, column_names, data);
157}
158
159template <typename T>
160void Cluster::Insert(
161 OptionalCommandControl optional_cc,
162 const std::string& table_name,
163 const std::vector<std::string_view>& column_names,
164 const T& data
165) const {
166 const auto request = impl::InsertionRequest::Create(table_name, column_names, data);
167
168 DoInsert(optional_cc, request);
169}
170
171template <typename Container>
172void Cluster::InsertRows(
173 const std::string& table_name,
174 const std::vector<std::string_view>& column_names,
175 const Container& data
176) const {
177 InsertRows(OptionalCommandControl{}, table_name, column_names, data);
178}
179
180template <typename Container>
181void Cluster::InsertRows(
182 OptionalCommandControl optional_cc,
183 const std::string& table_name,
184 const std::vector<std::string_view>& column_names,
185 const Container& data
186) const {
187 if (data.empty()) return;
188
189 const auto request = impl::InsertionRequest::CreateFromRows(table_name, column_names, data);
190
191 DoInsert(optional_cc, request);
192}
193
194template <typename... Args>
195ExecutionResult Cluster::Execute(const Query& query, const Args&... args) const {
196 return Execute(OptionalCommandControl{}, query, args...);
197}
198
199template <typename... Args>
200ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc, const Query& query, const Args&... args) const {
201 const auto formatted_query = impl::WithArgs(query, args...);
202 return DoExecute(optional_cc, formatted_query);
203}
204
205} // namespace storages::clickhouse
206
207USERVER_NAMESPACE_END