userver: userver/ydb/table.hpp Source File
Loading...
Searching...
No Matches
table.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/ydb/table.hpp
4/// @brief @copybrief ydb::TableClient
5
6#include <atomic>
7#include <memory>
8
9#include <ydb-cpp-sdk/client/query/client.h>
10#include <ydb-cpp-sdk/client/query/query.h>
11#include <ydb-cpp-sdk/client/table/table.h>
12
13#include <userver/dynamic_config/source.hpp>
14#include <userver/utils/not_null.hpp>
15#include <userver/utils/statistics/fwd.hpp>
16
17#include <userver/ydb/builder.hpp>
18#include <userver/ydb/query.hpp>
19#include <userver/ydb/response.hpp>
20#include <userver/ydb/settings.hpp>
21#include <userver/ydb/transaction.hpp>
22
23namespace NMonitoring {
24class TMetricRegistry;
25} // namespace NMonitoring
26
27USERVER_NAMESPACE_BEGIN
28
29namespace engine {
30class Deadline;
31} // namespace engine
32
33namespace tracing {
34class Span;
35} // namespace tracing
36
37namespace utils {
38class RetryBudget;
39} // namespace utils
40
41namespace ydb {
42
43namespace impl {
44struct Stats;
45struct TableSettings;
46struct Connection;
47class Driver;
48template <typename Settings>
49class RequestContext;
50enum class IsStreaming : bool {};
51} // namespace impl
52
53using DescribePathSettings = NYdb::NScheme::TDescribePathSettings;
54using ListDirectorySettings = NYdb::NScheme::TListDirectorySettings;
55using MakeDirectorySettings = NYdb::NScheme::TMakeDirectorySettings;
56using RemoveDirectorySettings = NYdb::NScheme::TRemoveDirectorySettings;
57
58using BulkUpsertSettings = NYdb::NTable::TBulkUpsertSettings;
59using CreateTableSettings = NYdb::NTable::TCreateTableSettings;
60using DescribeTableSettings = NYdb::NTable::TDescribeTableSettings;
61using DropTableSettings = NYdb::NTable::TDropTableSettings;
62using ScanQuerySettings = NYdb::NTable::TStreamExecScanQuerySettings;
63
64/// @brief A dynamic transaction name for @see TableClient::Begin or
65/// @see TableClient::RetryTx.
66///
67/// @warning Make sure that transaction name has low cardinality.
68/// If transaction name is unique for every call, per-transaction metrics will overflow metrics quota,
69/// and metrics will become unusable.
70using DynamicTransactionName = utils::StrongTypedef<struct DynamicTransactionNameTag, std::string>;
71
72/// @brief YDB Table client
73class TableClient final {
74public:
75 /// @cond
76 // For internal use only.
77 TableClient(
78 impl::TableSettings settings,
79 OperationSettings operation_settings,
80 dynamic_config::Source config_source,
81 std::shared_ptr<impl::Driver> driver
82 );
83
84 ~TableClient();
85 /// @endcond
86
87 /// Query for creating/deleting tables
88 void ExecuteSchemeQuery(const std::string& query);
89
90 void MakeDirectory(const std::string& path, MakeDirectorySettings query_settings = {});
91 void RemoveDirectory(const std::string& path, RemoveDirectorySettings query_settings = {});
92
93 NYdb::NScheme::TDescribePathResult DescribePath(std::string_view path, DescribePathSettings query_settings = {});
94 NYdb::NScheme::TListDirectoryResult ListDirectory(std::string_view path, ListDirectorySettings query_settings = {});
95
96 NYdb::NTable::TDescribeTableResult DescribeTable(std::string_view path, DescribeTableSettings query_settings = {});
97 void CreateTable(
98 std::string_view path,
99 NYdb::NTable::TTableDescription&& table_desc,
100 CreateTableSettings query_settings = {}
101 );
102 void DropTable(std::string_view path, DropTableSettings query_settings = {});
103
104 /// @name Data queries execution
105 /// Execute a single data query outside of transactions. Query parameters are
106 /// passed in `Args` as "string key - value" pairs:
107 ///
108 /// @code
109 /// client.ExecuteDataQuery(query, "name1", value1, "name2", value2, ...);
110 /// @endcode
111 ///
112 /// @warning ExecuteDataQuery returns no more than 1000 rows. Consider @ref ExecuteQuery() instead, but make sure
113 /// that it works for your case.
114 ///
115 /// Use ydb::PreparedArgsBuilder for storing a generic buffer of query params if needed.
116 ///
117 /// It is convenient to keep YQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
118 /// for more info.
119 ///
120 /// @{
121 template <typename... Args>
122 ExecuteResponse ExecuteDataQuery(const Query& query, Args&&... args);
123
124 template <typename... Args>
125 ExecuteResponse ExecuteDataQuery(OperationSettings settings, const Query& query, Args&&... args);
126
127 ExecuteResponse ExecuteDataQuery(OperationSettings settings, const Query& query, PreparedArgsBuilder&& builder);
128
129 ExecuteResponse ExecuteDataQuery(
130 QuerySettings query_settings,
131 OperationSettings settings,
132 const Query& query,
133 PreparedArgsBuilder&& builder
134 );
135 /// @}
136
137 /// @name Transactions with retry
138 /// @brief Execute a transactional function with automatic retries.
139 ///
140 /// The user-provided function receives a TxActor for executing queries
141 /// and returns TxAction::kCommit or TxAction::kRollback. On transient
142 /// errors the whole function is retried automatically.
143 ///
144 /// @code
145 /// client.RetryTx("my_tx", {.retries = 3},
146 /// [](ydb::TxActor& tx) {
147 /// tx.Execute(query, "$id", 1);
148 /// return ydb::TxAction::kCommit;
149 /// });
150 /// @endcode
151 ///
152 /// @{
153 void RetryTx(utils::StringLiteral transaction_name, RetryTxSettings retry_settings, RetryTxFunction fn);
154
155 /// @warning Make sure that `transaction_name` has low cardinality.
156 void RetryTx(DynamicTransactionName transaction_name, RetryTxSettings retry_settings, RetryTxFunction fn);
157 /// @}
158
159 /// @name Transactions (deprecated)
160 /// @brief Begin a transaction with the specified name. The settings are used
161 /// for the `BEGIN` statement.
162 /// @deprecated Use RetryTx instead for automatic retry support.
163 /// @see ydb::Transaction
164 ///
165 /// @{
166 Transaction Begin(utils::StringLiteral transaction_name, OperationSettings settings = {});
167
168 /// @warning Make sure that `transaction_name` has low cardinality.
169 /// If `transaction_name` is unique for every call, per-transaction metrics will overflow metrics quota,
170 /// and metrics will become unusable.
171 Transaction Begin(DynamicTransactionName transaction_name, OperationSettings settings = {});
172
173 Transaction Begin(utils::StringLiteral transaction_name, TransactionMode tx_mode);
174 /// @}
175
176 /// Builder for storing dynamic query params.
177 PreparedArgsBuilder GetBuilder() const;
178
179 /// Efficiently write large ranges of table data.
181 std::string_view table,
182 NYdb::TValue&& rows,
183 OperationSettings settings = {},
184 BulkUpsertSettings query_settings = {}
185 );
186
187 /// Efficiently write large ranges of table data.
188 /// The passed range of structs is serialized to TValue.
189 template <typename RangeOfStructs>
190 void BulkUpsert(std::string_view table, const RangeOfStructs& rows, OperationSettings settings = {});
191
192 /// Efficiently read large ranges of table data.
193 ReadTableResults ReadTable(
194 std::string_view table,
195 NYdb::NTable::TReadTableSettings&& read_settings = {},
196 OperationSettings settings = {}
197 );
198
199 /// @name Scan queries execution
200 /// A separate data access interface designed primarily for performing
201 /// analytical ad-hoc queries.
202 /// @{
203 template <typename... Args>
204 ScanQueryResults ExecuteScanQuery(const Query& query, Args&&... args);
205
206 template <typename... Args>
207 ScanQueryResults ExecuteScanQuery(
208 ScanQuerySettings&& scan_settings,
209 OperationSettings settings,
210 const Query& query,
211 Args&&... args
212 );
213
214 ScanQueryResults ExecuteScanQuery(
215 ScanQuerySettings&& scan_settings,
216 OperationSettings settings,
217 const Query& query,
218 PreparedArgsBuilder&& builder
219 );
220 /// @}
221
222 /// @name Queries execution (using YDB Query SDK)
223 /// Execute a single query outside of transactions. Query parameters are
224 /// passed in `Args` as "string key - value" pairs:
225 ///
226 /// @code
227 /// client.ExecuteQuery(query, "name1", value1, "name2", value2, ...);
228 /// @endcode
229 ///
230 /// Use ydb::PreparedArgsBuilder for storing a generic buffer of query params if needed.
231 ///
232 /// If both exec_settings and settings args are passed,
233 /// exec_settings.client_timeout_ms and exec_settings.trace_id are ignored
234 /// and are overwritten by settings.client_timeout_ms and settings.trace_id.
235 ///
236 /// It is convenient to keep YQL queries in separate files, see @ref scripts/docs/en/userver/sql_files.md
237 /// for more info.
238 /// @{
239 template <typename... Args>
240 ExecuteResponse ExecuteQuery(const Query& query, Args&&... args);
241
242 template <typename... Args>
243 ExecuteResponse ExecuteQuery(OperationSettings settings, const Query& query, Args&&... args);
244
245 ExecuteResponse ExecuteQuery(OperationSettings settings, const Query& query, PreparedArgsBuilder&& builder);
246
247 ExecuteResponse ExecuteQuery(
248 NYdb::NQuery::TExecuteQuerySettings&& exec_settings,
249 OperationSettings settings,
250 const Query& query,
251 PreparedArgsBuilder&& builder
252 );
253 /// @}
254
255 /// @cond
256 // For internal use only.
257 friend void DumpMetric(utils::statistics::Writer& writer, const TableClient& table_client);
258 /// @endcond
259
260 /// Get native table, query or scheme client
261 /// @warning Use with care! Facilities from
262 /// `<core/include/userver/drivers/subscribable_futures.hpp>` can help with
263 /// non-blocking wait operations.
264 /// @{
265 NYdb::NTable::TTableClient& GetNativeTableClient();
266
267 NYdb::NQuery::TQueryClient& GetNativeQueryClient();
268
269 NYdb::NScheme::TSchemeClient& GetNativeSchemeClient();
270 /// @}
271
272 utils::RetryBudget& GetRetryBudget();
273
274 /// @cond
275 // For internal use only: runtime database routing (YDB_DATABASE_ROUTING).
276 // Redirects this client to use `target`'s connection for subsequent
277 // operations (pass *this to revert to its own), keeping `target` alive while
278 // it stays routed here.
279 void SwitchConnectionTo(const TableClient& target) noexcept;
280
281 template <typename Settings>
282 impl::RequestContext<Settings> MakeRequestContext(
283 const Query& query,
284 Settings&& settings,
285 impl::IsStreaming is_streaming = impl::IsStreaming{false},
286 tracing::Span* custom_parent_span = nullptr,
287 engine::Deadline parent_deadline = {}
288 );
289 /// @endcond
290
291private:
292 friend class Transaction;
293 friend class TxActor;
294 template <typename Settings>
295 friend class impl::RequestContext;
296
297 // Currently active connection (never null after construction).
298 impl::Connection& CurrentConnection() const noexcept;
299
300 void Select1();
301
302 NYdb::NQuery::TExecuteQuerySettings ToExecuteQuerySettings(const QuerySettings& query_settings) const;
303
304 template <typename... Args>
305 PreparedArgsBuilder MakeBuilder(Args&&... args);
306
307 // Func: (TSession, const std::string& full_path, const Settings&)
308 // -> NThreading::TFuture<T>
309 // OR
310 // (TTableClient&, const std::string& full_path, const Settings&)
311 // -> NThreading::TFuture<T>
312 // ExecuteSchemeQueryImpl -> T
313 template <typename QuerySettings, typename Func>
314 auto ExecuteWithPathImpl(
315 std::string_view path,
316 std::string_view operation_name,
317 OperationSettings settings,
318 QuerySettings&& query_settings,
319 Func&& func
320 );
321
322 dynamic_config::Source config_source_;
323 const OperationSettings default_settings_;
324 std::unique_ptr<impl::Stats> stats_;
325
326 // Connections are permanent: none is destroyed while the component lives
327 // (each is held by its home `own_connection_`), so the raw selector below is
328 // always valid. `routed_connection_` additionally keeps the routing target
329 // alive. If we ever start freeing detached connections, switch to rcu.
330 utils::SharedRef<impl::Connection> own_connection_;
331 utils::SharedRef<impl::Connection> routed_connection_;
332 // Lock-free selector read by every operation; swapped by SwitchConnectionTo().
333 std::atomic<utils::NotNull<impl::Connection*>> current_connection_;
334};
335
336template <typename... Args>
337PreparedArgsBuilder TableClient::MakeBuilder(Args&&... args) {
338 auto builder = GetBuilder();
339 builder.AddParams(std::forward<Args>(args)...);
340 return builder;
341}
342
343template <typename... Args>
344ExecuteResponse TableClient::ExecuteDataQuery(const Query& query, Args&&... args) {
345 return ExecuteDataQuery(OperationSettings{}, query, MakeBuilder(std::forward<Args>(args)...));
346}
347
348template <typename... Args>
349ExecuteResponse TableClient::ExecuteDataQuery(OperationSettings settings, const Query& query, Args&&... args) {
350 return ExecuteDataQuery(settings, query, MakeBuilder(std::forward<Args>(args)...));
351}
352
353template <typename RangeOfStructs>
354void TableClient::BulkUpsert(std::string_view table, const RangeOfStructs& rows, OperationSettings settings) {
355 NYdb::TValueBuilder builder;
356 ydb::Write(builder, rows);
357 BulkUpsert(table, builder.Build(), std::move(settings));
358}
359
360template <typename... Args>
361ScanQueryResults TableClient::ExecuteScanQuery(const Query& query, Args&&... args) {
362 return ExecuteScanQuery(ScanQuerySettings{}, OperationSettings{}, query, MakeBuilder(std::forward<Args>(args)...));
363}
364
365template <typename... Args>
366ScanQueryResults TableClient::ExecuteScanQuery(
367 ScanQuerySettings&& scan_settings,
368 OperationSettings settings,
369 const Query& query,
370 Args&&... args
371) {
372 return ExecuteScanQuery(
373 std::move(scan_settings),
374 std::move(settings),
375 query,
376 MakeBuilder(std::forward<Args>(args)...)
377 );
378}
379
380template <typename... Args>
381ExecuteResponse TableClient::ExecuteQuery(const Query& query, Args&&... args) {
382 return ExecuteQuery(OperationSettings{}, query, MakeBuilder(std::forward<Args>(args)...));
383}
384
385template <typename... Args>
386ExecuteResponse TableClient::ExecuteQuery(OperationSettings settings, const Query& query, Args&&... args) {
387 return ExecuteQuery(settings, query, MakeBuilder(std::forward<Args>(args)...));
388}
389
390} // namespace ydb
391
392USERVER_NAMESPACE_END