distribution/registry/storage/cache/cache.go
Stephen J Day b1f616cbff Define and implement layer info cache
This changeset defines the interface for layer info caches. Layer info caches
speed up access to layer meta data accessed in storage driver backends. The
two main operations are tests for repository membership and resolving path and
size information for backend blobs.

Two implementations are available. The main implementation leverages redis to
store layer info. An alternative implementation simply caches layer info in
maps, which should speed up resolution for less sophisticated implementations.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
2015-04-02 20:15:09 -07:00

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)
}