~james/core

core/spindle/mill/nix_cache.go -rw-r--r-- 2.4 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 14 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
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 &quota.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)
	}
}