Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix build metadata race condition #9756

Merged
merged 5 commits into from
Oct 27, 2024
Merged

Conversation

Turbo87
Copy link
Member

@Turbo87 Turbo87 commented Oct 25, 2024

This PR fixes a race condition in our publish endpoint. When two versions, 1.0.0+foo and 1.0.0+bar are published concurrently we previously could get into a situation where the "unique version number excluding build metadata" check succeeds for both, and then both versions are added to the database, when only one such version should exist.

This PR adds a new unique constraint on (crate_id, num_no_build) to prevent this from happening.

We currently have around 650 such cases still in the database though. In those cases the num_no_build column is adjusted to actually contain the build metadata too (see column comment).

Finally, this PR needs to be merged/deployed in multiple stages. The initial migration adds the column in a nullable way, because the SQL script to backfill the data for the column takes about 30 sec (on my machine), and this shouldn't prevent the API server from booting up because of a running schema migration. It is recommended to merge/deploy each migration in this PR independently!

This shall be filled by the following SQL script:

```sql
update versions
    set num_no_build = split_part(num, '+', 1);

with duplicates as (
    -- find all versions that have the same `crate_id` and `unique_num`
    select crate_id, num_no_build, array_agg(num ORDER BY id) as nums
    from versions
    group by crate_id, num_no_build
    having count(*) > 1
),
duplicates_to_update as (
    -- for each group of duplicates, update all versions except the one that
    -- doesn't have "build metadata", or the first one that was published if
    -- all versions have "build metadata"
    select crate_id, num_no_build, unnest(case when array_position(nums, num_no_build) IS NOT NULL then array_remove(nums, num_no_build) else nums[2:] end) as num
    from duplicates
)
update versions
    set num_no_build = duplicates_to_update.num
    from duplicates_to_update
    where versions.crate_id = duplicates_to_update.crate_id
    and versions.num = duplicates_to_update.num;
```

The script takes a few seconds to complete, so this should not be added to the database schema migration script, since it would block the API server from booting.
… already exists" response

Previously, it was theoretically possible to publish two versions with the same base version number, but different build metadata, at the same time due to a race condition between the check and the insert. This commit fixes the issue by instead relying on the database uniqueness error to build the appropriate response.
…ller code

The model layer is not supposed to know anything about HTTP API errors...
@Turbo87 Turbo87 added C-bug 🐞 Category: unintended, undesired behavior A-backend ⚙️ labels Oct 25, 2024
@Turbo87 Turbo87 changed the title Add versions.num_no_build column Fix build metadata race condition Oct 25, 2024
@Turbo87 Turbo87 requested a review from a team October 25, 2024 12:20
Copy link

codecov bot commented Oct 25, 2024

Codecov Report

Attention: Patch coverage is 96.00000% with 1 line in your changes missing coverage. Please review.

Please upload report for BASE (main@e8ef4e1). Learn more about missing BASE report.
Report is 16 commits behind head on main.

Files with missing lines Patch % Lines
src/controllers/krate/publish.rs 90.00% 1 Missing ⚠️
Additional details and impacted files
@@           Coverage Diff           @@
##             main    #9756   +/-   ##
=======================================
  Coverage        ?   88.81%           
=======================================
  Files           ?      289           
  Lines           ?    29825           
  Branches        ?        0           
=======================================
  Hits            ?    26488           
  Misses          ?     3337           
  Partials        ?        0           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@Turbo87 Turbo87 merged commit 3de6c20 into rust-lang:main Oct 27, 2024
10 checks passed
@Turbo87 Turbo87 deleted the num_no_build branch October 27, 2024 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-backend ⚙️ C-bug 🐞 Category: unintended, undesired behavior
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

1 participant