use std::hash::{Hash, Hasher};
use crate::error::Result;
use crate::Connection;
#[derive(Debug, Clone, Copy)]
pub struct PgAdvisoryLock {
key: i64,
}
impl PgAdvisoryLock {
pub fn new(key: i64) -> Self {
Self { key }
}
pub fn from_name(name: &str) -> Self {
let mut hasher = std::collections::hash_map::DefaultHasher::new();
name.hash(&mut hasher);
Self {
key: hasher.finish() as i64,
}
}
pub fn key(&self) -> i64 {
self.key
}
pub async fn acquire(&self, conn: &mut Connection) -> Result<PgAdvisoryLockGuard> {
conn.execute("SELECT pg_advisory_lock($1)", &[&self.key])
.await?;
Ok(PgAdvisoryLockGuard { key: self.key })
}
pub async fn try_acquire(&self, conn: &mut Connection) -> Result<Option<PgAdvisoryLockGuard>> {
let rows = conn
.query("SELECT pg_try_advisory_lock($1)", &[&self.key])
.await?;
let acquired: bool = rows
.first()
.map(|r| r.try_get::<bool>(0))
.transpose()?
.unwrap_or(false);
if acquired {
Ok(Some(PgAdvisoryLockGuard { key: self.key }))
} else {
Ok(None)
}
}
}
#[derive(Debug)]
pub struct PgAdvisoryLockGuard {
key: i64,
}
impl PgAdvisoryLockGuard {
pub fn key(&self) -> i64 {
self.key
}
pub async fn release(self, conn: &mut Connection) -> Result<()> {
conn.execute("SELECT pg_advisory_unlock($1)", &[&self.key])
.await?;
Ok(())
}
}