mirror of
https://github.com/neondatabase/neon.git
synced 2026-01-17 02:12:56 +00:00
Before, compute_ctl didn't have a good registry for what command would run when, depending exclusively on sync code to apply changes. When users have many databases/roles to manage, this step can take a substantial amount of time, breaking assumptions about low (re)start times in other systems. This commit reduces the time compute_ctl takes to restart when changes must be applied, by making all commands more or less blind writes, and applying these commands in an asynchronous context, only waiting for completion once we know the commands have all been sent. Additionally, this reduces time spent by batching per-database operations where previously we would create a new SQL connection for every user-database operation we planned to execute.
52 lines
1.6 KiB
Rust
52 lines
1.6 KiB
Rust
use anyhow::{anyhow, Ok, Result};
|
|
use tokio_postgres::NoTls;
|
|
use tracing::{error, instrument, warn};
|
|
|
|
use crate::compute::ComputeNode;
|
|
|
|
/// Update timestamp in a row in a special service table to check
|
|
/// that we can actually write some data in this particular timeline.
|
|
#[instrument(skip_all)]
|
|
pub async fn check_writability(compute: &ComputeNode) -> Result<()> {
|
|
// Connect to the database.
|
|
let (client, connection) = tokio_postgres::connect(compute.connstr.as_str(), NoTls).await?;
|
|
if client.is_closed() {
|
|
return Err(anyhow!("connection to postgres closed"));
|
|
}
|
|
|
|
// The connection object performs the actual communication with the database,
|
|
// so spawn it off to run on its own.
|
|
tokio::spawn(async move {
|
|
if let Err(e) = connection.await {
|
|
error!("connection error: {}", e);
|
|
}
|
|
});
|
|
|
|
let query = "
|
|
INSERT INTO health_check VALUES (1, now())
|
|
ON CONFLICT (id) DO UPDATE
|
|
SET updated_at = now();";
|
|
|
|
match client.simple_query(query).await {
|
|
Result::Ok(result) => {
|
|
if result.len() != 1 {
|
|
return Err(anyhow::anyhow!(
|
|
"expected 1 query results, but got {}",
|
|
result.len()
|
|
));
|
|
}
|
|
}
|
|
Err(err) => {
|
|
if let Some(state) = err.code() {
|
|
if state == &tokio_postgres::error::SqlState::DISK_FULL {
|
|
warn!("Tenant disk is full");
|
|
return Ok(());
|
|
}
|
|
}
|
|
return Err(err.into());
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|