Update metadata image store to be initialized once
The boltdb image store now manages its own transactions when one is not provided, but allows the caller to pass in a transaction through the context. This makes the image store more similar to the content and snapshot stores. Additionally, use the reference to the metadata database to mark the content store as dirty after an image has been deleted. The deletion of an image means a reference to a piece of content is gone and therefore garbage collection should be run to check if any resources can be cleaned up as a result. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
@@ -20,12 +20,12 @@ import (
|
||||
)
|
||||
|
||||
type imageStore struct {
|
||||
tx *bolt.Tx
|
||||
db *DB
|
||||
}
|
||||
|
||||
// NewImageStore returns a store backed by a bolt DB
|
||||
func NewImageStore(tx *bolt.Tx) images.Store {
|
||||
return &imageStore{tx: tx}
|
||||
func NewImageStore(db *DB) images.Store {
|
||||
return &imageStore{db: db}
|
||||
}
|
||||
|
||||
func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error) {
|
||||
@@ -36,19 +36,25 @@ func (s *imageStore) Get(ctx context.Context, name string) (images.Image, error)
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
bkt := getImagesBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getImagesBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
ibkt := bkt.Bucket([]byte(name))
|
||||
if ibkt == nil {
|
||||
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
ibkt := bkt.Bucket([]byte(name))
|
||||
if ibkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
image.Name = name
|
||||
if err := readImage(&image, ibkt); err != nil {
|
||||
return images.Image{}, errors.Wrapf(err, "image %q", name)
|
||||
image.Name = name
|
||||
if err := readImage(&image, ibkt); err != nil {
|
||||
return errors.Wrapf(err, "image %q", name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
return image, nil
|
||||
@@ -65,28 +71,30 @@ func (s *imageStore) List(ctx context.Context, fs ...string) ([]images.Image, er
|
||||
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
|
||||
}
|
||||
|
||||
bkt := getImagesBucket(s.tx, namespace)
|
||||
if bkt == nil {
|
||||
return nil, nil // empty store
|
||||
}
|
||||
|
||||
var m []images.Image
|
||||
if err := bkt.ForEach(func(k, v []byte) error {
|
||||
var (
|
||||
image = images.Image{
|
||||
Name: string(k),
|
||||
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getImagesBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return nil // empty store
|
||||
}
|
||||
|
||||
return bkt.ForEach(func(k, v []byte) error {
|
||||
var (
|
||||
image = images.Image{
|
||||
Name: string(k),
|
||||
}
|
||||
kbkt = bkt.Bucket(k)
|
||||
)
|
||||
|
||||
if err := readImage(&image, kbkt); err != nil {
|
||||
return err
|
||||
}
|
||||
kbkt = bkt.Bucket(k)
|
||||
)
|
||||
|
||||
if err := readImage(&image, kbkt); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if filter.Match(adaptImage(image)) {
|
||||
m = append(m, image)
|
||||
}
|
||||
return nil
|
||||
if filter.Match(adaptImage(image)) {
|
||||
m = append(m, image)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -100,11 +108,16 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
if err := validateImage(&image); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
if err := validateImage(&image); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bkt, err := createImagesBucket(tx, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return image, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||
ibkt, err := bkt.CreateBucket([]byte(image.Name))
|
||||
if err != nil {
|
||||
if err != bolt.ErrBucketExists {
|
||||
@@ -117,7 +130,11 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
|
||||
image.CreatedAt = time.Now().UTC()
|
||||
image.UpdatedAt = image.CreatedAt
|
||||
return writeImage(ibkt, &image)
|
||||
})
|
||||
}); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
return image, nil
|
||||
}
|
||||
|
||||
func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths ...string) (images.Image, error) {
|
||||
@@ -131,7 +148,13 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths
|
||||
}
|
||||
|
||||
var updated images.Image
|
||||
return updated, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||
|
||||
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt, err := createImagesBucket(tx, namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ibkt := bkt.Bucket([]byte(image.Name))
|
||||
if ibkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", image.Name)
|
||||
@@ -180,7 +203,12 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths
|
||||
updated.CreatedAt = createdat
|
||||
updated.UpdatedAt = time.Now().UTC()
|
||||
return writeImage(ibkt, &updated)
|
||||
})
|
||||
}); err != nil {
|
||||
return images.Image{}, err
|
||||
}
|
||||
|
||||
return updated, nil
|
||||
|
||||
}
|
||||
|
||||
func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.DeleteOpt) error {
|
||||
@@ -189,11 +217,24 @@ func (s *imageStore) Delete(ctx context.Context, name string, opts ...images.Del
|
||||
return err
|
||||
}
|
||||
|
||||
return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
|
||||
err := bkt.DeleteBucket([]byte(name))
|
||||
return update(ctx, s.db, func(tx *bolt.Tx) error {
|
||||
bkt := getImagesBucket(tx, namespace)
|
||||
if bkt == nil {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
err = bkt.DeleteBucket([]byte(name))
|
||||
if err == bolt.ErrBucketNotFound {
|
||||
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
|
||||
}
|
||||
|
||||
// A reference to a piece of content has been removed,
|
||||
// mark content store as dirty for triggering garbage
|
||||
// collection
|
||||
s.db.dirtyL.Lock()
|
||||
s.db.dirtyCS = true
|
||||
s.db.dirtyL.Unlock()
|
||||
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user