Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
Signed-off-by: Tibor Vass <tibor@docker.com>
| ... | ... |
@@ -110,6 +110,10 @@ func (s *snapshotter) chainID(key string) (layer.ChainID, bool) {
|
| 110 | 110 |
return "", false |
| 111 | 111 |
} |
| 112 | 112 |
|
| 113 |
+func (s *snapshotter) GetLayer(key string) (layer.Layer, error) {
|
|
| 114 |
+ return s.getLayer(key, true) |
|
| 115 |
+} |
|
| 116 |
+ |
|
| 113 | 117 |
func (s *snapshotter) getLayer(key string, withCommitted bool) (layer.Layer, error) {
|
| 114 | 118 |
s.mu.Lock() |
| 115 | 119 |
l, ok := s.refs[key] |
| ... | ... |
@@ -9,6 +9,7 @@ import ( |
| 9 | 9 |
"github.com/docker/docker/builder/builder-next/adapters/containerimage" |
| 10 | 10 |
"github.com/docker/docker/builder/builder-next/adapters/snapshot" |
| 11 | 11 |
containerimageexp "github.com/docker/docker/builder/builder-next/exporter" |
| 12 |
+ "github.com/docker/docker/builder/builder-next/imagerefchecker" |
|
| 12 | 13 |
mobyworker "github.com/docker/docker/builder/builder-next/worker" |
| 13 | 14 |
"github.com/docker/docker/daemon/graphdriver" |
| 14 | 15 |
"github.com/moby/buildkit/cache" |
| ... | ... |
@@ -69,11 +70,20 @@ func newController(rt http.RoundTripper, opt Opt) (*control.Controller, error) {
|
| 69 | 69 |
MetadataStore: md, |
| 70 | 70 |
}) |
| 71 | 71 |
|
| 72 |
+ layerGetter, ok := sbase.(imagerefchecker.LayerGetter) |
|
| 73 |
+ if !ok {
|
|
| 74 |
+ return nil, errors.Errorf("snapshotter does not implement layergetter")
|
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 77 |
+ refChecker := imagerefchecker.New(imagerefchecker.Opt{
|
|
| 78 |
+ ImageStore: dist.ImageStore, |
|
| 79 |
+ LayerGetter: layerGetter, |
|
| 80 |
+ }) |
|
| 81 |
+ |
|
| 72 | 82 |
cm, err := cache.NewManager(cache.ManagerOpt{
|
| 73 |
- Snapshotter: snapshotter, |
|
| 74 |
- MetadataStore: md, |
|
| 75 |
- // TODO: implement PruneRefChecker to correctly mark cache objects as "Shared" |
|
| 76 |
- PruneRefChecker: nil, |
|
| 83 |
+ Snapshotter: snapshotter, |
|
| 84 |
+ MetadataStore: md, |
|
| 85 |
+ PruneRefChecker: refChecker, |
|
| 77 | 86 |
}) |
| 78 | 87 |
if err != nil {
|
| 79 | 88 |
return nil, err |
| 80 | 89 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,96 @@ |
| 0 |
+package imagerefchecker |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "sync" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/docker/docker/image" |
|
| 6 |
+ "github.com/docker/docker/layer" |
|
| 7 |
+ "github.com/moby/buildkit/cache" |
|
| 8 |
+) |
|
| 9 |
+ |
|
| 10 |
+// LayerGetter abstracts away the snapshotter |
|
| 11 |
+type LayerGetter interface {
|
|
| 12 |
+ GetLayer(string) (layer.Layer, error) |
|
| 13 |
+} |
|
| 14 |
+ |
|
| 15 |
+// Opt represents the options needed to create a refchecker |
|
| 16 |
+type Opt struct {
|
|
| 17 |
+ LayerGetter LayerGetter |
|
| 18 |
+ ImageStore image.Store |
|
| 19 |
+} |
|
| 20 |
+ |
|
| 21 |
+// New creates new image reference checker that can be used to see if a reference |
|
| 22 |
+// is being used by any of the images in the image store |
|
| 23 |
+func New(opt Opt) cache.ExternalRefCheckerFunc {
|
|
| 24 |
+ return func() (cache.ExternalRefChecker, error) {
|
|
| 25 |
+ return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil
|
|
| 26 |
+ } |
|
| 27 |
+} |
|
| 28 |
+ |
|
| 29 |
+type lchain map[layer.DiffID]lchain |
|
| 30 |
+ |
|
| 31 |
+func (c lchain) add(ids []layer.DiffID) {
|
|
| 32 |
+ if len(ids) == 0 {
|
|
| 33 |
+ return |
|
| 34 |
+ } |
|
| 35 |
+ id := ids[0] |
|
| 36 |
+ ch, ok := c[id] |
|
| 37 |
+ if !ok {
|
|
| 38 |
+ ch = lchain{}
|
|
| 39 |
+ c[id] = ch |
|
| 40 |
+ } |
|
| 41 |
+ ch.add(ids[1:]) |
|
| 42 |
+} |
|
| 43 |
+ |
|
| 44 |
+func (c lchain) has(ids []layer.DiffID) bool {
|
|
| 45 |
+ if len(ids) == 0 {
|
|
| 46 |
+ return true |
|
| 47 |
+ } |
|
| 48 |
+ ch, ok := c[ids[0]] |
|
| 49 |
+ return ok && ch.has(ids[1:]) |
|
| 50 |
+} |
|
| 51 |
+ |
|
| 52 |
+type checker struct {
|
|
| 53 |
+ opt Opt |
|
| 54 |
+ once sync.Once |
|
| 55 |
+ layers lchain |
|
| 56 |
+ cache map[string]bool |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+func (c *checker) Exists(key string) bool {
|
|
| 60 |
+ if c.opt.ImageStore == nil {
|
|
| 61 |
+ return false |
|
| 62 |
+ } |
|
| 63 |
+ |
|
| 64 |
+ c.once.Do(c.init) |
|
| 65 |
+ |
|
| 66 |
+ if b, ok := c.cache[key]; ok {
|
|
| 67 |
+ return b |
|
| 68 |
+ } |
|
| 69 |
+ |
|
| 70 |
+ l, err := c.opt.LayerGetter.GetLayer(key) |
|
| 71 |
+ if err != nil || l == nil {
|
|
| 72 |
+ c.cache[key] = false |
|
| 73 |
+ return false |
|
| 74 |
+ } |
|
| 75 |
+ |
|
| 76 |
+ ok := c.layers.has(diffIDs(l)) |
|
| 77 |
+ c.cache[key] = ok |
|
| 78 |
+ return ok |
|
| 79 |
+} |
|
| 80 |
+ |
|
| 81 |
+func (c *checker) init() {
|
|
| 82 |
+ imgs := c.opt.ImageStore.Map() |
|
| 83 |
+ |
|
| 84 |
+ for _, img := range imgs {
|
|
| 85 |
+ c.layers.add(img.RootFS.DiffIDs) |
|
| 86 |
+ } |
|
| 87 |
+} |
|
| 88 |
+ |
|
| 89 |
+func diffIDs(l layer.Layer) []layer.DiffID {
|
|
| 90 |
+ p := l.Parent() |
|
| 91 |
+ if p == nil {
|
|
| 92 |
+ return []layer.DiffID{l.DiffID()}
|
|
| 93 |
+ } |
|
| 94 |
+ return append(diffIDs(p), l.DiffID()) |
|
| 95 |
+} |