forked from TrueCloudLab/distribution
Move storage package under registry package
Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
parent
d6308bc62b
commit
71e7ac33ca
40 changed files with 5411 additions and 8 deletions
159
docs/storage/blobstore.go
Normal file
159
docs/storage/blobstore.go
Normal file
|
@ -0,0 +1,159 @@
|
|||
package storage
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
ctxu "github.com/docker/distribution/context"
|
||||
"github.com/docker/distribution/digest"
|
||||
"github.com/docker/distribution/storagedriver"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// TODO(stevvooe): Currently, the blobStore implementation used by the
|
||||
// manifest store. The layer store should be refactored to better leverage the
|
||||
// blobStore, reducing duplicated code.
|
||||
|
||||
// blobStore implements a generalized blob store over a driver, supporting the
|
||||
// read side and link management. This object is intentionally a leaky
|
||||
// abstraction, providing utility methods that support creating and traversing
|
||||
// backend links.
|
||||
type blobStore struct {
|
||||
*registry
|
||||
ctx context.Context
|
||||
}
|
||||
|
||||
// exists reports whether or not the path exists. If the driver returns error
|
||||
// other than storagedriver.PathNotFound, an error may be returned.
|
||||
func (bs *blobStore) exists(dgst digest.Digest) (bool, error) {
|
||||
path, err := bs.path(dgst)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
ok, err := exists(bs.driver, path)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return ok, nil
|
||||
}
|
||||
|
||||
// get retrieves the blob by digest, returning it a byte slice. This should
|
||||
// only be used for small objects.
|
||||
func (bs *blobStore) get(dgst digest.Digest) ([]byte, error) {
|
||||
bp, err := bs.path(dgst)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bs.driver.GetContent(bp)
|
||||
}
|
||||
|
||||
// link links the path to the provided digest by writing the digest into the
|
||||
// target file.
|
||||
func (bs *blobStore) link(path string, dgst digest.Digest) error {
|
||||
if exists, err := bs.exists(dgst); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
return fmt.Errorf("cannot link non-existent blob")
|
||||
}
|
||||
|
||||
// The contents of the "link" file are the exact string contents of the
|
||||
// digest, which is specified in that package.
|
||||
return bs.driver.PutContent(path, []byte(dgst))
|
||||
}
|
||||
|
||||
// linked reads the link at path and returns the content.
|
||||
func (bs *blobStore) linked(path string) ([]byte, error) {
|
||||
linked, err := bs.readlink(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bs.get(linked)
|
||||
}
|
||||
|
||||
// readlink returns the linked digest at path.
|
||||
func (bs *blobStore) readlink(path string) (digest.Digest, error) {
|
||||
content, err := bs.driver.GetContent(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
linked, err := digest.ParseDigest(string(content))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if exists, err := bs.exists(linked); err != nil {
|
||||
return "", err
|
||||
} else if !exists {
|
||||
return "", fmt.Errorf("link %q invalid: blob %s does not exist", path, linked)
|
||||
}
|
||||
|
||||
return linked, nil
|
||||
}
|
||||
|
||||
// resolve reads the digest link at path and returns the blob store link.
|
||||
func (bs *blobStore) resolve(path string) (string, error) {
|
||||
dgst, err := bs.readlink(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return bs.path(dgst)
|
||||
}
|
||||
|
||||
// put stores the content p in the blob store, calculating the digest. If the
|
||||
// content is already present, only the digest will be returned. This should
|
||||
// only be used for small objects, such as manifests.
|
||||
func (bs *blobStore) put(p []byte) (digest.Digest, error) {
|
||||
dgst, err := digest.FromBytes(p)
|
||||
if err != nil {
|
||||
ctxu.GetLogger(bs.ctx).Errorf("error digesting content: %v, %s", err, string(p))
|
||||
return "", err
|
||||
}
|
||||
|
||||
bp, err := bs.path(dgst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// If the content already exists, just return the digest.
|
||||
if exists, err := bs.exists(dgst); err != nil {
|
||||
return "", err
|
||||
} else if exists {
|
||||
return dgst, nil
|
||||
}
|
||||
|
||||
return dgst, bs.driver.PutContent(bp, p)
|
||||
}
|
||||
|
||||
// path returns the canonical path for the blob identified by digest. The blob
|
||||
// may or may not exist.
|
||||
func (bs *blobStore) path(dgst digest.Digest) (string, error) {
|
||||
bp, err := bs.pm.path(blobDataPathSpec{
|
||||
digest: dgst,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return bp, nil
|
||||
}
|
||||
|
||||
// exists provides a utility method to test whether or not
|
||||
func exists(driver storagedriver.StorageDriver, path string) (bool, error) {
|
||||
if _, err := driver.Stat(path); err != nil {
|
||||
switch err := err.(type) {
|
||||
case storagedriver.PathNotFoundError:
|
||||
return false, nil
|
||||
default:
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue