userver: userver/storages/clickhouse/cluster.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
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 {
37 public:
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
44 Cluster(clients::dns::Resolver& resolver,
45 const impl::ClickhouseSettings& settings,
46 const components::ComponentConfig& config);
47 /// Cluster destructor
49
50 Cluster(const Cluster&) = delete;
51
52 /// @brief Execute a statement at some host of the cluster
53 /// with args as query parameters.
54 template <typename... Args>
55 ExecutionResult Execute(const Query& query, const Args&... args) const;
56
57 /// @brief Execute a statement with specified command control settings
58 /// at some host of the cluster with args as query parameters.
59 template <typename... Args>
60 ExecutionResult Execute(OptionalCommandControl, const Query& query,
61 const Args&... args) const;
62
63 /// @brief Insert data at some host of the cluster;
64 /// `T` is expected to be a struct of vectors of same length.
65 /// @param table_name table to insert into
66 /// @param column_names names of columns of the table
67 /// @param data data to insert
68 /// See @ref clickhouse_io for better understanding of T's requirements.
69 template <typename T>
70 void Insert(const std::string& table_name,
71 const std::vector<std::string_view>& column_names,
72 const T& data) const;
73
74 /// @brief Insert data with specified command control settings
75 /// at some host of the cluster;
76 /// `T` is expected to be a struct of vectors of same length.
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(OptionalCommandControl, const std::string& table_name,
83 const std::vector<std::string_view>& column_names,
84 const T& data) const;
85
86 /// @brief Insert data at some host of the cluster;
87 /// `Container` is expected to be an iterable of clickhouse-mapped type.
88 /// @param table_name table to insert into
89 /// @param column_names names of columns of the table
90 /// @param data data to insert
91 /// See @ref clickhouse_io for better understanding of
92 /// `Container::value_type`'s requirements.
93 /// @note This version of insert is less performant than `Insert` (it makes 2
94 /// copies of data instead of just 1 copy) due to implementation details, so
95 /// consider using less convenient but more performant analogue if performance
96 /// is a concern.
97 template <typename Container>
98 void InsertRows(const std::string& table_name,
99 const std::vector<std::string_view>& column_names,
100 const Container& data) const;
101
102 /// @brief Insert data with specified command control settings
103 /// at some host of the cluster;
104 /// `Container` is expected to be an iterable of clickhouse-mapped type.
105 /// @param table_name table to insert into
106 /// @param column_names names of columns of the table
107 /// @param data data to insert
108 /// See @ref clickhouse_io for better understanding of
109 /// `Container::value_type`'s requirements.
110 /// @note This version of insert is less performant than `Insert` (it makes 2
111 /// copies of data instead of just 1 copy) due to implementation details, so
112 /// consider using less convenient but more performant analogue if performance
113 /// is a concern.
114 template <typename Container>
115 void InsertRows(OptionalCommandControl, const std::string& table_name,
116 const std::vector<std::string_view>& column_names,
117 const Container& data) const;
118
119 /// Write cluster statistics
121 USERVER_NAMESPACE::utils::statistics::Writer& writer) const;
122
123 /// Exception that is thrown if all specified endpoints are unavailable
124 class NoAvailablePoolError : public std::runtime_error {
125 using std::runtime_error::runtime_error;
126 };
127
128 private:
129 void DoInsert(OptionalCommandControl,
130 const impl::InsertionRequest& request) const;
131
132 ExecutionResult DoExecute(OptionalCommandControl, const Query& query) const;
133
134 const impl::Pool& GetPool() const;
135
136 std::vector<impl::Pool> pools_;
137 mutable std::atomic<std::size_t> current_pool_ind_{0};
138};
139
140template <typename T>
141void Cluster::Insert(const std::string& table_name,
142 const std::vector<std::string_view>& column_names,
143 const T& data) const {
144 Insert(OptionalCommandControl{}, table_name, column_names, data);
145}
146
147template <typename T>
148void Cluster::Insert(OptionalCommandControl optional_cc,
149 const std::string& table_name,
150 const std::vector<std::string_view>& column_names,
151 const T& data) const {
152 const auto request =
153 impl::InsertionRequest::Create(table_name, column_names, data);
154
155 DoInsert(optional_cc, request);
156}
157
158template <typename Container>
159void Cluster::InsertRows(const std::string& table_name,
160 const std::vector<std::string_view>& column_names,
161 const Container& data) const {
162 InsertRows(OptionalCommandControl{}, table_name, column_names, data);
163}
164
165template <typename Container>
166void Cluster::InsertRows(OptionalCommandControl optional_cc,
167 const std::string& table_name,
168 const std::vector<std::string_view>& column_names,
169 const Container& data) const {
170 if (data.empty()) return;
171
172 const auto request =
173 impl::InsertionRequest::CreateFromRows(table_name, column_names, data);
174
175 DoInsert(optional_cc, request);
176}
177
178template <typename... Args>
179ExecutionResult Cluster::Execute(const Query& query,
180 const Args&... args) const {
181 return Execute(OptionalCommandControl{}, query, args...);
182}
183
184template <typename... Args>
185ExecutionResult Cluster::Execute(OptionalCommandControl optional_cc,
186 const Query& query,
187 const Args&... args) const {
188 const auto formatted_query = query.WithArgs(args...);
189 return DoExecute(optional_cc, formatted_query);
190}
191
192} // namespace storages::clickhouse
193
194USERVER_NAMESPACE_END