Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .schema/pgdog.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -416,6 +416,24 @@
"format": "uint64",
"minimum": 0
},
"idle_timeout_primary": {
"description": "Idle connection timeout for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
},
"idle_timeout_replica": {
"description": "Idle connection timeout for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
},
"lb_weight": {
"description": "Used for weighted load balancing.",
"type": "integer",
Expand All @@ -442,6 +460,24 @@
"format": "uint",
"minimum": 0
},
"min_pool_size_primary": {
"description": "Minimum pool size for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"min_pool_size_replica": {
"description": "Minimum pool size for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"name": {
"description": "Name of your database. Clients that connect to PgDog will need to use this name to refer to the database. For multiple entries that are part of the same cluster, use the same value.\n\n<https://docs.pgdog.dev/configuration/pgdog.toml/databases/#name>",
"type": "string"
Expand All @@ -462,6 +498,24 @@
"format": "uint",
"minimum": 0
},
"pool_size_primary": {
"description": "Maximum pool size for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"pool_size_replica": {
"description": "Maximum pool size for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"pooler_mode": {
"description": "Overrides the `pooler_mode` setting. Connections to this database will use this connection pool mode.\n\n<https://docs.pgdog.dev/configuration/pgdog.toml/databases/#pooler_mode>",
"anyOf": [
Expand Down
54 changes: 54 additions & 0 deletions .schema/users.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,24 @@
"format": "uint64",
"minimum": 0
},
"idle_timeout_primary": {
"description": "Idle connection timeout for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
},
"idle_timeout_replica": {
"description": "Idle connection timeout for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint64",
"minimum": 0
},
"lock_timeout": {
"description": "Lock timeout.\n\nSets the `lock_timeout` on all server connections at connection creation.\nAborts any statement that waits longer than the specified duration to acquire a lock.\nUnlike `statement_timeout`, this only counts time spent waiting for locks, not execution time.\nRecommended for replication destination connections to prevent cross-shard deadlocks\nfrom hanging indefinitely.\n\n**Note:** Nothing is preventing the user from manually changing this setting at runtime,\ne.g., by running `SET lock_timeout TO 0`;\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#lock_timeout>",
"type": [
Expand All @@ -161,6 +179,24 @@
"format": "uint",
"minimum": 0
},
"min_pool_size_primary": {
"description": "Minimum pool size for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"min_pool_size_replica": {
"description": "Minimum pool size for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"name": {
"description": "Name of the user. Clients that connect to PgDog will need to use this username.\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#name>",
"type": "string"
Expand Down Expand Up @@ -196,6 +232,24 @@
"format": "uint",
"minimum": 0
},
"pool_size_primary": {
"description": "Maximum pool size for the primary database in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"pool_size_replica": {
"description": "Maximum pool size for the replica databases in the cluster.",
"type": [
"integer",
"null"
],
"format": "uint",
"minimum": 0
},
"pooler_mode": {
"description": "Overrides [`pooler_mode`](https://docs.pgdog.dev/configuration/pgdog.toml/general/) for this user. This allows users in [session mode](https://docs.pgdog.dev/features/session-mode/) to connect to the same PgDog instance as users in [transaction mode](https://docs.pgdog.dev/features/transaction-mode/).\n\n<https://docs.pgdog.dev/configuration/users.toml/users/#pooler_mode>",
"anyOf": [
Expand Down
6 changes: 6 additions & 0 deletions pgdog-config/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ use std::{
str::FromStr,
};

use crate::RoleConfig;

use super::pooling::PoolerMode;

/// How aggressive the query parser should be in determining read vs. write queries.
Expand Down Expand Up @@ -207,6 +209,10 @@ pub struct Database {
/// Used for weighted load balancing.
#[serde(default = "Database::lb_weight")]
pub lb_weight: u8,

/// Role-specific settings.
#[serde(flatten, default)]
pub role_config: RoleConfig,
}

impl Database {
Expand Down
2 changes: 2 additions & 0 deletions pgdog-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod overrides;
pub mod pooling;
pub mod replication;
pub mod rewrite;
pub mod role_config;
pub mod sharding;
pub mod system_catalogs;
#[cfg(test)]
Expand All @@ -37,6 +38,7 @@ pub use overrides::Overrides;
pub use pooling::{PoolerMode, PreparedStatements};
pub use replication::*;
pub use rewrite::{Rewrite, RewriteMode};
pub use role_config::RoleConfig;
pub use sharding::*;
pub use system_catalogs::system_catalogs;
pub use users::{Admin, Plugin, ServerAuth, User, Users};
Expand Down
71 changes: 71 additions & 0 deletions pgdog-config/src/role_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

/// Database-role specific configuration.
#[derive(
Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema, PartialOrd, Eq, Ord,
)]
#[serde(rename_all = "snake_case", deny_unknown_fields)]
pub struct RoleConfig {
/// Maximum pool size for the primary database in the cluster.
pub pool_size_primary: Option<usize>,
/// Maximum pool size for the replica databases in the cluster.
pub pool_size_replica: Option<usize>,
/// Minimum pool size for the primary database in the cluster.
pub min_pool_size_primary: Option<usize>,
/// Minimum pool size for the replica databases in the cluster.
pub min_pool_size_replica: Option<usize>,
/// Idle connection timeout for the primary database in the cluster.
pub idle_timeout_primary: Option<u64>,
/// Idle connection timeout for the replica databases in the cluster.
pub idle_timeout_replica: Option<u64>,
}

#[cfg(test)]
mod test {
use super::super::{Config, Users};

#[test]
fn test_role_config_with_databases() {
let config = r#"
[[databases]]
name = "prod"
host = "127.0.0.1"
pool_size_primary = 10
pool_size_replica = 20
min_pool_size_primary = 2
min_pool_size_replica = 4
idle_timeout_primary = 500
idle_timeout_replica = 1_000
"#;

let config: Config = toml::from_str(config).unwrap();
let role_config = &config.databases[0].role_config;

assert_eq!(role_config.pool_size_primary, Some(10));
assert_eq!(role_config.pool_size_replica, Some(20));
assert_eq!(role_config.min_pool_size_primary, Some(2));
assert_eq!(role_config.min_pool_size_replica, Some(4));
assert_eq!(role_config.idle_timeout_primary, Some(500));
assert_eq!(role_config.idle_timeout_replica, Some(1_000));
}

#[test]
fn test_role_config_with_users() {
let config = r#"
[[users]]
name = "pgdog"
database = "prod"
pool_size_primary = 10
min_pool_size_primary = 2
idle_timeout_primary = 500
idle_timeout_replica = 1_000
"#;

let users: Users = toml::from_str(config).unwrap();
assert_eq!(users.users[0].role_config.pool_size_primary, Some(10));
assert_eq!(users.users[0].role_config.min_pool_size_primary, Some(2));
assert_eq!(users.users[0].role_config.idle_timeout_primary, Some(500));
assert_eq!(users.users[0].role_config.idle_timeout_replica, Some(1_000));
}
}
15 changes: 15 additions & 0 deletions pgdog-config/src/users.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use tracing::warn;

use super::core::Config;
use super::pooling::PoolerMode;
use crate::RoleConfig;
use crate::util::random_string;
use schemars::JsonSchema;

Expand Down Expand Up @@ -390,6 +391,20 @@ pub struct User {
/// Maximum random adjustment applied to `server_lifetime` per backend connection (milliseconds).
/// Overrides the database-level and general-level `server_lifetime_jitter` setting for this user.
pub server_lifetime_jitter: Option<u64>,

/// Role-specific configuration settings.
///
/// These are flattened, so they appear directly in the [[users]] entry, e.g.,
///
/// ```toml
/// [[users]]
/// name = "pgdog"
/// database = "pgdog"
/// pool_size_primary = 10
/// ```
///
#[serde(flatten, default)]
pub role_config: RoleConfig,
}

impl User {
Expand Down
36 changes: 35 additions & 1 deletion pgdog-stats/src/pool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::{
time::Duration,
};

use pgdog_config::{PoolerMode, PreparedStatements, pooling::ConnectionRecovery};
use pgdog_config::{PoolerMode, PreparedStatements, Role, pooling::ConnectionRecovery};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -275,14 +275,26 @@ pub struct State {
pub struct Config {
/// Minimum connections that should be in the pool.
pub min: usize,
/// Minimum connections that should be in the pool if it's a primary.
pub min_primary: Option<usize>,
/// Minimum connections that should be in the pool if it's a replica.
pub min_replica: Option<usize>,
/// Maximum connections allowed in the pool.
pub max: usize,
/// Maximum connection allowed in the pool if its a primary.
pub max_primary: Option<usize>,
/// Maximum connections allowed in the pool if its a replica.
pub max_replica: Option<usize>,
/// How long to wait for a connection before giving up.
pub checkout_timeout: Duration, // ms
/// Interval duration of DNS cache refresh.
pub dns_ttl: Duration, // ms
/// Close connections that have been idle for longer than this.
pub idle_timeout: Duration, // ms
/// Close primary connections that have been idle for longer than this.
pub idle_timeout_primary: Option<Duration>, // ms
/// Close replica connections that have been idle for longer than this.
pub idle_timeout_replica: Option<Duration>, // ms
/// How long to wait for connections to be created.
pub connect_timeout: Duration, // ms
/// How many times to attempt a connection before returning an error.
Expand Down Expand Up @@ -348,13 +360,35 @@ pub struct Config {
pub prepared_statements_level: PreparedStatements,
}

pub struct RoleSpecificConfig<T: Copy> {
pub value: T,
pub value_primary: Option<T>,
pub value_replica: Option<T>,
}

impl<T: Copy> RoleSpecificConfig<T> {
/// Get value given role.
pub fn value(&self, role: Role) -> T {
match role {
Role::Auto | Role::Replica => self.value_replica.unwrap_or(self.value),
Role::Primary => self.value_primary.unwrap_or(self.value),
}
}
}

impl Default for Config {
fn default() -> Self {
Self {
min: 1,
min_primary: None,
min_replica: None,
max: 10,
max_primary: None,
max_replica: None,
checkout_timeout: Duration::from_millis(5_000),
idle_timeout: Duration::from_millis(60_000),
idle_timeout_primary: None,
idle_timeout_replica: None,
connect_timeout: Duration::from_millis(5_000),
connect_attempts: 1,
connect_attempt_delay: Duration::from_millis(10),
Expand Down
Loading
Loading