From 58513d4647ab2ab5284f6ab94652a8fcbc904c54 Mon Sep 17 00:00:00 2001 From: Wael Nasreddine Date: Wed, 11 Feb 2026 15:05:55 -0800 Subject: [PATCH] fix: normalize the URL when storing in the database By normalizing the NAR URL before storing it or checking for its existence in the database, we ensure that the hash used in the 'nar_files' table matches the actual hash of the file in the storage layer. This prevents duplicate 'nar_file' records when the same NAR is referenced by different 'narinfo' files with varying URL formats (e.g., with or without a hash prefix). Changes: - Call '.Normalize()' on the parsed NAR URL in 'storeInDatabase'. - Call '.Normalize()' on the parsed NAR URL in 'storeNarInfoInDatabase'. --- pkg/cache/cache.go | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 0fdad289b..abf859691 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -2798,9 +2798,13 @@ func (c *Cache) storeInDatabase( return fmt.Errorf("error parsing the nar URL: %w", err) } + // Normalize the NAR URL to remove any narinfo hash prefix. + // This ensures nar_files.hash matches what's actually stored in the storage layer. + normalizedNarURL := narURL.Normalize() + // Check if nar_file already exists (multiple narinfos can share the same nar_file) - narFileID, err := c.ensureNarFile(ctx, qtx, narURL, narInfo.FileSize) + narFileID, err := createOrUpdateNarFile(ctx, qtx, normalizedNarURL, narInfo.FileSize) if err != nil { return err } @@ -2943,7 +2947,7 @@ func (c *Cache) checkAndFixNarInfosForNar(ctx context.Context, narURL nar.URL) e return errors.Join(errs...) } -func (c *Cache) ensureNarFile( +func createOrUpdateNarFile( ctx context.Context, qtx database.Querier, narURL nar.URL, @@ -3195,21 +3199,20 @@ func storeNarInfoInDatabase(ctx context.Context, db database.Querier, hash strin return fmt.Errorf("error parsing the nar URL: %w", err) } + // Normalize the NAR URL to remove any narinfo hash prefix. + // This ensures nar_files.hash matches what's actually stored in the storage layer. + normalizedNarURL := narURL.Normalize() + // Create or get nar_file record - newNarFile, err := qtx.CreateNarFile(ctx, database.CreateNarFileParams{ - Hash: narURL.Hash, - Compression: narURL.Compression.String(), - Query: narURL.Query.Encode(), - FileSize: narInfo.FileSize, - }) + narFileID, err := createOrUpdateNarFile(ctx, qtx, normalizedNarURL, narInfo.FileSize) if err != nil { - return fmt.Errorf("error creating or updating nar_file record in the database: %w", err) + return err } // Link narinfo to nar_file if err := qtx.LinkNarInfoToNarFile(ctx, database.LinkNarInfoToNarFileParams{ NarInfoID: nir.ID, - NarFileID: newNarFile.ID, + NarFileID: narFileID, }); err != nil { // Duplicate key errors are expected with UPSERT if !database.IsDuplicateKeyError(err) {