Store the content address on Version instead of parsing full_name - #863
Conversation
|
Tophat looks good! And the code changes in general make sense! QQ about something I noticed in how we validate content-addressable versions. In the Version model, a version is only considered content-addressable when it is platformed and has a ruby_abi. But in the compact index token rendering ( That means an inconsistent row like How likely is it for that case to happen? And should we make these rules consistent? |
|
@girachawda yes good point. Right now, we are setting a content address before validation if there's a Ruby ABI set, but we aren't checking if content address is |
girachawda
left a comment
There was a problem hiding this comment.
Thanks, this addresses my concern. I reran the tophat locally and also checked the validation path with a gem that had ruby_abi as nil. It wasn't considered content addressable which is expected ✅
The content address was the only component of full_name without its own column, so the compact index paths re-extracted it from the string with a format heuristic and Version re-derived it with a uniqueness probe on every call. Store it at push time (content_addressify! runs before full_nameify!, so full_name is derived from the column), read it directly in the compact index queries, and validate its format. A partial unique index on (rubygem_id, number, content_address) enforces the collision the full_name string used to embed implicitly, mirroring the existing (rubygem_id, number, platform) uniqueness. Note for non-production environments: content-addressable versions pushed before this migration have a NULL content_address and need a backfill, otherwise their /versions tokens change.
4030ba8 to
2dac644
Compare
0fd16f7
into
ho/feature-branch-ca-server-changes
rubygems#6674
Problem
Every component of
full_namehas its own column (rubygems.name,versions.number,versions.platform) — except the content address, which only existed embedded in the string. That forced two workarounds: the compact index paths re-extracted it with a hex-format heuristic (gated on ABI + platform to avoid mistaking date-style version numbers like20260101for addresses), andVersion#content_addressre-ran the DB uniqueness probe on every call. There was also no database-level guard against two versions of a gem computing the same identity — uniquelower(full_name)indexes are impossible on this table (97 grandfathered case-collision groups from 2009–2010, most still live).Solution
Store the address in
versions.content_address:content_addressify!(abefore_validationalongsidefull_nameify!/gem_full_nameify!) runs the uniqueness probe once at push time and stores the result;full_nameis derived from the column/versionsand/infoselect the column directly — the extraction heuristic is deleted/\A[0-9a-f]{8,64}\z/,allow_nil) keeps junk addresses outTophat
Pushes three real
.gemfiles through the pipeline (flag enabled), then verifies the column against the digest andfull_name, the/versions+/infooutput, and the unique index.Run from the repo root with the server on
:3000— paste the whole block into your console:Tophat script (single paste)
Output (10 passed, 0 failed)