check / check (push) Canceled after 0s
The dotfiles, REPO_POLICIES.md and the standard scripts are fetched whole from sneak/prompts e3f79c4, with pixa's own entries kept after them. Check builds pass a new CACHEBUST build argument instead of --no-cache, and every Dockerfile stage declares it first, so every RUN step still runs while Go's build cache is kept. Lint runs golangci-lint v2.14.0, and the test phase runs on the Debian Go image. Of the two new lint findings, one is fixed and one (gosec G703 on the fixed config file locations) is suppressed. The agent guidance moves unchanged from CLAUDE.md to AGENTS.md. Deviation: the workflow keeps its docker-smoke step while issue 203 waits on the owner. Model: opus-5-5
86 lines
2.6 KiB
Go
86 lines
2.6 KiB
Go
package imgcache
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"path/filepath"
|
|
"syscall"
|
|
)
|
|
|
|
// DefaultCacheMaxBytesFloor is the minimum computed default for the
|
|
// cache_max_bytes setting: 500 MiB. The floor applies only to the
|
|
// computed default (when the key is omitted from the configuration),
|
|
// never to explicitly configured values.
|
|
const DefaultCacheMaxBytesFloor int64 = 524288000
|
|
|
|
// freeSpaceFractionNumerator and freeSpaceFractionDenominator express
|
|
// the 75% share used for the computed default limit as integer
|
|
// arithmetic (dividing before multiplying avoids overflow).
|
|
const (
|
|
freeSpaceFractionNumerator uint64 = 3
|
|
freeSpaceFractionDenominator uint64 = 4
|
|
)
|
|
|
|
var errNegativeBlockSize = errors.New("statfs reported negative block size")
|
|
|
|
// FreeSpaceProbeFunc reports the number of free bytes available on the
|
|
// filesystem containing path. It is a function type so tests can
|
|
// inject a fake probe instead of depending on the host disk.
|
|
type FreeSpaceProbeFunc func(path string) (uint64, error)
|
|
|
|
// defaultFreeSpaceProbe reports free filesystem bytes via statfs on
|
|
// the given path, as available to unprivileged processes.
|
|
func defaultFreeSpaceProbe(path string) (uint64, error) {
|
|
var stat syscall.Statfs_t
|
|
|
|
err := syscall.Statfs(path, &stat)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if stat.Bsize < 0 {
|
|
return 0, fmt.Errorf("%w %d for %q", errNegativeBlockSize, stat.Bsize, path)
|
|
}
|
|
|
|
blockSize := uint64(stat.Bsize)
|
|
|
|
return stat.Bavail * blockSize, nil
|
|
}
|
|
|
|
// computeDefaultMaxBytes returns the default cache size limit: 75% of
|
|
// the sum of the free bytes probe reports for <state_dir>/cache/ and
|
|
// the bytes the cache already holds, with a floor of
|
|
// DefaultCacheMaxBytesFloor. Counting what the cache holds keeps the
|
|
// limit from shrinking as the cache fills.
|
|
func (c *Cache) computeDefaultMaxBytes(
|
|
ctx context.Context, probe FreeSpaceProbeFunc,
|
|
) (int64, error) {
|
|
cacheDir := filepath.Join(c.config.StateDir, "cache")
|
|
|
|
freeBytes, err := probe(cacheDir)
|
|
if err != nil {
|
|
return 0, fmt.Errorf(
|
|
"default cache_max_bytes: cannot determine free space for %q: %w",
|
|
cacheDir, err)
|
|
}
|
|
|
|
usedBytes, err := c.UsageBytes(ctx)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Both terms are at most math.MaxInt64, so the sum cannot overflow.
|
|
//nolint:gosec // G115: UsageBytes returns the total cache usage, never negative
|
|
spaceBytes := min(freeBytes, math.MaxInt64) + uint64(usedBytes)
|
|
|
|
computed := spaceBytes / freeSpaceFractionDenominator * freeSpaceFractionNumerator
|
|
computed = min(computed, math.MaxInt64)
|
|
|
|
limit := int64(computed)
|
|
limit = max(limit, DefaultCacheMaxBytesFloor)
|
|
|
|
return limit, nil
|
|
}
|