userver: userver/storages/postgres/options.hpp Source File
Loading...
Searching...
No Matches
options.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/options.hpp
4/// @brief Options
5
6#include <chrono>
7#include <cstdint>
8#include <iosfwd>
9#include <optional>
10#include <string>
11#include <unordered_map>
12#include <unordered_set>
13
14#include <userver/congestion_control/controllers/linear.hpp>
15#include <userver/storages/postgres/postgres_fwd.hpp>
16#include <userver/utils/impl/transparent_hash.hpp>
17#include <userver/utils/str_icase.hpp>
18#include <userver/utils/string_literal.hpp>
19
20USERVER_NAMESPACE_BEGIN
21
22namespace storages::postgres {
23
24/*! [Isolation levels] */
25/// @brief SQL transaction isolation level
26/// @see https://www.postgresql.org/docs/current/static/sql-set-transaction.html
28 kReadCommitted, //!< READ COMMITTED
29 kRepeatableRead, //!< REPEATABLE READ
30 kSerializable, //!< SERIALIZABLE
31 kReadUncommitted //!< READ UNCOMMITTED @warning In Postgres READ UNCOMMITTED
32 //!< is treated as READ COMMITTED
33};
34/*! [Isolation levels] */
35
36std::ostream& operator<<(std::ostream&, IsolationLevel);
37
38/// @brief PostgreSQL transaction options
39///
40/// A transaction can be started using all isolation levels and modes
41/// supported by PostgreSQL server as specified in it's documentation.
42///
43/// Default isolation level is READ COMMITTED, default mode is READ WRITE.
44/// @code
45/// // Read-write read committed transaction.
46/// TransactionOptions opts;
47/// @endcode
48///
49/// Transaction class provides constants Transaction::RW, Transaction::RO and
50/// Transaction::Deferrable for convenience.
51///
52/// Other variants can be created with TransactionOptions constructors
53/// that are constexpr.
54///
55/// @see https://www.postgresql.org/docs/current/static/sql-set-transaction.html
57 /*! [Transaction modes] */
58 enum Mode : std::uint16_t {
59 kReadWrite = 0,
60 kReadOnly = 1,
61 kDeferrable = 3 //!< Deferrable transaction is read only
62 };
63 /*! [Transaction modes] */
65 Mode mode = kReadWrite;
66
67 constexpr TransactionOptions() = default;
68 constexpr explicit TransactionOptions(IsolationLevel lvl) : isolation_level{lvl} {}
69 constexpr TransactionOptions(IsolationLevel lvl, Mode m) : isolation_level{lvl}, mode{m} {}
70 constexpr explicit TransactionOptions(Mode m) : mode{m} {}
71
72 bool IsReadOnly() const { return mode & kReadOnly; }
73
74 /// The deferrable property has effect only if the transaction is also
75 /// serializable and read only
77};
78
79constexpr inline bool operator==(TransactionOptions lhs, TransactionOptions rhs) {
80 return lhs.isolation_level == rhs.isolation_level && lhs.mode == rhs.mode;
81}
82USERVER_NAMESPACE::utils::StringLiteral BeginStatement(TransactionOptions opts) noexcept;
83
84/// A structure to control timeouts for PosrgreSQL queries
85///
86/// There are two parameters, `execute` and `statement`.
87///
88/// `execute` parameter controls the overall time the driver spends executing a
89/// query, that includes:
90/// * connecting to PostgreSQL server, if there are no connections available and
91/// connection pool still has space for new connections;
92/// * waiting for a connection to become idle if there are no idle connections
93/// and connection pool already has reached it's max size;
94/// * preparing a statement if the statement is run for the first time on the
95/// connection;
96/// * binding parameters and executing the statement;
97/// * waiting for the first results to arrive from the server. If the result set
98/// is big, only time to the first data packet is taken into account.
99///
100/// `statement` is rather straightforward, it's the PostgreSQL server-side
101/// parameter, and it controls the time the database backend can spend executing
102/// a single statement. It is very costly to change the statement timeout
103/// often, as it requires a roundtrip to the database to change the setting.
104/// @see https://www.postgresql.org/docs/12/runtime-config-client.html
105///
106/// `execute` timeout should always be greater than the `statement` timeout!
107///
108/// In case of a timeout, either back-end or overall, the client gets an
109/// exception and the driver tries to clean up the connection for further reuse.
111 /// Overall timeout for a command being executed
112 TimeoutDuration network_timeout_ms{};
113 /// PostgreSQL server-side timeout
114 TimeoutDuration statement_timeout_ms{};
115
116 enum class PreparedStatementsOptionOverride { kNoOverride, kEnabled, kDisabled };
117
118 PreparedStatementsOptionOverride prepared_statements_enabled{PreparedStatementsOptionOverride::kNoOverride};
119
120 constexpr CommandControl(
121 TimeoutDuration network_timeout_ms,
122 TimeoutDuration statement_timeout_ms,
123 PreparedStatementsOptionOverride prepared_statements_enabled = PreparedStatementsOptionOverride::kNoOverride
124 )
125 : network_timeout_ms(network_timeout_ms),
126 statement_timeout_ms(statement_timeout_ms),
127 prepared_statements_enabled(prepared_statements_enabled) {}
128
129 constexpr CommandControl WithExecuteTimeout(TimeoutDuration n) const noexcept { return {n, statement_timeout_ms}; }
130
131 constexpr CommandControl WithStatementTimeout(TimeoutDuration s) const noexcept { return {network_timeout_ms, s}; }
132
133 bool operator==(const CommandControl& rhs) const {
135 prepared_statements_enabled == rhs.prepared_statements_enabled;
136 }
137
138 bool operator!=(const CommandControl& rhs) const { return !(*this == rhs); }
139};
140
141/// @brief storages::postgres::CommandControl that may not be set
142using OptionalCommandControl = std::optional<CommandControl>;
143
144using CommandControlByMethodMap = USERVER_NAMESPACE::utils::impl::TransparentMap<std::string, CommandControl>;
145using CommandControlByHandlerMap =
146 USERVER_NAMESPACE::utils::impl::TransparentMap<std::string, CommandControlByMethodMap>;
147using CommandControlByQueryMap = USERVER_NAMESPACE::utils::impl::TransparentMap<std::string, CommandControl>;
148
149OptionalCommandControl
150GetHandlerOptionalCommandControl(const CommandControlByHandlerMap& map, std::string_view path, std::string_view method);
151
152OptionalCommandControl GetQueryOptionalCommandControl(const CommandControlByQueryMap& map, std::string_view query_name);
153
154/// Default initial pool connection count
155inline constexpr std::size_t kDefaultPoolMinSize = 4;
156
157/// Default maximum replication lag
158inline constexpr auto kDefaultMaxReplicationLag = std::chrono::seconds{60};
159
160/// Default pool connections limit
161inline constexpr std::size_t kDefaultPoolMaxSize = 15;
162
163/// Default size of queue for clients waiting for connections
164inline constexpr std::size_t kDefaultPoolMaxQueueSize = 200;
165
166/// Default limit for concurrent establishing connections number
167inline constexpr std::size_t kDefaultConnectingLimit = 0;
168
169/// @brief PostgreSQL topology options
170///
171/// Dynamic option @ref POSTGRES_TOPOLOGY_SETTINGS
173 /// Maximum replication lag. Once the replica lag exceeds this value it will be automatically disabled.
175
176 /// List of manually disabled replicas (FQDNs).
177 std::unordered_set<std::string, USERVER_NAMESPACE::utils::StrIcaseHash, USERVER_NAMESPACE::utils::StrIcaseEqual>
179};
180
181/// @brief PostgreSQL connection pool options
182///
183/// Dynamic option @ref POSTGRES_CONNECTION_POOL_SETTINGS
184struct PoolSettings final {
185 /// Number of connections created initially
187
188 /// Maximum number of created connections
190
191 /// Maximum number of clients waiting for a connection
193
194 /// Limits number of concurrent establishing connections (0 - unlimited)
196
197 bool operator==(const PoolSettings& rhs) const {
198 return min_size == rhs.min_size && max_size == rhs.max_size && max_queue_size == rhs.max_queue_size &&
200 }
201};
202
203// Configs with a suffix `Dynamic` are need to compatibility with static:
204// We must update only fields that were updated in a dynamic config (not a full config!).
205struct PoolSettingsDynamic final {
206 std::optional<std::size_t> min_size;
207 std::optional<std::size_t> max_size;
208 std::optional<std::size_t> max_queue_size;
209 std::optional<std::size_t> connecting_limit;
210};
211
212/// Default size limit for prepared statements cache
213inline constexpr std::size_t kDefaultMaxPreparedCacheSize = 200;
214
215/// Pipeline mode configuration
216///
217/// Dynamic option @ref POSTGRES_CONNECTION_PIPELINE_EXPERIMENT
218enum class PipelineMode { kDisabled, kEnabled };
219
220/// Whether to omit excessive D(escribe) message
221/// when executing prepared statements
222///
223/// Dynamic option @ref POSTGRES_OMIT_DESCRIBE_IN_EXECUTE
224enum class OmitDescribeInExecuteMode { kDisabled, kEnabled };
225
226/// PostgreSQL connection options
227///
228/// Dynamic option @ref POSTGRES_CONNECTION_SETTINGS
230 enum PreparedStatementOptions {
231 kCachePreparedStatements,
232 kNoPreparedStatements,
233 };
234 enum UserTypesOptions {
235 kUserTypesEnabled,
236 kUserTypesEnforced,
237 kPredefinedTypesOnly,
238 };
239 enum CheckQueryParamsOptions {
240 kIgnoreUnused,
241 kCheckUnused,
242 };
243 enum DiscardOnConnectOptions {
244 kDiscardNone,
245 kDiscardAll,
246 };
247 enum StatementLogMode {
248 kLogSkip,
249 kLog,
250 };
251 using SettingsVersion = std::size_t;
252
253 /// Cache prepared statements or not
254 PreparedStatementOptions prepared_statements = kCachePreparedStatements;
255
256 /// Enables the usage of user-defined types
257 UserTypesOptions user_types = kUserTypesEnabled;
258
259 /// Checks for not-NULL query params that are not used in query
260 CheckQueryParamsOptions ignore_unused_query_params = kCheckUnused;
261
262 /// Limits the size or prepared statements cache
264
265 /// Turns on connection pipeline mode
267
268 /// Enables protocol-level optimization when executing prepared statements
270
271 /// This many connection errors in 15 seconds block new connections opening
272 std::size_t recent_errors_threshold = 2;
273
274 /// The maximum lifetime of the connection after which it will be closed
275 std::optional<std::chrono::seconds> max_ttl{};
276
277 /// Execute discard all after establishing a new connection
278 DiscardOnConnectOptions discard_on_connect = kDiscardAll;
279
280 /// Statement logging in span tags
281 StatementLogMode statement_log_mode = kLog;
282
283 bool deadline_propagation_enabled = true;
284
285 /// Helps keep track of the changes in settings
286 SettingsVersion version{0U};
287
288 bool operator==(const ConnectionSettings& rhs) const {
289 return !RequiresConnectionReset(rhs) && recent_errors_threshold == rhs.recent_errors_threshold;
290 }
291
292 bool operator!=(const ConnectionSettings& rhs) const { return !(*this == rhs); }
293
294 bool RequiresConnectionReset(const ConnectionSettings& rhs) const {
295 // TODO: max_prepared_cache_size check could be relaxed
301 }
302};
303
304struct ConnectionSettingsDynamic final {
305 std::optional<ConnectionSettings::PreparedStatementOptions> prepared_statements{};
306 std::optional<ConnectionSettings::UserTypesOptions> user_types{};
307 std::optional<std::size_t> max_prepared_cache_size{};
308 std::optional<std::size_t> recent_errors_threshold{};
309 std::optional<ConnectionSettings::CheckQueryParamsOptions> ignore_unused_query_params{};
310 std::optional<std::chrono::seconds> max_ttl{};
311 std::optional<ConnectionSettings::DiscardOnConnectOptions> discard_on_connect{};
312 std::optional<bool> deadline_propagation_enabled{};
313};
314
315/// @brief PostgreSQL statements metrics options
316///
317/// Dynamic option @ref POSTGRES_STATEMENT_METRICS_SETTINGS
318struct StatementMetricsSettings final {
319 /// Store metrics in LRU of this size
320 std::size_t max_statements{0};
321
322 bool operator==(const StatementMetricsSettings& other) const { return max_statements == other.max_statements; }
323};
324
325/// Initialization modes
326enum class InitMode {
327 kSync = 0,
328 kAsync,
329};
330
331enum class ConnlimitMode {
332 kManual = 0,
333 kAuto,
334};
335
336/// Settings for storages::postgres::Cluster
338 /// settings for statements metrics
339 StatementMetricsSettings statement_metrics_settings;
340
341 /// settings for host discovery
343
344 /// settings for connection pools
345 PoolSettings pool_settings;
346
347 /// settings for individual connections
349
350 /// initialization mode
352
353 /// database name
354 std::string db_name;
355
356 /// connection limit change mode
357 ConnlimitMode connlimit_mode = ConnlimitMode::kAuto;
358
359 /// congestion control settings
360 congestion_control::v2::LinearController::StaticConfig cc_config;
361};
362
363} // namespace storages::postgres
364
365USERVER_NAMESPACE_END