From 325738f3b04504ba01e6fbfcd087e3ea5f4af08c Mon Sep 17 00:00:00 2001 From: Denis Cornehl Date: Fri, 21 Nov 2025 19:22:30 +0100 Subject: [PATCH] fix huge diff in consistency check due to different sorting --- ...4271d5ad5901b6a9e292a256bd405b76e769.json} | 4 +- src/utils/consistency/db.rs | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 4 deletions(-) rename .sqlx/{query-f0bdee589c06dea8b71c5dd09cf8d3a4ebef2018ccefb61af8ed2dde44148ccc.json => query-c8b2cc25bc619c4631709515e9b04271d5ad5901b6a9e292a256bd405b76e769.json} (94%) diff --git a/.sqlx/query-f0bdee589c06dea8b71c5dd09cf8d3a4ebef2018ccefb61af8ed2dde44148ccc.json b/.sqlx/query-c8b2cc25bc619c4631709515e9b04271d5ad5901b6a9e292a256bd405b76e769.json similarity index 94% rename from .sqlx/query-f0bdee589c06dea8b71c5dd09cf8d3a4ebef2018ccefb61af8ed2dde44148ccc.json rename to .sqlx/query-c8b2cc25bc619c4631709515e9b04271d5ad5901b6a9e292a256bd405b76e769.json index 3951f398f..f31f9daec 100644 --- a/.sqlx/query-f0bdee589c06dea8b71c5dd09cf8d3a4ebef2018ccefb61af8ed2dde44148ccc.json +++ b/.sqlx/query-c8b2cc25bc619c4631709515e9b04271d5ad5901b6a9e292a256bd405b76e769.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT\n name as \"name!\",\n version as \"version!: Version\",\n yanked\n FROM (\n SELECT\n crates.name,\n releases.version,\n releases.yanked\n FROM crates\n INNER JOIN releases ON releases.crate_id = crates.id\n UNION ALL\n -- crates & releases that are already queued\n -- don't have to be requeued.\n SELECT\n queue.name,\n queue.version,\n NULL as yanked\n FROM queue\n LEFT OUTER JOIN crates ON crates.name = queue.name\n LEFT OUTER JOIN releases ON (\n releases.crate_id = crates.id AND\n releases.version = queue.version\n )\n WHERE queue.attempt < $1 AND (\n crates.id IS NULL OR\n releases.id IS NULL\n )\n ) AS inp\n ORDER BY name, version", + "query": "SELECT\n name as \"name!\",\n version as \"version!: Version\",\n yanked\n FROM (\n SELECT\n crates.name,\n releases.version,\n releases.yanked\n FROM crates\n INNER JOIN releases ON releases.crate_id = crates.id\n UNION ALL\n -- crates & releases that are already queued\n -- don't have to be requeued.\n SELECT\n queue.name,\n queue.version,\n NULL as yanked\n FROM queue\n LEFT OUTER JOIN crates ON crates.name = queue.name\n LEFT OUTER JOIN releases ON (\n releases.crate_id = crates.id AND\n releases.version = queue.version\n )\n WHERE queue.attempt < $1 AND (\n crates.id IS NULL OR\n releases.id IS NULL\n )\n ) AS inp\n ORDER BY name", "describe": { "columns": [ { @@ -30,5 +30,5 @@ null ] }, - "hash": "f0bdee589c06dea8b71c5dd09cf8d3a4ebef2018ccefb61af8ed2dde44148ccc" + "hash": "c8b2cc25bc619c4631709515e9b04271d5ad5901b6a9e292a256bd405b76e769" } diff --git a/src/utils/consistency/db.rs b/src/utils/consistency/db.rs index c05c781e2..de4607fa5 100644 --- a/src/utils/consistency/db.rs +++ b/src/utils/consistency/db.rs @@ -34,7 +34,7 @@ pub(super) async fn load(conn: &mut sqlx::PgConnection, config: &Config) -> Resu releases.id IS NULL ) ) AS inp - ORDER BY name, version"#, + ORDER BY name"#, config.build_attempts as i32, ) .fetch_all(conn) @@ -43,13 +43,15 @@ pub(super) async fn load(conn: &mut sqlx::PgConnection, config: &Config) -> Resu let mut crates = Crates::new(); for (crate_name, release_rows) in &rows.iter().chunk_by(|row| row.name.clone()) { - let releases: Releases = release_rows + let mut releases: Releases = release_rows .map(|row| Release { version: row.version.clone(), yanked: row.yanked, }) .collect(); + releases.sort_by(|lhs, rhs| lhs.version.cmp(&rhs.version)); + crates.push(Crate { name: crate_name, releases, @@ -63,6 +65,7 @@ pub(super) async fn load(conn: &mut sqlx::PgConnection, config: &Config) -> Resu mod tests { use super::*; use crate::test::{V1, V2, V3, async_wrapper}; + use pretty_assertions::assert_eq; #[test] fn test_load() { @@ -84,6 +87,35 @@ mod tests { .create() .await?; + // these two releases are there to ensure we sort correctly. + // In the past, we sorted the version (from the crates index & our database) + // as string, which lead to "0.10.3" coming before "0.9.3". + // When both sides are sorted the same way, this is fine and doesn't break the + // consistency check. + // But after migrating everything to using `semver::Version`, the sorting changed + // on the index-side, while we still sorted by string on the database side. + // + // Since I still run the consistency check manually, every now and then, this wasn't + // an issue, because I saw the odd huge difference. + // + // The solution is to sort both sides semver correctly. + const V0_9_3: Version = Version::new(0, 9, 3); + const V0_10_3: Version = Version::new(0, 10, 3); + env.fake_release() + .await + .name("krate") + .version(V0_9_3) + .yanked(false) + .create() + .await?; + env.fake_release() + .await + .name("krate") + .version(V0_10_3) + .yanked(false) + .create() + .await?; + let mut conn = env.async_db().async_conn().await; let result = load(&mut conn, env.config()).await?; @@ -93,6 +125,14 @@ mod tests { Crate { name: "krate".into(), releases: vec![ + Release { + version: V0_9_3, + yanked: Some(false), + }, + Release { + version: V0_10_3, + yanked: Some(false), + }, Release { version: V2, yanked: Some(false),