Skip to content

Commit 01d5443

Browse files
feat(postgres): remove lifetime from PgAdvisoryLockGuard (#3495)
Unlike with CPU synchronization primitives, there is no semantic requirement that the guard borrows the lock object. We preserve the optimization of memoizing the release query by wrapping it in an Arc. This way all instances of `PgAdvisoryLockGuard` that originate from the same lock will share a single instance of the release query. Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
1 parent 21598cf commit 01d5443

File tree

1 file changed

+16
-17
lines changed

1 file changed

+16
-17
lines changed

sqlx-postgres/src/advisory_lock.rs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use crate::PgConnection;
44
use hkdf::Hkdf;
55
use sha2::Sha256;
66
use std::ops::{Deref, DerefMut};
7+
use std::sync::Arc;
78
use std::sync::OnceLock;
89

910
/// A mutex-like type utilizing [Postgres advisory locks].
@@ -37,7 +38,7 @@ use std::sync::OnceLock;
3738
pub struct PgAdvisoryLock {
3839
key: PgAdvisoryLockKey,
3940
/// The query to execute to release this lock.
40-
release_query: OnceLock<String>,
41+
release_query: Arc<OnceLock<String>>,
4142
}
4243

4344
/// A key type natively used by Postgres advisory locks.
@@ -77,8 +78,8 @@ pub enum PgAdvisoryLockKey {
7778
///
7879
/// This means the lock is not actually released as soon as the guard is dropped. To ensure the
7980
/// lock is eagerly released, you can call [`.release_now().await`][Self::release_now()].
80-
pub struct PgAdvisoryLockGuard<'lock, C: AsMut<PgConnection>> {
81-
lock: &'lock PgAdvisoryLock,
81+
pub struct PgAdvisoryLockGuard<C: AsMut<PgConnection>> {
82+
lock: PgAdvisoryLock,
8283
conn: Option<C>,
8384
}
8485

@@ -163,7 +164,7 @@ impl PgAdvisoryLock {
163164
pub fn with_key(key: PgAdvisoryLockKey) -> Self {
164165
Self {
165166
key,
166-
release_query: OnceLock::new(),
167+
release_query: Arc::new(OnceLock::new()),
167168
}
168169
}
169170

@@ -201,7 +202,7 @@ impl PgAdvisoryLock {
201202
pub async fn acquire<C: AsMut<PgConnection>>(
202203
&self,
203204
mut conn: C,
204-
) -> Result<PgAdvisoryLockGuard<'_, C>> {
205+
) -> Result<PgAdvisoryLockGuard<C>> {
205206
match &self.key {
206207
PgAdvisoryLockKey::BigInt(key) => {
207208
crate::query::query("SELECT pg_advisory_lock($1)")
@@ -218,7 +219,7 @@ impl PgAdvisoryLock {
218219
}
219220
}
220221

221-
Ok(PgAdvisoryLockGuard::new(self, conn))
222+
Ok(PgAdvisoryLockGuard::new(self.clone(), conn))
222223
}
223224

224225
/// Acquires an exclusive lock using `pg_try_advisory_lock()`, returning immediately
@@ -244,7 +245,7 @@ impl PgAdvisoryLock {
244245
pub async fn try_acquire<C: AsMut<PgConnection>>(
245246
&self,
246247
mut conn: C,
247-
) -> Result<Either<PgAdvisoryLockGuard<'_, C>, C>> {
248+
) -> Result<Either<PgAdvisoryLockGuard<C>, C>> {
248249
let locked: bool = match &self.key {
249250
PgAdvisoryLockKey::BigInt(key) => {
250251
crate::query_scalar::query_scalar("SELECT pg_try_advisory_lock($1)")
@@ -262,7 +263,7 @@ impl PgAdvisoryLock {
262263
};
263264

264265
if locked {
265-
Ok(Either::Left(PgAdvisoryLockGuard::new(self, conn)))
266+
Ok(Either::Left(PgAdvisoryLockGuard::new(self.clone(), conn)))
266267
} else {
267268
Ok(Either::Right(conn))
268269
}
@@ -322,8 +323,8 @@ impl PgAdvisoryLockKey {
322323

323324
const NONE_ERR: &str = "BUG: PgAdvisoryLockGuard.conn taken";
324325

325-
impl<'lock, C: AsMut<PgConnection>> PgAdvisoryLockGuard<'lock, C> {
326-
fn new(lock: &'lock PgAdvisoryLock, conn: C) -> Self {
326+
impl<C: AsMut<PgConnection>> PgAdvisoryLockGuard<C> {
327+
fn new(lock: PgAdvisoryLock, conn: C) -> Self {
327328
PgAdvisoryLockGuard {
328329
lock,
329330
conn: Some(conn),
@@ -362,7 +363,7 @@ impl<'lock, C: AsMut<PgConnection>> PgAdvisoryLockGuard<'lock, C> {
362363
}
363364
}
364365

365-
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> Deref for PgAdvisoryLockGuard<'_, C> {
366+
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> Deref for PgAdvisoryLockGuard<C> {
366367
type Target = PgConnection;
367368

368369
fn deref(&self) -> &Self::Target {
@@ -376,15 +377,13 @@ impl<C: AsMut<PgConnection> + AsRef<PgConnection>> Deref for PgAdvisoryLockGuard
376377
/// However, replacing the connection with a different one using, e.g. [`std::mem::replace()`]
377378
/// is a logic error and will cause a warning to be logged by the PostgreSQL server when this
378379
/// guard attempts to release the lock.
379-
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> DerefMut for PgAdvisoryLockGuard<'_, C> {
380+
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> DerefMut for PgAdvisoryLockGuard<C> {
380381
fn deref_mut(&mut self) -> &mut Self::Target {
381382
self.conn.as_mut().expect(NONE_ERR).as_mut()
382383
}
383384
}
384385

385-
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> AsRef<PgConnection>
386-
for PgAdvisoryLockGuard<'_, C>
387-
{
386+
impl<C: AsMut<PgConnection> + AsRef<PgConnection>> AsRef<PgConnection> for PgAdvisoryLockGuard<C> {
388387
fn as_ref(&self) -> &PgConnection {
389388
self.conn.as_ref().expect(NONE_ERR).as_ref()
390389
}
@@ -396,7 +395,7 @@ impl<C: AsMut<PgConnection> + AsRef<PgConnection>> AsRef<PgConnection>
396395
/// However, replacing the connection with a different one using, e.g. [`std::mem::replace()`]
397396
/// is a logic error and will cause a warning to be logged by the PostgreSQL server when this
398397
/// guard attempts to release the lock.
399-
impl<C: AsMut<PgConnection>> AsMut<PgConnection> for PgAdvisoryLockGuard<'_, C> {
398+
impl<C: AsMut<PgConnection>> AsMut<PgConnection> for PgAdvisoryLockGuard<C> {
400399
fn as_mut(&mut self) -> &mut PgConnection {
401400
self.conn.as_mut().expect(NONE_ERR).as_mut()
402401
}
@@ -405,7 +404,7 @@ impl<C: AsMut<PgConnection>> AsMut<PgConnection> for PgAdvisoryLockGuard<'_, C>
405404
/// Queues a `pg_advisory_unlock()` call on the wrapped connection which will be flushed
406405
/// to the server the next time it is used, or when it is returned to [`PgPool`][crate::PgPool]
407406
/// in the case of [`PoolConnection<Postgres>`][crate::pool::PoolConnection].
408-
impl<C: AsMut<PgConnection>> Drop for PgAdvisoryLockGuard<'_, C> {
407+
impl<C: AsMut<PgConnection>> Drop for PgAdvisoryLockGuard<C> {
409408
fn drop(&mut self) {
410409
if let Some(mut conn) = self.conn.take() {
411410
// Queue a simple query message to execute next time the connection is used.

0 commit comments

Comments
 (0)