cache: Remove ImageRef from DescHandlers

Signed-off-by: Erik Sipsma <erik@sipsma.dev>
v0.8
Erik Sipsma 2020-08-05 16:51:19 -07:00
parent 926ca1804c
commit 1b30fd146b
6 changed files with 133 additions and 21 deletions

40
cache/manager.go vendored
View File

@ -157,6 +157,9 @@ func (cm *cacheManager) GetByBlob(ctx context.Context, desc ocispec.Descriptor,
if p != nil { if p != nil {
releaseParent = true releaseParent = true
} }
if err := setImageRefMetadata(ref, opts...); err != nil {
return nil, errors.Wrapf(err, "failed to append image ref metadata to ref %s", ref.ID())
}
return ref, nil return ref, nil
} }
@ -234,6 +237,10 @@ func (cm *cacheManager) GetByBlob(ctx context.Context, desc ocispec.Descriptor,
return nil, err return nil, err
} }
if err := setImageRefMetadata(rec, opts...); err != nil {
return nil, errors.Wrapf(err, "failed to append image ref metadata to ref %s", rec.ID())
}
queueDiffID(rec.md, diffID.String()) queueDiffID(rec.md, diffID.String())
queueBlob(rec.md, desc.Digest.String()) queueBlob(rec.md, desc.Digest.String())
queueChainID(rec.md, chainID.String()) queueChainID(rec.md, chainID.String())
@ -429,6 +436,10 @@ func (cm *cacheManager) getRecord(ctx context.Context, id string, opts ...RefOpt
return nil, err return nil, err
} }
if err := setImageRefMetadata(rec, opts...); err != nil {
return nil, errors.Wrapf(err, "failed to append image ref metadata to ref %s", rec.ID())
}
cm.records[id] = rec cm.records[id] = rec
if err := checkLazyProviders(rec); err != nil { if err := checkLazyProviders(rec); err != nil {
return nil, err return nil, err
@ -515,6 +526,10 @@ func (cm *cacheManager) New(ctx context.Context, s ImmutableRef, opts ...RefOpti
return nil, err return nil, err
} }
if err := setImageRefMetadata(rec, opts...); err != nil {
return nil, errors.Wrapf(err, "failed to append image ref metadata to ref %s", rec.ID())
}
cm.mu.Lock() cm.mu.Lock()
defer cm.mu.Unlock() defer cm.mu.Unlock()
@ -1004,6 +1019,31 @@ func WithCreationTime(tm time.Time) RefOption {
} }
} }
// Need a separate type for imageRef because it needs to be called outside
// initializeMetadata while still being a RefOption, so wrapping it in a
// different type ensures initializeMetadata won't catch it too and duplicate
// setting the metadata.
type imageRefOption func(m withMetadata) error
// WithImageRef appends the given imageRef to the cache ref's metadata
func WithImageRef(imageRef string) RefOption {
return imageRefOption(func(m withMetadata) error {
return appendImageRef(m.Metadata(), imageRef)
})
}
func setImageRefMetadata(m withMetadata, opts ...RefOption) error {
md := m.Metadata()
for _, opt := range opts {
if fn, ok := opt.(imageRefOption); ok {
if err := fn(m); err != nil {
return err
}
}
}
return md.Commit()
}
func initializeMetadata(m withMetadata, parent string, opts ...RefOption) error { func initializeMetadata(m withMetadata, parent string, opts ...RefOption) error {
md := m.Metadata() md := m.Metadata()
if tm := GetCreatedAt(md); !tm.IsZero() { if tm := GetCreatedAt(md); !tm.IsZero() {

35
cache/metadata.go vendored
View File

@ -28,6 +28,7 @@ const keyBlob = "cache.blob"
const keySnapshot = "cache.snapshot" const keySnapshot = "cache.snapshot"
const keyBlobOnly = "cache.blobonly" const keyBlobOnly = "cache.blobonly"
const keyMediaType = "cache.mediatype" const keyMediaType = "cache.mediatype"
const keyImageRefs = "cache.imageRefs"
// BlobSize is the packed blob size as specified in the oci descriptor // BlobSize is the packed blob size as specified in the oci descriptor
const keyBlobSize = "cache.blobsize" const keyBlobSize = "cache.blobsize"
@ -310,6 +311,40 @@ func getSize(si *metadata.StorageItem) int64 {
return size return size
} }
func appendImageRef(si *metadata.StorageItem, s string) error {
return si.GetAndSetValue(keyImageRefs, func(v *metadata.Value) (*metadata.Value, error) {
var imageRefs []string
if v != nil {
if err := v.Unmarshal(&imageRefs); err != nil {
return nil, err
}
}
for _, existing := range imageRefs {
if existing == s {
return nil, metadata.ErrSkipSetValue
}
}
imageRefs = append(imageRefs, s)
v, err := metadata.NewValue(imageRefs)
if err != nil {
return nil, errors.Wrap(err, "failed to create imageRefs value")
}
return v, nil
})
}
func getImageRefs(si *metadata.StorageItem) []string {
v := si.Get(keyImageRefs)
if v == nil {
return nil
}
var refs []string
if err := v.Unmarshal(&refs); err != nil {
return nil
}
return refs
}
func queueBlobSize(si *metadata.StorageItem, s int64) error { func queueBlobSize(si *metadata.StorageItem, s int64) error {
v, err := metadata.NewValue(s) v, err := metadata.NewValue(s)
if err != nil { if err != nil {

View File

@ -372,6 +372,22 @@ func (s *StorageItem) SetValue(b *bolt.Bucket, key string, v *Value) error {
return nil return nil
} }
var ErrSkipSetValue = errors.New("skip setting metadata value")
func (s *StorageItem) GetAndSetValue(key string, fn func(*Value) (*Value, error)) error {
s.mu.Lock()
defer s.mu.Unlock()
return s.Update(func(b *bolt.Bucket) error {
v, err := fn(s.values[key])
if errors.Is(err, ErrSkipSetValue) {
return nil
} else if err != nil {
return err
}
return s.SetValue(b, key, v)
})
}
type Value struct { type Value struct {
Value json.RawMessage `json:"value,omitempty"` Value json.RawMessage `json:"value,omitempty"`
Index string `json:"index,omitempty"` Index string `json:"index,omitempty"`

1
cache/opts.go vendored
View File

@ -10,7 +10,6 @@ import (
type DescHandler struct { type DescHandler struct {
Provider content.Provider Provider content.Provider
ImageRef string
Progress progress.Controller Progress progress.Controller
} }

58
cache/remote.go vendored
View File

@ -58,26 +58,46 @@ func (sr *immutableRef) GetRemote(ctx context.Context, createIfNeeded bool, comp
} }
} }
dh := sr.descHandlers[desc.Digest] // update distribution source annotation for lazy-refs (non-lazy refs
// will already have their dsl stored in the content store, which is
// used by the push handlers)
if isLazy, err := ref.isLazy(ctx); err != nil {
return nil, err
} else if isLazy {
imageRefs := getImageRefs(ref.md)
for _, imageRef := range imageRefs {
refspec, err := reference.Parse(imageRef)
if err != nil {
return nil, err
}
// update distribution source annotation u, err := url.Parse("dummy://" + refspec.Locator)
if dh != nil && dh.ImageRef != "" { if err != nil {
refspec, err := reference.Parse(dh.ImageRef) return nil, err
if err != nil { }
return nil, err
}
u, err := url.Parse("dummy://" + refspec.Locator) source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/")
if err != nil { if desc.Annotations == nil {
return nil, err desc.Annotations = make(map[string]string)
} }
dslKey := fmt.Sprintf("%s.%s", "containerd.io/distribution.source", source)
source, repo := u.Hostname(), strings.TrimPrefix(u.Path, "/") var existingRepos []string
if desc.Annotations == nil { if existings, ok := desc.Annotations[dslKey]; ok {
desc.Annotations = make(map[string]string) existingRepos = strings.Split(existings, ",")
}
addNewRepo := true
for _, existing := range existingRepos {
if existing == repo {
addNewRepo = false
break
}
}
if addNewRepo {
existingRepos = append(existingRepos, repo)
}
desc.Annotations[dslKey] = strings.Join(existingRepos, ",")
} }
dslKey := fmt.Sprintf("%s.%s", "containerd.io/distribution.source", source)
desc.Annotations[dslKey] = repo
} }
remote.Descriptors = append(remote.Descriptors, desc) remote.Descriptors = append(remote.Descriptors, desc)
@ -161,9 +181,11 @@ func (p lazyRefProvider) Unlazy(ctx context.Context) error {
return nil, err return nil, err
} }
if p.dh.ImageRef != "" { if imageRefs := getImageRefs(p.ref.md); len(imageRefs) > 0 {
// just use the first image ref, it's arbitrary
imageRef := imageRefs[0]
if GetDescription(p.ref.md) == "" { if GetDescription(p.ref.md) == "" {
queueDescription(p.ref.md, "pulled from "+p.dh.ImageRef) queueDescription(p.ref.md, "pulled from "+imageRef)
err := p.ref.md.Commit() err := p.ref.md.Commit()
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -212,7 +212,6 @@ func (p *puller) CacheKey(ctx context.Context, g session.Group, index int) (cach
descHandler := &cache.DescHandler{ descHandler := &cache.DescHandler{
Provider: p.manifest.Remote.Provider, Provider: p.manifest.Remote.Provider,
ImageRef: p.manifest.Ref,
Progress: progressController, Progress: progressController,
} }
@ -275,7 +274,8 @@ func (p *puller) Snapshot(ctx context.Context, g session.Group) (ir cache.Immuta
var parent cache.ImmutableRef var parent cache.ImmutableRef
for _, layerDesc := range p.manifest.Remote.Descriptors { for _, layerDesc := range p.manifest.Remote.Descriptors {
parent = current parent = current
current, err = p.CacheAccessor.GetByBlob(ctx, layerDesc, parent, p.descHandlers) current, err = p.CacheAccessor.GetByBlob(ctx, layerDesc, parent,
p.descHandlers, cache.WithImageRef(p.manifest.Ref))
if parent != nil { if parent != nil {
parent.Release(context.TODO()) parent.Release(context.TODO())
} }