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