152af63ec5
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>
158 lines
4.2 KiB
Go
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)
|
|
}
|