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