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;
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