yb_postgres/config.rs
1//! Connection configuration.
2
3use crate::connection::Connection;
4use crate::Client;
5use log::info;
6use std::collections::HashMap;
7use std::fmt;
8use std::net::IpAddr;
9use std::path::Path;
10use std::str::FromStr;
11use std::sync::Arc;
12use std::time::Duration;
13use tokio::runtime;
14#[doc(inline)]
15pub use yb_tokio_postgres::config::{
16 ChannelBinding, Host, LoadBalanceHosts, SslMode, TargetSessionAttrs,
17};
18use yb_tokio_postgres::error::DbError;
19use yb_tokio_postgres::tls::{MakeTlsConnect, TlsConnect};
20use yb_tokio_postgres::{Error, Socket};
21
22/// Connection configuration.
23///
24/// Configuration can be parsed from libpq-style connection strings. These strings come in two formats:
25///
26/// # Key-Value
27///
28/// This format consists of space-separated key-value pairs. Values which are either the empty string or contain
29/// whitespace should be wrapped in `'`. `'` and `\` characters should be backslash-escaped.
30///
31/// ## Keys
32///
33/// * `user` - The username to authenticate with. Defaults to the user executing this process.
34/// * `password` - The password to authenticate with.
35/// * `dbname` - The name of the database to connect to. Defaults to the username.
36/// * `options` - Command line options used to configure the server.
37/// * `application_name` - Sets the `application_name` parameter on the server.
38/// * `sslmode` - Controls usage of TLS. If set to `disable`, TLS will not be used. If set to `prefer`, TLS will be used
39/// if available, but not used otherwise. If set to `require`, TLS will be forced to be used. Defaults to `prefer`.
40/// * `host` - The host to connect to. On Unix platforms, if the host starts with a `/` character it is treated as the
41/// path to the directory containing Unix domain sockets. Otherwise, it is treated as a hostname. Multiple hosts
42/// can be specified, separated by commas. Each host will be tried in turn when connecting. Required if connecting
43/// with the `connect` method.
44/// * `hostaddr` - Numeric IP address of host to connect to. This should be in the standard IPv4 address format,
45/// e.g., 172.28.40.9. If your machine supports IPv6, you can also use those addresses.
46/// If this parameter is not specified, the value of `host` will be looked up to find the corresponding IP address,
47/// or if host specifies an IP address, that value will be used directly.
48/// Using `hostaddr` allows the application to avoid a host name look-up, which might be important in applications
49/// with time constraints. However, a host name is required for TLS certificate verification.
50/// Specifically:
51/// * If `hostaddr` is specified without `host`, the value for `hostaddr` gives the server network address.
52/// The connection attempt will fail if the authentication method requires a host name;
53/// * If `host` is specified without `hostaddr`, a host name lookup occurs;
54/// * If both `host` and `hostaddr` are specified, the value for `hostaddr` gives the server network address.
55/// The value for `host` is ignored unless the authentication method requires it,
56/// in which case it will be used as the host name.
57/// * `port` - The port to connect to. Multiple ports can be specified, separated by commas. The number of ports must be
58/// either 1, in which case it will be used for all hosts, or the same as the number of hosts. Defaults to 5432 if
59/// omitted or the empty string.
60/// * `connect_timeout` - The time limit in seconds applied to each socket-level connection attempt. Note that hostnames
61/// can resolve to multiple IP addresses, and this limit is applied to each address. Defaults to no timeout.
62/// * `tcp_user_timeout` - The time limit that transmitted data may remain unacknowledged before a connection is forcibly closed.
63/// This is ignored for Unix domain socket connections. It is only supported on systems where TCP_USER_TIMEOUT is available
64/// and will default to the system default if omitted or set to 0; on other systems, it has no effect.
65/// * `keepalives` - Controls the use of TCP keepalive. A value of 0 disables keepalive and nonzero integers enable it.
66/// This option is ignored when connecting with Unix sockets. Defaults to on.
67/// * `keepalives_idle` - The number of seconds of inactivity after which a keepalive message is sent to the server.
68/// This option is ignored when connecting with Unix sockets. Defaults to 2 hours.
69/// * `keepalives_interval` - The time interval between TCP keepalive probes.
70/// This option is ignored when connecting with Unix sockets.
71/// * `keepalives_retries` - The maximum number of TCP keepalive probes that will be sent before dropping a connection.
72/// This option is ignored when connecting with Unix sockets.
73/// * `target_session_attrs` - Specifies requirements of the session. If set to `read-write`, the client will check that
74/// the `transaction_read_write` session parameter is set to `on`. This can be used to connect to the primary server
75/// in a database cluster as opposed to the secondary read-only mirrors. Defaults to `all`.
76/// * `channel_binding` - Controls usage of channel binding in the authentication process. If set to `disable`, channel
77/// binding will not be used. If set to `prefer`, channel binding will be used if available, but not used otherwise.
78/// If set to `require`, the authentication process will fail if channel binding is not used. Defaults to `prefer`.
79/// * `load_balance_hosts` - Controls the order in which the client tries to connect to the available hosts and
80/// addresses. Once a connection attempt is successful no other hosts and addresses will be tried. This parameter
81/// is typically used in combination with multiple host names or a DNS record that returns multiple IPs. If set to
82/// `disable`, hosts and addresses will be tried in the order provided. If set to `random`, hosts will be tried
83/// in a random order, and the IP addresses resolved from a hostname will also be tried in a random order. Defaults
84/// to `disable`.
85/// * `load_balance` - Defaults to upstream driver behavior unless set to one of the allowed values (true or any, only-rr, only-primary,
86/// prefer-primary, prefer-rr and false) other than 'false'.
87/// * `topology_keys` - It takes a comma separated geo-location values. A single geo-location can be given as 'cloud.region.zone'.
88/// Multiple geo-locations too can be specified, separated by comma (,). Each placement value can be suffixed with a colon (:)
89/// followed by a preference value between 1 and 10. A preference value of :1 means it is a primary placement. A preference
90/// value of :2 means it is the first fallback placement and so on. If no preference value is provided, it is considered to
91/// be a primary placement (equivalent to one with preference value :1).
92/// * `yb_servers_refresh_interval` - Time interval, in seconds, between two attempts to refresh the information about cluster nodes.
93/// Default is 300. Valid values are integers between 0 and 600. Value 0 means refresh for each connection request. Any value
94/// outside this range is ignored and the default is used.
95/// * `fallback_to_topology_keys_only` - (default value: false) Applicable only for TopologyAware Load Balancing. When set to true,
96/// the smart driver does not attempt to connect to servers outside of primary and fallback placements specified via property.
97/// The default behaviour is to fallback to any available server in the entire cluster.
98/// * `failed_host_reconnect_delay_secs` - (default value: 5 seconds) The driver marks a server as failed with a timestamp, when it cannot
99/// connect to it. Later, whenever it refreshes the server list via yb_servers(), if it sees the failed server in the response,
100/// it marks the server as UP only if failed-host-reconnect-delay-secs time has elapsed. (The yb_servers() function does not remove
101/// a failed server immediately from its result and retains it for a while.)
102///
103/// ## Examples
104///
105/// ```not_rust
106/// host=localhost user=postgres connect_timeout=10 keepalives=0
107/// ```
108///
109/// ```not_rust
110/// host=/var/lib/postgresql,localhost port=1234 user=postgres password='password with spaces'
111/// ```
112///
113/// ```not_rust
114/// host=host1,host2,host3 port=1234,,5678 hostaddr=127.0.0.1,127.0.0.2,127.0.0.3 user=postgres target_session_attrs=read-write
115/// ```
116///
117/// ```not_rust
118/// host=host1,host2,host3 port=1234,,5678 user=postgres target_session_attrs=read-write
119/// ```
120///
121/// # Url
122///
123/// This format resembles a URL with a scheme of either `postgres://` or `postgresql://`. All components are optional,
124/// and the format accepts query parameters for all of the key-value pairs described in the section above. Multiple
125/// host/port pairs can be comma-separated. Unix socket paths in the host section of the URL should be percent-encoded,
126/// as the path component of the URL specifies the database name.
127///
128/// ## Examples
129///
130/// ```not_rust
131/// postgresql://user@localhost
132/// ```
133///
134/// ```not_rust
135/// postgresql://user:password@%2Fvar%2Flib%2Fpostgresql/mydb?connect_timeout=10
136/// ```
137///
138/// ```not_rust
139/// postgresql://user@host1:1234,host2,host3:5678?target_session_attrs=read-write
140/// ```
141///
142/// ```not_rust
143/// postgresql:///mydb?user=user&host=/var/lib/postgresql
144/// ```
145#[derive(Clone)]
146pub struct Config {
147 config: yb_tokio_postgres::Config,
148 notice_callback: Arc<dyn Fn(DbError) + Send + Sync>,
149}
150
151impl fmt::Debug for Config {
152 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
153 fmt.debug_struct("Config")
154 .field("config", &self.config)
155 .finish()
156 }
157}
158
159impl Default for Config {
160 fn default() -> Config {
161 Config::new()
162 }
163}
164
165impl Config {
166 /// Creates a new configuration.
167 pub fn new() -> Config {
168 yb_tokio_postgres::Config::new().into()
169 }
170
171 /// Sets the user to authenticate with.
172 ///
173 /// If the user is not set, then this defaults to the user executing this process.
174 pub fn user(&mut self, user: &str) -> &mut Config {
175 self.config.user(user);
176 self
177 }
178
179 /// Gets the user to authenticate with, if one has been configured with
180 /// the `user` method.
181 pub fn get_user(&self) -> Option<&str> {
182 self.config.get_user()
183 }
184
185 /// Sets the password to authenticate with.
186 pub fn password<T>(&mut self, password: T) -> &mut Config
187 where
188 T: AsRef<[u8]>,
189 {
190 self.config.password(password);
191 self
192 }
193
194 /// Gets the password to authenticate with, if one has been configured with
195 /// the `password` method.
196 pub fn get_password(&self) -> Option<&[u8]> {
197 self.config.get_password()
198 }
199
200 /// Sets the name of the database to connect to.
201 ///
202 /// Defaults to the user.
203 pub fn dbname(&mut self, dbname: &str) -> &mut Config {
204 self.config.dbname(dbname);
205 self
206 }
207
208 /// Gets the name of the database to connect to, if one has been configured
209 /// with the `dbname` method.
210 pub fn get_dbname(&self) -> Option<&str> {
211 self.config.get_dbname()
212 }
213
214 /// Sets command line options used to configure the server.
215 pub fn options(&mut self, options: &str) -> &mut Config {
216 self.config.options(options);
217 self
218 }
219
220 /// Gets the command line options used to configure the server, if the
221 /// options have been set with the `options` method.
222 pub fn get_options(&self) -> Option<&str> {
223 self.config.get_options()
224 }
225
226 /// Sets the value of the `application_name` runtime parameter.
227 pub fn application_name(&mut self, application_name: &str) -> &mut Config {
228 self.config.application_name(application_name);
229 self
230 }
231
232 /// Gets the value of the `application_name` runtime parameter, if it has
233 /// been set with the `application_name` method.
234 pub fn get_application_name(&self) -> Option<&str> {
235 self.config.get_application_name()
236 }
237
238 /// Sets the SSL configuration.
239 ///
240 /// Defaults to `prefer`.
241 pub fn ssl_mode(&mut self, ssl_mode: SslMode) -> &mut Config {
242 self.config.ssl_mode(ssl_mode);
243 self
244 }
245
246 /// Gets the SSL configuration.
247 pub fn get_ssl_mode(&self) -> SslMode {
248 self.config.get_ssl_mode()
249 }
250
251 /// Adds a host to the configuration.
252 ///
253 /// Multiple hosts can be specified by calling this method multiple times, and each will be tried in order. On Unix
254 /// systems, a host starting with a `/` is interpreted as a path to a directory containing Unix domain sockets.
255 /// There must be either no hosts, or the same number of hosts as hostaddrs.
256 pub fn host(&mut self, host: &str) -> &mut Config {
257 self.config.host(host);
258 self
259 }
260
261 /// Gets the hosts that have been added to the configuration with `host`.
262 pub fn get_hosts(&self) -> &[Host] {
263 self.config.get_hosts()
264 }
265
266 /// Gets the hostaddrs that have been added to the configuration with `hostaddr`.
267 pub fn get_hostaddrs(&self) -> &[IpAddr] {
268 self.config.get_hostaddrs()
269 }
270
271 /// Adds a Unix socket host to the configuration.
272 ///
273 /// Unlike `host`, this method allows non-UTF8 paths.
274 #[cfg(unix)]
275 pub fn host_path<T>(&mut self, host: T) -> &mut Config
276 where
277 T: AsRef<Path>,
278 {
279 self.config.host_path(host);
280 self
281 }
282
283 /// Adds a hostaddr to the configuration.
284 ///
285 /// Multiple hostaddrs can be specified by calling this method multiple times, and each will be tried in order.
286 /// There must be either no hostaddrs, or the same number of hostaddrs as hosts.
287 pub fn hostaddr(&mut self, hostaddr: IpAddr) -> &mut Config {
288 self.config.hostaddr(hostaddr);
289 self
290 }
291
292 /// Adds a port to the configuration.
293 ///
294 /// Multiple ports can be specified by calling this method multiple times. There must either be no ports, in which
295 /// case the default of 5432 is used, a single port, in which it is used for all hosts, or the same number of ports
296 /// as hosts.
297 pub fn port(&mut self, port: u16) -> &mut Config {
298 self.config.port(port);
299 self
300 }
301
302 /// Gets the ports that have been added to the configuration with `port`.
303 pub fn get_ports(&self) -> &[u16] {
304 self.config.get_ports()
305 }
306
307 /// Sets the timeout applied to socket-level connection attempts.
308 ///
309 /// Note that hostnames can resolve to multiple IP addresses, and this timeout will apply to each address of each
310 /// host separately. Defaults to no limit.
311 pub fn connect_timeout(&mut self, connect_timeout: Duration) -> &mut Config {
312 self.config.connect_timeout(connect_timeout);
313 self
314 }
315
316 /// Gets the connection timeout, if one has been set with the
317 /// `connect_timeout` method.
318 pub fn get_connect_timeout(&self) -> Option<&Duration> {
319 self.config.get_connect_timeout()
320 }
321
322 /// Sets the TCP user timeout.
323 ///
324 /// This is ignored for Unix domain socket connections. It is only supported on systems where
325 /// TCP_USER_TIMEOUT is available and will default to the system default if omitted or set to 0;
326 /// on other systems, it has no effect.
327 pub fn tcp_user_timeout(&mut self, tcp_user_timeout: Duration) -> &mut Config {
328 self.config.tcp_user_timeout(tcp_user_timeout);
329 self
330 }
331
332 /// Gets the TCP user timeout, if one has been set with the
333 /// `user_timeout` method.
334 pub fn get_tcp_user_timeout(&self) -> Option<&Duration> {
335 self.config.get_tcp_user_timeout()
336 }
337
338 /// Controls the use of TCP keepalive.
339 ///
340 /// This is ignored for Unix domain socket connections. Defaults to `true`.
341 pub fn keepalives(&mut self, keepalives: bool) -> &mut Config {
342 self.config.keepalives(keepalives);
343 self
344 }
345
346 /// Reports whether TCP keepalives will be used.
347 pub fn get_keepalives(&self) -> bool {
348 self.config.get_keepalives()
349 }
350
351 /// Sets the amount of idle time before a keepalive packet is sent on the connection.
352 ///
353 /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled. Defaults to 2 hours.
354 pub fn keepalives_idle(&mut self, keepalives_idle: Duration) -> &mut Config {
355 self.config.keepalives_idle(keepalives_idle);
356 self
357 }
358
359 /// Gets the configured amount of idle time before a keepalive packet will
360 /// be sent on the connection.
361 pub fn get_keepalives_idle(&self) -> Duration {
362 self.config.get_keepalives_idle()
363 }
364
365 /// Sets the time interval between TCP keepalive probes.
366 /// On Windows, this sets the value of the tcp_keepalive struct’s keepaliveinterval field.
367 ///
368 /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled.
369 pub fn keepalives_interval(&mut self, keepalives_interval: Duration) -> &mut Config {
370 self.config.keepalives_interval(keepalives_interval);
371 self
372 }
373
374 /// Gets the time interval between TCP keepalive probes.
375 pub fn get_keepalives_interval(&self) -> Option<Duration> {
376 self.config.get_keepalives_interval()
377 }
378
379 /// Sets the maximum number of TCP keepalive probes that will be sent before dropping a connection.
380 ///
381 /// This is ignored for Unix domain sockets, or if the `keepalives` option is disabled.
382 pub fn keepalives_retries(&mut self, keepalives_retries: u32) -> &mut Config {
383 self.config.keepalives_retries(keepalives_retries);
384 self
385 }
386
387 /// Gets the maximum number of TCP keepalive probes that will be sent before dropping a connection.
388 pub fn get_keepalives_retries(&self) -> Option<u32> {
389 self.config.get_keepalives_retries()
390 }
391
392 /// Sets the requirements of the session.
393 ///
394 /// This can be used to connect to the primary server in a clustered database rather than one of the read-only
395 /// secondary servers. Defaults to `Any`.
396 pub fn target_session_attrs(
397 &mut self,
398 target_session_attrs: TargetSessionAttrs,
399 ) -> &mut Config {
400 self.config.target_session_attrs(target_session_attrs);
401 self
402 }
403
404 /// Gets the requirements of the session.
405 pub fn get_target_session_attrs(&self) -> TargetSessionAttrs {
406 self.config.get_target_session_attrs()
407 }
408
409 /// Sets the channel binding behavior.
410 ///
411 /// Defaults to `prefer`.
412 pub fn channel_binding(&mut self, channel_binding: ChannelBinding) -> &mut Config {
413 self.config.channel_binding(channel_binding);
414 self
415 }
416
417 /// Gets the channel binding behavior.
418 pub fn get_channel_binding(&self) -> ChannelBinding {
419 self.config.get_channel_binding()
420 }
421
422 /// Sets the host load balancing behavior.
423 ///
424 /// Defaults to `disable`.
425 pub fn load_balance_hosts(&mut self, load_balance_hosts: LoadBalanceHosts) -> &mut Config {
426 self.config.load_balance_hosts(load_balance_hosts);
427 self
428 }
429
430 /// Gets the host load balancing behavior.
431 pub fn get_load_balance_hosts(&self) -> LoadBalanceHosts {
432 self.config.get_load_balance_hosts()
433 }
434
435 /// YugabyteDB Specific.
436 ///
437 /// Sets the load balance parameter.
438 ///
439 /// Defaults to false.
440 pub fn load_balance(&mut self, load_balance: &str) -> &mut Config {
441 self.config.load_balance(load_balance);
442 self
443 }
444
445 /// YugabyteDB Specific.
446 ///
447 /// Gets the load balance value
448 pub fn get_load_balance(&self) -> String {
449 self.config.get_load_balance()
450 }
451
452 /// YugabyteDB Specific.
453 ///
454 /// Sets the topology key parameter.
455 ///
456 /// Defaults to Hashmap::new().
457 pub fn topology_keys(&mut self, topology_key: &str, priority: i64) -> &mut Config {
458 self.config.topology_keys(topology_key, priority);
459 self
460 }
461
462 /// YugabyteDB Specific.
463 ///
464 /// Gets the host topology keys value.
465 pub fn get_topology_keys(&self) -> HashMap<i64, Vec<String>> {
466 self.config.get_topology_keys()
467 }
468
469 /// YugabyteDB Specific.
470 ///
471 /// Sets the yb_servers_refresh_interval parameter.
472 ///
473 /// Defaults to 300 sec.
474 pub fn yb_servers_refresh_interval(
475 &mut self,
476 yb_servers_refresh_interval: Duration,
477 ) -> &mut Config {
478 self.config
479 .yb_servers_refresh_interval(yb_servers_refresh_interval);
480 self
481 }
482
483 /// YugabyteDB Specific.
484 ///
485 /// Gets the yb_servers_refresh_interval value.
486 pub fn get_yb_servers_refresh_interval(&self) -> Duration {
487 self.config.get_yb_servers_refresh_interval()
488 }
489
490 /// YugabyteDB Specific.
491 ///
492 /// Sets the fallback_to_topology_keys_only parameter.
493 ///
494 /// Defaults to false.
495 pub fn fallback_to_topology_keys_only(
496 &mut self,
497 fallback_to_topology_keys_only: bool,
498 ) -> &mut Config {
499 self.config
500 .fallback_to_topology_keys_only(fallback_to_topology_keys_only);
501 self
502 }
503
504 /// YugabyteDB Specific.
505 ///
506 /// Gets the fallback_to_topology_keys_only value.
507 pub fn get_fallback_to_topology_keys_only(&self) -> bool {
508 self.config.get_fallback_to_topology_keys_only()
509 }
510
511 /// YugabyteDB Specific.
512 ///
513 /// Sets the failed_host_reconnect_delay_secs parameter.
514 ///
515 /// Defaults to 5 sec.
516 pub fn failed_host_reconnect_delay_secs(
517 &mut self,
518 failed_host_reconnect_delay_secs: Duration,
519 ) -> &mut Config {
520 self.config
521 .failed_host_reconnect_delay_secs(failed_host_reconnect_delay_secs);
522 self
523 }
524
525 /// YugabyteDB Specific.
526 ///
527 /// Gets the failed_host_reconnect_delay_secs value.
528 pub fn get_failed_host_reconnect_delay_secs(&self) -> Duration {
529 self.config.get_failed_host_reconnect_delay_secs()
530 }
531
532 /// Sets the notice callback.
533 ///
534 /// This callback will be invoked with the contents of every
535 /// [`AsyncMessage::Notice`] that is received by the connection. Notices use
536 /// the same structure as errors, but they are not "errors" per-se.
537 ///
538 /// Notices are distinct from notifications, which are instead accessible
539 /// via the [`Notifications`] API.
540 ///
541 /// [`AsyncMessage::Notice`]: yb_tokio_postgres::AsyncMessage::Notice
542 /// [`Notifications`]: crate::Notifications
543 pub fn notice_callback<F>(&mut self, f: F) -> &mut Config
544 where
545 F: Fn(DbError) + Send + Sync + 'static,
546 {
547 self.notice_callback = Arc::new(f);
548 self
549 }
550
551 /// Opens a connection to a PostgreSQL database.
552 pub fn connect<T>(&self, tls: T) -> Result<Client, Error>
553 where
554 T: MakeTlsConnect<Socket> + 'static + Send,
555 T::TlsConnect: Send,
556 T::Stream: Send,
557 <T::TlsConnect as TlsConnect<Socket>>::Future: Send,
558 {
559 let runtime = runtime::Builder::new_current_thread()
560 .enable_all()
561 .build()
562 .unwrap(); // FIXME don't unwrap
563
564 let (client, connection) = runtime.block_on(self.config.connect(tls))?;
565
566 let connection = Connection::new(runtime, connection, self.notice_callback.clone());
567 Ok(Client::new(connection, client))
568 }
569}
570
571impl FromStr for Config {
572 type Err = Error;
573
574 fn from_str(s: &str) -> Result<Config, Error> {
575 s.parse::<yb_tokio_postgres::Config>().map(Config::from)
576 }
577}
578
579impl From<yb_tokio_postgres::Config> for Config {
580 fn from(config: yb_tokio_postgres::Config) -> Config {
581 Config {
582 config,
583 notice_callback: Arc::new(|notice| {
584 info!("{}: {}", notice.severity(), notice.message())
585 }),
586 }
587 }
588}