customizable db locking during migration (#2063)

* customizable db locking during migration

* Update sqlx-core/src/migrate/migrator.rs

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>

* [migrator.rs] cargo fmt

* fix Migrator 'locking' param doctest fail

Co-authored-by: Austin Bonander <austin.bonander@gmail.com>
This commit is contained in:
fuzzbuck 2022-09-06 22:42:56 +02:00 committed by GitHub
parent c5f3513f7d
commit 18a76fbdbf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 29 additions and 4 deletions

View file

@ -9,6 +9,7 @@ use std::slice;
pub struct Migrator {
pub migrations: Cow<'static, [Migration]>,
pub ignore_missing: bool,
pub locking: bool,
}
fn validate_applied_migrations(
@ -56,6 +57,7 @@ impl Migrator {
Ok(Self {
migrations: Cow::Owned(source.resolve().await.map_err(MigrateError::Source)?),
ignore_missing: false,
locking: true,
})
}
@ -65,6 +67,19 @@ impl Migrator {
self
}
/// Specify whether or not to lock database during migration. Defaults to `true`.
///
/// ### Warning
/// Disabling locking can lead to errors or data loss if multiple clients attempt to apply migrations simultaneously
/// without some sort of mutual exclusion.
///
/// This should only be used if the database does not support locking, e.g. CockroachDB which talks the Postgres
/// protocol but does not support advisory locks used by SQLx's migrations support for Postgres.
pub fn set_locking(&mut self, locking: bool) -> &Self {
self.locking = locking;
self
}
/// Get an iterator over all known migrations.
pub fn iter(&self) -> slice::Iter<'_, Migration> {
self.migrations.iter()
@ -103,7 +118,9 @@ impl Migrator {
C: Migrate,
{
// lock the database for exclusive access by the migrator
conn.lock().await?;
if self.locking {
conn.lock().await?;
}
// creates [_migrations] table only if needed
// eventually this will likely migrate previous versions of the table
@ -141,7 +158,9 @@ impl Migrator {
// unlock the migrator to allow other migrators to run
// but do nothing as we already migrated
conn.unlock().await?;
if self.locking {
conn.unlock().await?;
}
Ok(())
}
@ -170,7 +189,9 @@ impl Migrator {
let mut conn = migrator.acquire().await?;
// lock the database for exclusive access by the migrator
conn.lock().await?;
if self.locking {
conn.lock().await?;
}
// creates [_migrations] table only if needed
// eventually this will likely migrate previous versions of the table
@ -201,7 +222,9 @@ impl Migrator {
// unlock the migrator to allow other migrators to run
// but do nothing as we already migrated
conn.unlock().await?;
if self.locking {
conn.unlock().await?;
}
Ok(())
}

View file

@ -146,6 +146,7 @@ pub(crate) fn expand_migrator(path: &Path) -> crate::Result<TokenStream> {
#(#migrations),*
]),
ignore_missing: false,
locking: true,
}
})
}

View file

@ -132,6 +132,7 @@ use sqlx::PgPool;
# static MIGRATOR: sqlx::migrate::Migrator = sqlx::migrate::Migrator {
# migrations: Cow::Borrowed(&[]),
# ignore_missing: false,
# locking: true,
# };
# }