...

Source file src/github.com/docker/distribution/registry/storage/cache/memory/memory.go

Documentation: github.com/docker/distribution/registry/storage/cache/memory

     1  package memory
     2  
     3  import (
     4  	"context"
     5  	"sync"
     6  
     7  	"github.com/distribution/reference"
     8  	"github.com/docker/distribution"
     9  	"github.com/docker/distribution/registry/storage/cache"
    10  	"github.com/opencontainers/go-digest"
    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.ParseNormalizedNamed(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  	rsimbdcp.parent.mu.Lock()
    81  	repo := rsimbdcp.repository
    82  	rsimbdcp.parent.mu.Unlock()
    83  
    84  	if repo == nil {
    85  		return distribution.Descriptor{}, distribution.ErrBlobUnknown
    86  	}
    87  
    88  	return repo.Stat(ctx, dgst)
    89  }
    90  
    91  func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
    92  	rsimbdcp.parent.mu.Lock()
    93  	repo := rsimbdcp.repository
    94  	rsimbdcp.parent.mu.Unlock()
    95  
    96  	if repo == nil {
    97  		return distribution.ErrBlobUnknown
    98  	}
    99  
   100  	return repo.Clear(ctx, dgst)
   101  }
   102  
   103  func (rsimbdcp *repositoryScopedInMemoryBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
   104  	rsimbdcp.parent.mu.Lock()
   105  	repo := rsimbdcp.repository
   106  	if repo == nil {
   107  		// allocate map since we are setting it now.
   108  		var ok bool
   109  		// have to read back value since we may have allocated elsewhere.
   110  		repo, ok = rsimbdcp.parent.repositories[rsimbdcp.repo]
   111  		if !ok {
   112  			repo = newMapBlobDescriptorCache()
   113  			rsimbdcp.parent.repositories[rsimbdcp.repo] = repo
   114  		}
   115  		rsimbdcp.repository = repo
   116  	}
   117  	rsimbdcp.parent.mu.Unlock()
   118  
   119  	if err := repo.SetDescriptor(ctx, dgst, desc); err != nil {
   120  		return err
   121  	}
   122  
   123  	return rsimbdcp.parent.SetDescriptor(ctx, dgst, desc)
   124  }
   125  
   126  // mapBlobDescriptorCache provides a simple map-based implementation of the
   127  // descriptor cache.
   128  type mapBlobDescriptorCache struct {
   129  	descriptors map[digest.Digest]distribution.Descriptor
   130  	mu          sync.RWMutex
   131  }
   132  
   133  var _ distribution.BlobDescriptorService = &mapBlobDescriptorCache{}
   134  
   135  func newMapBlobDescriptorCache() *mapBlobDescriptorCache {
   136  	return &mapBlobDescriptorCache{
   137  		descriptors: make(map[digest.Digest]distribution.Descriptor),
   138  	}
   139  }
   140  
   141  func (mbdc *mapBlobDescriptorCache) Stat(ctx context.Context, dgst digest.Digest) (distribution.Descriptor, error) {
   142  	if err := dgst.Validate(); err != nil {
   143  		return distribution.Descriptor{}, err
   144  	}
   145  
   146  	mbdc.mu.RLock()
   147  	defer mbdc.mu.RUnlock()
   148  
   149  	desc, ok := mbdc.descriptors[dgst]
   150  	if !ok {
   151  		return distribution.Descriptor{}, distribution.ErrBlobUnknown
   152  	}
   153  
   154  	return desc, nil
   155  }
   156  
   157  func (mbdc *mapBlobDescriptorCache) Clear(ctx context.Context, dgst digest.Digest) error {
   158  	mbdc.mu.Lock()
   159  	defer mbdc.mu.Unlock()
   160  
   161  	delete(mbdc.descriptors, dgst)
   162  	return nil
   163  }
   164  
   165  func (mbdc *mapBlobDescriptorCache) SetDescriptor(ctx context.Context, dgst digest.Digest, desc distribution.Descriptor) error {
   166  	if err := dgst.Validate(); err != nil {
   167  		return err
   168  	}
   169  
   170  	if err := cache.ValidateDescriptor(desc); err != nil {
   171  		return err
   172  	}
   173  
   174  	mbdc.mu.Lock()
   175  	defer mbdc.mu.Unlock()
   176  
   177  	mbdc.descriptors[dgst] = desc
   178  	return nil
   179  }
   180  

View as plain text