distribution/registry/storage/cache/memory/memory.go
Sebastiaan van Stijn 152af63ec5
deprecate reference package, migrate to github.com/distribution/reference
This integrates the new module, which was extracted from this repository
at commit b9b19409cf458dcb9e1253ff44ba75bd0620faa6;

    # install filter-repo (https://github.com/newren/git-filter-repo/blob/main/INSTALL.md)
    brew install git-filter-repo

    # create a temporary clone of docker
    cd ~/Projects
    git clone https://github.com/distribution/distribution.git reference
    cd reference

    # commit taken from
    git rev-parse --verify HEAD
    b9b19409cf

    # remove all code, except for general files, 'reference/', and rename to /
    git filter-repo \
      --path .github/workflows/codeql-analysis.yml \
      --path .github/workflows/fossa.yml \
      --path .golangci.yml \
      --path distribution-logo.svg \
      --path CODE-OF-CONDUCT.md \
      --path CONTRIBUTING.md \
      --path GOVERNANCE.md \
      --path README.md \
      --path LICENSE \
      --path MAINTAINERS \
      --path-glob 'reference/*.*' \
      --path-rename reference/:

    # initialize go.mod
    go mod init github.com/distribution/reference
    go mod tidy -go=1.20

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2023-08-31 15:47:06 +02:00

158 lines
4.2 KiB
Go

package memory
import (
"context"
"math"
"github.com/distribution/distribution/v3"
"github.com/distribution/distribution/v3/registry/storage/cache"
"github.com/distribution/reference"
"github.com/hashicorp/golang-lru/arc/v2"
"github.com/opencontainers/go-digest"
)
const (
// DefaultSize is the default cache size to use if no size is explicitly
// configured.
DefaultSize = 10000
// UnlimitedSize indicates the cache size should not be limited.
UnlimitedSize = math.MaxInt
)
type descriptorCacheKey struct {
digest digest.Digest
repo string
}
type inMemoryBlobDescriptorCacheProvider struct {
lru *arc.ARCCache[descriptorCacheKey, distribution.Descriptor]
}
// NewInMemoryBlobDescriptorCacheProvider returns a new mapped-based cache for
// storing blob descriptor data.
func NewInMemoryBlobDescriptorCacheProvider(size int) cache.BlobDescriptorCacheProvider {
if size <= 0 {
size = math.MaxInt
}
lruCache, err := arc.NewARC[descriptorCacheKey, distribution.Descriptor](size)
if err != nil {
// NewARC can only fail if size is <= 0, so this unreachable
panic(err)
}
return &inMemoryBlobDescriptorCacheProvider{
lru: lruCache,
}
}
func (imbdcp *inMemoryBlobDescriptorCacheProvider) RepositoryScoped(repo string) (distribution.BlobDescriptorService, error) {
if _, err := reference.ParseNormalizedNamed(repo); err != nil {
return nil, err
}
return &repositoryScopedInMemoryBlobDescriptorCache{
repo: repo,
parent: imbdcp,
}, nil
}
func (imbdcp *inMemoryBlobDescriptorCacheProvider) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
if err := dgst.Validate(); err != nil {
return distribution.Descriptor{}, err
}
key := descriptorCacheKey{
digest: dgst,
}
descriptor, ok := imbdcp.lru.Get(key)
if ok {
return descriptor, nil
}
return distribution.Descriptor{}, distribution.ErrBlobUnknown
}
func (imbdcp *inMemoryBlobDescriptorCacheProvider) Clear(ctx context.Context, dgst digest.Digest) error {
key := descriptorCacheKey{
digest: dgst,
}
imbdcp.lru.Remove(key)
return nil
}
func (imbdcp *inMemoryBlobDescriptorCacheProvider) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
_, err := imbdcp.Stat(ctx, dgst)
if err == distribution.ErrBlobUnknown {
if dgst.Algorithm() != desc.Digest.Algorithm() && dgst != desc.Digest {
// if the digests differ, set the other canonical mapping
if err := imbdcp.SetDescriptor(ctx, desc.Digest, desc); err != nil {
return err
}
}
if err := dgst.Validate(); err != nil {
return err
}
if err := cache.ValidateDescriptor(desc); err != nil {
return err
}
key := descriptorCacheKey{
digest: dgst,
}
imbdcp.lru.Add(key, desc)
return nil
}
// we already know it, do nothing
return err
}
// repositoryScopedInMemoryBlobDescriptorCache provides the request scoped
// repository cache. Instances are not thread-safe but the delegated
// operations are.
type repositoryScopedInMemoryBlobDescriptorCache struct {
repo string
parent *inMemoryBlobDescriptorCacheProvider // allows lazy allocation of repo's map
}
func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
if err := dgst.Validate(); err != nil {
return distribution.Descriptor{}, err
}
key := descriptorCacheKey{
digest: dgst,
repo: rsimbdcp.repo,
}
descriptor, ok := rsimbdcp.parent.lru.Get(key)
if ok {
return descriptor, nil
}
return distribution.Descriptor{}, distribution.ErrBlobUnknown
}
func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
key := descriptorCacheKey{
digest: dgst,
repo: rsimbdcp.repo,
}
rsimbdcp.parent.lru.Remove(key)
return nil
}
func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
if err := dgst.Validate(); err != nil {
return err
}
if err := cache.ValidateDescriptor(desc); err != nil {
return err
}
key := descriptorCacheKey{
digest: dgst,
repo: rsimbdcp.repo,
}
rsimbdcp.parent.lru.Add(key, desc)
return rsimbdcp.parent.SetDescriptor(ctx, dgst, desc)
}