checker.go 1.8 KB

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