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}