Skip to content

Commit 058da20

Browse files
committed
wip volume snapshotter support
Signed-off-by: Erik Sipsma <[email protected]>
1 parent ffadc9f commit 058da20

File tree

5 files changed

+218
-26
lines changed

5 files changed

+218
-26
lines changed

cache/manager.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/moby/buildkit/identity"
2222
"github.com/moby/buildkit/session"
2323
"github.com/moby/buildkit/snapshot"
24+
"github.com/moby/buildkit/solver/pb"
2425
"github.com/moby/buildkit/util/bklog"
2526
"github.com/moby/buildkit/util/flightcontrol"
2627
"github.com/moby/buildkit/util/progress"
@@ -49,6 +50,9 @@ type ManagerOpt struct {
4950
Differ diff.Comparer
5051
MetadataStore *metadata.Store
5152
MountPoolRoot string
53+
54+
// dagger-specific, see manager_dagger.go
55+
VolumeSnapshotter CtdVolumeSnapshotter
5256
}
5357

5458
type Accessor interface {
@@ -62,6 +66,9 @@ type Accessor interface {
6266
IdentityMapping() *idtools.IdentityMapping
6367
Merge(ctx context.Context, parents []ImmutableRef, pg progress.Controller, opts ...RefOption) (ImmutableRef, error)
6468
Diff(ctx context.Context, lower, upper ImmutableRef, pg progress.Controller, opts ...RefOption) (ImmutableRef, error)
69+
70+
// Dagger-specific, see manager_dagger.go
71+
GetOrInitVolume(ctx context.Context, id string, sharingMode pb.CacheSharingOpt, parent ImmutableRef) (MutableRef, error)
6572
}
6673

6774
type Controller interface {
@@ -97,6 +104,9 @@ type cacheManager struct {
97104

98105
muPrune sync.Mutex // make sure parallel prune is not allowed so there will not be inconsistent results
99106
unlazyG flightcontrol.Group[struct{}]
107+
108+
// dagger-specific, see manager_dagger.go
109+
volumeSnapshotter VolumeSnapshotter
100110
}
101111

102112
func NewManager(opt ManagerOpt) (Manager, error) {
@@ -110,6 +120,8 @@ func NewManager(opt ManagerOpt) (Manager, error) {
110120
Differ: opt.Differ,
111121
MetadataStore: opt.MetadataStore,
112122
records: make(map[string]*cacheRecord),
123+
124+
volumeSnapshotter: newVolumeSnapshotter(context.TODO(), opt.VolumeSnapshotter, opt.LeaseManager),
113125
}
114126

115127
if err := cm.init(context.TODO()); err != nil {
@@ -444,7 +456,7 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, opts ...RefOpt
444456
return rec, nil
445457
} else if IsNotFound(err) {
446458
// The equal mutable for this ref is not found, check to see if our snapshot exists
447-
if _, statErr := cm.Snapshotter.Stat(ctx, md.getSnapshotID()); statErr != nil {
459+
if _, statErr := cm.snapshotterFor(md).Stat(ctx, md.getSnapshotID()); statErr != nil {
448460
// this ref's snapshot also doesn't exist, just remove this record
449461
cm.MetadataStore.Clear(id)
450462
return nil, errors.Wrap(errNotFound, id)
@@ -484,7 +496,7 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, opts ...RefOpt
484496

485497
if rec.mutable {
486498
// If the record is mutable, then the snapshot must exist
487-
if _, err := cm.Snapshotter.Stat(ctx, rec.ID()); err != nil {
499+
if _, err := cm.snapshotterFor(md).Stat(ctx, rec.ID()); err != nil {
488500
if !cerrdefs.IsNotFound(err) {
489501
return nil, errors.Wrap(err, "failed to check mutable ref snapshot")
490502
}

cache/manager_dagger.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package cache
2+
3+
import (
4+
"context"
5+
"errors"
6+
"fmt"
7+
"sync"
8+
"time"
9+
10+
"github.com/containerd/containerd/leases"
11+
ctdsnapshots "github.com/containerd/containerd/snapshots"
12+
cerrdefs "github.com/containerd/errdefs"
13+
"github.com/moby/buildkit/client"
14+
"github.com/moby/buildkit/snapshot"
15+
"github.com/moby/buildkit/snapshot/containerd"
16+
"github.com/moby/buildkit/solver/pb"
17+
"github.com/moby/buildkit/util/bklog"
18+
)
19+
20+
type AcquireSnapshotter interface {
21+
Acquire(ctx context.Context, key string, sharingMode pb.CacheSharingOpt) (func() error, error)
22+
}
23+
24+
type CtdVolumeSnapshotter interface {
25+
ctdsnapshots.Snapshotter
26+
Name() string
27+
AcquireSnapshotter
28+
}
29+
30+
type VolumeSnapshotter interface {
31+
snapshot.MergeSnapshotter
32+
AcquireSnapshotter
33+
}
34+
35+
func newVolumeSnapshotter(ctx context.Context, ctdSnapshoter CtdVolumeSnapshotter, leaseManager leases.Manager) VolumeSnapshotter {
36+
return volumeSnapshotterAdapter{
37+
MergeSnapshotter: snapshot.NewMergeSnapshotter(ctx, containerd.NewSnapshotter(
38+
ctdSnapshoter.Name(),
39+
ctdSnapshoter,
40+
"buildkit",
41+
nil, // no idmapping
42+
), leaseManager),
43+
base: ctdSnapshoter,
44+
}
45+
46+
}
47+
48+
type volumeSnapshotterAdapter struct {
49+
snapshot.MergeSnapshotter
50+
base CtdVolumeSnapshotter
51+
}
52+
53+
var _ VolumeSnapshotter = (*volumeSnapshotterAdapter)(nil)
54+
55+
func (sn volumeSnapshotterAdapter) Acquire(ctx context.Context, key string, sharingMode pb.CacheSharingOpt) (func() error, error) {
56+
return sn.base.Acquire(ctx, key, sharingMode)
57+
}
58+
59+
func (cm *cacheManager) GetOrInitVolume(
60+
ctx context.Context,
61+
id string,
62+
sharingMode pb.CacheSharingOpt,
63+
parent ImmutableRef,
64+
) (_ MutableRef, rerr error) {
65+
// TODO: support parent ref
66+
if parent != nil {
67+
return nil, fmt.Errorf("parent ref is not supported")
68+
}
69+
parentID := ""
70+
71+
rec, err := func() (*cacheRecord, error) {
72+
cm.mu.Lock()
73+
defer cm.mu.Unlock()
74+
75+
rec, err := cm.getRecord(ctx, id)
76+
switch {
77+
case err == nil:
78+
return rec, nil
79+
80+
case errors.Is(err, errNotFound):
81+
// TODO: more optimal to Lease+Prepare outside of manager lock, could put in rec lock?
82+
83+
l, err := cm.LeaseManager.Create(ctx, func(l *leases.Lease) error {
84+
l.ID = id
85+
l.Labels = map[string]string{
86+
"containerd.io/gc.flat": time.Now().UTC().Format(time.RFC3339Nano),
87+
}
88+
return nil
89+
})
90+
if err != nil {
91+
return nil, fmt.Errorf("failed to create lease: %w", err)
92+
}
93+
defer func() {
94+
if err != nil {
95+
ctx := context.WithoutCancel(ctx)
96+
if err := cm.LeaseManager.Delete(ctx, leases.Lease{
97+
ID: l.ID,
98+
}); err != nil {
99+
bklog.G(ctx).Errorf("failed to remove lease: %+v", err)
100+
}
101+
}
102+
}()
103+
104+
if err := cm.LeaseManager.AddResource(ctx, l, leases.Resource{
105+
ID: id,
106+
Type: "snapshots/" + cm.volumeSnapshotter.Name(),
107+
}); err != nil && !cerrdefs.IsAlreadyExists(err) {
108+
return nil, fmt.Errorf("failed to add snapshot %s resource to lease: %w", id, err)
109+
}
110+
111+
if err := cm.volumeSnapshotter.Prepare(ctx, id, parentID); err != nil {
112+
return nil, fmt.Errorf("failed to prepare volume: %w", err)
113+
}
114+
115+
md, _ := cm.getMetadata(id)
116+
117+
rec = &cacheRecord{
118+
mu: &sync.Mutex{},
119+
mutable: true,
120+
cm: cm,
121+
refs: make(map[ref]struct{}),
122+
cacheMetadata: md,
123+
}
124+
125+
opts := []RefOption{
126+
WithRecordType(client.UsageRecordTypeCacheMount),
127+
WithDescription(fmt.Sprintf("cache mount %s", id)), // TODO: support human readable name?
128+
CachePolicyRetain,
129+
withSnapshotID(id),
130+
}
131+
if err := initializeMetadata(rec.cacheMetadata, rec.parentRefs, opts...); err != nil {
132+
return nil, err
133+
}
134+
135+
cm.records[id] = rec
136+
return rec, nil
137+
138+
default:
139+
return nil, fmt.Errorf("failed to get volume cache record: %w", err)
140+
}
141+
}()
142+
143+
releaseFunc, err := cm.volumeSnapshotter.Acquire(ctx, id, sharingMode)
144+
if err != nil {
145+
return nil, fmt.Errorf("failed to acquire volume: %w", err)
146+
}
147+
defer func() {
148+
if rerr != nil {
149+
rerr = errors.Join(rerr, releaseFunc())
150+
}
151+
}()
152+
153+
rec.mu.Lock()
154+
defer rec.mu.Unlock()
155+
156+
// TODO: note about how we are creating multiple mutable refs on a cacheRecord but it is safe to do so it turns out
157+
ref := rec.mref(true, DescHandlers{})
158+
ref.releaseFunc = releaseFunc
159+
return ref, nil
160+
}
161+
162+
func (cm *cacheManager) snapshotterFor(md *cacheMetadata) snapshot.MergeSnapshotter {
163+
if md.GetRecordType() == client.UsageRecordTypeCacheMount {
164+
return cm.volumeSnapshotter
165+
}
166+
return cm.Snapshotter
167+
}

0 commit comments

Comments
 (0)