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