v0.3.3-pre.003
This commit is contained in:
@@ -1,18 +1,23 @@
|
||||
// file: crates/ksp-store-postgres-lib/src/migration.rs
|
||||
// version: 3
|
||||
// version: 4
|
||||
|
||||
use sha2::Digest; // rust-rules: trait-import
|
||||
|
||||
const ADVISORY_LOCK_KEY: i64 = 0x4b53_5053_544f_5245;
|
||||
const EMBEDDED_MIGRATIONS: &[EmbeddedMigration] = &[EmbeddedMigration {
|
||||
hook: MigrationHook::None,
|
||||
name: "bootstrap",
|
||||
sql: include_str!("../migrations/V000__bootstrap.sql"),
|
||||
version: 0,
|
||||
}];
|
||||
const EMBEDDED_MIGRATIONS: &[EmbeddedMigration] = &[
|
||||
EmbeddedMigration { hook: MigrationHook::None, name: "bootstrap", sql: include_str!("../migrations/V000__bootstrap.sql"), version: 0 },
|
||||
EmbeddedMigration {
|
||||
hook: MigrationHook::StoreIdentity,
|
||||
name: "raw_transaction",
|
||||
sql: include_str!("../migrations/V001__raw_transaction.sql"),
|
||||
version: 1,
|
||||
},
|
||||
];
|
||||
const HEX_LOWER: &[u8; 16] = b"0123456789abcdef";
|
||||
const HISTORY_INSERT_SQL: &str = "INSERT INTO ksp_store_schema_migrations (version, name, checksum, applied_at) VALUES ($1, $2, $3, CURRENT_TIMESTAMP)";
|
||||
const HISTORY_LOAD_SQL: &str = "SELECT version, name, checksum FROM ksp_store_schema_migrations ORDER BY version";
|
||||
const IDENTITY_INSERT_SQL: &str = "INSERT INTO ksp_store_identity (singleton, network) VALUES (1, $1)";
|
||||
const IDENTITY_LOAD_SQL: &str = "SELECT singleton, network FROM ksp_store_identity ORDER BY singleton LIMIT 2";
|
||||
const LOCK_POLL_INTERVAL_MS: u64 = 25;
|
||||
const METADATA_EXISTS_SQL: &str = r#"SELECT EXISTS (
|
||||
SELECT 1 FROM information_schema.tables
|
||||
@@ -54,6 +59,7 @@ struct EmbeddedMigration {
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum MigrationHook {
|
||||
None,
|
||||
StoreIdentity,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -80,7 +86,11 @@ pub(crate) async fn bootstrap(
|
||||
if let std::result::Result::Err(error) = registry_result {
|
||||
return std::result::Result::Err(error);
|
||||
}
|
||||
let bounded = tokio::time::timeout(migration_timeout, bootstrap_inner(client, network, auto_migrate, migration_timeout, migration_lock_timeout)).await;
|
||||
let bounded = tokio::time::timeout(
|
||||
migration_timeout,
|
||||
bootstrap_inner(client, network, auto_migrate, migration_timeout, migration_lock_timeout),
|
||||
)
|
||||
.await;
|
||||
return match bounded {
|
||||
std::result::Result::Ok(result) => result,
|
||||
std::result::Result::Err(_) => {
|
||||
@@ -310,16 +320,86 @@ async fn run_applied_migration_hooks(
|
||||
}
|
||||
|
||||
async fn run_migration_hook(
|
||||
_transaction: &deadpool_postgres::Transaction<'_>,
|
||||
_network: &ksp_store_api::RawNetworkId,
|
||||
transaction: &deadpool_postgres::Transaction<'_>,
|
||||
network: &ksp_store_api::RawNetworkId,
|
||||
hook: MigrationHook,
|
||||
_context: MigrationHookContext,
|
||||
context: MigrationHookContext,
|
||||
) -> std::result::Result<(), crate::PostgresBackendError> {
|
||||
return match hook {
|
||||
MigrationHook::None => std::result::Result::Ok(()),
|
||||
MigrationHook::StoreIdentity => bind_store_identity(transaction, network, context).await,
|
||||
};
|
||||
}
|
||||
|
||||
async fn bind_store_identity(
|
||||
transaction: &deadpool_postgres::Transaction<'_>,
|
||||
network: &ksp_store_api::RawNetworkId,
|
||||
context: MigrationHookContext,
|
||||
) -> std::result::Result<(), crate::PostgresBackendError> {
|
||||
if context == MigrationHookContext::AppliedNow {
|
||||
let insert_result = transaction.execute(IDENTITY_INSERT_SQL, &[&network.as_str()]).await;
|
||||
match insert_result {
|
||||
std::result::Result::Ok(1) => {},
|
||||
std::result::Result::Ok(_) | std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationFailed,
|
||||
"store_identity_insert",
|
||||
));
|
||||
},
|
||||
}
|
||||
}
|
||||
let rows_result = transaction.query(IDENTITY_LOAD_SQL, &[]).await;
|
||||
let rows = match rows_result {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_read",
|
||||
));
|
||||
},
|
||||
};
|
||||
if rows.len() != 1 {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_count",
|
||||
));
|
||||
}
|
||||
let row = &rows[0];
|
||||
let singleton_result = row.try_get::<usize, i16>(0);
|
||||
let network_result = row.try_get::<usize, std::string::String>(1);
|
||||
let (singleton, stored_network) = match (singleton_result, network_result) {
|
||||
(std::result::Result::Ok(singleton), std::result::Result::Ok(stored_network)) => (singleton, stored_network),
|
||||
_ => {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_decode",
|
||||
));
|
||||
},
|
||||
};
|
||||
if singleton != 1 {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_singleton",
|
||||
));
|
||||
}
|
||||
let stored_network = match ksp_store_api::RawNetworkId::new(stored_network) {
|
||||
std::result::Result::Ok(value) => value,
|
||||
std::result::Result::Err(_) => {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_network",
|
||||
));
|
||||
},
|
||||
};
|
||||
if stored_network.as_str() != network.as_str() {
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(
|
||||
crate::PostgresBackendErrorKind::MigrationMismatch,
|
||||
"store_identity_network",
|
||||
));
|
||||
}
|
||||
return std::result::Result::Ok(());
|
||||
}
|
||||
|
||||
async fn set_statement_timeout(
|
||||
transaction: &deadpool_postgres::Transaction<'_>,
|
||||
timeout: std::time::Duration,
|
||||
@@ -384,8 +464,12 @@ async fn verify_metadata_shape(transaction: &deadpool_postgres::Transaction<'_>)
|
||||
return std::result::Result::Err(crate::PostgresBackendError::new(crate::PostgresBackendErrorKind::MigrationFailed, "metadata_shape"));
|
||||
},
|
||||
};
|
||||
const REQUIRED: [(&str, &str, &str); 4] =
|
||||
[("version", "bigint", "NO"), ("name", "text", "NO"), ("checksum", "text", "NO"), ("applied_at", "timestamp with time zone", "NO")];
|
||||
const REQUIRED: [(&str, &str, &str); 4] = [
|
||||
("version", "bigint", "NO"),
|
||||
("name", "text", "NO"),
|
||||
("checksum", "text", "NO"),
|
||||
("applied_at", "timestamp with time zone", "NO"),
|
||||
];
|
||||
let mut found = [false; REQUIRED.len()];
|
||||
for row in rows {
|
||||
let name_result = row.try_get::<usize, std::string::String>(0);
|
||||
|
||||
Reference in New Issue
Block a user