solver: add selector support to cache
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>docker-18.09
parent
c2920e66b4
commit
71774ae35f
|
@ -122,12 +122,16 @@ func (e *edge) commitOptions() (CacheKey, []Result) {
|
||||||
return NewCacheKey(e.cacheMap.Digest, e.edge.Index, nil), nil
|
return NewCacheKey(e.cacheMap.Digest, e.edge.Index, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs := make([]CacheKey, len(e.deps))
|
inputs := make([]CacheKeyWithSelector, len(e.deps))
|
||||||
results := make([]Result, len(e.deps))
|
results := make([]Result, len(e.deps))
|
||||||
for i, dep := range e.deps {
|
for i, dep := range e.deps {
|
||||||
inputs[i] = dep.result.CacheKey()
|
inputs[i] = CacheKeyWithSelector{CacheKey: dep.result.CacheKey(), Selector: e.cacheMap.Deps[i].Selector}
|
||||||
if dep.slowCacheKey != nil {
|
if dep.slowCacheKey != nil {
|
||||||
inputs[i] = NewCacheKey("", 0, []CacheKey{inputs[i], dep.slowCacheKey})
|
inputs[i] = CacheKeyWithSelector{CacheKey: NewCacheKey("", 0, []CacheKeyWithSelector{
|
||||||
|
inputs[i],
|
||||||
|
{CacheKey: dep.slowCacheKey, Selector: NoSelector},
|
||||||
|
},
|
||||||
|
)}
|
||||||
}
|
}
|
||||||
results[i] = dep.result
|
results[i] = dep.result
|
||||||
}
|
}
|
||||||
|
@ -165,7 +169,7 @@ func (e *edge) probeCache(d *dep, keys []CacheKey) {
|
||||||
if e.op.IgnoreCache() {
|
if e.op.IgnoreCache() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
records, err := e.op.Cache().Query(keys, d.index, e.cacheMap.Digest, e.edge.Index)
|
records, err := e.op.Cache().Query(keys, d.index, e.cacheMap.Digest, e.edge.Index, e.cacheMap.Deps[d.index].Selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
e.err = errors.Wrap(err, "error on cache query")
|
e.err = errors.Wrap(err, "error on cache query")
|
||||||
}
|
}
|
||||||
|
@ -291,7 +295,7 @@ func (e *edge) processUpdate(upt pipe.Receiver) (depChanged bool) {
|
||||||
if len(e.deps) == 0 {
|
if len(e.deps) == 0 {
|
||||||
if !e.op.IgnoreCache() {
|
if !e.op.IgnoreCache() {
|
||||||
k := NewCacheKey(e.cacheMap.Digest, e.edge.Index, nil)
|
k := NewCacheKey(e.cacheMap.Digest, e.edge.Index, nil)
|
||||||
records, err := e.op.Cache().Query(nil, 0, e.cacheMap.Digest, e.edge.Index)
|
records, err := e.op.Cache().Query(nil, 0, e.cacheMap.Digest, e.edge.Index, "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Error(errors.Wrap(err, "invalid query response")) // make the build fail for this error
|
logrus.Error(errors.Wrap(err, "invalid query response")) // make the build fail for this error
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -186,7 +186,8 @@ func getUniqueID(k CacheKey) digest.Digest {
|
||||||
|
|
||||||
dgstr := digest.SHA256.Digester()
|
dgstr := digest.SHA256.Digester()
|
||||||
for _, inp := range k.Deps() {
|
for _, inp := range k.Deps() {
|
||||||
dgstr.Hash().Write([]byte(getUniqueID(inp)))
|
dgstr.Hash().Write([]byte(getUniqueID(inp.CacheKey)))
|
||||||
|
dgstr.Hash().Write([]byte(inp.Selector))
|
||||||
}
|
}
|
||||||
|
|
||||||
dgstr.Hash().Write([]byte(k.Digest()))
|
dgstr.Hash().Write([]byte(k.Digest()))
|
||||||
|
|
|
@ -17,6 +17,8 @@ type internalMemoryKeyT string
|
||||||
|
|
||||||
var internalMemoryKey = internalMemoryKeyT("buildkit/memory-cache-id")
|
var internalMemoryKey = internalMemoryKeyT("buildkit/memory-cache-id")
|
||||||
|
|
||||||
|
var NoSelector = digest.FromBytes(nil)
|
||||||
|
|
||||||
func NewInMemoryCacheManager() CacheManager {
|
func NewInMemoryCacheManager() CacheManager {
|
||||||
return &inMemoryCacheManager{
|
return &inMemoryCacheManager{
|
||||||
byID: map[string]*inMemoryCacheKey{},
|
byID: map[string]*inMemoryCacheKey{},
|
||||||
|
@ -29,13 +31,13 @@ type inMemoryCacheKey struct {
|
||||||
id string
|
id string
|
||||||
dgst digest.Digest
|
dgst digest.Digest
|
||||||
output Index
|
output Index
|
||||||
deps []CacheKey // only []*inMemoryCacheManager
|
deps []CacheKeyWithSelector // only []*inMemoryCacheKey
|
||||||
|
|
||||||
results map[Index]map[string]savedResult
|
results map[Index]map[string]savedResult
|
||||||
links map[link]map[string]struct{}
|
links map[link]map[string]struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ck *inMemoryCacheKey) Deps() []CacheKey {
|
func (ck *inMemoryCacheKey) Deps() []CacheKeyWithSelector {
|
||||||
return ck.deps
|
return ck.deps
|
||||||
}
|
}
|
||||||
func (ck *inMemoryCacheKey) Digest() digest.Digest {
|
func (ck *inMemoryCacheKey) Digest() digest.Digest {
|
||||||
|
@ -53,6 +55,7 @@ type savedResult struct {
|
||||||
type link struct {
|
type link struct {
|
||||||
input, output Index
|
input, output Index
|
||||||
digest digest.Digest
|
digest digest.Digest
|
||||||
|
selector digest.Digest
|
||||||
}
|
}
|
||||||
|
|
||||||
type inMemoryCacheManager struct {
|
type inMemoryCacheManager struct {
|
||||||
|
@ -65,7 +68,7 @@ func (c *inMemoryCacheManager) ID() string {
|
||||||
return c.id
|
return c.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *inMemoryCacheManager) Query(deps []CacheKey, input Index, dgst digest.Digest, output Index) ([]*CacheRecord, error) {
|
func (c *inMemoryCacheManager) Query(deps []CacheKey, input Index, dgst digest.Digest, output Index, selector digest.Digest) ([]*CacheRecord, error) {
|
||||||
c.mu.RLock()
|
c.mu.RLock()
|
||||||
defer c.mu.RUnlock()
|
defer c.mu.RUnlock()
|
||||||
|
|
||||||
|
@ -75,10 +78,13 @@ func (c *inMemoryCacheManager) Query(deps []CacheKey, input Index, dgst digest.D
|
||||||
for _, dep := range deps {
|
for _, dep := range deps {
|
||||||
ck, err := c.getInternalKey(dep, false)
|
ck, err := c.getInternalKey(dep, false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
for key := range ck.links[link{input, output, dgst}] {
|
for key := range ck.links[link{input, output, dgst, selector}] {
|
||||||
refs[key] = struct{}{}
|
refs[key] = struct{}{}
|
||||||
}
|
}
|
||||||
for key := range ck.links[link{Index(-1), Index(0), ""}] {
|
for key := range ck.links[link{Index(-1), Index(0), "", selector}] {
|
||||||
|
sublinks[key] = struct{}{}
|
||||||
|
}
|
||||||
|
for key := range ck.links[link{Index(-1), Index(0), "", NoSelector}] {
|
||||||
sublinks[key] = struct{}{}
|
sublinks[key] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +92,7 @@ func (c *inMemoryCacheManager) Query(deps []CacheKey, input Index, dgst digest.D
|
||||||
|
|
||||||
for id := range sublinks {
|
for id := range sublinks {
|
||||||
if ck, ok := c.byID[id]; ok {
|
if ck, ok := c.byID[id]; ok {
|
||||||
for key := range ck.links[link{input, output, dgst}] {
|
for key := range ck.links[link{input, output, dgst, ""}] {
|
||||||
refs[key] = struct{}{}
|
refs[key] = struct{}{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -165,15 +171,15 @@ func (c *inMemoryCacheManager) getInternalKey(k CacheKey, createIfNotExist bool)
|
||||||
}
|
}
|
||||||
return ck, nil
|
return ck, nil
|
||||||
}
|
}
|
||||||
inputs := make([]CacheKey, len(k.Deps()))
|
inputs := make([]CacheKeyWithSelector, len(k.Deps()))
|
||||||
dgstr := digest.SHA256.Digester()
|
dgstr := digest.SHA256.Digester()
|
||||||
for i, inp := range k.Deps() {
|
for i, inp := range k.Deps() {
|
||||||
ck, err := c.getInternalKey(inp, createIfNotExist)
|
ck, err := c.getInternalKey(inp.CacheKey, createIfNotExist)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
inputs[i] = ck
|
inputs[i] = CacheKeyWithSelector{CacheKey: ck, Selector: inp.Selector}
|
||||||
if _, err := dgstr.Hash().Write([]byte(ck.id)); err != nil {
|
if _, err := dgstr.Hash().Write([]byte(fmt.Sprintf("%s:%s,", ck.id, inp.Selector))); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -209,7 +215,7 @@ func (c *inMemoryCacheManager) getInternalKey(k CacheKey, createIfNotExist bool)
|
||||||
if ck.dgst == "" {
|
if ck.dgst == "" {
|
||||||
i = -1
|
i = -1
|
||||||
}
|
}
|
||||||
if err := c.addLink(link{Index(i), ck.output, ck.dgst}, inp.(*inMemoryCacheKey), ck); err != nil {
|
if err := c.addLink(link{Index(i), ck.output, ck.dgst, inp.Selector}, inp.CacheKey.(*inMemoryCacheKey), ck); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,14 +265,14 @@ func (cm *combinedCacheManager) ID() string {
|
||||||
return cm.id
|
return cm.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cm *combinedCacheManager) Query(inp []CacheKey, inputIndex Index, dgst digest.Digest, outputIndex Index) ([]*CacheRecord, error) {
|
func (cm *combinedCacheManager) Query(inp []CacheKey, inputIndex Index, dgst digest.Digest, outputIndex Index, selector digest.Digest) ([]*CacheRecord, error) {
|
||||||
eg, _ := errgroup.WithContext(context.TODO())
|
eg, _ := errgroup.WithContext(context.TODO())
|
||||||
res := make(map[string]*CacheRecord, len(cm.cms))
|
res := make(map[string]*CacheRecord, len(cm.cms))
|
||||||
var mu sync.Mutex
|
var mu sync.Mutex
|
||||||
for i, c := range cm.cms {
|
for i, c := range cm.cms {
|
||||||
func(i int, c CacheManager) {
|
func(i int, c CacheManager) {
|
||||||
eg.Go(func() error {
|
eg.Go(func() error {
|
||||||
recs, err := c.Query(inp, inputIndex, dgst, outputIndex)
|
recs, err := c.Query(inp, inputIndex, dgst, outputIndex, selector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ func TestInMemoryCache(t *testing.T) {
|
||||||
cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0, nil), testResult("result0"))
|
cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0, nil), testResult("result0"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
matches, err := m.Query(nil, 0, dgst("foo"), 0)
|
matches, err := m.Query(nil, 0, dgst("foo"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ func TestInMemoryCache(t *testing.T) {
|
||||||
cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0, nil), testResult("result1"))
|
cacheBar, err := m.Save(NewCacheKey(dgst("bar"), 0, nil), testResult("result1"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
matches, err = m.Query(nil, 0, dgst("bar"), 0)
|
matches, err = m.Query(nil, 0, dgst("bar"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
|
@ -38,30 +38,30 @@ func TestInMemoryCache(t *testing.T) {
|
||||||
require.Equal(t, "result1", unwrap(res))
|
require.Equal(t, "result1", unwrap(res))
|
||||||
|
|
||||||
// invalid request
|
// invalid request
|
||||||
matches, err = m.Query(nil, 0, dgst("baz"), 0)
|
matches, err = m.Query(nil, 0, dgst("baz"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 0)
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
// second level
|
// second level
|
||||||
k := NewCacheKey(dgst("baz"), Index(1), []CacheKey{
|
k := NewCacheKey(dgst("baz"), Index(1), []CacheKeyWithSelector{
|
||||||
cacheFoo, cacheBar,
|
{CacheKey: cacheFoo}, {CacheKey: cacheBar},
|
||||||
})
|
})
|
||||||
cacheBaz, err := m.Save(k, testResult("result2"))
|
cacheBaz, err := m.Save(k, testResult("result2"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
matches, err = m.Query(nil, 0, dgst("baz"), 0)
|
matches, err = m.Query(nil, 0, dgst("baz"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 0)
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), 0)
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 0)
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheFoo}, 1, dgst("baz"), Index(1))
|
matches, err = m.Query([]CacheKey{cacheFoo}, 1, dgst("baz"), Index(1), "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 0)
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), Index(1))
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), Index(1), "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
|
@ -69,50 +69,129 @@ func TestInMemoryCache(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "result2", unwrap(res))
|
require.Equal(t, "result2", unwrap(res))
|
||||||
|
|
||||||
matches2, err := m.Query([]CacheKey{cacheBar}, 1, dgst("baz"), Index(1))
|
matches2, err := m.Query([]CacheKey{cacheBar}, 1, dgst("baz"), Index(1), "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches2), 1)
|
require.Equal(t, len(matches2), 1)
|
||||||
|
|
||||||
require.Equal(t, matches[0].ID, matches2[0].ID)
|
require.Equal(t, matches[0].ID, matches2[0].ID)
|
||||||
|
|
||||||
k = NewCacheKey(dgst("baz"), Index(1), []CacheKey{
|
k = NewCacheKey(dgst("baz"), Index(1), []CacheKeyWithSelector{
|
||||||
cacheFoo,
|
{CacheKey: cacheFoo},
|
||||||
})
|
})
|
||||||
_, err = m.Save(k, testResult("result3"))
|
_, err = m.Save(k, testResult("result3"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), Index(1))
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("baz"), Index(1), "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 2)
|
require.Equal(t, len(matches), 2)
|
||||||
|
|
||||||
// combination save
|
// combination save
|
||||||
k2 := NewCacheKey("", 0, []CacheKey{
|
k2 := NewCacheKey("", 0, []CacheKeyWithSelector{
|
||||||
cacheFoo, cacheBaz,
|
{CacheKey: cacheFoo}, {CacheKey: cacheBaz},
|
||||||
})
|
})
|
||||||
|
|
||||||
k = NewCacheKey(dgst("bax"), 0, []CacheKey{
|
k = NewCacheKey(dgst("bax"), 0, []CacheKeyWithSelector{
|
||||||
k2, cacheBar,
|
{CacheKey: k2}, {CacheKey: cacheBar},
|
||||||
})
|
})
|
||||||
_, err = m.Save(k, testResult("result4"))
|
_, err = m.Save(k, testResult("result4"))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// foo, bar, baz should all point to result4
|
// foo, bar, baz should all point to result4
|
||||||
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bax"), 0)
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bax"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
id := matches[0].ID
|
id := matches[0].ID
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheBar}, 1, dgst("bax"), 0)
|
matches, err = m.Query([]CacheKey{cacheBar}, 1, dgst("bax"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
require.Equal(t, matches[0].ID, id)
|
require.Equal(t, matches[0].ID, id)
|
||||||
|
|
||||||
matches, err = m.Query([]CacheKey{cacheBaz}, 0, dgst("bax"), 0)
|
matches, err = m.Query([]CacheKey{cacheBaz}, 0, dgst("bax"), 0, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, len(matches), 1)
|
require.Equal(t, len(matches), 1)
|
||||||
require.Equal(t, matches[0].ID, id)
|
require.Equal(t, matches[0].ID, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInMemoryCacheSelector(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
m := NewInMemoryCacheManager()
|
||||||
|
|
||||||
|
cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0, nil), testResult("result0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = m.Save(NewCacheKey(dgst("bar"), 0, []CacheKeyWithSelector{
|
||||||
|
{CacheKey: cacheFoo, Selector: dgst("sel0")},
|
||||||
|
}), testResult("result1"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
matches, err := m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, "sel-invalid")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, dgst("sel0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
|
res, err := m.Load(ctx, matches[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "result1", unwrap(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInMemoryCacheSelectorNested(t *testing.T) {
|
||||||
|
ctx := context.TODO()
|
||||||
|
|
||||||
|
m := NewInMemoryCacheManager()
|
||||||
|
|
||||||
|
cacheFoo, err := m.Save(NewCacheKey(dgst("foo"), 0, nil), testResult("result0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
k2 := NewCacheKey("", 0, []CacheKeyWithSelector{
|
||||||
|
{CacheKey: cacheFoo, Selector: dgst("sel0")},
|
||||||
|
{CacheKey: NewCacheKey(dgst("second"), 0, nil), Selector: NoSelector},
|
||||||
|
})
|
||||||
|
|
||||||
|
_, err = m.Save(NewCacheKey(dgst("bar"), 0, []CacheKeyWithSelector{
|
||||||
|
{CacheKey: k2},
|
||||||
|
}), testResult("result1"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
matches, err := m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, dgst("sel0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 1)
|
||||||
|
res, err := m.Load(ctx, matches[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "result1", unwrap(res))
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{cacheFoo}, 0, dgst("bar"), 0, dgst("bar"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 0)
|
||||||
|
|
||||||
|
// keys with NoSelector always match
|
||||||
|
matches, err = m.Query([]CacheKey{NewCacheKey(dgst("second"), 0, nil)}, 0, dgst("bar"), 0, dgst("sel0"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 1)
|
||||||
|
res, err = m.Load(ctx, matches[0])
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, "result1", unwrap(res))
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{NewCacheKey(dgst("second"), 0, nil)}, 0, dgst("bar"), 0, "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 1)
|
||||||
|
|
||||||
|
matches, err = m.Query([]CacheKey{NewCacheKey(dgst("second"), 0, nil)}, 0, dgst("bar"), 0, dgst("bar"))
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, len(matches), 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func dgst(s string) digest.Digest {
|
func dgst(s string) digest.Digest {
|
||||||
|
|
|
@ -68,7 +68,6 @@ type CacheMap struct {
|
||||||
Digest digest.Digest
|
Digest digest.Digest
|
||||||
Deps []struct {
|
Deps []struct {
|
||||||
// Optional digest that is merged with the cache key of the input
|
// Optional digest that is merged with the cache key of the input
|
||||||
// TODO(tonistiigi): not implemented
|
|
||||||
Selector digest.Digest
|
Selector digest.Digest
|
||||||
// Optional function that returns a digest for the input based on its
|
// Optional function that returns a digest for the input based on its
|
||||||
// return value
|
// return value
|
||||||
|
@ -79,7 +78,7 @@ type CacheMap struct {
|
||||||
// CacheKey is an identifier for storing/loading build cache
|
// CacheKey is an identifier for storing/loading build cache
|
||||||
type CacheKey interface {
|
type CacheKey interface {
|
||||||
// Deps are dependant cache keys
|
// Deps are dependant cache keys
|
||||||
Deps() []CacheKey
|
Deps() []CacheKeyWithSelector
|
||||||
// Base digest for operation. Usually CacheMap.Digest
|
// Base digest for operation. Usually CacheMap.Digest
|
||||||
Digest() digest.Digest
|
Digest() digest.Digest
|
||||||
// Index for the output that is cached
|
// Index for the output that is cached
|
||||||
|
@ -107,7 +106,7 @@ type CacheManager interface {
|
||||||
ID() string
|
ID() string
|
||||||
// Query searches for cache paths from one cache key to the output of a
|
// Query searches for cache paths from one cache key to the output of a
|
||||||
// possible match.
|
// possible match.
|
||||||
Query(inp []CacheKey, inputIndex Index, dgst digest.Digest, outputIndex Index) ([]*CacheRecord, error)
|
Query(inp []CacheKey, inputIndex Index, dgst digest.Digest, outputIndex Index, selector digest.Digest) ([]*CacheRecord, error)
|
||||||
// Load pulls and returns the cached result
|
// Load pulls and returns the cached result
|
||||||
Load(ctx context.Context, rec *CacheRecord) (Result, error)
|
Load(ctx context.Context, rec *CacheRecord) (Result, error)
|
||||||
// Save saves a result based on a cache key
|
// Save saves a result based on a cache key
|
||||||
|
@ -115,7 +114,7 @@ type CacheManager interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCacheKey creates a new cache key for a specific output index
|
// NewCacheKey creates a new cache key for a specific output index
|
||||||
func NewCacheKey(dgst digest.Digest, index Index, deps []CacheKey) CacheKey {
|
func NewCacheKey(dgst digest.Digest, index Index, deps []CacheKeyWithSelector) CacheKey {
|
||||||
return &cacheKey{
|
return &cacheKey{
|
||||||
dgst: dgst,
|
dgst: dgst,
|
||||||
deps: deps,
|
deps: deps,
|
||||||
|
@ -124,10 +123,17 @@ func NewCacheKey(dgst digest.Digest, index Index, deps []CacheKey) CacheKey {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CacheKeyWithSelector combines a cache key with an optional selector digest.
|
||||||
|
// Used to limit the matches for dependency cache key.
|
||||||
|
type CacheKeyWithSelector struct {
|
||||||
|
Selector digest.Digest
|
||||||
|
CacheKey CacheKey
|
||||||
|
}
|
||||||
|
|
||||||
type cacheKey struct {
|
type cacheKey struct {
|
||||||
dgst digest.Digest
|
dgst digest.Digest
|
||||||
index Index
|
index Index
|
||||||
deps []CacheKey
|
deps []CacheKeyWithSelector
|
||||||
values *sync.Map
|
values *sync.Map
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +146,7 @@ func (ck *cacheKey) GetValue(key interface{}) interface{} {
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ck *cacheKey) Deps() []CacheKey {
|
func (ck *cacheKey) Deps() []CacheKeyWithSelector {
|
||||||
return ck.deps
|
return ck.deps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue