Remove transaction from abort

All migrations can be aborted idempotently at the moment and hence we
don't need to use a transaction for atomicity.
This commit is contained in:
fabianlindfors 2022-01-12 13:15:26 +01:00
parent b617c8dcda
commit c787111c77
3 changed files with 29 additions and 44 deletions

View File

@ -151,13 +151,10 @@ impl Reshape {
last_migration_index + 1, last_migration_index + 1,
last_action_index + 1, last_action_index + 1,
); );
self.state.save(&mut self.db)?;
self.abort_migrations( // Abort will only
&remaining_migrations, self.abort()?;
last_migration_index + 1,
last_action_index + 1,
)?;
return Err(err); return Err(err);
} }
@ -494,31 +491,19 @@ impl Reshape {
continue; continue;
} }
// Run each action abort as a separate transaction. We need atomicity
// to ensure the abort changes are run only once for each action.
let mut transaction = self
.db
.transaction()
.context("failed to start transaction")?;
let ctx = MigrationContext::new(migration_index, action_index); let ctx = MigrationContext::new(migration_index, action_index);
action action
.abort(&ctx, &mut transaction) .abort(&ctx, &mut self.db)
.with_context(|| format!("failed to abort migration {}", migration.name)) .with_context(|| format!("failed to abort migration {}", migration.name))
.with_context(|| format!("failed to abort action: {}", action.describe()))?; .with_context(|| format!("failed to abort action: {}", action.describe()))?;
// Update state with which migrations and actions have been aborted. By running this // Update state with which migrations and actions have been aborted.
// in a transaction, we guarantee that an action is only aborted once. // We don't need to run this in a transaction as aborts are idempotent.
// We want to use a single transaction for each action to keep the length
// of the transaction as short as possible.
self.state self.state
.aborting(migrations.to_vec(), migration_index, action_index); .aborting(migrations.to_vec(), migration_index, action_index);
self.state self.state
.save(&mut transaction) .save(&mut self.db)
.context("failed to save state")?; .context("failed to save state")?;
transaction
.commit()
.context("failed to commit transaction")?;
} }
println!("{}", "done".green()); println!("{}", "done".green());

View File

@ -250,17 +250,6 @@ impl Action for AddColumn {
} }
fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> { fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> {
// Remove triggers and procedures
let query = format!(
"
DROP TRIGGER IF EXISTS {trigger_name} ON {table};
DROP FUNCTION IF EXISTS {trigger_name};
",
table = self.table,
trigger_name = self.trigger_name(ctx),
);
db.run(&query).context("failed to drop up trigger")?;
// Remove column // Remove column
let query = format!( let query = format!(
" "
@ -272,6 +261,17 @@ impl Action for AddColumn {
); );
db.run(&query).context("failed to drop column")?; db.run(&query).context("failed to drop column")?;
// Remove triggers and procedures
let query = format!(
"
DROP TRIGGER IF EXISTS {trigger_name} ON {table};
DROP FUNCTION IF EXISTS {trigger_name};
",
table = self.table,
trigger_name = self.trigger_name(ctx),
);
db.run(&query).context("failed to drop up trigger")?;
Ok(()) Ok(())
} }
} }

View File

@ -311,6 +311,17 @@ impl Action for AlterColumn {
} }
fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> { fn abort(&self, ctx: &MigrationContext, db: &mut dyn Conn) -> anyhow::Result<()> {
// Drop temporary column
let query = format!(
"
ALTER TABLE {table}
DROP COLUMN IF EXISTS {temp_column};
",
table = self.table,
temp_column = self.temporary_column_name(ctx),
);
db.run(&query).context("failed to drop temporary column")?;
// Remove triggers and procedures // Remove triggers and procedures
let query = format!( let query = format!(
" "
@ -327,17 +338,6 @@ impl Action for AlterColumn {
db.run(&query) db.run(&query)
.context("failed to drop up and down triggers")?; .context("failed to drop up and down triggers")?;
// Drop temporary column
let query = format!(
"
ALTER TABLE {table}
DROP COLUMN IF EXISTS {temp_column};
",
table = self.table,
temp_column = self.temporary_column_name(ctx),
);
db.run(&query).context("failed to drop temporary column")?;
Ok(()) Ok(())
} }
} }