forked from TrueCloudLab/distribution
99 lines
3.2 KiB
Go
99 lines
3.2 KiB
Go
|
// Package cache provides facilities to speed up access to the storage
|
||
|
// backend. Typically cache implementations deal with internal implementation
|
||
|
// details at the backend level, rather than generalized caches for
|
||
|
// distribution related interfaces. In other words, unless the cache is
|
||
|
// specific to the storage package, it belongs in another package.
|
||
|
package cache
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
|
||
|
"github.com/docker/distribution/digest"
|
||
|
"golang.org/x/net/context"
|
||
|
)
|
||
|
|
||
|
// ErrNotFound is returned when a meta item is not found.
|
||
|
var ErrNotFound = fmt.Errorf("not found")
|
||
|
|
||
|
// LayerMeta describes the backend location and length of layer data.
|
||
|
type LayerMeta struct {
|
||
|
Path string
|
||
|
Length int64
|
||
|
}
|
||
|
|
||
|
// LayerInfoCache is a driver-aware cache of layer metadata. Basically, it
|
||
|
// provides a fast cache for checks against repository metadata, avoiding
|
||
|
// round trips to backend storage. Note that this is different from a pure
|
||
|
// layer cache, which would also provide access to backing data, as well. Such
|
||
|
// a cache should be implemented as a middleware, rather than integrated with
|
||
|
// the storage backend.
|
||
|
//
|
||
|
// Note that most implementations rely on the caller to do strict checks on on
|
||
|
// repo and dgst arguments, since these are mostly used behind existing
|
||
|
// implementations.
|
||
|
type LayerInfoCache interface {
|
||
|
// Contains returns true if the repository with name contains the layer.
|
||
|
Contains(ctx context.Context, repo string, dgst digest.Digest) (bool, error)
|
||
|
|
||
|
// Add includes the layer in the given repository cache.
|
||
|
Add(ctx context.Context, repo string, dgst digest.Digest) error
|
||
|
|
||
|
// Meta provides the location of the layer on the backend and its size. Membership of a
|
||
|
// repository should be tested before using the result, if required.
|
||
|
Meta(ctx context.Context, dgst digest.Digest) (LayerMeta, error)
|
||
|
|
||
|
// SetMeta sets the meta data for the given layer.
|
||
|
SetMeta(ctx context.Context, dgst digest.Digest, meta LayerMeta) error
|
||
|
}
|
||
|
|
||
|
// base implements common checks between cache implementations. Note that
|
||
|
// these are not full checks of input, since that should be done by the
|
||
|
// caller.
|
||
|
type base struct {
|
||
|
LayerInfoCache
|
||
|
}
|
||
|
|
||
|
func (b *base) Contains(ctx context.Context, repo string, dgst digest.Digest) (bool, error) {
|
||
|
if repo == "" {
|
||
|
return false, fmt.Errorf("cache: cannot check for empty repository name")
|
||
|
}
|
||
|
|
||
|
if dgst == "" {
|
||
|
return false, fmt.Errorf("cache: cannot check for empty digests")
|
||
|
}
|
||
|
|
||
|
return b.LayerInfoCache.Contains(ctx, repo, dgst)
|
||
|
}
|
||
|
|
||
|
func (b *base) Add(ctx context.Context, repo string, dgst digest.Digest) error {
|
||
|
if repo == "" {
|
||
|
return fmt.Errorf("cache: cannot add empty repository name")
|
||
|
}
|
||
|
|
||
|
if dgst == "" {
|
||
|
return fmt.Errorf("cache: cannot add empty digest")
|
||
|
}
|
||
|
|
||
|
return b.LayerInfoCache.Add(ctx, repo, dgst)
|
||
|
}
|
||
|
|
||
|
func (b *base) Meta(ctx context.Context, dgst digest.Digest) (LayerMeta, error) {
|
||
|
if dgst == "" {
|
||
|
return LayerMeta{}, fmt.Errorf("cache: cannot get meta for empty digest")
|
||
|
}
|
||
|
|
||
|
return b.LayerInfoCache.Meta(ctx, dgst)
|
||
|
}
|
||
|
|
||
|
func (b *base) SetMeta(ctx context.Context, dgst digest.Digest, meta LayerMeta) error {
|
||
|
if dgst == "" {
|
||
|
return fmt.Errorf("cache: cannot set meta for empty digest")
|
||
|
}
|
||
|
|
||
|
if meta.Path == "" {
|
||
|
return fmt.Errorf("cache: cannot set empty path for meta")
|
||
|
}
|
||
|
|
||
|
return b.LayerInfoCache.SetMeta(ctx, dgst, meta)
|
||
|
}
|