Skip to content

Commit

Permalink
fix: performance issue in update_deprecated_advisory
Browse files Browse the repository at this point in the history
  • Loading branch information
ctron committed Oct 18, 2024
1 parent fa2570a commit 03e2637
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
2 changes: 2 additions & 0 deletions migration/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod m0000640_create_product_status;
mod m0000650_alter_advisory_tracking;
mod m0000660_purl_id_indexes;
mod m0000670_version_cmp;
mod m0000680_fix_update_deprecated_advisory;

pub struct Migrator;

Expand Down Expand Up @@ -175,6 +176,7 @@ impl MigratorTrait for Migrator {
Box::new(m0000650_alter_advisory_tracking::Migration),
Box::new(m0000660_purl_id_indexes::Migration),
Box::new(m0000670_version_cmp::Migration),
Box::new(m0000680_fix_update_deprecated_advisory::Migration),
]
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ CREATE OR REPLACE FUNCTION update_deprecated_advisory(identifier_input TEXT DEFA
RETURNS VOID AS
$$
BEGIN
WITH MostRecent AS (SELECT DISTINCT ON (identifier) id
FROM advisory
WHERE identifier = COALESCE(identifier_input, identifier)
ORDER BY identifier, modified DESC)
UPDATE advisory
SET deprecated = (id != (SELECT id
FROM advisory a
WHERE a.identifier = COALESCE(identifier_input, advisory.identifier)
ORDER BY a.modified DESC
LIMIT 1))
SET deprecated = CASE
WHEN id IN (SELECT id FROM MostRecent) THEN FALSE
ELSE TRUE
END
WHERE identifier = COALESCE(identifier_input, identifier);
END;
$$ LANGUAGE plpgsql;
33 changes: 33 additions & 0 deletions migration/src/m0000680_fix_update_deprecated_advisory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
// This one is a bit special. The original migration was bugged by a performance issue. So
// we need to replace that function if it was already present and passed the migration. But
// We also need to replace the function in case the migration was not yet run. Because
// otherwise, the migration would not pass.
//
// The strategy is to replace the original function with the new content, and re-apply it
// with this migration. If the original migration did not yet pass, it would now. In any
// case, this migration ensures the new content of the function from now on.
manager
.get_connection()
.execute_unprepared(include_str!(
"m0000650_alter_advisory_tracking/update_deprecated_advisory.sql"
))
.await
.map(|_| ())?;

Ok(())
}

async fn down(&self, _manager: &SchemaManager) -> Result<(), DbErr> {
// As the original version of this function was flawed, we replaced the original content
// and don't migrate back.
Ok(())
}
}

0 comments on commit 03e2637

Please sign in to comment.