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  }