Watch
1
0
Fork
You've already forked pkg-proxy
1
mirror of https://github.com/git-pkgs/proxy.git synced 2026-11-09 23:59:16 -05:00
pkg-proxy/internal/database/metadata_dates.go

77 lines
2.7 KiB
Go
Raw Permalink Normal View History

package database
import (
"database/sql"
"errors"
"fmt"
"time"
)
// MetadataDate is the Last-Modified a package's rewritten metadata is served
// with, and the ETag of the rewrite it dates.
//
// Rewritten metadata has no date of its own, so the proxy assigns one when a
// package starts serving a new rewrite. Keeping it in the database rather than
// in process memory is what lets replicas sharing the database agree on it: a
// date one replica gave out is never given by another to a different rewrite.
type MetadataDate struct {
ETag string
LastModified time.Time
}
type metadataDateRow struct {
ETag string `db:"etag"`
LastModified int64 `db:"last_modified"`
}
// GetMetadataDate returns the date recorded for a package's metadata as
// rewritten for proxyURL, or nil when there is none.
func (db *DB) GetMetadataDate(ecosystem, proxyURL, name string) (*MetadataDate, error) {
var row metadataDateRow
err := db.Get(&row, db.Rebind(`
SELECT etag, last_modified FROM metadata_dates
WHERE ecosystem = ? AND proxy_url = ? AND name = ?
`), ecosystem, proxyURL, name)
if errors.Is(err, sql.ErrNoRows) {
return nil, nil
}
if err != nil {
return nil, fmt.Errorf("getting metadata date: %w", err)
}
return &MetadataDate{ETag: row.ETag, LastModified: time.Unix(row.LastModified, 0).UTC()}, nil
}
// InsertMetadataDate records the first date of a package's metadata and
// reports whether it did; it leaves a date another replica recorded first.
func (db *DB) InsertMetadataDate(ecosystem, proxyURL, name string, date MetadataDate) (bool, error) {
result, err := db.Exec(db.Rebind(`
INSERT INTO metadata_dates (ecosystem, proxy_url, name, etag, last_modified)
VALUES (?, ?, ?, ?, ?)
ON CONFLICT (ecosystem, proxy_url, name) DO NOTHING
`), ecosystem, proxyURL, name, date.ETag, date.LastModified.Unix())
if err != nil {
return false, fmt.Errorf("inserting metadata date: %w", err)
}
return affectedOne(result)
}
// SwapMetadataDate replaces a package's date with next if it is still old,
// and reports whether it did; it leaves a date another replica swapped in.
func (db *DB) SwapMetadataDate(ecosystem, proxyURL, name string, old, next MetadataDate) (bool, error) {
result, err := db.Exec(db.Rebind(`
UPDATE metadata_dates SET etag = ?, last_modified = ?
WHERE ecosystem = ? AND proxy_url = ? AND name = ? AND etag = ? AND last_modified = ?
`), next.ETag, next.LastModified.Unix(), ecosystem, proxyURL, name, old.ETag, old.LastModified.Unix())
if err != nil {
return false, fmt.Errorf("swapping metadata date: %w", err)
}
return affectedOne(result)
}
func affectedOne(result sql.Result) (bool, error) {
n, err := result.RowsAffected()
if err != nil {
return false, fmt.Errorf("counting affected rows: %w", err)
}
return n == 1, nil
}