github.com/lusis/distribution@v2.0.1+incompatible/registry/storage/cache/redis.go (about)

     1  package cache
     2  
     3  import (
     4  	ctxu "github.com/docker/distribution/context"
     5  	"github.com/docker/distribution/digest"
     6  	"github.com/garyburd/redigo/redis"
     7  	"golang.org/x/net/context"
     8  )
     9  
    10  // redisLayerInfoCache provides an implementation of storage.LayerInfoCache
    11  // based on redis. Layer info is stored in two parts. The first provide fast
    12  // access to repository membership through a redis set for each repo. The
    13  // second is a redis hash keyed by the digest of the layer, providing path and
    14  // length information. Note that there is no implied relationship between
    15  // these two caches. The layer may exist in one, both or none and the code
    16  // must be written this way.
    17  type redisLayerInfoCache struct {
    18  	pool *redis.Pool
    19  
    20  	// TODO(stevvooe): We use a pool because we don't have great control over
    21  	// the cache lifecycle to manage connections. A new connection if fetched
    22  	// for each operation. Once we have better lifecycle management of the
    23  	// request objects, we can change this to a connection.
    24  }
    25  
    26  // NewRedisLayerInfoCache returns a new redis-based LayerInfoCache using the
    27  // provided redis connection pool.
    28  func NewRedisLayerInfoCache(pool *redis.Pool) LayerInfoCache {
    29  	return &base{&redisLayerInfoCache{
    30  		pool: pool,
    31  	}}
    32  }
    33  
    34  // Contains does a membership check on the repository blob set in redis. This
    35  // is used as an access check before looking up global path information. If
    36  // false is returned, the caller should still check the backend to if it
    37  // exists elsewhere.
    38  func (rlic *redisLayerInfoCache) Contains(ctx context.Context, repo string, dgst digest.Digest) (bool, error) {
    39  	conn := rlic.pool.Get()
    40  	defer conn.Close()
    41  
    42  	ctxu.GetLogger(ctx).Debugf("(*redisLayerInfoCache).Contains(%q, %q)", repo, dgst)
    43  	return redis.Bool(conn.Do("SISMEMBER", rlic.repositoryBlobSetKey(repo), dgst))
    44  }
    45  
    46  // Add adds the layer to the redis repository blob set.
    47  func (rlic *redisLayerInfoCache) Add(ctx context.Context, repo string, dgst digest.Digest) error {
    48  	conn := rlic.pool.Get()
    49  	defer conn.Close()
    50  
    51  	ctxu.GetLogger(ctx).Debugf("(*redisLayerInfoCache).Add(%q, %q)", repo, dgst)
    52  	_, err := conn.Do("SADD", rlic.repositoryBlobSetKey(repo), dgst)
    53  	return err
    54  }
    55  
    56  // Meta retrieves the layer meta data from the redis hash, returning
    57  // ErrUnknownLayer if not found.
    58  func (rlic *redisLayerInfoCache) Meta(ctx context.Context, dgst digest.Digest) (LayerMeta, error) {
    59  	conn := rlic.pool.Get()
    60  	defer conn.Close()
    61  
    62  	reply, err := redis.Values(conn.Do("HMGET", rlic.blobMetaHashKey(dgst), "path", "length"))
    63  	if err != nil {
    64  		return LayerMeta{}, err
    65  	}
    66  
    67  	if len(reply) < 2 || reply[0] == nil || reply[1] == nil {
    68  		return LayerMeta{}, ErrNotFound
    69  	}
    70  
    71  	var meta LayerMeta
    72  	if _, err := redis.Scan(reply, &meta.Path, &meta.Length); err != nil {
    73  		return LayerMeta{}, err
    74  	}
    75  
    76  	return meta, nil
    77  }
    78  
    79  // SetMeta sets the meta data for the given digest using a redis hash. A hash
    80  // is used here since we may store unrelated fields about a layer in the
    81  // future.
    82  func (rlic *redisLayerInfoCache) SetMeta(ctx context.Context, dgst digest.Digest, meta LayerMeta) error {
    83  	conn := rlic.pool.Get()
    84  	defer conn.Close()
    85  
    86  	_, err := conn.Do("HMSET", rlic.blobMetaHashKey(dgst), "path", meta.Path, "length", meta.Length)
    87  	return err
    88  }
    89  
    90  // repositoryBlobSetKey returns the key for the blob set in the cache.
    91  func (rlic *redisLayerInfoCache) repositoryBlobSetKey(repo string) string {
    92  	return "repository::" + repo + "::blobs"
    93  }
    94  
    95  // blobMetaHashKey returns the cache key for immutable blob meta data.
    96  func (rlic *redisLayerInfoCache) blobMetaHashKey(dgst digest.Digest) string {
    97  	return "blobs::" + dgst.String()
    98  }