package solver import ( "maps" "slices" "sync" digest "github.com/opencontainers/go-digest" ) // NewCacheKey creates a new cache key for a specific output index func NewCacheKey(dgst, vtx digest.Digest, output Index) *CacheKey { return &CacheKey{ ID: rootKey(dgst, output).String(), digest: dgst, vtx: vtx, output: output, ids: map[*cacheManager]string{}, } } // 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 ExportableCacheKey } func (ck CacheKeyWithSelector) TraceFields() map[string]any { fields := ck.CacheKey.TraceFields() fields["selector"] = ck.Selector.String() return fields } type CacheKey struct { mu sync.RWMutex ID string deps [][]CacheKeyWithSelector // digest is the digest returned by the CacheMap implementation of this op digest digest.Digest // vtx is the LLB digest that this op was created for vtx digest.Digest output Index ids map[*cacheManager]string indexIDs []string } func (ck *CacheKey) TraceFields() map[string]any { ck.mu.RLock() defer ck.mu.RUnlock() idsMap := map[string]string{} for cm, id := range ck.ids { idsMap[cm.ID()] = id } // don't recurse more than one level in showing deps depsMap := make([]map[string]string, len(ck.deps)) for i, deps := range ck.deps { depsMap[i] = map[string]string{} for _, ck := range deps { depsMap[i]["id"] = ck.CacheKey.ID depsMap[i]["selector"] = ck.Selector.String() } } return map[string]any{ "id": ck.ID, "digest": ck.digest, "vtx": ck.vtx, "output": ck.output, "indexIDs": ck.indexIDs, "ids": idsMap, "deps": depsMap, } } func (ck *CacheKey) Deps() [][]CacheKeyWithSelector { ck.mu.RLock() defer ck.mu.RUnlock() deps := make([][]CacheKeyWithSelector, len(ck.deps)) for i := range ck.deps { deps[i] = slices.Clone(ck.deps[i]) } return deps } func (ck *CacheKey) Digest() digest.Digest { return ck.digest } func (ck *CacheKey) Output() Index { return ck.output } func (ck *CacheKey) clone() *CacheKey { ck.mu.RLock() nk := &CacheKey{ ID: ck.ID, digest: ck.digest, vtx: ck.vtx, output: ck.output, ids: make(map[*cacheManager]string, len(ck.ids)), } maps.Copy(nk.ids, ck.ids) ck.mu.RUnlock() return nk }