github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/storage/cache/memory/memory.go (about) 1 package memory 2 3 import ( 4 "sync" 5 6 "github.com/docker/distribution" 7 "github.com/docker/distribution/context" 8 "github.com/docker/distribution/digest" 9 "github.com/docker/distribution/reference" 10 "github.com/docker/distribution/registry/storage/cache" 11 ) 12 13 type inMemoryBlobDescriptorCacheProvider struct { 14 global *mapBlobDescriptorCache 15 repositories map[string]*mapBlobDescriptorCache 16 mu sync.RWMutex 17 } 18 19 // NewInMemoryBlobDescriptorCacheProvider returns a new mapped-based cache for 20 // storing blob descriptor data. 21 func NewInMemoryBlobDescriptorCacheProvider() cache.BlobDescriptorCacheProvider { 22 return &inMemoryBlobDescriptorCacheProvider{ 23 global: newMapBlobDescriptorCache(), 24 repositories: make(map[string]*mapBlobDescriptorCache), 25 } 26 } 27 28 func (imbdcp *inMemoryBlobDescriptorCacheProvider) RepositoryScoped(repo string) (distribution.BlobDescriptorService, error) { 29 if _, err := reference.ParseNamed(repo); err != nil { 30 return nil, err 31 } 32 33 imbdcp.mu.RLock() 34 defer imbdcp.mu.RUnlock() 35 36 return &repositoryScopedInMemoryBlobDescriptorCache{ 37 repo: repo, 38 parent: imbdcp, 39 repository: imbdcp.repositories[repo], 40 }, nil 41 } 42 43 func (imbdcp *inMemoryBlobDescriptorCacheProvider) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { 44 return imbdcp.global.Stat(ctx, dgst) 45 } 46 47 func (imbdcp *inMemoryBlobDescriptorCacheProvider) Clear(ctx context.Context, dgst digest.Digest) error { 48 return imbdcp.global.Clear(ctx, dgst) 49 } 50 51 func (imbdcp *inMemoryBlobDescriptorCacheProvider) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { 52 _, err := imbdcp.Stat(ctx, dgst) 53 if err == distribution.ErrBlobUnknown { 54 55 if dgst.Algorithm() != desc.Digest.Algorithm() && dgst != desc.Digest { 56 // if the digests differ, set the other canonical mapping 57 if err := imbdcp.global.SetDescriptor(ctx, desc.Digest, desc); err != nil { 58 return err 59 } 60 } 61 62 // unknown, just set it 63 return imbdcp.global.SetDescriptor(ctx, dgst, desc) 64 } 65 66 // we already know it, do nothing 67 return err 68 } 69 70 // repositoryScopedInMemoryBlobDescriptorCache provides the request scoped 71 // repository cache. Instances are not thread-safe but the delegated 72 // operations are. 73 type repositoryScopedInMemoryBlobDescriptorCache struct { 74 repo string 75 parent *inMemoryBlobDescriptorCacheProvider // allows lazy allocation of repo's map 76 repository *mapBlobDescriptorCache 77 } 78 79 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { 80 if rsimbdcp.repository == nil { 81 return distribution.Descriptor{}, distribution.ErrBlobUnknown 82 } 83 84 return rsimbdcp.repository.Stat(ctx, dgst) 85 } 86 87 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error { 88 if rsimbdcp.repository == nil { 89 return distribution.ErrBlobUnknown 90 } 91 92 return rsimbdcp.repository.Clear(ctx, dgst) 93 } 94 95 func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { 96 if rsimbdcp.repository == nil { 97 // allocate map since we are setting it now. 98 rsimbdcp.parent.mu.Lock() 99 var ok bool 100 // have to read back value since we may have allocated elsewhere. 101 rsimbdcp.repository, ok = rsimbdcp.parent.repositories[rsimbdcp.repo] 102 if !ok { 103 rsimbdcp.repository = newMapBlobDescriptorCache() 104 rsimbdcp.parent.repositories[rsimbdcp.repo] = rsimbdcp.repository 105 } 106 107 rsimbdcp.parent.mu.Unlock() 108 } 109 110 if err := rsimbdcp.repository.SetDescriptor(ctx, dgst, desc); err != nil { 111 return err 112 } 113 114 return rsimbdcp.parent.SetDescriptor(ctx, dgst, desc) 115 } 116 117 // mapBlobDescriptorCache provides a simple map-based implementation of the 118 // descriptor cache. 119 type mapBlobDescriptorCache struct { 120 descriptors map[digest.Digest]distribution.Descriptor 121 mu sync.RWMutex 122 } 123 124 var _ distribution.BlobDescriptorService = &mapBlobDescriptorCache{} 125 126 func newMapBlobDescriptorCache() *mapBlobDescriptorCache { 127 return &mapBlobDescriptorCache{ 128 descriptors: make(map[digest.Digest]distribution.Descriptor), 129 } 130 } 131 132 func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) { 133 if err := dgst.Validate(); err != nil { 134 return distribution.Descriptor{}, err 135 } 136 137 mbdc.mu.RLock() 138 defer mbdc.mu.RUnlock() 139 140 desc, ok := mbdc.descriptors[dgst] 141 if !ok { 142 return distribution.Descriptor{}, distribution.ErrBlobUnknown 143 } 144 145 return desc, nil 146 } 147 148 func (mbdc *mapBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error { 149 mbdc.mu.Lock() 150 defer mbdc.mu.Unlock() 151 152 delete(mbdc.descriptors, dgst) 153 return nil 154 } 155 156 func (mbdc *mapBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error { 157 if err := dgst.Validate(); err != nil { 158 return err 159 } 160 161 if err := cache.ValidateDescriptor(desc); err != nil { 162 return err 163 } 164 165 mbdc.mu.Lock() 166 defer mbdc.mu.Unlock() 167 168 mbdc.descriptors[dgst] = desc 169 return nil 170 }