From d491221e899db55d74a0eb34edc8c3d22362da61 Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Fri, 18 Oct 2024 10:54:52 +0200 Subject: [PATCH] fix: performance issue in update_deprecated_advisory --- migration/src/lib.rs | 2 ++ .../update_deprecated_advisory.sql | 13 +++++--- ...m0000680_fix_update_deprecated_advisory.rs | 33 +++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 migration/src/m0000680_fix_update_deprecated_advisory.rs diff --git a/migration/src/lib.rs b/migration/src/lib.rs index 7fe039b3..67120295 100644 --- a/migration/src/lib.rs +++ b/migration/src/lib.rs @@ -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; @@ -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), ] } } diff --git a/migration/src/m0000650_alter_advisory_tracking/update_deprecated_advisory.sql b/migration/src/m0000650_alter_advisory_tracking/update_deprecated_advisory.sql index b3e84911..2817068b 100644 --- a/migration/src/m0000650_alter_advisory_tracking/update_deprecated_advisory.sql +++ b/migration/src/m0000650_alter_advisory_tracking/update_deprecated_advisory.sql @@ -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; diff --git a/migration/src/m0000680_fix_update_deprecated_advisory.rs b/migration/src/m0000680_fix_update_deprecated_advisory.rs new file mode 100644 index 00000000..7331a9af --- /dev/null +++ b/migration/src/m0000680_fix_update_deprecated_advisory.rs @@ -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(()) + } +}