Decouple redis dependency from blob descriptor cache

Ensure that clients can use the blob descriptor cache provider without needing
the redis package.

Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2015-05-20 17:12:40 -07:00
parent fd982a8bd5
commit 812c8099a6
12 changed files with 53 additions and 50 deletions

View file

@ -18,6 +18,7 @@ import (
"github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution/registry/client/transport" "github.com/docker/distribution/registry/client/transport"
"github.com/docker/distribution/registry/storage/cache" "github.com/docker/distribution/registry/storage/cache"
"github.com/docker/distribution/registry/storage/cache/memory"
) )
// NewRepository creates a new Repository for the given repository name and base URL // NewRepository creates a new Repository for the given repository name and base URL
@ -66,7 +67,7 @@ func (r *repository) Blobs(ctx context.Context) distribution.BlobStore {
name: r.Name(), name: r.Name(),
ub: r.ub, ub: r.ub,
client: r.client, client: r.client,
statter: cache.NewCachedBlobStatter(cache.NewInMemoryBlobDescriptorCacheProvider(), statter), statter: cache.NewCachedBlobStatter(memory.NewInMemoryBlobDescriptorCacheProvider(), statter),
} }
} }

View file

@ -18,7 +18,8 @@ import (
registrymiddleware "github.com/docker/distribution/registry/middleware/registry" registrymiddleware "github.com/docker/distribution/registry/middleware/registry"
repositorymiddleware "github.com/docker/distribution/registry/middleware/repository" repositorymiddleware "github.com/docker/distribution/registry/middleware/repository"
"github.com/docker/distribution/registry/storage" "github.com/docker/distribution/registry/storage"
"github.com/docker/distribution/registry/storage/cache" memorycache "github.com/docker/distribution/registry/storage/cache/memory"
rediscache "github.com/docker/distribution/registry/storage/cache/redis"
storagedriver "github.com/docker/distribution/registry/storage/driver" storagedriver "github.com/docker/distribution/registry/storage/driver"
"github.com/docker/distribution/registry/storage/driver/factory" "github.com/docker/distribution/registry/storage/driver/factory"
storagemiddleware "github.com/docker/distribution/registry/storage/driver/middleware" storagemiddleware "github.com/docker/distribution/registry/storage/driver/middleware"
@ -114,10 +115,10 @@ func NewApp(ctx context.Context, configuration configuration.Configuration) *App
if app.redis == nil { if app.redis == nil {
panic("redis configuration required to use for layerinfo cache") panic("redis configuration required to use for layerinfo cache")
} }
app.registry = storage.NewRegistryWithDriver(app, app.driver, cache.NewRedisBlobDescriptorCacheProvider(app.redis)) app.registry = storage.NewRegistryWithDriver(app, app.driver, rediscache.NewRedisBlobDescriptorCacheProvider(app.redis))
ctxu.GetLogger(app).Infof("using redis blob descriptor cache") ctxu.GetLogger(app).Infof("using redis blob descriptor cache")
case "inmemory": case "inmemory":
app.registry = storage.NewRegistryWithDriver(app, app.driver, cache.NewInMemoryBlobDescriptorCacheProvider()) app.registry = storage.NewRegistryWithDriver(app, app.driver, memorycache.NewInMemoryBlobDescriptorCacheProvider())
ctxu.GetLogger(app).Infof("using inmemory blob descriptor cache") ctxu.GetLogger(app).Infof("using inmemory blob descriptor cache")
default: default:
if v != "" { if v != "" {

View file

@ -13,7 +13,7 @@ import (
"github.com/docker/distribution/registry/auth" "github.com/docker/distribution/registry/auth"
_ "github.com/docker/distribution/registry/auth/silly" _ "github.com/docker/distribution/registry/auth/silly"
"github.com/docker/distribution/registry/storage" "github.com/docker/distribution/registry/storage"
"github.com/docker/distribution/registry/storage/cache" memorycache "github.com/docker/distribution/registry/storage/cache/memory"
"github.com/docker/distribution/registry/storage/driver/inmemory" "github.com/docker/distribution/registry/storage/driver/inmemory"
"golang.org/x/net/context" "golang.org/x/net/context"
) )
@ -30,7 +30,7 @@ func TestAppDispatcher(t *testing.T) {
Context: ctx, Context: ctx,
router: v2.Router(), router: v2.Router(),
driver: driver, driver: driver,
registry: storage.NewRegistryWithDriver(ctx, driver, cache.NewInMemoryBlobDescriptorCacheProvider()), registry: storage.NewRegistryWithDriver(ctx, driver, memorycache.NewInMemoryBlobDescriptorCacheProvider()),
} }
server := httptest.NewServer(app) server := httptest.NewServer(app)
router := v2.Router() router := v2.Router()

View file

@ -12,7 +12,7 @@ import (
"github.com/docker/distribution" "github.com/docker/distribution"
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/registry/storage/cache" "github.com/docker/distribution/registry/storage/cache/memory"
"github.com/docker/distribution/registry/storage/driver/inmemory" "github.com/docker/distribution/registry/storage/driver/inmemory"
"github.com/docker/distribution/testutil" "github.com/docker/distribution/testutil"
) )
@ -35,7 +35,7 @@ func TestSimpleBlobUpload(t *testing.T) {
ctx := context.Background() ctx := context.Background()
imageName := "foo/bar" imageName := "foo/bar"
driver := inmemory.New() driver := inmemory.New()
registry := NewRegistryWithDriver(ctx, driver, cache.NewInMemoryBlobDescriptorCacheProvider()) registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider())
repository, err := registry.Repository(ctx, imageName) repository, err := registry.Repository(ctx, imageName)
if err != nil { if err != nil {
t.Fatalf("unexpected error getting repo: %v", err) t.Fatalf("unexpected error getting repo: %v", err)
@ -148,7 +148,7 @@ func TestSimpleBlobRead(t *testing.T) {
ctx := context.Background() ctx := context.Background()
imageName := "foo/bar" imageName := "foo/bar"
driver := inmemory.New() driver := inmemory.New()
registry := NewRegistryWithDriver(ctx, driver, cache.NewInMemoryBlobDescriptorCacheProvider()) registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider())
repository, err := registry.Repository(ctx, imageName) repository, err := registry.Repository(ctx, imageName)
if err != nil { if err != nil {
t.Fatalf("unexpected error getting repo: %v", err) t.Fatalf("unexpected error getting repo: %v", err)
@ -252,7 +252,7 @@ func TestLayerUploadZeroLength(t *testing.T) {
ctx := context.Background() ctx := context.Background()
imageName := "foo/bar" imageName := "foo/bar"
driver := inmemory.New() driver := inmemory.New()
registry := NewRegistryWithDriver(ctx, driver, cache.NewInMemoryBlobDescriptorCacheProvider()) registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider())
repository, err := registry.Repository(ctx, imageName) repository, err := registry.Repository(ctx, imageName)
if err != nil { if err != nil {
t.Fatalf("unexpected error getting repo: %v", err) t.Fatalf("unexpected error getting repo: %v", err)

View file

@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"github.com/docker/distribution" "github.com/docker/distribution"
"github.com/docker/distribution/digest"
) )
// BlobDescriptorCacheProvider provides repository scoped // BlobDescriptorCacheProvider provides repository scoped
@ -17,12 +16,10 @@ type BlobDescriptorCacheProvider interface {
RepositoryScoped(repo string) (distribution.BlobDescriptorService, error) RepositoryScoped(repo string) (distribution.BlobDescriptorService, error)
} }
func validateDigest(dgst digest.Digest) error { // ValidateDescriptor provides a helper function to ensure that caches have
return dgst.Validate() // common criteria for admitting descriptors.
} func ValidateDescriptor(desc distribution.Descriptor) error {
if err := desc.Digest.Validate(); err != nil {
func validateDescriptor(desc distribution.Descriptor) error {
if err := validateDigest(desc.Digest); err != nil {
return err return err
} }

View file

@ -1,4 +1,4 @@
package cache package memory
import ( import (
"sync" "sync"
@ -7,6 +7,7 @@ import (
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/registry/api/v2" "github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution/registry/storage/cache"
) )
type inMemoryBlobDescriptorCacheProvider struct { type inMemoryBlobDescriptorCacheProvider struct {
@ -17,7 +18,7 @@ type inMemoryBlobDescriptorCacheProvider struct {
// NewInMemoryBlobDescriptorCacheProvider returns a new mapped-based cache for // NewInMemoryBlobDescriptorCacheProvider returns a new mapped-based cache for
// storing blob descriptor data. // storing blob descriptor data.
func NewInMemoryBlobDescriptorCacheProvider() BlobDescriptorCacheProvider { func NewInMemoryBlobDescriptorCacheProvider() cache.BlobDescriptorCacheProvider {
return &inMemoryBlobDescriptorCacheProvider{ return &inMemoryBlobDescriptorCacheProvider{
global: newMapBlobDescriptorCache(), global: newMapBlobDescriptorCache(),
repositories: make(map[string]*mapBlobDescriptorCache), repositories: make(map[string]*mapBlobDescriptorCache),
@ -117,7 +118,7 @@ func newMapBlobDescriptorCache() *mapBlobDescriptorCache {
} }
func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return distribution.Descriptor{}, err return distribution.Descriptor{}, err
} }
@ -133,11 +134,11 @@ func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest
} }
func (mbdc *mapBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { func (mbdc *mapBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return err return err
} }
if err := validateDescriptor(desc); err != nil { if err := cache.ValidateDescriptor(desc); err != nil {
return err return err
} }

View file

@ -0,0 +1,13 @@
package memory
import (
"testing"
"github.com/docker/distribution/registry/storage/cache"
)
// TestInMemoryBlobInfoCache checks the in memory implementation is working
// correctly.
func TestInMemoryBlobInfoCache(t *testing.T) {
cache.CheckBlobDescriptorCache(t, NewInMemoryBlobDescriptorCacheProvider())
}

View file

@ -1,9 +0,0 @@
package cache
import "testing"
// TestInMemoryBlobInfoCache checks the in memory implementation is working
// correctly.
func TestInMemoryBlobInfoCache(t *testing.T) {
checkBlobDescriptorCache(t, NewInMemoryBlobDescriptorCacheProvider())
}

View file

@ -1,13 +1,13 @@
package cache package redis
import ( import (
"fmt" "fmt"
"github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution" "github.com/docker/distribution"
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/registry/api/v2"
"github.com/docker/distribution/registry/storage/cache"
"github.com/garyburd/redigo/redis" "github.com/garyburd/redigo/redis"
) )
@ -31,11 +31,9 @@ type redisBlobDescriptorService struct {
// request objects, we can change this to a connection. // request objects, we can change this to a connection.
} }
var _ BlobDescriptorCacheProvider = &redisBlobDescriptorService{}
// NewRedisBlobDescriptorCacheProvider returns a new redis-based // NewRedisBlobDescriptorCacheProvider returns a new redis-based
// BlobDescriptorCacheProvider using the provided redis connection pool. // BlobDescriptorCacheProvider using the provided redis connection pool.
func NewRedisBlobDescriptorCacheProvider(pool *redis.Pool) BlobDescriptorCacheProvider { func NewRedisBlobDescriptorCacheProvider(pool *redis.Pool) cache.BlobDescriptorCacheProvider {
return &redisBlobDescriptorService{ return &redisBlobDescriptorService{
pool: pool, pool: pool,
} }
@ -55,7 +53,7 @@ func (rbds *redisBlobDescriptorService) RepositoryScoped(repo string) (distribut
// Stat retrieves the descriptor data from the redis hash entry. // Stat retrieves the descriptor data from the redis hash entry.
func (rbds *redisBlobDescriptorService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { func (rbds *redisBlobDescriptorService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return distribution.Descriptor{}, err return distribution.Descriptor{}, err
} }
@ -89,11 +87,11 @@ func (rbds *redisBlobDescriptorService) stat(ctx context.Context, conn redis.Con
// hash. A hash is used here since we may store unrelated fields about a layer // hash. A hash is used here since we may store unrelated fields about a layer
// in the future. // in the future.
func (rbds *redisBlobDescriptorService) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { func (rbds *redisBlobDescriptorService) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return err return err
} }
if err := validateDescriptor(desc); err != nil { if err := cache.ValidateDescriptor(desc); err != nil {
return err return err
} }
@ -134,7 +132,7 @@ var _ distribution.BlobDescriptorService = &repositoryScopedRedisBlobDescriptorS
// forwards the descriptor request to the global blob store. If the media type // forwards the descriptor request to the global blob store. If the media type
// differs for the repository, we override it. // differs for the repository, we override it.
func (rsrbds *repositoryScopedRedisBlobDescriptorService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { func (rsrbds *repositoryScopedRedisBlobDescriptorService) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return distribution.Descriptor{}, err return distribution.Descriptor{}, err
} }
@ -170,11 +168,11 @@ func (rsrbds *repositoryScopedRedisBlobDescriptorService) Stat(ctx context.Conte
} }
func (rsrbds *repositoryScopedRedisBlobDescriptorService) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { func (rsrbds *repositoryScopedRedisBlobDescriptorService) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
if err := validateDigest(dgst); err != nil { if err := dgst.Validate(); err != nil {
return err return err
} }
if err := validateDescriptor(desc); err != nil { if err := cache.ValidateDescriptor(desc); err != nil {
return err return err
} }

View file

@ -1,4 +1,4 @@
package cache package redis
import ( import (
"flag" "flag"
@ -6,6 +6,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/docker/distribution/registry/storage/cache"
"github.com/garyburd/redigo/redis" "github.com/garyburd/redigo/redis"
) )
@ -46,5 +47,5 @@ func TestRedisBlobDescriptorCacheProvider(t *testing.T) {
t.Fatalf("unexpected error flushing redis db: %v", err) t.Fatalf("unexpected error flushing redis db: %v", err)
} }
checkBlobDescriptorCache(t, NewRedisBlobDescriptorCacheProvider(pool)) cache.CheckBlobDescriptorCache(t, NewRedisBlobDescriptorCacheProvider(pool))
} }

View file

@ -8,10 +8,10 @@ import (
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
) )
// checkBlobDescriptorCache takes a cache implementation through a common set // CheckBlobDescriptorCache takes a cache implementation through a common set
// of operations. If adding new tests, please add them here so new // of operations. If adding new tests, please add them here so new
// implementations get the benefit. // implementations get the benefit. This should be used for unit tests.
func checkBlobDescriptorCache(t *testing.T, provider BlobDescriptorCacheProvider) { func CheckBlobDescriptorCache(t *testing.T, provider BlobDescriptorCacheProvider) {
ctx := context.Background() ctx := context.Background()
checkBlobDescriptorCacheEmptyRepository(t, ctx, provider) checkBlobDescriptorCacheEmptyRepository(t, ctx, provider)

View file

@ -10,7 +10,7 @@ import (
"github.com/docker/distribution/context" "github.com/docker/distribution/context"
"github.com/docker/distribution/digest" "github.com/docker/distribution/digest"
"github.com/docker/distribution/manifest" "github.com/docker/distribution/manifest"
"github.com/docker/distribution/registry/storage/cache" "github.com/docker/distribution/registry/storage/cache/memory"
"github.com/docker/distribution/registry/storage/driver" "github.com/docker/distribution/registry/storage/driver"
"github.com/docker/distribution/registry/storage/driver/inmemory" "github.com/docker/distribution/registry/storage/driver/inmemory"
"github.com/docker/distribution/testutil" "github.com/docker/distribution/testutil"
@ -29,7 +29,7 @@ type manifestStoreTestEnv struct {
func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv { func newManifestStoreTestEnv(t *testing.T, name, tag string) *manifestStoreTestEnv {
ctx := context.Background() ctx := context.Background()
driver := inmemory.New() driver := inmemory.New()
registry := NewRegistryWithDriver(ctx, driver, cache.NewInMemoryBlobDescriptorCacheProvider()) registry := NewRegistryWithDriver(ctx, driver, memory.NewInMemoryBlobDescriptorCacheProvider())
repo, err := registry.Repository(ctx, name) repo, err := registry.Repository(ctx, name)
if err != nil { if err != nil {