From 1ec543e38404d80f1670c816f9a0b4389c345796 Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Wed, 9 Jan 2019 17:42:46 -0800 Subject: [PATCH 1/2] solver: exclude randomized cache keys from exporter Signed-off-by: Tonis Tiigi --- cache/remotecache/v1/chains.go | 13 +++++++++++++ solver/cachemanager.go | 4 ++++ solver/llbsolver/ops/source.go | 9 ++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/cache/remotecache/v1/chains.go b/cache/remotecache/v1/chains.go index 52806b9c4498..d89f64eb34fc 100644 --- a/cache/remotecache/v1/chains.go +++ b/cache/remotecache/v1/chains.go @@ -1,6 +1,7 @@ package cacheimport import ( + "strings" "time" "github.com/containerd/containerd/content" @@ -19,6 +20,9 @@ type CacheChains struct { } func (c *CacheChains) Add(dgst digest.Digest) solver.CacheExporterRecord { + if strings.HasPrefix(dgst.String(), "random:") { + return &nopRecord{} + } it := &item{c: c, dgst: dgst} c.items = append(c.items, it) return it @@ -124,4 +128,13 @@ func (c *item) LinkFrom(rec solver.CacheExporterRecord, index int, selector stri c.links[index][link{src: src, selector: selector}] = struct{}{} } +type nopRecord struct { +} + +func (c *nopRecord) AddResult(createdAt time.Time, result *solver.Remote) { +} + +func (c *nopRecord) LinkFrom(rec solver.CacheExporterRecord, index int, selector string) { +} + var _ solver.CacheExporterTarget = &CacheChains{} diff --git a/solver/cachemanager.go b/solver/cachemanager.go index ce41aa791b30..214ace5da169 100644 --- a/solver/cachemanager.go +++ b/solver/cachemanager.go @@ -3,6 +3,7 @@ package solver import ( "context" "fmt" + "strings" "sync" "github.com/moby/buildkit/identity" @@ -273,5 +274,8 @@ func (c *cacheManager) getIDFromDeps(k *CacheKey) string { } func rootKey(dgst digest.Digest, output Index) digest.Digest { + if strings.HasPrefix(dgst.String(), "random:") { + return digest.Digest("random:" + strings.TrimPrefix(digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))).String(), digest.Canonical.String()+":")) + } return digest.FromBytes([]byte(fmt.Sprintf("%s@%d", dgst, output))) } diff --git a/solver/llbsolver/ops/source.go b/solver/llbsolver/ops/source.go index 722861eeb4f0..30df745e715d 100644 --- a/solver/llbsolver/ops/source.go +++ b/solver/llbsolver/ops/source.go @@ -2,6 +2,7 @@ package ops import ( "context" + "strings" "sync" "github.com/moby/buildkit/solver" @@ -59,9 +60,15 @@ func (s *sourceOp) CacheMap(ctx context.Context, index int) (*solver.CacheMap, b return nil, false, err } + dgst := digest.FromBytes([]byte(sourceCacheType + ":" + k)) + + if strings.HasPrefix(k, "session:") { + dgst = digest.Digest("random:" + strings.TrimPrefix(dgst.String(), dgst.Algorithm().String()+":")) + } + return &solver.CacheMap{ // TODO: add os/arch - Digest: digest.FromBytes([]byte(sourceCacheType + ":" + k)), + Digest: dgst, }, done, nil } From ac4037a1d95c4609288bcfd890aac81986552eef Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Thu, 10 Jan 2019 08:43:27 -0800 Subject: [PATCH 2/2] solver: keep original cache creation date when copying between stores Signed-off-by: Tonis Tiigi --- cache/remotecache/v1/cachestorage.go | 3 ++- solver/cache_test.go | 35 ++++++++++++++-------------- solver/cachemanager.go | 6 ++--- solver/cachestorage.go | 2 +- solver/combinedcache.go | 7 +++--- solver/edge.go | 3 ++- solver/llbsolver/bridge.go | 5 ++-- solver/memorycachestorage.go | 4 ++-- solver/types.go | 2 +- worker/cacheresult.go | 4 ++-- 10 files changed, 38 insertions(+), 33 deletions(-) diff --git a/cache/remotecache/v1/cachestorage.go b/cache/remotecache/v1/cachestorage.go index 27b19587c820..243f9dba3864 100644 --- a/cache/remotecache/v1/cachestorage.go +++ b/cache/remotecache/v1/cachestorage.go @@ -2,6 +2,7 @@ package cacheimport import ( "context" + "time" "github.com/moby/buildkit/identity" "github.com/moby/buildkit/solver" @@ -191,7 +192,7 @@ type cacheResultStorage struct { byResult map[string]map[string]struct{} } -func (cs *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error) { +func (cs *cacheResultStorage) Save(res solver.Result, createdAt time.Time) (solver.CacheResult, error) { return solver.CacheResult{}, errors.Errorf("importer is immutable") } diff --git a/solver/cache_test.go b/solver/cache_test.go index 5727d2dd2346..20e6daec2b60 100644 --- a/solver/cache_test.go +++ b/solver/cache_test.go @@ -3,6 +3,7 @@ package solver import ( "context" "testing" + "time" "github.com/moby/buildkit/identity" digest "github.com/opencontainers/go-digest" @@ -41,7 +42,7 @@ func TestInMemoryCache(t *testing.T) { m := NewInMemoryCacheManager() - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0")) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0"), time.Now()) require.NoError(t, err) keys, err := m.Query(nil, 0, dgst("foo"), 0) @@ -57,7 +58,7 @@ func TestInMemoryCache(t *testing.T) { require.Equal(t, "result0", unwrap(res)) // another record - cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0), testResult("result1")) + cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0), testResult("result1"), time.Now()) require.NoError(t, err) keys, err = m.Query(nil, 0, dgst("bar"), 0) @@ -79,7 +80,7 @@ func TestInMemoryCache(t *testing.T) { // second level k := testCacheKey(dgst("baz"), Index(1), *cacheFoo, *cacheBar) - cacheBaz, err := m.Save(k, testResult("result2")) + cacheBaz, err := m.Save(k, testResult("result2"), time.Now()) require.NoError(t, err) keys, err = m.Query(nil, 0, dgst("baz"), 0) @@ -113,7 +114,7 @@ func TestInMemoryCache(t *testing.T) { require.Equal(t, keys[0].ID, keys2[0].ID) k = testCacheKey(dgst("baz"), Index(1), *cacheFoo) - _, err = m.Save(k, testResult("result3")) + _, err = m.Save(k, testResult("result3"), time.Now()) require.NoError(t, err) keys, err = m.Query(depKeys(*cacheFoo), 0, dgst("baz"), Index(1)) @@ -128,7 +129,7 @@ func TestInMemoryCache(t *testing.T) { {{CacheKey: *cacheFoo}, {CacheKey: *cacheBaz}}, {{CacheKey: *cacheBar}}, }) - _, err = m.Save(k, testResult("result4")) + _, err = m.Save(k, testResult("result4"), time.Now()) require.NoError(t, err) // foo, bar, baz should all point to result4 @@ -154,12 +155,12 @@ func TestInMemoryCacheSelector(t *testing.T) { m := NewInMemoryCacheManager() - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0")) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0"), time.Now()) require.NoError(t, err) _, err = m.Save(testCacheKeyWithDeps(dgst("bar"), 0, [][]CacheKeyWithSelector{ {{CacheKey: *cacheFoo, Selector: dgst("sel0")}}, - }), testResult("result1")) + }), testResult("result1"), time.Now()) require.NoError(t, err) keys, err := m.Query(depKeys(*cacheFoo), 0, dgst("bar"), 0) @@ -188,12 +189,12 @@ func TestInMemoryCacheSelectorNested(t *testing.T) { m := NewInMemoryCacheManager() - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0")) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("result0"), time.Now()) require.NoError(t, err) _, err = m.Save(testCacheKeyWithDeps(dgst("bar"), 0, [][]CacheKeyWithSelector{ {{CacheKey: *cacheFoo, Selector: dgst("sel0")}, {CacheKey: expKey(NewCacheKey(dgst("second"), 0))}}, - }), testResult("result1")) + }), testResult("result1"), time.Now()) require.NoError(t, err) keys, err := m.Query( @@ -241,11 +242,11 @@ func TestInMemoryCacheReleaseParent(t *testing.T) { m := NewCacheManager(identity.NewID(), storage, results) res0 := testResult("result0") - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), res0) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), res0, time.Now()) require.NoError(t, err) res1 := testResult("result1") - _, err = m.Save(testCacheKey(dgst("bar"), 0, *cacheFoo), res1) + _, err = m.Save(testCacheKey(dgst("bar"), 0, *cacheFoo), res1, time.Now()) require.NoError(t, err) keys, err := m.Query(nil, 0, dgst("foo"), 0) @@ -293,15 +294,15 @@ func TestInMemoryCacheRestoreOfflineDeletion(t *testing.T) { m := NewCacheManager(identity.NewID(), storage, results) res0 := testResult("result0") - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), res0) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), res0, time.Now()) require.NoError(t, err) res1 := testResult("result1") - _, err = m.Save(testCacheKey(dgst("bar"), 0, *cacheFoo), res1) + _, err = m.Save(testCacheKey(dgst("bar"), 0, *cacheFoo), res1, time.Now()) require.NoError(t, err) results2 := NewInMemoryResultStorage() - _, err = results2.Save(res1) // only add bar + _, err = results2.Save(res1, time.Now()) // only add bar require.NoError(t, err) m = NewCacheManager(identity.NewID(), storage, results2) @@ -328,15 +329,15 @@ func TestCarryOverFromSublink(t *testing.T) { results := NewInMemoryResultStorage() m := NewCacheManager(identity.NewID(), storage, results) - cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("resultFoo")) + cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0), testResult("resultFoo"), time.Now()) require.NoError(t, err) _, err = m.Save(testCacheKeyWithDeps(dgst("res"), 0, [][]CacheKeyWithSelector{ {{CacheKey: *cacheFoo, Selector: dgst("sel0")}, {CacheKey: expKey(NewCacheKey(dgst("content0"), 0))}}, - }), testResult("result0")) + }), testResult("result0"), time.Now()) require.NoError(t, err) - cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0), testResult("resultBar")) + cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0), testResult("resultBar"), time.Now()) require.NoError(t, err) keys, err := m.Query([]CacheKeyWithSelector{ diff --git a/solver/cachemanager.go b/solver/cachemanager.go index 214ace5da169..d133af78ba37 100644 --- a/solver/cachemanager.go +++ b/solver/cachemanager.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" "sync" + "time" "github.com/moby/buildkit/identity" digest "github.com/opencontainers/go-digest" @@ -143,15 +144,14 @@ func (c *cacheManager) Load(ctx context.Context, rec *CacheRecord) (Result, erro return c.results.Load(ctx, res) } -func (c *cacheManager) Save(k *CacheKey, r Result) (*ExportableCacheKey, error) { +func (c *cacheManager) Save(k *CacheKey, r Result, createdAt time.Time) (*ExportableCacheKey, error) { c.mu.Lock() defer c.mu.Unlock() - res, err := c.results.Save(r) + res, err := c.results.Save(r, createdAt) if err != nil { return nil, err } - if err := c.backend.AddResult(c.getID(k), res); err != nil { return nil, err } diff --git a/solver/cachestorage.go b/solver/cachestorage.go index 65225f757b34..cc1e21134638 100644 --- a/solver/cachestorage.go +++ b/solver/cachestorage.go @@ -44,7 +44,7 @@ type CacheInfoLink struct { // CacheResultStorage is interface for converting cache metadata result to // actual solve result type CacheResultStorage interface { - Save(Result) (CacheResult, error) + Save(Result, time.Time) (CacheResult, error) Load(ctx context.Context, res CacheResult) (Result, error) LoadRemote(ctx context.Context, res CacheResult) (*Remote, error) Exists(id string) bool diff --git a/solver/combinedcache.go b/solver/combinedcache.go index b4205d3ed063..9b2762e38505 100644 --- a/solver/combinedcache.go +++ b/solver/combinedcache.go @@ -4,6 +4,7 @@ import ( "context" "strings" "sync" + "time" digest "github.com/opencontainers/go-digest" "github.com/pkg/errors" @@ -71,14 +72,14 @@ func (cm *combinedCacheManager) Load(ctx context.Context, rec *CacheRecord) (Res if err != nil { return nil, err } - if _, err := cm.main.Save(rec.key, res); err != nil { + if _, err := cm.main.Save(rec.key, res, rec.CreatedAt); err != nil { return nil, err } return res, nil } -func (cm *combinedCacheManager) Save(key *CacheKey, s Result) (*ExportableCacheKey, error) { - return cm.main.Save(key, s) +func (cm *combinedCacheManager) Save(key *CacheKey, s Result, createdAt time.Time) (*ExportableCacheKey, error) { + return cm.main.Save(key, s, createdAt) } func (cm *combinedCacheManager) Records(ck *CacheKey) ([]*CacheRecord, error) { diff --git a/solver/edge.go b/solver/edge.go index 07e67a3e194c..397fc03a3bdc 100644 --- a/solver/edge.go +++ b/solver/edge.go @@ -3,6 +3,7 @@ package solver import ( "context" "sync" + "time" "github.com/moby/buildkit/solver/internal/pipe" digest "github.com/opencontainers/go-digest" @@ -845,7 +846,7 @@ func (e *edge) execOp(ctx context.Context) (interface{}, error) { var exporters []CacheExporter for _, cacheKey := range cacheKeys { - ck, err := e.op.Cache().Save(cacheKey, res) + ck, err := e.op.Cache().Save(cacheKey, res, time.Now()) if err != nil { return nil, err } diff --git a/solver/llbsolver/bridge.go b/solver/llbsolver/bridge.go index 121f12f3a7ba..76f8f12361e6 100644 --- a/solver/llbsolver/bridge.go +++ b/solver/llbsolver/bridge.go @@ -6,6 +6,7 @@ import ( "io" "strings" "sync" + "time" "github.com/containerd/containerd/platforms" "github.com/moby/buildkit/cache" @@ -190,11 +191,11 @@ func (lcm *lazyCacheManager) Load(ctx context.Context, rec *solver.CacheRecord) } return lcm.main.Load(ctx, rec) } -func (lcm *lazyCacheManager) Save(key *solver.CacheKey, s solver.Result) (*solver.ExportableCacheKey, error) { +func (lcm *lazyCacheManager) Save(key *solver.CacheKey, s solver.Result, createdAt time.Time) (*solver.ExportableCacheKey, error) { if err := lcm.wait(); err != nil { return nil, err } - return lcm.main.Save(key, s) + return lcm.main.Save(key, s, createdAt) } func (lcm *lazyCacheManager) wait() error { diff --git a/solver/memorycachestorage.go b/solver/memorycachestorage.go index 75c8abdeadce..e0e58f0a7b62 100644 --- a/solver/memorycachestorage.go +++ b/solver/memorycachestorage.go @@ -284,9 +284,9 @@ type inMemoryResultStore struct { m *sync.Map } -func (s *inMemoryResultStore) Save(r Result) (CacheResult, error) { +func (s *inMemoryResultStore) Save(r Result, createdAt time.Time) (CacheResult, error) { s.m.Store(r.ID(), r) - return CacheResult{ID: r.ID(), CreatedAt: time.Now()}, nil + return CacheResult{ID: r.ID(), CreatedAt: createdAt}, nil } func (s *inMemoryResultStore) Load(ctx context.Context, res CacheResult) (Result, error) { diff --git a/solver/types.go b/solver/types.go index ccf4cad012c6..a905ba55133e 100644 --- a/solver/types.go +++ b/solver/types.go @@ -164,5 +164,5 @@ type CacheManager interface { // Load pulls and returns the cached result Load(ctx context.Context, rec *CacheRecord) (Result, error) // Save saves a result based on a cache key - Save(key *CacheKey, s Result) (*ExportableCacheKey, error) + Save(key *CacheKey, s Result, createdAt time.Time) (*ExportableCacheKey, error) } diff --git a/worker/cacheresult.go b/worker/cacheresult.go index fb11525d7724..d0ee1a2a6a61 100644 --- a/worker/cacheresult.go +++ b/worker/cacheresult.go @@ -20,7 +20,7 @@ type cacheResultStorage struct { wc *Controller } -func (s *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error) { +func (s *cacheResultStorage) Save(res solver.Result, createdAt time.Time) (solver.CacheResult, error) { ref, ok := res.Sys().(*WorkerRef) if !ok { return solver.CacheResult{}, errors.Errorf("invalid result: %T", res.Sys()) @@ -33,7 +33,7 @@ func (s *cacheResultStorage) Save(res solver.Result) (solver.CacheResult, error) ref.ImmutableRef.Metadata().Commit() } } - return solver.CacheResult{ID: ref.ID(), CreatedAt: time.Now()}, nil + return solver.CacheResult{ID: ref.ID(), CreatedAt: createdAt}, nil } func (s *cacheResultStorage) Load(ctx context.Context, res solver.CacheResult) (solver.Result, error) { return s.load(res.ID, false)