builder: implement ref checker
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com> Signed-off-by: Tibor Vass <tibor@docker.com>
This commit is contained in:
parent
d47435a004
commit
354c241041
3 changed files with 114 additions and 4 deletions
|
@ -110,6 +110,10 @@ func (s *snapshotter) chainID(key string) (layer.ChainID, bool) {
|
|||
return "", false
|
||||
}
|
||||
|
||||
func (s *snapshotter) GetLayer(key string) (layer.Layer, error) {
|
||||
return s.getLayer(key, true)
|
||||
}
|
||||
|
||||
func (s *snapshotter) getLayer(key string, withCommitted bool) (layer.Layer, error) {
|
||||
s.mu.Lock()
|
||||
l, ok := s.refs[key]
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/docker/docker/builder/builder-next/adapters/containerimage"
|
||||
"github.com/docker/docker/builder/builder-next/adapters/snapshot"
|
||||
containerimageexp "github.com/docker/docker/builder/builder-next/exporter"
|
||||
"github.com/docker/docker/builder/builder-next/imagerefchecker"
|
||||
mobyworker "github.com/docker/docker/builder/builder-next/worker"
|
||||
"github.com/docker/docker/daemon/graphdriver"
|
||||
"github.com/moby/buildkit/cache"
|
||||
|
@ -69,11 +70,20 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
|
|||
MetadataStore: md,
|
||||
})
|
||||
|
||||
layerGetter, ok := sbase.(imagerefchecker.LayerGetter)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("snapshotter does not implement layergetter")
|
||||
}
|
||||
|
||||
refChecker := imagerefchecker.New(imagerefchecker.Opt{
|
||||
ImageStore: dist.ImageStore,
|
||||
LayerGetter: layerGetter,
|
||||
})
|
||||
|
||||
cm, err := cache.NewManager(cache.ManagerOpt{
|
||||
Snapshotter: snapshotter,
|
||||
MetadataStore: md,
|
||||
// TODO: implement PruneRefChecker to correctly mark cache objects as "Shared"
|
||||
PruneRefChecker: nil,
|
||||
Snapshotter: snapshotter,
|
||||
MetadataStore: md,
|
||||
PruneRefChecker: refChecker,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
96
builder/builder-next/imagerefchecker/checker.go
Normal file
96
builder/builder-next/imagerefchecker/checker.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package imagerefchecker
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/docker/docker/image"
|
||||
"github.com/docker/docker/layer"
|
||||
"github.com/moby/buildkit/cache"
|
||||
)
|
||||
|
||||
// LayerGetter abstracts away the snapshotter
|
||||
type LayerGetter interface {
|
||||
GetLayer(string) (layer.Layer, error)
|
||||
}
|
||||
|
||||
// Opt represents the options needed to create a refchecker
|
||||
type Opt struct {
|
||||
LayerGetter LayerGetter
|
||||
ImageStore image.Store
|
||||
}
|
||||
|
||||
// New creates new image reference checker that can be used to see if a reference
|
||||
// is being used by any of the images in the image store
|
||||
func New(opt Opt) cache.ExternalRefCheckerFunc {
|
||||
return func() (cache.ExternalRefChecker, error) {
|
||||
return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil
|
||||
}
|
||||
}
|
||||
|
||||
type lchain map[layer.DiffID]lchain
|
||||
|
||||
func (c lchain) add(ids []layer.DiffID) {
|
||||
if len(ids) == 0 {
|
||||
return
|
||||
}
|
||||
id := ids[0]
|
||||
ch, ok := c[id]
|
||||
if !ok {
|
||||
ch = lchain{}
|
||||
c[id] = ch
|
||||
}
|
||||
ch.add(ids[1:])
|
||||
}
|
||||
|
||||
func (c lchain) has(ids []layer.DiffID) bool {
|
||||
if len(ids) == 0 {
|
||||
return true
|
||||
}
|
||||
ch, ok := c[ids[0]]
|
||||
return ok && ch.has(ids[1:])
|
||||
}
|
||||
|
||||
type checker struct {
|
||||
opt Opt
|
||||
once sync.Once
|
||||
layers lchain
|
||||
cache map[string]bool
|
||||
}
|
||||
|
||||
func (c *checker) Exists(key string) bool {
|
||||
if c.opt.ImageStore == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
c.once.Do(c.init)
|
||||
|
||||
if b, ok := c.cache[key]; ok {
|
||||
return b
|
||||
}
|
||||
|
||||
l, err := c.opt.LayerGetter.GetLayer(key)
|
||||
if err != nil || l == nil {
|
||||
c.cache[key] = false
|
||||
return false
|
||||
}
|
||||
|
||||
ok := c.layers.has(diffIDs(l))
|
||||
c.cache[key] = ok
|
||||
return ok
|
||||
}
|
||||
|
||||
func (c *checker) init() {
|
||||
imgs := c.opt.ImageStore.Map()
|
||||
|
||||
for _, img := range imgs {
|
||||
c.layers.add(img.RootFS.DiffIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func diffIDs(l layer.Layer) []layer.DiffID {
|
||||
p := l.Parent()
|
||||
if p == nil {
|
||||
return []layer.DiffID{l.DiffID()}
|
||||
}
|
||||
return append(diffIDs(p), l.DiffID())
|
||||
}
|
Loading…
Reference in a new issue