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) } }