Browse code

builder: remove legacy build's session handling

This feature was used by docker build --stream and it was kept experimental.

Users of this endpoint should enable BuildKit anyway by setting Version to BuilderBuildKit.

Signed-off-by: Tibor Vass <tibor@docker.com>

Tibor Vass authored on 2019/09/25 06:37:38
Showing 10 changed files
... ...
@@ -9,11 +9,9 @@ import (
9 9
 	"github.com/docker/docker/api/types/backend"
10 10
 	"github.com/docker/docker/builder"
11 11
 	buildkit "github.com/docker/docker/builder/builder-next"
12
-	"github.com/docker/docker/builder/fscache"
13 12
 	"github.com/docker/docker/image"
14 13
 	"github.com/docker/docker/pkg/stringid"
15 14
 	"github.com/pkg/errors"
16
-	"golang.org/x/sync/errgroup"
17 15
 	"google.golang.org/grpc"
18 16
 )
19 17
 
... ...
@@ -31,14 +29,13 @@ type Builder interface {
31 31
 // Backend provides build functionality to the API router
32 32
 type Backend struct {
33 33
 	builder        Builder
34
-	fsCache        *fscache.FSCache
35 34
 	imageComponent ImageComponent
36 35
 	buildkit       *buildkit.Builder
37 36
 }
38 37
 
39 38
 // NewBackend creates a new build backend from components
40
-func NewBackend(components ImageComponent, builder Builder, fsCache *fscache.FSCache, buildkit *buildkit.Builder) (*Backend, error) {
41
-	return &Backend{imageComponent: components, builder: builder, fsCache: fsCache, buildkit: buildkit}, nil
39
+func NewBackend(components ImageComponent, builder Builder, buildkit *buildkit.Builder) (*Backend, error) {
40
+	return &Backend{imageComponent: components, builder: builder, buildkit: buildkit}, nil
42 41
 }
43 42
 
44 43
 // RegisterGRPC registers buildkit controller to the grpc server.
... ...
@@ -99,34 +96,11 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
99 99
 
100 100
 // PruneCache removes all cached build sources
101 101
 func (b *Backend) PruneCache(ctx context.Context, opts types.BuildCachePruneOptions) (*types.BuildCachePruneReport, error) {
102
-	eg, ctx := errgroup.WithContext(ctx)
103
-
104
-	var fsCacheSize uint64
105
-	eg.Go(func() error {
106
-		var err error
107
-		fsCacheSize, err = b.fsCache.Prune(ctx)
108
-		if err != nil {
109
-			return errors.Wrap(err, "failed to prune fscache")
110
-		}
111
-		return nil
112
-	})
113
-
114
-	var buildCacheSize int64
115
-	var cacheIDs []string
116
-	eg.Go(func() error {
117
-		var err error
118
-		buildCacheSize, cacheIDs, err = b.buildkit.Prune(ctx, opts)
119
-		if err != nil {
120
-			return errors.Wrap(err, "failed to prune build cache")
121
-		}
122
-		return nil
123
-	})
124
-
125
-	if err := eg.Wait(); err != nil {
126
-		return nil, err
102
+	buildCacheSize, cacheIDs, err := b.buildkit.Prune(ctx, opts)
103
+	if err != nil {
104
+		return nil, errors.Wrap(err, "failed to prune build cache")
127 105
 	}
128
-
129
-	return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
106
+	return &types.BuildCachePruneReport{SpaceReclaimed: uint64(buildCacheSize), CachesDeleted: cacheIDs}, nil
130 107
 }
131 108
 
132 109
 // Cancel cancels the build by ID
... ...
@@ -3,7 +3,6 @@ package system // import "github.com/docker/docker/api/server/router/system"
3 3
 import (
4 4
 	"github.com/docker/docker/api/server/router"
5 5
 	buildkit "github.com/docker/docker/builder/builder-next"
6
-	"github.com/docker/docker/builder/fscache"
7 6
 )
8 7
 
9 8
 // systemRouter provides information about the Docker system overall.
... ...
@@ -12,17 +11,15 @@ type systemRouter struct {
12 12
 	backend  Backend
13 13
 	cluster  ClusterBackend
14 14
 	routes   []router.Route
15
-	fscache  *fscache.FSCache // legacy
16 15
 	builder  *buildkit.Builder
17 16
 	features *map[string]bool
18 17
 }
19 18
 
20 19
 // NewRouter initializes a new system router
21
-func NewRouter(b Backend, c ClusterBackend, fscache *fscache.FSCache, builder *buildkit.Builder, features *map[string]bool) router.Router {
20
+func NewRouter(b Backend, c ClusterBackend, builder *buildkit.Builder, features *map[string]bool) router.Router {
22 21
 	r := &systemRouter{
23 22
 		backend:  b,
24 23
 		cluster:  c,
25
-		fscache:  fscache,
26 24
 		builder:  builder,
27 25
 		features: features,
28 26
 	}
... ...
@@ -101,16 +101,6 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
101 101
 		return err
102 102
 	})
103 103
 
104
-	var builderSize int64 // legacy
105
-	eg.Go(func() error {
106
-		var err error
107
-		builderSize, err = s.fscache.DiskUsage(ctx)
108
-		if err != nil {
109
-			return pkgerrors.Wrap(err, "error getting fscache build cache usage")
110
-		}
111
-		return nil
112
-	})
113
-
114 104
 	var buildCache []*types.BuildCache
115 105
 	eg.Go(func() error {
116 106
 		var err error
... ...
@@ -125,6 +115,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
125 125
 		return err
126 126
 	}
127 127
 
128
+	var builderSize int64
128 129
 	for _, b := range buildCache {
129 130
 		builderSize += b.Size
130 131
 	}
... ...
@@ -8,14 +8,12 @@ import (
8 8
 	"io/ioutil"
9 9
 	"sort"
10 10
 	"strings"
11
-	"time"
12 11
 
13 12
 	"github.com/containerd/containerd/platforms"
14 13
 	"github.com/docker/docker/api/types"
15 14
 	"github.com/docker/docker/api/types/backend"
16 15
 	"github.com/docker/docker/api/types/container"
17 16
 	"github.com/docker/docker/builder"
18
-	"github.com/docker/docker/builder/fscache"
19 17
 	"github.com/docker/docker/builder/remotecontext"
20 18
 	"github.com/docker/docker/errdefs"
21 19
 	"github.com/docker/docker/pkg/idtools"
... ...
@@ -25,7 +23,6 @@ import (
25 25
 	"github.com/moby/buildkit/frontend/dockerfile/instructions"
26 26
 	"github.com/moby/buildkit/frontend/dockerfile/parser"
27 27
 	"github.com/moby/buildkit/frontend/dockerfile/shell"
28
-	"github.com/moby/buildkit/session"
29 28
 	specs "github.com/opencontainers/image-spec/specs-go/v1"
30 29
 	"github.com/pkg/errors"
31 30
 	"github.com/sirupsen/logrus"
... ...
@@ -49,31 +46,19 @@ const (
49 49
 	stepFormat = "Step %d/%d : %v"
50 50
 )
51 51
 
52
-// SessionGetter is object used to get access to a session by uuid
53
-type SessionGetter interface {
54
-	Get(ctx context.Context, uuid string) (session.Caller, error)
55
-}
56
-
57 52
 // BuildManager is shared across all Builder objects
58 53
 type BuildManager struct {
59 54
 	idMapping *idtools.IdentityMapping
60 55
 	backend   builder.Backend
61 56
 	pathCache pathCache // TODO: make this persistent
62
-	sg        SessionGetter
63
-	fsCache   *fscache.FSCache
64 57
 }
65 58
 
66 59
 // NewBuildManager creates a BuildManager
67
-func NewBuildManager(b builder.Backend, sg SessionGetter, fsCache *fscache.FSCache, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
60
+func NewBuildManager(b builder.Backend, identityMapping *idtools.IdentityMapping) (*BuildManager, error) {
68 61
 	bm := &BuildManager{
69 62
 		backend:   b,
70 63
 		pathCache: &syncmap.Map{},
71
-		sg:        sg,
72 64
 		idMapping: identityMapping,
73
-		fsCache:   fsCache,
74
-	}
75
-	if err := fsCache.RegisterTransport(remotecontext.ClientSessionRemote, NewClientSessionTransport()); err != nil {
76
-		return nil, err
77 65
 	}
78 66
 	return bm, nil
79 67
 }
... ...
@@ -100,10 +85,8 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
100 100
 	ctx, cancel := context.WithCancel(ctx)
101 101
 	defer cancel()
102 102
 
103
-	if src, err := bm.initializeClientSession(ctx, cancel, config.Options); err != nil {
104
-		return nil, err
105
-	} else if src != nil {
106
-		source = src
103
+	if config.Options.SessionID != "" {
104
+		return nil, errors.New("experimental session with v1 builder is no longer supported, use builder version v2 (BuildKit) instead")
107 105
 	}
108 106
 
109 107
 	builderOptions := builderOptions{
... ...
@@ -120,39 +103,6 @@ func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (
120 120
 	return b.build(source, dockerfile)
121 121
 }
122 122
 
123
-func (bm *BuildManager) initializeClientSession(ctx context.Context, cancel func(), options *types.ImageBuildOptions) (builder.Source, error) {
124
-	if options.SessionID == "" || bm.sg == nil {
125
-		return nil, nil
126
-	}
127
-	logrus.Debug("client is session enabled")
128
-
129
-	connectCtx, cancelCtx := context.WithTimeout(ctx, sessionConnectTimeout)
130
-	defer cancelCtx()
131
-
132
-	c, err := bm.sg.Get(connectCtx, options.SessionID)
133
-	if err != nil {
134
-		return nil, err
135
-	}
136
-	go func() {
137
-		<-c.Context().Done()
138
-		cancel()
139
-	}()
140
-	if options.RemoteContext == remotecontext.ClientSessionRemote {
141
-		st := time.Now()
142
-		csi, err := NewClientSessionSourceIdentifier(ctx, bm.sg, options.SessionID)
143
-		if err != nil {
144
-			return nil, err
145
-		}
146
-		src, err := bm.fsCache.SyncFrom(ctx, csi)
147
-		if err != nil {
148
-			return nil, err
149
-		}
150
-		logrus.Debugf("sync-time: %v", time.Since(st))
151
-		return src, nil
152
-	}
153
-	return nil, nil
154
-}
155
-
156 123
 // builderOptions are the dependencies required by the builder
157 124
 type builderOptions struct {
158 125
 	Options        *types.ImageBuildOptions
159 126
deleted file mode 100644
... ...
@@ -1,76 +0,0 @@
1
-package dockerfile // import "github.com/docker/docker/builder/dockerfile"
2
-
3
-import (
4
-	"context"
5
-	"time"
6
-
7
-	"github.com/docker/docker/builder/fscache"
8
-	"github.com/docker/docker/builder/remotecontext"
9
-	"github.com/moby/buildkit/session"
10
-	"github.com/moby/buildkit/session/filesync"
11
-	"github.com/pkg/errors"
12
-)
13
-
14
-const sessionConnectTimeout = 5 * time.Second
15
-
16
-// ClientSessionTransport is a transport for copying files from docker client
17
-// to the daemon.
18
-type ClientSessionTransport struct{}
19
-
20
-// NewClientSessionTransport returns new ClientSessionTransport instance
21
-func NewClientSessionTransport() *ClientSessionTransport {
22
-	return &ClientSessionTransport{}
23
-}
24
-
25
-// Copy data from a remote to a destination directory.
26
-func (cst *ClientSessionTransport) Copy(ctx context.Context, id fscache.RemoteIdentifier, dest string, cu filesync.CacheUpdater) error {
27
-	csi, ok := id.(*ClientSessionSourceIdentifier)
28
-	if !ok {
29
-		return errors.New("invalid identifier for client session")
30
-	}
31
-
32
-	return filesync.FSSync(ctx, csi.caller, filesync.FSSendRequestOpt{
33
-		IncludePatterns: csi.includePatterns,
34
-		DestDir:         dest,
35
-		CacheUpdater:    cu,
36
-	})
37
-}
38
-
39
-// ClientSessionSourceIdentifier is an identifier that can be used for requesting
40
-// files from remote client
41
-type ClientSessionSourceIdentifier struct {
42
-	includePatterns []string
43
-	caller          session.Caller
44
-	uuid            string
45
-}
46
-
47
-// NewClientSessionSourceIdentifier returns new ClientSessionSourceIdentifier instance
48
-func NewClientSessionSourceIdentifier(ctx context.Context, sg SessionGetter, uuid string) (*ClientSessionSourceIdentifier, error) {
49
-	csi := &ClientSessionSourceIdentifier{
50
-		uuid: uuid,
51
-	}
52
-	caller, err := sg.Get(ctx, uuid)
53
-	if err != nil {
54
-		return nil, errors.Wrapf(err, "failed to get session for %s", uuid)
55
-	}
56
-
57
-	csi.caller = caller
58
-	return csi, nil
59
-}
60
-
61
-// Transport returns transport identifier for remote identifier
62
-func (csi *ClientSessionSourceIdentifier) Transport() string {
63
-	return remotecontext.ClientSessionRemote
64
-}
65
-
66
-// SharedKey returns shared key for remote identifier. Shared key is used
67
-// for finding the base for a repeated transfer.
68
-func (csi *ClientSessionSourceIdentifier) SharedKey() string {
69
-	return csi.caller.SharedKey()
70
-}
71
-
72
-// Key returns unique key for remote identifier. Requests with same key return
73
-// same data.
74
-func (csi *ClientSessionSourceIdentifier) Key() string {
75
-	return csi.uuid
76
-}
77 1
deleted file mode 100644
... ...
@@ -1,654 +0,0 @@
1
-package fscache // import "github.com/docker/docker/builder/fscache"
2
-
3
-import (
4
-	"archive/tar"
5
-	"context"
6
-	"crypto/sha256"
7
-	"encoding/json"
8
-	"hash"
9
-	"os"
10
-	"path/filepath"
11
-	"sort"
12
-	"sync"
13
-	"time"
14
-
15
-	"github.com/docker/docker/builder"
16
-	"github.com/docker/docker/builder/remotecontext"
17
-	"github.com/docker/docker/pkg/archive"
18
-	"github.com/docker/docker/pkg/directory"
19
-	"github.com/docker/docker/pkg/stringid"
20
-	"github.com/docker/docker/pkg/tarsum"
21
-	"github.com/moby/buildkit/session/filesync"
22
-	"github.com/pkg/errors"
23
-	"github.com/sirupsen/logrus"
24
-	"github.com/tonistiigi/fsutil"
25
-	fsutiltypes "github.com/tonistiigi/fsutil/types"
26
-	bolt "go.etcd.io/bbolt"
27
-	"golang.org/x/sync/singleflight"
28
-)
29
-
30
-const dbFile = "fscache.db"
31
-const cacheKey = "cache"
32
-const metaKey = "meta"
33
-
34
-// Backend is a backing implementation for FSCache
35
-type Backend interface {
36
-	Get(id string) (string, error)
37
-	Remove(id string) error
38
-}
39
-
40
-// FSCache allows syncing remote resources to cached snapshots
41
-type FSCache struct {
42
-	opt        Opt
43
-	transports map[string]Transport
44
-	mu         sync.Mutex
45
-	g          singleflight.Group
46
-	store      *fsCacheStore
47
-}
48
-
49
-// Opt defines options for initializing FSCache
50
-type Opt struct {
51
-	Backend  Backend
52
-	Root     string // for storing local metadata
53
-	GCPolicy GCPolicy
54
-}
55
-
56
-// GCPolicy defines policy for garbage collection
57
-type GCPolicy struct {
58
-	MaxSize         uint64
59
-	MaxKeepDuration time.Duration
60
-}
61
-
62
-// NewFSCache returns new FSCache object
63
-func NewFSCache(opt Opt) (*FSCache, error) {
64
-	store, err := newFSCacheStore(opt)
65
-	if err != nil {
66
-		return nil, err
67
-	}
68
-	return &FSCache{
69
-		store:      store,
70
-		opt:        opt,
71
-		transports: make(map[string]Transport),
72
-	}, nil
73
-}
74
-
75
-// Transport defines a method for syncing remote data to FSCache
76
-type Transport interface {
77
-	Copy(ctx context.Context, id RemoteIdentifier, dest string, cs filesync.CacheUpdater) error
78
-}
79
-
80
-// RemoteIdentifier identifies a transfer request
81
-type RemoteIdentifier interface {
82
-	Key() string
83
-	SharedKey() string
84
-	Transport() string
85
-}
86
-
87
-// RegisterTransport registers a new transport method
88
-func (fsc *FSCache) RegisterTransport(id string, transport Transport) error {
89
-	fsc.mu.Lock()
90
-	defer fsc.mu.Unlock()
91
-	if _, ok := fsc.transports[id]; ok {
92
-		return errors.Errorf("transport %v already exists", id)
93
-	}
94
-	fsc.transports[id] = transport
95
-	return nil
96
-}
97
-
98
-// SyncFrom returns a source based on a remote identifier
99
-func (fsc *FSCache) SyncFrom(ctx context.Context, id RemoteIdentifier) (builder.Source, error) { // cacheOpt
100
-	trasportID := id.Transport()
101
-	fsc.mu.Lock()
102
-	transport, ok := fsc.transports[id.Transport()]
103
-	if !ok {
104
-		fsc.mu.Unlock()
105
-		return nil, errors.Errorf("invalid transport %s", trasportID)
106
-	}
107
-
108
-	logrus.Debugf("SyncFrom %s %s", id.Key(), id.SharedKey())
109
-	fsc.mu.Unlock()
110
-	sourceRef, err, _ := fsc.g.Do(id.Key(), func() (interface{}, error) {
111
-		var sourceRef *cachedSourceRef
112
-		sourceRef, err := fsc.store.Get(id.Key())
113
-		if err == nil {
114
-			return sourceRef, nil
115
-		}
116
-
117
-		// check for unused shared cache
118
-		sharedKey := id.SharedKey()
119
-		if sharedKey != "" {
120
-			r, err := fsc.store.Rebase(sharedKey, id.Key())
121
-			if err == nil {
122
-				sourceRef = r
123
-			}
124
-		}
125
-
126
-		if sourceRef == nil {
127
-			var err error
128
-			sourceRef, err = fsc.store.New(id.Key(), sharedKey)
129
-			if err != nil {
130
-				return nil, errors.Wrap(err, "failed to create remote context")
131
-			}
132
-		}
133
-
134
-		if err := syncFrom(ctx, sourceRef, transport, id); err != nil {
135
-			sourceRef.Release()
136
-			return nil, err
137
-		}
138
-		if err := sourceRef.resetSize(-1); err != nil {
139
-			return nil, err
140
-		}
141
-		return sourceRef, nil
142
-	})
143
-	if err != nil {
144
-		return nil, err
145
-	}
146
-	ref := sourceRef.(*cachedSourceRef)
147
-	if ref.src == nil { // failsafe
148
-		return nil, errors.Errorf("invalid empty pull")
149
-	}
150
-	wc := &wrappedContext{Source: ref.src, closer: func() error {
151
-		ref.Release()
152
-		return nil
153
-	}}
154
-	return wc, nil
155
-}
156
-
157
-// DiskUsage reports how much data is allocated by the cache
158
-func (fsc *FSCache) DiskUsage(ctx context.Context) (int64, error) {
159
-	return fsc.store.DiskUsage(ctx)
160
-}
161
-
162
-// Prune allows manually cleaning up the cache
163
-func (fsc *FSCache) Prune(ctx context.Context) (uint64, error) {
164
-	return fsc.store.Prune(ctx)
165
-}
166
-
167
-// Close stops the gc and closes the persistent db
168
-func (fsc *FSCache) Close() error {
169
-	return fsc.store.Close()
170
-}
171
-
172
-func syncFrom(ctx context.Context, cs *cachedSourceRef, transport Transport, id RemoteIdentifier) (retErr error) {
173
-	src := cs.src
174
-	if src == nil {
175
-		src = remotecontext.NewCachableSource(cs.Dir())
176
-	}
177
-
178
-	if !cs.cached {
179
-		if err := cs.storage.db.View(func(tx *bolt.Tx) error {
180
-			b := tx.Bucket([]byte(id.Key()))
181
-			dt := b.Get([]byte(cacheKey))
182
-			if dt != nil {
183
-				if err := src.UnmarshalBinary(dt); err != nil {
184
-					return err
185
-				}
186
-			} else {
187
-				return errors.Wrap(src.Scan(), "failed to scan cache records")
188
-			}
189
-			return nil
190
-		}); err != nil {
191
-			return err
192
-		}
193
-	}
194
-
195
-	dc := &detectChanges{f: src.HandleChange}
196
-
197
-	// todo: probably send a bucket to `Copy` and let it return source
198
-	// but need to make sure that tx is safe
199
-	if err := transport.Copy(ctx, id, cs.Dir(), dc); err != nil {
200
-		return errors.Wrapf(err, "failed to copy to %s", cs.Dir())
201
-	}
202
-
203
-	if !dc.supported {
204
-		if err := src.Scan(); err != nil {
205
-			return errors.Wrap(err, "failed to scan cache records after transfer")
206
-		}
207
-	}
208
-	cs.cached = true
209
-	cs.src = src
210
-	return cs.storage.db.Update(func(tx *bolt.Tx) error {
211
-		dt, err := src.MarshalBinary()
212
-		if err != nil {
213
-			return err
214
-		}
215
-		b := tx.Bucket([]byte(id.Key()))
216
-		return b.Put([]byte(cacheKey), dt)
217
-	})
218
-}
219
-
220
-type fsCacheStore struct {
221
-	mu       sync.Mutex
222
-	sources  map[string]*cachedSource
223
-	db       *bolt.DB
224
-	fs       Backend
225
-	gcTimer  *time.Timer
226
-	gcPolicy GCPolicy
227
-}
228
-
229
-// CachePolicy defines policy for keeping a resource in cache
230
-type CachePolicy struct {
231
-	Priority int
232
-	LastUsed time.Time
233
-}
234
-
235
-func defaultCachePolicy() CachePolicy {
236
-	return CachePolicy{Priority: 10, LastUsed: time.Now()}
237
-}
238
-
239
-func newFSCacheStore(opt Opt) (*fsCacheStore, error) {
240
-	if err := os.MkdirAll(opt.Root, 0700); err != nil {
241
-		return nil, err
242
-	}
243
-	p := filepath.Join(opt.Root, dbFile)
244
-	db, err := bolt.Open(p, 0600, nil)
245
-	if err != nil {
246
-		return nil, errors.Wrap(err, "failed to open database file %s")
247
-	}
248
-	s := &fsCacheStore{db: db, sources: make(map[string]*cachedSource), fs: opt.Backend, gcPolicy: opt.GCPolicy}
249
-	db.View(func(tx *bolt.Tx) error {
250
-		return tx.ForEach(func(name []byte, b *bolt.Bucket) error {
251
-			dt := b.Get([]byte(metaKey))
252
-			if dt == nil {
253
-				return nil
254
-			}
255
-			var sm sourceMeta
256
-			if err := json.Unmarshal(dt, &sm); err != nil {
257
-				return err
258
-			}
259
-			dir, err := s.fs.Get(sm.BackendID)
260
-			if err != nil {
261
-				return err // TODO: handle gracefully
262
-			}
263
-			source := &cachedSource{
264
-				refs:       make(map[*cachedSourceRef]struct{}),
265
-				id:         string(name),
266
-				dir:        dir,
267
-				sourceMeta: sm,
268
-				storage:    s,
269
-			}
270
-			s.sources[string(name)] = source
271
-			return nil
272
-		})
273
-	})
274
-
275
-	s.gcTimer = s.startPeriodicGC(5 * time.Minute)
276
-	return s, nil
277
-}
278
-
279
-func (s *fsCacheStore) startPeriodicGC(interval time.Duration) *time.Timer {
280
-	var t *time.Timer
281
-	t = time.AfterFunc(interval, func() {
282
-		if err := s.GC(); err != nil {
283
-			logrus.Errorf("build gc error: %v", err)
284
-		}
285
-		t.Reset(interval)
286
-	})
287
-	return t
288
-}
289
-
290
-func (s *fsCacheStore) Close() error {
291
-	s.gcTimer.Stop()
292
-	return s.db.Close()
293
-}
294
-
295
-func (s *fsCacheStore) New(id, sharedKey string) (*cachedSourceRef, error) {
296
-	s.mu.Lock()
297
-	defer s.mu.Unlock()
298
-	var ret *cachedSource
299
-	if err := s.db.Update(func(tx *bolt.Tx) error {
300
-		b, err := tx.CreateBucket([]byte(id))
301
-		if err != nil {
302
-			return err
303
-		}
304
-		backendID := stringid.GenerateRandomID()
305
-		dir, err := s.fs.Get(backendID)
306
-		if err != nil {
307
-			return err
308
-		}
309
-		source := &cachedSource{
310
-			refs: make(map[*cachedSourceRef]struct{}),
311
-			id:   id,
312
-			dir:  dir,
313
-			sourceMeta: sourceMeta{
314
-				BackendID:   backendID,
315
-				SharedKey:   sharedKey,
316
-				CachePolicy: defaultCachePolicy(),
317
-			},
318
-			storage: s,
319
-		}
320
-		dt, err := json.Marshal(source.sourceMeta)
321
-		if err != nil {
322
-			return err
323
-		}
324
-		if err := b.Put([]byte(metaKey), dt); err != nil {
325
-			return err
326
-		}
327
-		s.sources[id] = source
328
-		ret = source
329
-		return nil
330
-	}); err != nil {
331
-		return nil, err
332
-	}
333
-	return ret.getRef(), nil
334
-}
335
-
336
-func (s *fsCacheStore) Rebase(sharedKey, newid string) (*cachedSourceRef, error) {
337
-	s.mu.Lock()
338
-	defer s.mu.Unlock()
339
-	var ret *cachedSource
340
-	for id, snap := range s.sources {
341
-		if snap.SharedKey == sharedKey && len(snap.refs) == 0 {
342
-			if err := s.db.Update(func(tx *bolt.Tx) error {
343
-				if err := tx.DeleteBucket([]byte(id)); err != nil {
344
-					return err
345
-				}
346
-				b, err := tx.CreateBucket([]byte(newid))
347
-				if err != nil {
348
-					return err
349
-				}
350
-				snap.id = newid
351
-				snap.CachePolicy = defaultCachePolicy()
352
-				dt, err := json.Marshal(snap.sourceMeta)
353
-				if err != nil {
354
-					return err
355
-				}
356
-				if err := b.Put([]byte(metaKey), dt); err != nil {
357
-					return err
358
-				}
359
-				delete(s.sources, id)
360
-				s.sources[newid] = snap
361
-				return nil
362
-			}); err != nil {
363
-				return nil, err
364
-			}
365
-			ret = snap
366
-			break
367
-		}
368
-	}
369
-	if ret == nil {
370
-		return nil, errors.Errorf("no candidate for rebase")
371
-	}
372
-	return ret.getRef(), nil
373
-}
374
-
375
-func (s *fsCacheStore) Get(id string) (*cachedSourceRef, error) {
376
-	s.mu.Lock()
377
-	defer s.mu.Unlock()
378
-	src, ok := s.sources[id]
379
-	if !ok {
380
-		return nil, errors.Errorf("not found")
381
-	}
382
-	return src.getRef(), nil
383
-}
384
-
385
-// DiskUsage reports how much data is allocated by the cache
386
-func (s *fsCacheStore) DiskUsage(ctx context.Context) (int64, error) {
387
-	s.mu.Lock()
388
-	defer s.mu.Unlock()
389
-	var size int64
390
-
391
-	for _, snap := range s.sources {
392
-		if len(snap.refs) == 0 {
393
-			ss, err := snap.getSize(ctx)
394
-			if err != nil {
395
-				return 0, err
396
-			}
397
-			size += ss
398
-		}
399
-	}
400
-	return size, nil
401
-}
402
-
403
-// Prune allows manually cleaning up the cache
404
-func (s *fsCacheStore) Prune(ctx context.Context) (uint64, error) {
405
-	s.mu.Lock()
406
-	defer s.mu.Unlock()
407
-	var size uint64
408
-
409
-	for id, snap := range s.sources {
410
-		select {
411
-		case <-ctx.Done():
412
-			logrus.Debugf("Cache prune operation cancelled, pruned size: %d", size)
413
-			// when the context is cancelled, only return current size and nil
414
-			return size, nil
415
-		default:
416
-		}
417
-		if len(snap.refs) == 0 {
418
-			ss, err := snap.getSize(ctx)
419
-			if err != nil {
420
-				return size, err
421
-			}
422
-			if err := s.delete(id); err != nil {
423
-				return size, errors.Wrapf(err, "failed to delete %s", id)
424
-			}
425
-			size += uint64(ss)
426
-		}
427
-	}
428
-	return size, nil
429
-}
430
-
431
-// GC runs a garbage collector on FSCache
432
-func (s *fsCacheStore) GC() error {
433
-	s.mu.Lock()
434
-	defer s.mu.Unlock()
435
-	var size uint64
436
-
437
-	ctx := context.Background()
438
-	cutoff := time.Now().Add(-s.gcPolicy.MaxKeepDuration)
439
-	var blacklist []*cachedSource
440
-
441
-	for id, snap := range s.sources {
442
-		if len(snap.refs) == 0 {
443
-			if cutoff.After(snap.CachePolicy.LastUsed) {
444
-				if err := s.delete(id); err != nil {
445
-					return errors.Wrapf(err, "failed to delete %s", id)
446
-				}
447
-			} else {
448
-				ss, err := snap.getSize(ctx)
449
-				if err != nil {
450
-					return err
451
-				}
452
-				size += uint64(ss)
453
-				blacklist = append(blacklist, snap)
454
-			}
455
-		}
456
-	}
457
-
458
-	sort.Sort(sortableCacheSources(blacklist))
459
-	for _, snap := range blacklist {
460
-		if size <= s.gcPolicy.MaxSize {
461
-			break
462
-		}
463
-		ss, err := snap.getSize(ctx)
464
-		if err != nil {
465
-			return err
466
-		}
467
-		if err := s.delete(snap.id); err != nil {
468
-			return errors.Wrapf(err, "failed to delete %s", snap.id)
469
-		}
470
-		size -= uint64(ss)
471
-	}
472
-	return nil
473
-}
474
-
475
-// keep mu while calling this
476
-func (s *fsCacheStore) delete(id string) error {
477
-	src, ok := s.sources[id]
478
-	if !ok {
479
-		return nil
480
-	}
481
-	if len(src.refs) > 0 {
482
-		return errors.Errorf("can't delete %s because it has active references", id)
483
-	}
484
-	delete(s.sources, id)
485
-	if err := s.db.Update(func(tx *bolt.Tx) error {
486
-		return tx.DeleteBucket([]byte(id))
487
-	}); err != nil {
488
-		return err
489
-	}
490
-	return s.fs.Remove(src.BackendID)
491
-}
492
-
493
-type sourceMeta struct {
494
-	SharedKey   string
495
-	BackendID   string
496
-	CachePolicy CachePolicy
497
-	Size        int64
498
-}
499
-
500
-//nolint:structcheck
501
-type cachedSource struct {
502
-	sourceMeta
503
-	refs    map[*cachedSourceRef]struct{}
504
-	id      string
505
-	dir     string
506
-	src     *remotecontext.CachableSource
507
-	storage *fsCacheStore
508
-	cached  bool // keep track if cache is up to date
509
-}
510
-
511
-type cachedSourceRef struct {
512
-	*cachedSource
513
-}
514
-
515
-func (cs *cachedSource) Dir() string {
516
-	return cs.dir
517
-}
518
-
519
-// hold storage lock before calling
520
-func (cs *cachedSource) getRef() *cachedSourceRef {
521
-	ref := &cachedSourceRef{cachedSource: cs}
522
-	cs.refs[ref] = struct{}{}
523
-	return ref
524
-}
525
-
526
-// hold storage lock before calling
527
-func (cs *cachedSource) getSize(ctx context.Context) (int64, error) {
528
-	if cs.sourceMeta.Size < 0 {
529
-		ss, err := directory.Size(ctx, cs.dir)
530
-		if err != nil {
531
-			return 0, err
532
-		}
533
-		if err := cs.resetSize(ss); err != nil {
534
-			return 0, err
535
-		}
536
-		return ss, nil
537
-	}
538
-	return cs.sourceMeta.Size, nil
539
-}
540
-
541
-func (cs *cachedSource) resetSize(val int64) error {
542
-	cs.sourceMeta.Size = val
543
-	return cs.saveMeta()
544
-}
545
-func (cs *cachedSource) saveMeta() error {
546
-	return cs.storage.db.Update(func(tx *bolt.Tx) error {
547
-		b := tx.Bucket([]byte(cs.id))
548
-		dt, err := json.Marshal(cs.sourceMeta)
549
-		if err != nil {
550
-			return err
551
-		}
552
-		return b.Put([]byte(metaKey), dt)
553
-	})
554
-}
555
-
556
-func (csr *cachedSourceRef) Release() error {
557
-	csr.cachedSource.storage.mu.Lock()
558
-	defer csr.cachedSource.storage.mu.Unlock()
559
-	delete(csr.cachedSource.refs, csr)
560
-	if len(csr.cachedSource.refs) == 0 {
561
-		go csr.cachedSource.storage.GC()
562
-	}
563
-	return nil
564
-}
565
-
566
-type detectChanges struct {
567
-	f         fsutil.ChangeFunc
568
-	supported bool
569
-}
570
-
571
-func (dc *detectChanges) HandleChange(kind fsutil.ChangeKind, path string, fi os.FileInfo, err error) error {
572
-	if dc == nil {
573
-		return nil
574
-	}
575
-	return dc.f(kind, path, fi, err)
576
-}
577
-
578
-func (dc *detectChanges) MarkSupported(v bool) {
579
-	if dc == nil {
580
-		return
581
-	}
582
-	dc.supported = v
583
-}
584
-
585
-func (dc *detectChanges) ContentHasher() fsutil.ContentHasher {
586
-	return newTarsumHash
587
-}
588
-
589
-type wrappedContext struct {
590
-	builder.Source
591
-	closer func() error
592
-}
593
-
594
-func (wc *wrappedContext) Close() error {
595
-	if err := wc.Source.Close(); err != nil {
596
-		return err
597
-	}
598
-	return wc.closer()
599
-}
600
-
601
-type sortableCacheSources []*cachedSource
602
-
603
-// Len is the number of elements in the collection.
604
-func (s sortableCacheSources) Len() int {
605
-	return len(s)
606
-}
607
-
608
-// Less reports whether the element with
609
-// index i should sort before the element with index j.
610
-func (s sortableCacheSources) Less(i, j int) bool {
611
-	return s[i].CachePolicy.LastUsed.Before(s[j].CachePolicy.LastUsed)
612
-}
613
-
614
-// Swap swaps the elements with indexes i and j.
615
-func (s sortableCacheSources) Swap(i, j int) {
616
-	s[i], s[j] = s[j], s[i]
617
-}
618
-
619
-func newTarsumHash(stat *fsutiltypes.Stat) (hash.Hash, error) {
620
-	fi := &fsutil.StatInfo{Stat: stat}
621
-	p := stat.Path
622
-	if fi.IsDir() {
623
-		p += string(os.PathSeparator)
624
-	}
625
-	h, err := archive.FileInfoHeader(p, fi, stat.Linkname)
626
-	if err != nil {
627
-		return nil, err
628
-	}
629
-	h.Name = p
630
-	h.Uid = int(stat.Uid)
631
-	h.Gid = int(stat.Gid)
632
-	h.Linkname = stat.Linkname
633
-	if stat.Xattrs != nil {
634
-		h.Xattrs = make(map[string]string)
635
-		for k, v := range stat.Xattrs {
636
-			h.Xattrs[k] = string(v)
637
-		}
638
-	}
639
-
640
-	tsh := &tarsumHash{h: h, Hash: sha256.New()}
641
-	tsh.Reset()
642
-	return tsh, nil
643
-}
644
-
645
-// Reset resets the Hash to its initial state.
646
-func (tsh *tarsumHash) Reset() {
647
-	tsh.Hash.Reset()
648
-	tarsum.WriteV1Header(tsh.h, tsh.Hash)
649
-}
650
-
651
-type tarsumHash struct {
652
-	hash.Hash
653
-	h *tar.Header
654
-}
655 1
deleted file mode 100644
... ...
@@ -1,132 +0,0 @@
1
-package fscache // import "github.com/docker/docker/builder/fscache"
2
-
3
-import (
4
-	"context"
5
-	"io/ioutil"
6
-	"os"
7
-	"path/filepath"
8
-	"testing"
9
-	"time"
10
-
11
-	"github.com/moby/buildkit/session/filesync"
12
-	"gotest.tools/assert"
13
-	is "gotest.tools/assert/cmp"
14
-)
15
-
16
-func TestFSCache(t *testing.T) {
17
-	tmpDir, err := ioutil.TempDir("", "fscache")
18
-	assert.Check(t, err)
19
-	defer os.RemoveAll(tmpDir)
20
-
21
-	backend := NewNaiveCacheBackend(filepath.Join(tmpDir, "backend"))
22
-
23
-	opt := Opt{
24
-		Root:     tmpDir,
25
-		Backend:  backend,
26
-		GCPolicy: GCPolicy{MaxSize: 15, MaxKeepDuration: time.Hour},
27
-	}
28
-
29
-	fscache, err := NewFSCache(opt)
30
-	assert.Check(t, err)
31
-
32
-	defer fscache.Close()
33
-
34
-	err = fscache.RegisterTransport("test", &testTransport{})
35
-	assert.Check(t, err)
36
-
37
-	src1, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo", "data", "bar"})
38
-	assert.Check(t, err)
39
-
40
-	dt, err := ioutil.ReadFile(filepath.Join(src1.Root().Path(), "foo"))
41
-	assert.Check(t, err)
42
-	assert.Check(t, is.Equal(string(dt), "data"))
43
-
44
-	// same id doesn't recalculate anything
45
-	src2, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo", "data2", "bar"})
46
-	assert.Check(t, err)
47
-	assert.Check(t, is.Equal(src1.Root().Path(), src2.Root().Path()))
48
-
49
-	dt, err = ioutil.ReadFile(filepath.Join(src1.Root().Path(), "foo"))
50
-	assert.Check(t, err)
51
-	assert.Check(t, is.Equal(string(dt), "data"))
52
-	assert.Check(t, src2.Close())
53
-
54
-	src3, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo2", "data2", "bar"})
55
-	assert.Check(t, err)
56
-	assert.Check(t, src1.Root().Path() != src3.Root().Path())
57
-
58
-	dt, err = ioutil.ReadFile(filepath.Join(src3.Root().Path(), "foo2"))
59
-	assert.Check(t, err)
60
-	assert.Check(t, is.Equal(string(dt), "data2"))
61
-
62
-	s, err := fscache.DiskUsage(context.TODO())
63
-	assert.Check(t, err)
64
-	assert.Check(t, is.Equal(s, int64(0)))
65
-
66
-	assert.Check(t, src3.Close())
67
-
68
-	s, err = fscache.DiskUsage(context.TODO())
69
-	assert.Check(t, err)
70
-	assert.Check(t, is.Equal(s, int64(5)))
71
-
72
-	// new upload with the same shared key shoutl overwrite
73
-	src4, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo3", "data3", "bar"})
74
-	assert.Check(t, err)
75
-	assert.Check(t, src1.Root().Path() != src3.Root().Path())
76
-
77
-	dt, err = ioutil.ReadFile(filepath.Join(src3.Root().Path(), "foo3"))
78
-	assert.Check(t, err)
79
-	assert.Check(t, is.Equal(string(dt), "data3"))
80
-	assert.Check(t, is.Equal(src4.Root().Path(), src3.Root().Path()))
81
-	assert.Check(t, src4.Close())
82
-
83
-	s, err = fscache.DiskUsage(context.TODO())
84
-	assert.Check(t, err)
85
-	assert.Check(t, is.Equal(s, int64(10)))
86
-
87
-	// this one goes over the GC limit
88
-	src5, err := fscache.SyncFrom(context.TODO(), &testIdentifier{"foo4", "datadata", "baz"})
89
-	assert.Check(t, err)
90
-	assert.Check(t, src5.Close())
91
-
92
-	// GC happens async
93
-	time.Sleep(100 * time.Millisecond)
94
-
95
-	// only last insertion after GC
96
-	s, err = fscache.DiskUsage(context.TODO())
97
-	assert.Check(t, err)
98
-	assert.Check(t, is.Equal(s, int64(8)))
99
-
100
-	// prune deletes everything
101
-	released, err := fscache.Prune(context.TODO())
102
-	assert.Check(t, err)
103
-	assert.Check(t, is.Equal(released, uint64(8)))
104
-
105
-	s, err = fscache.DiskUsage(context.TODO())
106
-	assert.Check(t, err)
107
-	assert.Check(t, is.Equal(s, int64(0)))
108
-}
109
-
110
-type testTransport struct {
111
-}
112
-
113
-func (t *testTransport) Copy(ctx context.Context, id RemoteIdentifier, dest string, cs filesync.CacheUpdater) error {
114
-	testid := id.(*testIdentifier)
115
-	return ioutil.WriteFile(filepath.Join(dest, testid.filename), []byte(testid.data), 0600)
116
-}
117
-
118
-type testIdentifier struct {
119
-	filename  string
120
-	data      string
121
-	sharedKey string
122
-}
123
-
124
-func (t *testIdentifier) Key() string {
125
-	return t.filename
126
-}
127
-func (t *testIdentifier) SharedKey() string {
128
-	return t.sharedKey
129
-}
130
-func (t *testIdentifier) Transport() string {
131
-	return "test"
132
-}
133 1
deleted file mode 100644
... ...
@@ -1,28 +0,0 @@
1
-package fscache // import "github.com/docker/docker/builder/fscache"
2
-
3
-import (
4
-	"os"
5
-	"path/filepath"
6
-
7
-	"github.com/pkg/errors"
8
-)
9
-
10
-// NewNaiveCacheBackend is a basic backend implementation for fscache
11
-func NewNaiveCacheBackend(root string) Backend {
12
-	return &naiveCacheBackend{root: root}
13
-}
14
-
15
-type naiveCacheBackend struct {
16
-	root string
17
-}
18
-
19
-func (tcb *naiveCacheBackend) Get(id string) (string, error) {
20
-	d := filepath.Join(tcb.root, id)
21
-	if err := os.MkdirAll(d, 0700); err != nil {
22
-		return "", errors.Wrapf(err, "failed to create tmp dir for %s", d)
23
-	}
24
-	return d, nil
25
-}
26
-func (tcb *naiveCacheBackend) Remove(id string) error {
27
-	return errors.WithStack(os.RemoveAll(filepath.Join(tcb.root, id)))
28
-}
... ...
@@ -31,7 +31,6 @@ import (
31 31
 	"github.com/docker/docker/api/server/router/volume"
32 32
 	buildkit "github.com/docker/docker/builder/builder-next"
33 33
 	"github.com/docker/docker/builder/dockerfile"
34
-	"github.com/docker/docker/builder/fscache"
35 34
 	"github.com/docker/docker/cli/debug"
36 35
 	"github.com/docker/docker/daemon"
37 36
 	"github.com/docker/docker/daemon/cluster"
... ...
@@ -269,7 +268,6 @@ func (cli *DaemonCli) start(opts *daemonOptions) (err error) {
269 269
 type routerOptions struct {
270 270
 	sessionManager *session.Manager
271 271
 	buildBackend   *buildbackend.Backend
272
-	buildCache     *fscache.FSCache // legacy
273 272
 	features       *map[string]bool
274 273
 	buildkit       *buildkit.Builder
275 274
 	daemon         *daemon.Daemon
... ...
@@ -284,21 +282,7 @@ func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, e
284 284
 		return opts, errors.Wrap(err, "failed to create sessionmanager")
285 285
 	}
286 286
 
287
-	builderStateDir := filepath.Join(config.Root, "builder")
288
-
289
-	buildCache, err := fscache.NewFSCache(fscache.Opt{
290
-		Backend: fscache.NewNaiveCacheBackend(builderStateDir),
291
-		Root:    builderStateDir,
292
-		GCPolicy: fscache.GCPolicy{ // TODO: expose this in config
293
-			MaxSize:         1024 * 1024 * 512,  // 512MB
294
-			MaxKeepDuration: 7 * 24 * time.Hour, // 1 week
295
-		},
296
-	})
297
-	if err != nil {
298
-		return opts, errors.Wrap(err, "failed to create fscache")
299
-	}
300
-
301
-	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), sm, buildCache, d.IdentityMapping())
287
+	manager, err := dockerfile.NewBuildManager(d.BuilderBackend(), d.IdentityMapping())
302 288
 	if err != nil {
303 289
 		return opts, err
304 290
 	}
... ...
@@ -319,14 +303,13 @@ func newRouterOptions(config *config.Config, d *daemon.Daemon) (routerOptions, e
319 319
 		return opts, err
320 320
 	}
321 321
 
322
-	bb, err := buildbackend.NewBackend(d.ImageService(), manager, buildCache, bk)
322
+	bb, err := buildbackend.NewBackend(d.ImageService(), manager, bk)
323 323
 	if err != nil {
324 324
 		return opts, errors.Wrap(err, "failed to create buildmanager")
325 325
 	}
326 326
 	return routerOptions{
327 327
 		sessionManager: sm,
328 328
 		buildBackend:   bb,
329
-		buildCache:     buildCache,
330 329
 		buildkit:       bk,
331 330
 		features:       d.Features(),
332 331
 		daemon:         d,
... ...
@@ -494,7 +477,7 @@ func initRouter(opts routerOptions) {
494 494
 		checkpointrouter.NewRouter(opts.daemon, decoder),
495 495
 		container.NewRouter(opts.daemon, decoder),
496 496
 		image.NewRouter(opts.daemon.ImageService()),
497
-		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildCache, opts.buildkit, opts.features),
497
+		systemrouter.NewRouter(opts.daemon, opts.cluster, opts.buildkit, opts.features),
498 498
 		volume.NewRouter(opts.daemon.VolumesService()),
499 499
 		build.NewRouter(opts.buildBackend, opts.daemon, opts.features),
500 500
 		sessionrouter.NewRouter(opts.sessionManager),
... ...
@@ -22,6 +22,7 @@ import (
22 22
 )
23 23
 
24 24
 func TestBuildWithSession(t *testing.T) {
25
+	t.Skip("TODO: BuildKit")
25 26
 	skip.If(t, testEnv.DaemonInfo.OSType == "windows")
26 27
 	skip.If(t, versions.LessThan(testEnv.DaemonAPIVersion(), "1.39"), "experimental in older versions")
27 28