Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 15:49:16 -05:00
pkg-proxy/internal/handler/container_metadata.go
Christian Heim d56d4367c9
Count cached metadata against max_size and evict it LRU (#507)
* max_size now counts cached metadata as well as artifacts, and eviction drops whichever was used least recently, so metadata no longer piles up for good (#461). Metadata rows record when they were last served, an artifact not yet served counts from its download, and Arch stores a database blob again if eviction removed it under a refreshed row.

* Shorter comments on the metadata last-access migration.

* Show evicted metadata on the analytics page next to evicted artifacts, and cover the new counter in the metric surface test.

* Evicting metadata now drops the row and queues its path in one transaction, so a crash before the blob is deleted leaves it to reclaim instead of orphaning it.

* The last-access backfill now runs in the background in batches of 1000 instead of inside the migration, resuming after a restart, and until a row is backfilled eviction orders it by its write time.

---------

Co-authored-by: Andrew Nesbitt <andrewnez@gmail.com>
2026-10-20 10:22:55 +01:00

62 lines
2.1 KiB
Go

package handler
import (
"bytes"
"context"
"database/sql"
"fmt"
"time"
"github.com/git-pkgs/proxy/internal/database"
)
func (h *ContainerHandler) storeContainerMetadata(ctx context.Context, ecosystem, cacheKey string, body []byte, etag, link, contentType, contentDigest string, lastModified, fetchedAt time.Time) (int64, error) {
if h.proxy.DB == nil || h.proxy.Storage == nil {
return int64(len(body)), nil
}
storagePath := metadataStoragePath(ecosystem, cacheKey)
size, _, err := h.proxy.Storage.Store(ctx, storagePath, bytes.NewReader(body))
if err != nil {
return 0, fmt.Errorf("storing metadata: %w", err)
}
err = h.proxy.DB.UpsertMetadataCache(&database.MetadataCacheEntry{
Ecosystem: ecosystem,
Name: cacheKey,
StoragePath: storagePath,
ETag: sql.NullString{String: etag, Valid: etag != ""},
Link: sql.NullString{String: link, Valid: link != ""},
ContentType: sql.NullString{String: contentType, Valid: contentType != ""},
ContentDigest: sql.NullString{String: contentDigest, Valid: contentDigest != ""},
Size: sql.NullInt64{Int64: size, Valid: true},
LastModified: sql.NullTime{Time: lastModified, Valid: !lastModified.IsZero()},
FetchedAt: sql.NullTime{Time: fetchedAt, Valid: !fetchedAt.IsZero()},
})
if err != nil {
return 0, err
}
return size, nil
}
// loadContainerMetadata returns a cached metadata row and its body, or nil
// when nothing usable is cached.
func (h *ContainerHandler) loadContainerMetadata(ctx context.Context, ecosystem, cacheKey string) (*database.MetadataCacheEntry, []byte, error) {
if h.proxy.DB == nil || h.proxy.Storage == nil {
return nil, nil, nil
}
entry, err := h.proxy.DB.GetMetadataCache(ecosystem, cacheKey)
if err != nil || entry == nil {
return nil, nil, err
}
reader, err := h.proxy.Storage.Open(ctx, entry.StoragePath)
if err != nil {
return nil, nil, nil
}
defer func() { _ = reader.Close() }()
body, err := h.proxy.ReadMetadata(reader)
if err != nil {
return nil, nil, err
}
h.proxy.recordMetadataRead(entry)
return entry, body, nil
}