package mill
import (
"context"
"errors"
"fmt"
"time"
millv1 "tangled.org/core/spindle/mill/proto/gen"
"tangled.org/core/spindle/nixcache"
"tangled.org/core/spindle/quota"
)
// the name comes from the repo, so a restored lease gets the same one
func (m *Mill) leaseNixCache(repoDID string) string {
if !m.cfg.NixCaches {
return ""
}
cache, err := nixcache.CacheName(repoDID)
if err != nil {
return ""
}
return cache
}
func nixObjectFromProto(obj *millv1.NixObject, kind quota.Kind, leaseCache string) (*quota.NixObject, error) {
if obj == nil {
if kind == quota.KindNixCache && leaseCache != "" {
return nil, errors.New("nix cache reservation names no nix object")
}
return nil, nil
}
if leaseCache == "" || obj.GetCache() != leaseCache {
return nil, fmt.Errorf("nix object names cache %q, which this lease cannot write", obj.GetCache())
}
return "a.NixObject{
Cache: obj.GetCache(),
StoreHash: obj.GetStoreHash(),
StorePath: obj.GetStorePath(),
NarSize: obj.GetNarSize(),
References: obj.GetReferences(),
}, nil
}
const (
nixUseConcurrency = 8
nixUseTimeout = 5 * time.Second
)
func (m *Mill) startNixCacheUsed(s *millSession, req *millv1.NixCacheUsed) {
select {
case m.nixUseSlots <- struct{}{}:
go func() {
defer func() { <-m.nixUseSlots }()
m.handleNixCacheUsed(s, req)
}()
default:
s.l.Debug("dropping nix cache use report, too many in flight", "node", s.nodeID, "lease", req.GetLeaseId())
}
}
// best effort with no reply. a lost report only makes lru less exact
func (m *Mill) handleNixCacheUsed(s *millSession, req *millv1.NixCacheUsed) {
if m.qm == nil {
return
}
m.mu.Lock()
lease := m.leases[req.GetLeaseId()]
m.mu.Unlock()
if lease == nil || lease.nodeID != s.nodeID || lease.epoch != s.epoch {
s.l.Warn("nix cache use for a lease this node does not hold", "node", s.nodeID, "lease", req.GetLeaseId())
return
}
lease.mu.Lock()
repoDID := lease.repoDID
lease.mu.Unlock()
granted := m.leaseNixCache(repoDID)
if granted == "" || req.GetCache() != granted {
s.l.Warn("nix cache use names a cache the lease was not granted", "node", s.nodeID, "lease", req.GetLeaseId(), "cache", req.GetCache())
return
}
ctx, cancel := context.WithTimeout(s.ctx, nixUseTimeout)
defer cancel()
if err := m.qm.RecordNixUse(ctx, granted, req.GetStoreHashes()); err != nil {
s.l.Warn("recording nix cache use failed", "lease", req.GetLeaseId(), "error", err)
}
}