userver: userver/storages/clickhouse/cluster.hpp Source File
Loading...
Searching...
No Matches
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;
26class ParameterStore;
27
28namespace impl {
29struct ClickhouseSettings;
30}
31
32/// @ingroup userver_clients
33///
34/// @brief Interface for executing queries on a cluster of ClickHouse servers.
35///
36/// Usually retrieved from components::ClickHouse component.
37class Cluster final {
38public:
39 /// Cluster constructor
40 /// @param resolver asynchronous DNS resolver
41 /// @param settings struct with settings fields:
42 /// endpoints - list of endpoints (host + port)
43 /// auth_settings - authentication settings (user, password, database)
44 /// @param config components::ClickHouse component config
46 clients::dns::Resolver& resolver,
47 const impl::ClickhouseSettings& settings,
48 const components::ComponentConfig& config
49 );
50 /// Cluster destructor
52
53 Cluster(const Cluster&) = delete;
54
55 /// @brief Execute a statement at some host of the cluster
56 /// with args as query parameters.
57 ///
58 /// It is convinient to keep SQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
59 /// for more info.
60 template <typename... Args>
61 ExecutionResult Execute(const Query& query, const Args&... args) const;
62
63 /// @brief Execute a statement with specified command control settings
64 /// at some host of the cluster with args as query parameters.
65 ///
66 /// It is convinient to keep SQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
67 /// for more info.
68 ///
69 /// # Example usage:
70 /// @snippet clickhouse/src/storages/tests/escape_chtest.cpp basic_usage
71 template <typename... Args>
72 ExecutionResult Execute(OptionalCommandControl, const Query& query, const Args&... args) const;
73
74 /// @overload
75 ExecutionResult Execute(const Query& query, const ParameterStore& params) const;
76
77 /// @overload
78 ExecutionResult Execute(OptionalCommandControl, const Query& query, const ParameterStore& params) const;
79
80 /// @brief Insert data at some host of the cluster;
81 /// `T` is expected to be a struct of vectors of same length.
82 /// @param table_name table to insert into
83 /// @param column_names names of columns of the table
84 /// @param data data to insert
85 /// See @ref clickhouse_io for better understanding of T's requirements.
86 template <typename T>
87 void Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data) const;
88
89 /// @brief Insert data with specified command control settings
90 /// at some host of the cluster;
91 /// `T` is expected to be a struct of vectors of same length.
92 /// @param optional_cc optional request QOS overrides
93 /// @param table_name table to insert into
94 /// @param column_names names of columns of the table
95 /// @param data data to insert
96 /// See @ref clickhouse_io for better understanding of T's requirements.
97 template <typename T>
98 void Insert(
99 OptionalCommandControl optional_cc,
100 const std::string& table_name,
101 const std::vector<std::string_view>& column_names,
102 const T& data
103 ) const;
104
105 /// @brief Insert data at some host of the cluster;
106 /// `Container` is expected to be an iterable of clickhouse-mapped type.
107 /// @param table_name table to insert into
108 /// @param column_names names of columns of the table
109 /// @param data data to insert
110 /// See @ref clickhouse_io for better understanding of
111 /// `Container::value_type`'s requirements.
112 /// @note This version of insert is less performant than `Insert` (it makes 2
113 /// copies of data instead of just 1 copy) due to implementation details, so
114 /// consider using less convenient but more performant analogue if performance
115 /// is a concern.
116 template <typename Container>
117 void InsertRows(
118 const std::string& table_name,
119 const std::vector<std::string_view>& column_names,
120 const Container& data
121 ) const;
122
123 /// @brief Insert data with specified command control settings
124 /// at some host of the cluster;
125 /// `Container` is expected to be an iterable of clickhouse-mapped type.
126 /// @param optional_cc optional request QOS overrides
127 /// @param table_name table to insert into
128 /// @param column_names names of columns of the table
129 /// @param data data to insert
130 /// See @ref clickhouse_io for better understanding of
131 /// `Container::value_type`'s requirements.
132 /// @note This version of insert is less performant than `Insert` (it makes 2
133 /// copies of data instead of just 1 copy) due to implementation details, so
134 /// consider using less convenient but more performant analogue if performance
135 /// is a concern.
136 template <typename Container>
137 void InsertRows(
138 OptionalCommandControl optional_cc,
139 const std::string& table_name,
140 const std::vector<std::string_view>& column_names,
141 const Container& data
142 ) const;
143
144 /// Write cluster statistics
145 void WriteStatistics(USERVER_NAMESPACE::utils::statistics::Writer& writer) const;
146
147 /// Exception that is thrown if all specified endpoints are unavailable
148 class NoAvailablePoolError : public std::runtime_error {
149 using std::runtime_error::runtime_error;
150 };
151
152private:
153 void DoInsert(OptionalCommandControl, const impl::InsertionRequest& request) const;
154
155 ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const;
156
157 const impl::Pool& GetPool() const;
158
159 std::vector<impl::Pool> pools_;
160 mutable std::atomic<std::size_t> current_pool_ind_{0};
161};
162
163template <typename T>
164void Cluster::Insert(const std::string& table_name, const std::vector<std::string_view>& column_names, const T& data)
165 const {
166 Insert(OptionalCommandControl{}, table_name, column_names, data);
167}
168
169template <typename T>
170void Cluster::Insert(
171 OptionalCommandControl optional_cc,
172 const std::string& table_name,
173 const std::vector<std::string_view>& column_names,
174 const T& data
175) const {
176 const auto request = impl::InsertionRequest::Create(table_name, column_names, data);
177
178 DoInsert(optional_cc, request);
179}
180
181template <typename Container>
182void Cluster::InsertRows(
183 const std::string& table_name,
184 const std::vector<std::string_view>& column_names,
185 const Container& data
186) const {
187 InsertRows(OptionalCommandControl{}, table_name, column_names, data);
188}
189
190template <typename Container>
191void Cluster::InsertRows(
192 OptionalCommandControl optional_cc,
193 const std::string& table_name,
194 const std::vector<std::string_view>& column_names,
195 const Container& data
196) const {
197 if (data.empty()) return;
198
199 const auto request = impl::InsertionRequest::CreateFromRows(table_name, column_names, data);
200
201 DoInsert(optional_cc, request);
202}
203
204template <typename... Args>
205ExecutionResult Cluster::Execute(const Query& query, const Args&... args) const {
206 return Execute(OptionalCommandControl{}, query, args...);
207}
208
209template <typename... Args>
210ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc, const Query& query, const Args&... args) const {
211 const auto formatted_query = impl::WithArgs(query, args...);
212 return DoExecute(optional_cc, formatted_query);
213}
214
215} // namespace storages::clickhouse
216
217USERVER_NAMESPACE_END