Skip to content

Commit d2179c2

Browse files
authored
Merge pull request #2018 from dmcgowan/cherry-pick-image-removal-gc
[release/1.0] metadata: image removal triggers GC
2 parents 9b55aab + d04746b commit d2179c2

6 files changed

Lines changed: 217 additions & 240 deletions

File tree

metadata/buckets.go

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -106,13 +106,8 @@ func imagesBucketPath(namespace string) [][]byte {
106106
return [][]byte{bucketKeyVersion, []byte(namespace), bucketKeyObjectImages}
107107
}
108108

109-
func withImagesBucket(tx *bolt.Tx, namespace string, fn func(bkt *bolt.Bucket) error) error {
110-
bkt, err := createBucketIfNotExists(tx, imagesBucketPath(namespace)...)
111-
if err != nil {
112-
return err
113-
}
114-
115-
return fn(bkt)
109+
func createImagesBucket(tx *bolt.Tx, namespace string) (*bolt.Bucket, error) {
110+
return createBucketIfNotExists(tx, imagesBucketPath(namespace)...)
116111
}
117112

118113
func getImagesBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
@@ -143,6 +138,10 @@ func createSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) (*bolt.
143138
return bkt, nil
144139
}
145140

141+
func getSnapshottersBucket(tx *bolt.Tx, namespace string) *bolt.Bucket {
142+
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots)
143+
}
144+
146145
func getSnapshotterBucket(tx *bolt.Tx, namespace, snapshotter string) *bolt.Bucket {
147146
return getBucket(tx, bucketKeyVersion, []byte(namespace), bucketKeyObjectSnapshots, []byte(snapshotter))
148147
}

metadata/db_test.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ func TestMetadataCollector(t *testing.T) {
261261

262262
if err := mdb.Update(func(tx *bolt.Tx) error {
263263
for _, obj := range objects {
264-
node, err := create(obj, tx, cs, sn)
264+
node, err := create(obj, tx, NewImageStore(mdb), cs, sn)
265265
if err != nil {
266266
return err
267267
}
@@ -336,7 +336,7 @@ func benchmarkTrigger(n int) func(b *testing.B) {
336336

337337
if err := mdb.Update(func(tx *bolt.Tx) error {
338338
for _, obj := range objects {
339-
node, err := create(obj, tx, cs, sn)
339+
node, err := create(obj, tx, NewImageStore(mdb), cs, sn)
340340
if err != nil {
341341
return err
342342
}
@@ -416,7 +416,7 @@ type object struct {
416416
labels map[string]string
417417
}
418418

419-
func create(obj object, tx *bolt.Tx, cs content.Store, sn snapshots.Snapshotter) (*gc.Node, error) {
419+
func create(obj object, tx *bolt.Tx, is images.Store, cs content.Store, sn snapshots.Snapshotter) (*gc.Node, error) {
420420
var (
421421
node *gc.Node
422422
namespace = "test"
@@ -469,12 +469,14 @@ func create(obj object, tx *bolt.Tx, cs content.Store, sn snapshots.Snapshotter)
469469
}
470470
}
471471
case testImage:
472+
ctx := WithTransactionContext(ctx, tx)
473+
472474
image := images.Image{
473475
Name: v.name,
474476
Target: v.target,
475477
Labels: obj.labels,
476478
}
477-
_, err := NewImageStore(tx).Create(ctx, image)
479+
_, err := is.Create(ctx, image)
478480
if err != nil {
479481
return nil, errors.Wrap(err, "failed to create image")
480482
}

metadata/images.go

Lines changed: 83 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ import (
2020
)
2121

2222
type imageStore struct {
23-
tx *bolt.Tx
23+
db *DB
2424
}
2525

2626
// NewImageStore returns a store backed by a bolt DB
27-
func NewImageStore(tx *bolt.Tx) images.Store {
28-
return &imageStore{tx: tx}
27+
func NewImageStore(db *DB) images.Store {
28+
return &imageStore{db: db}
2929
}
3030

3131
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)
3636
return images.Image{}, err
3737
}
3838

39-
bkt := getImagesBucket(s.tx, namespace)
40-
if bkt == nil {
41-
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
42-
}
39+
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
40+
bkt := getImagesBucket(tx, namespace)
41+
if bkt == nil {
42+
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
43+
}
4344

44-
ibkt := bkt.Bucket([]byte(name))
45-
if ibkt == nil {
46-
return images.Image{}, errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
47-
}
45+
ibkt := bkt.Bucket([]byte(name))
46+
if ibkt == nil {
47+
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
48+
}
4849

49-
image.Name = name
50-
if err := readImage(&image, ibkt); err != nil {
51-
return images.Image{}, errors.Wrapf(err, "image %q", name)
50+
image.Name = name
51+
if err := readImage(&image, ibkt); err != nil {
52+
return errors.Wrapf(err, "image %q", name)
53+
}
54+
55+
return nil
56+
}); err != nil {
57+
return images.Image{}, err
5258
}
5359

5460
return image, nil
@@ -65,28 +71,30 @@ func (s *imageStore) List(ctx context.Context, fs ...string) ([]images.Image, er
6571
return nil, errors.Wrapf(errdefs.ErrInvalidArgument, err.Error())
6672
}
6773

68-
bkt := getImagesBucket(s.tx, namespace)
69-
if bkt == nil {
70-
return nil, nil // empty store
71-
}
72-
7374
var m []images.Image
74-
if err := bkt.ForEach(func(k, v []byte) error {
75-
var (
76-
image = images.Image{
77-
Name: string(k),
78-
}
79-
kbkt = bkt.Bucket(k)
80-
)
81-
82-
if err := readImage(&image, kbkt); err != nil {
83-
return err
75+
if err := view(ctx, s.db, func(tx *bolt.Tx) error {
76+
bkt := getImagesBucket(tx, namespace)
77+
if bkt == nil {
78+
return nil // empty store
8479
}
8580

86-
if filter.Match(adaptImage(image)) {
87-
m = append(m, image)
88-
}
89-
return nil
81+
return bkt.ForEach(func(k, v []byte) error {
82+
var (
83+
image = images.Image{
84+
Name: string(k),
85+
}
86+
kbkt = bkt.Bucket(k)
87+
)
88+
89+
if err := readImage(&image, kbkt); err != nil {
90+
return err
91+
}
92+
93+
if filter.Match(adaptImage(image)) {
94+
m = append(m, image)
95+
}
96+
return nil
97+
})
9098
}); err != nil {
9199
return nil, err
92100
}
@@ -100,11 +108,16 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
100108
return images.Image{}, err
101109
}
102110

103-
if err := validateImage(&image); err != nil {
104-
return images.Image{}, err
105-
}
111+
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
112+
if err := validateImage(&image); err != nil {
113+
return err
114+
}
115+
116+
bkt, err := createImagesBucket(tx, namespace)
117+
if err != nil {
118+
return err
119+
}
106120

107-
return image, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
108121
ibkt, err := bkt.CreateBucket([]byte(image.Name))
109122
if err != nil {
110123
if err != bolt.ErrBucketExists {
@@ -117,7 +130,11 @@ func (s *imageStore) Create(ctx context.Context, image images.Image) (images.Ima
117130
image.CreatedAt = time.Now().UTC()
118131
image.UpdatedAt = image.CreatedAt
119132
return writeImage(ibkt, &image)
120-
})
133+
}); err != nil {
134+
return images.Image{}, err
135+
}
136+
137+
return image, nil
121138
}
122139

123140
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
131148
}
132149

133150
var updated images.Image
134-
return updated, withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
151+
152+
if err := update(ctx, s.db, func(tx *bolt.Tx) error {
153+
bkt, err := createImagesBucket(tx, namespace)
154+
if err != nil {
155+
return err
156+
}
157+
135158
ibkt := bkt.Bucket([]byte(image.Name))
136159
if ibkt == nil {
137160
return errors.Wrapf(errdefs.ErrNotFound, "image %q", image.Name)
@@ -180,7 +203,12 @@ func (s *imageStore) Update(ctx context.Context, image images.Image, fieldpaths
180203
updated.CreatedAt = createdat
181204
updated.UpdatedAt = time.Now().UTC()
182205
return writeImage(ibkt, &updated)
183-
})
206+
}); err != nil {
207+
return images.Image{}, err
208+
}
209+
210+
return updated, nil
211+
184212
}
185213

186214
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
189217
return err
190218
}
191219

192-
return withImagesBucket(s.tx, namespace, func(bkt *bolt.Bucket) error {
193-
err := bkt.DeleteBucket([]byte(name))
220+
return update(ctx, s.db, func(tx *bolt.Tx) error {
221+
bkt := getImagesBucket(tx, namespace)
222+
if bkt == nil {
223+
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
224+
}
225+
226+
err = bkt.DeleteBucket([]byte(name))
194227
if err == bolt.ErrBucketNotFound {
195228
return errors.Wrapf(errdefs.ErrNotFound, "image %q", name)
196229
}
230+
231+
// A reference to a piece of content has been removed,
232+
// mark content store as dirty for triggering garbage
233+
// collection
234+
s.db.dirtyL.Lock()
235+
s.db.dirtyCS = true
236+
s.db.dirtyL.Unlock()
237+
197238
return err
198239
})
199240
}

0 commit comments

Comments
 (0)