1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

builder: expand prune to buildkit

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
This commit is contained in:
Tonis Tiigi 2018-05-15 15:12:03 -07:00
parent f0a9e54d20
commit 760ecf958b
4 changed files with 143 additions and 48 deletions

View file

@ -14,6 +14,7 @@ import (
"github.com/docker/docker/image" "github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid" "github.com/docker/docker/pkg/stringid"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup"
) )
// ImageComponent provides an interface for working with images // ImageComponent provides an interface for working with images
@ -89,11 +90,33 @@ func (b *Backend) Build(ctx context.Context, config backend.BuildConfig) (string
// PruneCache removes all cached build sources // PruneCache removes all cached build sources
func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport, error) { func (b *Backend) PruneCache(ctx context.Context) (*types.BuildCachePruneReport, error) {
size, err := b.fsCache.Prune(ctx) eg, ctx := errgroup.WithContext(ctx)
var fsCacheSize uint64
eg.Go(func() error {
var err error
fsCacheSize, err = b.fsCache.Prune(ctx)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to prune build cache") return errors.Wrap(err, "failed to prune fscache")
} }
return &types.BuildCachePruneReport{SpaceReclaimed: size}, nil return nil
})
var buildCacheSize int64
eg.Go(func() error {
var err error
buildCacheSize, err = b.buildkit.Prune(ctx)
if err != nil {
return errors.Wrap(err, "failed to prune build cache")
}
return nil
})
if err := eg.Wait(); err != nil {
return nil, err
}
return &types.BuildCachePruneReport{SpaceReclaimed: fsCacheSize + uint64(buildCacheSize)}, nil
} }
func (b *Backend) Cancel(ctx context.Context, id string) error { func (b *Backend) Cancel(ctx context.Context, id string) error {

View file

@ -13,7 +13,7 @@ import (
) )
func (s *snapshotter) EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error) { func (s *snapshotter) EnsureLayer(ctx context.Context, key string) ([]layer.DiffID, error) {
if l, err := s.getLayer(key); err != nil { if l, err := s.getLayer(key, true); err != nil {
return nil, err return nil, err
} else if l != nil { } else if l != nil {
return getDiffChain(l), nil return getDiffChain(l), nil
@ -57,7 +57,7 @@ func (s *snapshotter) EnsureLayer(ctx context.Context, key string) ([]layer.Diff
eg.Go(func() error { eg.Go(func() error {
parent := "" parent := ""
if p := info.Parent; p != "" { if p := info.Parent; p != "" {
if l, err := s.getLayer(p); err != nil { if l, err := s.getLayer(p, true); err != nil {
return err return err
} else if l != nil { } else if l != nil {
parent, err = getGraphID(l) parent, err = getGraphID(l)

View file

@ -74,7 +74,7 @@ func NewSnapshotter(opt Opt) (snapshot.SnapshotterBase, error) {
func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) error { func (s *snapshotter) Prepare(ctx context.Context, key, parent string, opts ...snapshots.Opt) error {
origParent := parent origParent := parent
if parent != "" { if parent != "" {
if l, err := s.getLayer(parent); err != nil { if l, err := s.getLayer(parent, false); err != nil {
return err return err
} else if l != nil { } else if l != nil {
parent, err = getGraphID(l) parent, err = getGraphID(l)
@ -115,12 +115,16 @@ func (s *snapshotter) chainID(key string) (layer.ChainID, bool) {
return "", false return "", false
} }
func (s *snapshotter) getLayer(key string) (layer.Layer, error) { func (s *snapshotter) getLayer(key string, withCommitted bool) (layer.Layer, error) {
s.mu.Lock() s.mu.Lock()
l, ok := s.refs[key] l, ok := s.refs[key]
if !ok { if !ok {
id, ok := s.chainID(key) id, ok := s.chainID(key)
if !ok { if !ok {
if !withCommitted {
s.mu.Unlock()
return nil, nil
}
if err := s.db.View(func(tx *bolt.Tx) error { if err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(key)) b := tx.Bucket([]byte(key))
if b == nil { if b == nil {
@ -146,7 +150,7 @@ func (s *snapshotter) getLayer(key string) (layer.Layer, error) {
s.mu.Unlock() s.mu.Unlock()
return nil, err return nil, err
} }
s.refs[string(id)] = l s.refs[key] = l
if err := s.db.Update(func(tx *bolt.Tx) error { if err := s.db.Update(func(tx *bolt.Tx) error {
_, err := tx.CreateBucketIfNotExists([]byte(key)) _, err := tx.CreateBucketIfNotExists([]byte(key))
return err return err
@ -179,25 +183,28 @@ func (s *snapshotter) getGraphDriverID(key string) (string, bool) {
} }
func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) { func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, error) {
if l, err := s.getLayer(key); err != nil {
return snapshots.Info{}, err
} else if l != nil {
var parentID string
if p := l.Parent(); p != nil {
parentID = p.ChainID().String()
}
info := snapshots.Info{
Kind: snapshots.KindCommitted,
Name: key,
Parent: parentID,
}
return info, nil
}
inf := snapshots.Info{ inf := snapshots.Info{
Kind: snapshots.KindActive, Kind: snapshots.KindActive,
} }
l, err := s.getLayer(key, false)
if err != nil {
return snapshots.Info{}, err
}
if l != nil {
if p := l.Parent(); p != nil {
inf.Parent = p.ChainID().String()
}
inf.Kind = snapshots.KindCommitted
inf.Name = string(key)
return inf, nil
}
l, err = s.getLayer(key, true)
if err != nil {
return snapshots.Info{}, err
}
id, committed := s.getGraphDriverID(key) id, committed := s.getGraphDriverID(key)
if committed { if committed {
inf.Kind = snapshots.KindCommitted inf.Kind = snapshots.KindCommitted
@ -205,13 +212,22 @@ func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, err
if err := s.db.View(func(tx *bolt.Tx) error { if err := s.db.View(func(tx *bolt.Tx) error {
b := tx.Bucket([]byte(id)) b := tx.Bucket([]byte(id))
if b == nil { if b == nil && l == nil {
return errors.Errorf("not found") // TODO: typed return errors.Errorf("snapshot %s not found", id) // TODO: typed
} }
inf.Name = string(key) inf.Name = string(key)
if b != nil {
v := b.Get(keyParent) v := b.Get(keyParent)
if v != nil { if v != nil {
inf.Parent = string(v) inf.Parent = string(v)
return nil
}
}
if l != nil {
if p := l.Parent(); p != nil {
inf.Parent = p.ChainID().String()
}
inf.Kind = snapshots.KindCommitted
} }
return nil return nil
}); err != nil { }); err != nil {
@ -221,7 +237,7 @@ func (s *snapshotter) Stat(ctx context.Context, key string) (snapshots.Info, err
} }
func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountable, error) { func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountable, error) {
l, err := s.getLayer(key) l, err := s.getLayer(key, true)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -269,16 +285,17 @@ func (s *snapshotter) Mounts(ctx context.Context, key string) (snapshot.Mountabl
} }
func (s *snapshotter) Remove(ctx context.Context, key string) error { func (s *snapshotter) Remove(ctx context.Context, key string) error {
l, err := s.getLayer(key) l, err := s.getLayer(key, true)
if err != nil { if err != nil {
return err return err
} }
id, _ := s.getGraphDriverID(key)
var found bool var found bool
if err := s.db.Update(func(tx *bolt.Tx) error { if err := s.db.Update(func(tx *bolt.Tx) error {
found = tx.Bucket([]byte(key)) != nil found = tx.Bucket([]byte(key)) != nil
if found { if found {
id, _ := s.getGraphDriverID(key)
tx.DeleteBucket([]byte(key)) tx.DeleteBucket([]byte(key))
if id != key { if id != key {
tx.DeleteBucket([]byte(id)) tx.DeleteBucket([]byte(id))
@ -298,7 +315,6 @@ func (s *snapshotter) Remove(ctx context.Context, key string) error {
return nil return nil
} }
id, _ := s.getGraphDriverID(key)
return s.opt.GraphDriver.Remove(id) return s.opt.GraphDriver.Remove(id)
} }
@ -331,9 +347,9 @@ func (s *snapshotter) Update(ctx context.Context, info snapshots.Info, fieldpath
return s.Stat(ctx, info.Name) return s.Stat(ctx, info.Name)
} }
func (s *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, error) { func (s *snapshotter) Usage(ctx context.Context, key string) (us snapshots.Usage, retErr error) {
usage := snapshots.Usage{} usage := snapshots.Usage{}
if l, err := s.getLayer(key); err != nil { if l, err := s.getLayer(key, true); err != nil {
return usage, err return usage, err
} else if l != nil { } else if l != nil {
s, err := l.DiffSize() s, err := l.DiffSize()
@ -376,8 +392,17 @@ func (s *snapshotter) Usage(ctx context.Context, key string) (snapshots.Usage, e
} }
var parent string var parent string
if info.Parent != "" { if info.Parent != "" {
if l, err := s.getLayer(info.Parent, false); err != nil {
return usage, err
} else if l != nil {
parent, err = getGraphID(l)
if err != nil {
return usage, err
}
} else {
parent, _ = s.getGraphDriverID(info.Parent) parent, _ = s.getGraphDriverID(info.Parent)
} }
}
diffSize, err := s.opt.GraphDriver.DiffSize(id, parent) diffSize, err := s.opt.GraphDriver.DiffSize(id, parent)
if err != nil { if err != nil {

View file

@ -80,6 +80,34 @@ func (b *Builder) DiskUsage(ctx context.Context) ([]*types.BuildCache, error) {
return items, nil return items, nil
} }
func (b *Builder) Prune(ctx context.Context) (int64, error) {
ch := make(chan *controlapi.UsageRecord)
eg, ctx := errgroup.WithContext(ctx)
eg.Go(func() error {
defer close(ch)
return b.controller.Prune(&controlapi.PruneRequest{}, &pruneProxy{
streamProxy: streamProxy{ctx: ctx},
ch: ch,
})
})
var size int64
eg.Go(func() error {
for r := range ch {
size += r.Size_
}
return nil
})
if err := eg.Wait(); err != nil {
return 0, err
}
return size, nil
}
func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.Result, error) { func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.Result, error) {
var out builder.Result var out builder.Result
@ -149,7 +177,7 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
defer close(ch) defer close(ch)
return b.controller.Status(&controlapi.StatusRequest{ return b.controller.Status(&controlapi.StatusRequest{
Ref: id, Ref: id,
}, &statusProxy{ctx: ctx, ch: ch}) }, &statusProxy{streamProxy: streamProxy{ctx: ctx}, ch: ch})
}) })
eg.Go(func() error { eg.Go(func() error {
@ -188,37 +216,56 @@ func (b *Builder) Build(ctx context.Context, opt backend.BuildConfig) (*builder.
return &out, nil return &out, nil
} }
type statusProxy struct { type streamProxy struct {
ctx context.Context ctx context.Context
}
func (sp *streamProxy) SetHeader(_ grpcmetadata.MD) error {
return nil
}
func (sp *streamProxy) SendHeader(_ grpcmetadata.MD) error {
return nil
}
func (sp *streamProxy) SetTrailer(_ grpcmetadata.MD) {
}
func (sp *streamProxy) Context() context.Context {
return sp.ctx
}
func (sp *streamProxy) RecvMsg(m interface{}) error {
return io.EOF
}
type statusProxy struct {
streamProxy
ch chan *controlapi.StatusResponse ch chan *controlapi.StatusResponse
} }
func (sp *statusProxy) SetHeader(_ grpcmetadata.MD) error {
return nil
}
func (sp *statusProxy) SendHeader(_ grpcmetadata.MD) error {
return nil
}
func (sp *statusProxy) SetTrailer(_ grpcmetadata.MD) {
}
func (sp *statusProxy) Send(resp *controlapi.StatusResponse) error { func (sp *statusProxy) Send(resp *controlapi.StatusResponse) error {
return sp.SendMsg(resp) return sp.SendMsg(resp)
} }
func (sp *statusProxy) Context() context.Context {
return sp.ctx
}
func (sp *statusProxy) SendMsg(m interface{}) error { func (sp *statusProxy) SendMsg(m interface{}) error {
if sr, ok := m.(*controlapi.StatusResponse); ok { if sr, ok := m.(*controlapi.StatusResponse); ok {
sp.ch <- sr sp.ch <- sr
} }
return nil return nil
} }
func (sp *statusProxy) RecvMsg(m interface{}) error {
return io.EOF type pruneProxy struct {
streamProxy
ch chan *controlapi.UsageRecord
}
func (sp *pruneProxy) Send(resp *controlapi.UsageRecord) error {
return sp.SendMsg(resp)
}
func (sp *pruneProxy) SendMsg(m interface{}) error {
if sr, ok := m.(*controlapi.UsageRecord); ok {
sp.ch <- sr
}
return nil
} }
type contentStoreNoLabels struct { type contentStoreNoLabels struct {