mirror of
https://github.com/postgresml/pgcat.git
synced 2026-03-27 18:56:30 +00:00
@@ -59,6 +59,8 @@ cd ../..
|
|||||||
|
|
||||||
# Admin tests
|
# Admin tests
|
||||||
psql -e -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW STATS' > /dev/null
|
psql -e -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW STATS' > /dev/null
|
||||||
|
psql -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD' > /dev/null
|
||||||
|
psql -h 127.0.0.1 -p 6432 -d pgbouncer -c 'SHOW CONFIG' > /dev/null
|
||||||
(! psql -e -h 127.0.0.1 -p 6432 -d random_db -c 'SHOW STATS' > /dev/null)
|
(! psql -e -h 127.0.0.1 -p 6432 -d random_db -c 'SHOW STATS' > /dev/null)
|
||||||
|
|
||||||
# Start PgCat in debug to demonstrate failover better
|
# Start PgCat in debug to demonstrate failover better
|
||||||
@@ -86,9 +88,6 @@ sed -i 's/pool_mode = "transaction"/pool_mode = "session"/' pgcat.toml
|
|||||||
# Reload config test
|
# Reload config test
|
||||||
kill -SIGHUP $(pgrep pgcat)
|
kill -SIGHUP $(pgrep pgcat)
|
||||||
|
|
||||||
# Reload again with the admin database
|
|
||||||
psql -h 127.0.0.1 -p 6432 -d pgbouncer -c 'RELOAD' > /dev/null
|
|
||||||
|
|
||||||
# Prepared statements that will only work in session mode
|
# Prepared statements that will only work in session mode
|
||||||
pgbench -h 127.0.0.1 -p 6432 -t 500 -c 2 --protocol prepared
|
pgbench -h 127.0.0.1 -p 6432 -t 500 -c 2 --protocol prepared
|
||||||
|
|
||||||
|
|||||||
91
src/admin.rs
91
src/admin.rs
@@ -2,6 +2,8 @@ use bytes::{Buf, BufMut, BytesMut};
|
|||||||
use log::{info, trace};
|
use log::{info, trace};
|
||||||
use tokio::net::tcp::OwnedWriteHalf;
|
use tokio::net::tcp::OwnedWriteHalf;
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::config::{get_config, parse};
|
use crate::config::{get_config, parse};
|
||||||
use crate::constants::{OID_NUMERIC, OID_TEXT};
|
use crate::constants::{OID_NUMERIC, OID_TEXT};
|
||||||
use crate::errors::Error;
|
use crate::errors::Error;
|
||||||
@@ -27,6 +29,9 @@ pub async fn handle_admin(stream: &mut OwnedWriteHalf, mut query: BytesMut) -> R
|
|||||||
} else if query.starts_with("RELOAD") {
|
} else if query.starts_with("RELOAD") {
|
||||||
trace!("RELOAD");
|
trace!("RELOAD");
|
||||||
reload(stream).await
|
reload(stream).await
|
||||||
|
} else if query.starts_with("SHOW CONFIG") {
|
||||||
|
trace!("SHOW CONFIG");
|
||||||
|
show_config(stream).await
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ProtocolSyncError)
|
Err(Error::ProtocolSyncError)
|
||||||
}
|
}
|
||||||
@@ -61,6 +66,92 @@ pub async fn reload(stream: &mut OwnedWriteHalf) -> Result<(), Error> {
|
|||||||
write_all_half(stream, res).await
|
write_all_half(stream, res).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn show_config(stream: &mut OwnedWriteHalf) -> Result<(), Error> {
|
||||||
|
let guard = get_config();
|
||||||
|
let config = &*guard.clone();
|
||||||
|
let config: HashMap<String, String> = config.into();
|
||||||
|
drop(guard);
|
||||||
|
|
||||||
|
// Configs that cannot be changed dynamically.
|
||||||
|
let immutables = ["host", "port", "connect_timeout"];
|
||||||
|
|
||||||
|
// Columns
|
||||||
|
let columns = ["key", "value", "default", "changeable"];
|
||||||
|
|
||||||
|
// RowDescription
|
||||||
|
let mut row_desc = BytesMut::new();
|
||||||
|
row_desc.put_i16(4 as i16); // key, value, default, changeable
|
||||||
|
|
||||||
|
for column in columns {
|
||||||
|
row_desc.put_slice(&format!("{}\0", column).as_bytes());
|
||||||
|
|
||||||
|
// Doesn't belong to any table
|
||||||
|
row_desc.put_i32(0);
|
||||||
|
|
||||||
|
// Doesn't belong to any table
|
||||||
|
row_desc.put_i16(0);
|
||||||
|
|
||||||
|
// Data type
|
||||||
|
row_desc.put_i32(OID_TEXT);
|
||||||
|
|
||||||
|
// text size = variable (-1)
|
||||||
|
row_desc.put_i16(-1);
|
||||||
|
|
||||||
|
// Type modifier: none that I know
|
||||||
|
row_desc.put_i32(-1);
|
||||||
|
|
||||||
|
// Format being used: text (0), binary (1)
|
||||||
|
row_desc.put_i16(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Response data
|
||||||
|
let mut res = BytesMut::new();
|
||||||
|
res.put_u8(b'T');
|
||||||
|
res.put_i32(row_desc.len() as i32 + 4);
|
||||||
|
res.put(row_desc);
|
||||||
|
|
||||||
|
// DataRow rows
|
||||||
|
for (key, value) in config {
|
||||||
|
let mut data_row = BytesMut::new();
|
||||||
|
|
||||||
|
data_row.put_i16(4 as i16); // key, value, default, changeable
|
||||||
|
|
||||||
|
let key_bytes = key.as_bytes();
|
||||||
|
let value = value.as_bytes();
|
||||||
|
|
||||||
|
data_row.put_i32(key_bytes.len() as i32);
|
||||||
|
data_row.put_slice(&key_bytes);
|
||||||
|
|
||||||
|
data_row.put_i32(value.len() as i32);
|
||||||
|
data_row.put_slice(&value);
|
||||||
|
|
||||||
|
data_row.put_i32(1 as i32);
|
||||||
|
data_row.put_slice(&"-".as_bytes());
|
||||||
|
|
||||||
|
let changeable = if immutables.iter().filter(|col| *col == &key).count() == 1 {
|
||||||
|
"no".as_bytes()
|
||||||
|
} else {
|
||||||
|
"yes".as_bytes()
|
||||||
|
};
|
||||||
|
data_row.put_i32(changeable.len() as i32);
|
||||||
|
data_row.put_slice(&changeable);
|
||||||
|
|
||||||
|
res.put_u8(b'D');
|
||||||
|
res.put_i32(data_row.len() as i32 + 4);
|
||||||
|
res.put(data_row);
|
||||||
|
}
|
||||||
|
|
||||||
|
res.put_u8(b'C');
|
||||||
|
res.put_i32("SHOW CONFIG\0".as_bytes().len() as i32 + 4);
|
||||||
|
res.put_slice(&"SHOW CONFIG\0".as_bytes());
|
||||||
|
|
||||||
|
res.put_u8(b'Z');
|
||||||
|
res.put_i32(5);
|
||||||
|
res.put_u8(b'I');
|
||||||
|
|
||||||
|
write_all_half(stream, res).await
|
||||||
|
}
|
||||||
|
|
||||||
/// SHOW STATS
|
/// SHOW STATS
|
||||||
pub async fn show_stats(stream: &mut OwnedWriteHalf) -> Result<(), Error> {
|
pub async fn show_stats(stream: &mut OwnedWriteHalf) -> Result<(), Error> {
|
||||||
let columns = [
|
let columns = [
|
||||||
|
|||||||
@@ -153,6 +153,52 @@ impl Default for Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<&Config> for std::collections::HashMap<String, String> {
|
||||||
|
fn from(config: &Config) -> HashMap<String, String> {
|
||||||
|
HashMap::from([
|
||||||
|
("host".to_string(), config.general.host.to_string()),
|
||||||
|
("port".to_string(), config.general.port.to_string()),
|
||||||
|
(
|
||||||
|
"pool_size".to_string(),
|
||||||
|
config.general.pool_size.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"pool_mode".to_string(),
|
||||||
|
config.general.pool_mode.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"connect_timeout".to_string(),
|
||||||
|
config.general.connect_timeout.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"healthcheck_timeout".to_string(),
|
||||||
|
config.general.healthcheck_timeout.to_string(),
|
||||||
|
),
|
||||||
|
("ban_time".to_string(), config.general.ban_time.to_string()),
|
||||||
|
(
|
||||||
|
"statsd_address".to_string(),
|
||||||
|
config.general.statsd_address.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"default_role".to_string(),
|
||||||
|
config.query_router.default_role.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"query_parser_enabled".to_string(),
|
||||||
|
config.query_router.query_parser_enabled.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"primary_reads_enabled".to_string(),
|
||||||
|
config.query_router.primary_reads_enabled.to_string(),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"sharding_function".to_string(),
|
||||||
|
config.query_router.sharding_function.to_string(),
|
||||||
|
),
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
pub fn show(&self) {
|
pub fn show(&self) {
|
||||||
info!("Pool size: {}", self.general.pool_size);
|
info!("Pool size: {}", self.general.pool_size);
|
||||||
|
|||||||
Reference in New Issue
Block a user