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 <iosfwd>
8#include <optional>
9#include <string>
10#include <unordered_map>
11
12#include <userver/congestion_control/controllers/linear.hpp>
13#include <userver/storages/postgres/postgres_fwd.hpp>
14#include <userver/utils/impl/transparent_hash.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::postgres {
19
20/*! [Isolation levels] */
21/// @brief SQL transaction isolation level
22/// @see https://www.postgresql.org/docs/current/static/sql-set-transaction.html
23enum class IsolationLevel {
24 kReadCommitted, //!< READ COMMITTED
25 kRepeatableRead, //!< REPEATABLE READ
26 kSerializable, //!< SERIALIZABLE
27 kReadUncommitted //!< READ UNCOMMITTED @warning In Postgres READ UNCOMMITTED
28 //!< is treated as READ COMMITTED
29};
30/*! [Isolation levels] */
31
32std::ostream& operator<<(std::ostream&, IsolationLevel);
33
34/// @brief PostgreSQL transaction options
35///
36/// A transaction can be started using all isolation levels and modes
37/// supported by PostgreSQL server as specified in it's documentation.
38///
39/// Default isolation level is READ COMMITTED, default mode is READ WRITE.
40/// @code
41/// // Read-write read committed transaction.
42/// TransactionOptions opts;
43/// @endcode
44///
45/// Transaction class provides constants Transaction::RW, Transaction::RO and
46/// Transaction::Deferrable for convenience.
47///
48/// Other variants can be created with TransactionOptions constructors
49/// that are constexpr.
50///
51/// @see https://www.postgresql.org/docs/current/static/sql-set-transaction.html
53 /*! [Transaction modes] */
54 enum Mode {
55 kReadWrite = 0,
56 kReadOnly = 1,
57 kDeferrable = 3 //!< Deferrable transaction is read only
58 };
59 /*! [Transaction modes] */
61 Mode mode = kReadWrite;
62
63 constexpr TransactionOptions() = default;
64 constexpr explicit TransactionOptions(IsolationLevel lvl)
65 : isolation_level{lvl} {}
66 constexpr TransactionOptions(IsolationLevel lvl, Mode m)
67 : isolation_level{lvl}, mode{m} {}
68 constexpr explicit TransactionOptions(Mode m) : mode{m} {}
69
70 bool IsReadOnly() const { return mode & kReadOnly; }
71
72 /// The deferrable property has effect only if the transaction is also
73 /// serializable and read only
74 static constexpr TransactionOptions Deferrable() {
76 }
77};
78
79constexpr inline bool operator==(const TransactionOptions& lhs,
80 const TransactionOptions& rhs) {
81 return lhs.isolation_level == rhs.isolation_level && lhs.mode == rhs.mode;
82}
83const std::string& BeginStatement(const TransactionOptions&);
84
85/// A structure to control timeouts for PosrgreSQL queries
86///
87/// There are two parameters, `execute` and `statement`.
88///
89/// `execute` parameter controls the overall time the driver spends executing a
90/// query, that includes:
91/// * connecting to PostgreSQL server, if there are no connections available and
92/// connection pool still has space for new connections;
93/// * waiting for a connection to become idle if there are no idle connections
94/// and connection pool already has reached it's max size;
95/// * preparing a statement if the statement is run for the first time on the
96/// connection;
97/// * binding parameters and executing the statement;
98/// * waiting for the first results to arrive from the server. If the result set
99/// is big, only time to the first data packet is taken into account.
100///
101/// `statement` is rather straightforward, it's the PostgreSQL server-side
102/// parameter, and it controls the time the database backend can spend executing
103/// a single statement. It is very costly to change the statement timeout
104/// often, as it requires a roundtrip to the database to change the setting.
105/// @see https://www.postgresql.org/docs/12/runtime-config-client.html
106///
107/// `execute` timeout should always be greater than the `statement` timeout!
108///
109/// In case of a timeout, either back-end or overall, the client gets an
110/// exception and the driver tries to clean up the connection for further reuse.
112 /// Overall timeout for a command being executed
113 TimeoutDuration execute{};
114 /// PostgreSQL server-side timeout
115 TimeoutDuration statement{};
116
117 constexpr CommandControl(TimeoutDuration execute, TimeoutDuration statement)
118 : execute(execute), statement(statement) {}
119
120 constexpr CommandControl WithExecuteTimeout(TimeoutDuration n) const
121 noexcept {
122 return {n, statement};
123 }
124
125 constexpr CommandControl WithStatementTimeout(TimeoutDuration s) const
126 noexcept {
127 return {execute, s};
128 }
129
130 bool operator==(const CommandControl& rhs) const {
131 return execute == rhs.execute && statement == rhs.statement;
132 }
133
134 bool operator!=(const CommandControl& rhs) const { return !(*this == rhs); }
135};
136
137/// @brief storages::postgres::CommandControl that may not be set
138using OptionalCommandControl = std::optional<CommandControl>;
139
141 USERVER_NAMESPACE::utils::impl::TransparentMap<std::string, CommandControl>;
143 USERVER_NAMESPACE::utils::impl::TransparentMap<std::string,
147
148OptionalCommandControl GetHandlerOptionalCommandControl(
149 const CommandControlByHandlerMap& map, std::string_view path,
150 std::string_view method);
151
152OptionalCommandControl GetQueryOptionalCommandControl(
153 const CommandControlByQueryMap& map, const std::string& query_name);
154
156 std::chrono::milliseconds max_replication_lag{0};
157};
158
159/// Default initial pool connection count
160static constexpr size_t kDefaultPoolMinSize = 4;
161
162/// Default pool connections limit
163static constexpr size_t kDefaultPoolMaxSize = 15;
164
165/// Default size of queue for clients waiting for connections
166static constexpr size_t kDefaultPoolMaxQueueSize = 200;
167
168/// Default limit for concurrent establishing connections number
169static constexpr size_t kDefaultConnectingLimit = 0;
170
171/// @brief PostgreSQL connection pool options
172///
173/// Dynamic option @ref POSTGRES_CONNECTION_POOL_SETTINGS
175 /// Number of connections created initially
177
178 /// Maximum number of created connections
180
181 /// Maximum number of clients waiting for a connection
183
184 /// Limits number of concurrent establishing connections (0 - unlimited)
186
187 bool operator==(const PoolSettings& rhs) const {
188 return min_size == rhs.min_size && max_size == rhs.max_size &&
189 max_queue_size == rhs.max_queue_size &&
190 connecting_limit == rhs.connecting_limit;
191 }
192};
193
194/// Default size limit for prepared statements cache
195static constexpr size_t kDefaultMaxPreparedCacheSize = 5000;
196
197/// Pipeline mode configuration
198///
199/// Dynamic option @ref POSTGRES_CONNECTION_PIPELINE_EXPERIMENT
200enum class PipelineMode { kDisabled, kEnabled };
201
202/// PostgreSQL connection options
203///
204/// Dynamic option @ref POSTGRES_CONNECTION_SETTINGS
206 enum PreparedStatementOptions {
207 kCachePreparedStatements,
208 kNoPreparedStatements,
209 };
210 enum UserTypesOptions {
211 kUserTypesEnabled,
212 kPredefinedTypesOnly,
213 };
214 enum CheckQueryParamsOptions {
215 kIgnoreUnused,
216 kCheckUnused,
217 };
218 using SettingsVersion = size_t;
219
220 /// Cache prepared statements or not
221 PreparedStatementOptions prepared_statements = kCachePreparedStatements;
222
223 /// Enables the usage of user-defined types
224 UserTypesOptions user_types = kUserTypesEnabled;
225
226 /// Checks for not-NULL query params that are not used in query
227 CheckQueryParamsOptions ignore_unused_query_params = kCheckUnused;
228
229 /// Limits the size or prepared statements cache
231
232 /// Turns on connection pipeline mode
234
235 /// This many connection errors in 15 seconds block new connections opening
237
238 /// Helps keep track of the changes in settings
240
241 bool operator==(const ConnectionSettings& rhs) const {
242 return prepared_statements == rhs.prepared_statements &&
243 user_types == rhs.user_types &&
244 ignore_unused_query_params == rhs.ignore_unused_query_params &&
245 max_prepared_cache_size == rhs.max_prepared_cache_size &&
246 pipeline_mode == rhs.pipeline_mode &&
247 recent_errors_threshold == rhs.recent_errors_threshold;
248 }
249
250 bool operator!=(const ConnectionSettings& rhs) const {
251 return !(*this == rhs);
252 }
253
254 bool RequiresConnectionReset(const ConnectionSettings& rhs) const {
255 // TODO: max_prepared_cache_size check could be relaxed
256 return prepared_statements != rhs.prepared_statements ||
257 user_types != rhs.user_types ||
258 ignore_unused_query_params != rhs.ignore_unused_query_params ||
259 max_prepared_cache_size != rhs.max_prepared_cache_size ||
260 pipeline_mode != rhs.pipeline_mode;
261 }
262};
263
264/// @brief PostgreSQL statements metrics options
265///
266/// Dynamic option @ref POSTGRES_STATEMENT_METRICS_SETTINGS
267struct StatementMetricsSettings final {
268 /// Store metrics in LRU of this size
270
271 bool operator==(const StatementMetricsSettings& other) const {
272 return max_statements == other.max_statements;
273 }
274};
275
276/// Initialization modes
277enum class InitMode {
278 kSync = 0,
279 kAsync,
280};
281
282enum class ConnlimitMode {
283 kManual = 0,
284 kAuto,
285};
286
287/// Settings for storages::postgres::Cluster
289 /// settings for statements metrics
290 StatementMetricsSettings statement_metrics_settings;
291
292 /// settings for host discovery
294
295 /// settings for connection pools
297
298 /// settings for individual connections
300
301 /// initialization mode
303
304 /// database name
305 std::string db_name;
306
307 /// connection limit change mode
308 ConnlimitMode connlimit_mode = ConnlimitMode::kManual;
309
310 /// congestion control settings
311 congestion_control::v2::LinearController::StaticConfig cc_config;
312};
313
314} // namespace storages::postgres
315
316USERVER_NAMESPACE_END