github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/builder/builder-next/imagerefchecker/checker.go (about)

     1  package imagerefchecker
     2  
     3  import (
     4  	"sync"
     5  
     6  	"github.com/docker/docker/image"
     7  	"github.com/docker/docker/layer"
     8  	"github.com/moby/buildkit/cache"
     9  	digest "github.com/opencontainers/go-digest"
    10  )
    11  
    12  // LayerGetter abstracts away the snapshotter
    13  type LayerGetter interface {
    14  	GetLayer(string) (layer.Layer, error)
    15  }
    16  
    17  // Opt represents the options needed to create a refchecker
    18  type Opt struct {
    19  	LayerGetter LayerGetter
    20  	ImageStore  image.Store
    21  }
    22  
    23  // New creates new image reference checker that can be used to see if a reference
    24  // is being used by any of the images in the image store
    25  func New(opt Opt) cache.ExternalRefCheckerFunc {
    26  	return func() (cache.ExternalRefChecker, error) {
    27  		return &checker{opt: opt, layers: lchain{}, cache: map[string]bool{}}, nil
    28  	}
    29  }
    30  
    31  type lchain map[layer.DiffID]lchain
    32  
    33  func (c lchain) add(ids []layer.DiffID) {
    34  	if len(ids) == 0 {
    35  		return
    36  	}
    37  	id := ids[0]
    38  	ch, ok := c[id]
    39  	if !ok {
    40  		ch = lchain{}
    41  		c[id] = ch
    42  	}
    43  	ch.add(ids[1:])
    44  }
    45  
    46  func (c lchain) has(ids []layer.DiffID) bool {
    47  	if len(ids) == 0 {
    48  		return true
    49  	}
    50  	ch, ok := c[ids[0]]
    51  	return ok && ch.has(ids[1:])
    52  }
    53  
    54  type checker struct {
    55  	opt    Opt
    56  	once   sync.Once
    57  	layers lchain
    58  	cache  map[string]bool
    59  }
    60  
    61  func (c *checker) Exists(key string, chain []digest.Digest) bool {
    62  	if c.opt.ImageStore == nil {
    63  		return false
    64  	}
    65  
    66  	c.once.Do(c.init)
    67  
    68  	if b, ok := c.cache[key]; ok {
    69  		return b
    70  	}
    71  
    72  	l, err := c.opt.LayerGetter.GetLayer(key)
    73  	if err != nil || l == nil {
    74  		c.cache[key] = false
    75  		return false
    76  	}
    77  
    78  	ok := c.layers.has(diffIDs(l))
    79  	c.cache[key] = ok
    80  	return ok
    81  }
    82  
    83  func (c *checker) init() {
    84  	imgs := c.opt.ImageStore.Map()
    85  
    86  	for _, img := range imgs {
    87  		c.layers.add(img.RootFS.DiffIDs)
    88  	}
    89  }
    90  
    91  func diffIDs(l layer.Layer) []layer.DiffID {
    92  	p := l.Parent()
    93  	if p == nil {
    94  		return []layer.DiffID{l.DiffID()}
    95  	}
    96  	return append(diffIDs(p), l.DiffID())
    97  }