Skip to content

Commit cfba7ef

Browse files
Merge pull request #3064 from dmcgowan/update-gc-content-references
Add content gc ref labels from containers, images, and snapshots
2 parents 04b2e5b + 7cfb99a commit cfba7ef

2 files changed

Lines changed: 69 additions & 90 deletions

File tree

metadata/gc.go

Lines changed: 49 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,18 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
6464
// iterate through each namespace
6565
v1c := v1bkt.Cursor()
6666

67+
// cerr indicates the scan did not successfully send all
68+
// the roots. The scan does not need to be cancelled but
69+
// must return error at the end.
70+
var cerr error
71+
fn := func(n gc.Node) {
72+
select {
73+
case nc <- n:
74+
case <-ctx.Done():
75+
cerr = ctx.Err()
76+
}
77+
}
78+
6779
for k, v := v1c.First(); k != nil; k, v = v1c.Next() {
6880
if v != nil {
6981
continue
@@ -92,11 +104,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
92104
}
93105
}
94106

95-
select {
96-
case nc <- gcnode(ResourceLease, ns, string(k)):
97-
case <-ctx.Done():
98-
return ctx.Err()
99-
}
107+
fn(gcnode(ResourceLease, ns, string(k)))
100108

101109
// Emit content and snapshots as roots instead of implementing
102110
// in references. Since leases cannot be referenced there is
@@ -106,11 +114,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
106114
cbkt := libkt.Bucket(bucketKeyObjectContent)
107115
if cbkt != nil {
108116
if err := cbkt.ForEach(func(k, v []byte) error {
109-
select {
110-
case nc <- gcnode(ResourceContent, ns, string(k)):
111-
case <-ctx.Done():
112-
return ctx.Err()
113-
}
117+
fn(gcnode(ResourceContent, ns, string(k)))
114118
return nil
115119
}); err != nil {
116120
return err
@@ -126,11 +130,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
126130
snbkt := sbkt.Bucket(sk)
127131

128132
return snbkt.ForEach(func(k, v []byte) error {
129-
select {
130-
case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)):
131-
case <-ctx.Done():
132-
return ctx.Err()
133-
}
133+
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)))
134134
return nil
135135
})
136136
}); err != nil {
@@ -141,11 +141,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
141141
ibkt := libkt.Bucket(bucketKeyObjectIngests)
142142
if ibkt != nil {
143143
if err := ibkt.ForEach(func(k, v []byte) error {
144-
select {
145-
case nc <- gcnode(ResourceIngest, ns, string(k)):
146-
case <-ctx.Done():
147-
return ctx.Err()
148-
}
144+
fn(gcnode(ResourceIngest, ns, string(k)))
149145
return nil
150146
}); err != nil {
151147
return err
@@ -168,18 +164,9 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
168164
target := ibkt.Bucket(k).Bucket(bucketKeyTarget)
169165
if target != nil {
170166
contentKey := string(target.Get(bucketKeyDigest))
171-
select {
172-
case nc <- gcnode(ResourceContent, ns, contentKey):
173-
case <-ctx.Done():
174-
return ctx.Err()
175-
}
167+
fn(gcnode(ResourceContent, ns, contentKey))
176168
}
177-
return sendSnapshotRefs(ns, ibkt.Bucket(k), func(n gc.Node) {
178-
select {
179-
case nc <- n:
180-
case <-ctx.Done():
181-
}
182-
})
169+
return sendLabelRefs(ns, ibkt.Bucket(k), fn)
183170
}); err != nil {
184171
return err
185172
}
@@ -200,11 +187,7 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
200187
if ea == nil || expThreshold.After(*ea) {
201188
return nil
202189
}
203-
select {
204-
case nc <- gcnode(ResourceIngest, ns, string(k)):
205-
case <-ctx.Done():
206-
return ctx.Err()
207-
}
190+
fn(gcnode(ResourceIngest, ns, string(k)))
208191
return nil
209192
}); err != nil {
210193
return err
@@ -216,7 +199,12 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
216199
if v != nil {
217200
return nil
218201
}
219-
return sendRootRef(ctx, nc, gcnode(ResourceContent, ns, string(k)), cbkt.Bucket(k))
202+
203+
if isRootRef(cbkt.Bucket(k)) {
204+
fn(gcnode(ResourceContent, ns, string(k)))
205+
}
206+
207+
return nil
220208
}); err != nil {
221209
return err
222210
}
@@ -229,23 +217,15 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
229217
if v != nil {
230218
return nil
231219
}
232-
snapshotter := string(cbkt.Bucket(k).Get(bucketKeySnapshotter))
220+
221+
cibkt := cbkt.Bucket(k)
222+
snapshotter := string(cibkt.Get(bucketKeySnapshotter))
233223
if snapshotter != "" {
234-
ss := string(cbkt.Bucket(k).Get(bucketKeySnapshotKey))
235-
select {
236-
case nc <- gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, ss)):
237-
case <-ctx.Done():
238-
return ctx.Err()
239-
}
224+
ss := string(cibkt.Get(bucketKeySnapshotKey))
225+
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, ss)))
240226
}
241227

242-
// TODO: Send additional snapshot refs through labels
243-
return sendSnapshotRefs(ns, cbkt.Bucket(k), func(n gc.Node) {
244-
select {
245-
case nc <- n:
246-
case <-ctx.Done():
247-
}
248-
})
228+
return sendLabelRefs(ns, cibkt, fn)
249229
}); err != nil {
250230
return err
251231
}
@@ -263,15 +243,17 @@ func scanRoots(ctx context.Context, tx *bolt.Tx, nc chan<- gc.Node) error {
263243
if v != nil {
264244
return nil
265245
}
266-
267-
return sendRootRef(ctx, nc, gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)), snbkt.Bucket(k))
246+
if isRootRef(snbkt.Bucket(k)) {
247+
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", sk, k)))
248+
}
249+
return nil
268250
})
269251
}); err != nil {
270252
return err
271253
}
272254
}
273255
}
274-
return nil
256+
return cerr
275257
}
276258

277259
func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)) error {
@@ -282,10 +264,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
282264
return nil
283265
}
284266

285-
if err := sendSnapshotRefs(node.Namespace, bkt, fn); err != nil {
286-
return err
287-
}
288-
return sendContentRefs(node.Namespace, bkt, fn)
267+
return sendLabelRefs(node.Namespace, bkt, fn)
289268
} else if node.Type == ResourceSnapshot {
290269
parts := strings.SplitN(node.Key, "/", 2)
291270
if len(parts) != 2 {
@@ -304,7 +283,7 @@ func references(ctx context.Context, tx *bolt.Tx, node gc.Node, fn func(gc.Node)
304283
fn(gcnode(ResourceSnapshot, node.Namespace, fmt.Sprintf("%s/%s", ss, pv)))
305284
}
306285

307-
return sendSnapshotRefs(node.Namespace, bkt, fn)
286+
return sendLabelRefs(node.Namespace, bkt, fn)
308287
} else if node.Type == ResourceIngest {
309288
// Send expected value
310289
bkt := getBucket(tx, bucketKeyVersion, []byte(node.Namespace), bucketKeyObjectContent, bucketKeyObjectIngests, []byte(node.Key))
@@ -456,25 +435,8 @@ func remove(ctx context.Context, tx *bolt.Tx, node gc.Node) error {
456435
return nil
457436
}
458437

459-
// sendSnapshotRefs sends all snapshot references referred to by the labels in the bkt
460-
func sendSnapshotRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
461-
lbkt := bkt.Bucket(bucketKeyObjectLabels)
462-
if lbkt != nil {
463-
lc := lbkt.Cursor()
464-
465-
for k, v := lc.Seek(labelGCSnapRef); k != nil && strings.HasPrefix(string(k), string(labelGCSnapRef)); k, v = lc.Next() {
466-
snapshotter := k[len(labelGCSnapRef):]
467-
if i := bytes.IndexByte(snapshotter, '/'); i >= 0 {
468-
snapshotter = snapshotter[:i]
469-
}
470-
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, v)))
471-
}
472-
}
473-
return nil
474-
}
475-
476-
// sendContentRefs sends all content references referred to by the labels in the bkt
477-
func sendContentRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
438+
// sendLabelRefs sends all snapshot and content references referred to by the labels in the bkt
439+
func sendLabelRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
478440
lbkt := bkt.Bucket(bucketKeyObjectLabels)
479441
if lbkt != nil {
480442
lc := lbkt.Cursor()
@@ -490,6 +452,15 @@ func sendContentRefs(ns string, bkt *bolt.Bucket, fn func(gc.Node)) error {
490452

491453
fn(gcnode(ResourceContent, ns, string(v)))
492454
}
455+
456+
for k, v := lc.Seek(labelGCSnapRef); k != nil && strings.HasPrefix(string(k), string(labelGCSnapRef)); k, v = lc.Next() {
457+
snapshotter := k[len(labelGCSnapRef):]
458+
if i := bytes.IndexByte(snapshotter, '/'); i >= 0 {
459+
snapshotter = snapshotter[:i]
460+
}
461+
fn(gcnode(ResourceSnapshot, ns, fmt.Sprintf("%s/%s", snapshotter, v)))
462+
}
463+
493464
}
494465
return nil
495466
}
@@ -506,17 +477,6 @@ func isRootRef(bkt *bolt.Bucket) bool {
506477
return false
507478
}
508479

509-
func sendRootRef(ctx context.Context, nc chan<- gc.Node, n gc.Node, bkt *bolt.Bucket) error {
510-
if isRootRef(bkt) {
511-
select {
512-
case nc <- n:
513-
case <-ctx.Done():
514-
return ctx.Err()
515-
}
516-
}
517-
return nil
518-
}
519-
520480
func gcnode(t gc.ResourceType, ns, key string) gc.Node {
521481
return gc.Node{
522482
Type: t,

metadata/gc_test.go

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,16 @@ func TestGCRoots(t *testing.T) {
4343
alters := []alterFunc{
4444
addImage("ns1", "image1", dgst(1), nil),
4545
addImage("ns1", "image2", dgst(2), labelmap(string(labelGCSnapRef)+"overlay", "sn2")),
46+
addImage("ns2", "image3", dgst(10), labelmap(string(labelGCContentRef), dgst(11).String())),
4647
addContainer("ns1", "container1", "overlay", "sn4", nil),
4748
addContainer("ns1", "container2", "overlay", "sn5", labelmap(string(labelGCSnapRef)+"overlay", "sn6")),
48-
addContainer("ns1", "container3", "overlay", "sn7", labelmap(string(labelGCSnapRef)+"overlay/anything-1", "sn8", string(labelGCSnapRef)+"overlay/anything-2", "sn9")),
49+
addContainer("ns1", "container3", "overlay", "sn7", labelmap(
50+
string(labelGCSnapRef)+"overlay/anything-1", "sn8",
51+
string(labelGCSnapRef)+"overlay/anything-2", "sn9",
52+
string(labelGCContentRef), dgst(7).String())),
53+
addContainer("ns1", "container4", "", "", labelmap(
54+
string(labelGCContentRef)+".0", dgst(8).String(),
55+
string(labelGCContentRef)+".1", dgst(9).String())),
4956
addContent("ns1", dgst(1), nil),
5057
addContent("ns1", dgst(2), nil),
5158
addContent("ns1", dgst(3), nil),
@@ -88,10 +95,15 @@ func TestGCRoots(t *testing.T) {
8895
expected := []gc.Node{
8996
gcnode(ResourceContent, "ns1", dgst(1).String()),
9097
gcnode(ResourceContent, "ns1", dgst(2).String()),
98+
gcnode(ResourceContent, "ns1", dgst(7).String()),
99+
gcnode(ResourceContent, "ns1", dgst(8).String()),
100+
gcnode(ResourceContent, "ns1", dgst(9).String()),
91101
gcnode(ResourceContent, "ns2", dgst(2).String()),
92102
gcnode(ResourceContent, "ns2", dgst(4).String()),
93103
gcnode(ResourceContent, "ns2", dgst(5).String()),
94104
gcnode(ResourceContent, "ns2", dgst(6).String()),
105+
gcnode(ResourceContent, "ns2", dgst(10).String()),
106+
gcnode(ResourceContent, "ns2", dgst(11).String()),
95107
gcnode(ResourceSnapshot, "ns1", "overlay/sn2"),
96108
gcnode(ResourceSnapshot, "ns1", "overlay/sn3"),
97109
gcnode(ResourceSnapshot, "ns1", "overlay/sn4"),
@@ -253,6 +265,9 @@ func TestGCRefs(t *testing.T) {
253265
addSnapshot("ns1", "btrfs", "sn1", "", nil),
254266
addSnapshot("ns2", "overlay", "sn1", "", nil),
255267
addSnapshot("ns2", "overlay", "sn2", "sn1", nil),
268+
addSnapshot("ns2", "overlay", "sn3", "", labelmap(
269+
string(labelGCContentRef), dgst(1).String(),
270+
string(labelGCContentRef)+".keep-me", dgst(6).String())),
256271
}
257272

258273
refs := map[gc.Node][]gc.Node{
@@ -293,6 +308,10 @@ func TestGCRefs(t *testing.T) {
293308
gcnode(ResourceSnapshot, "ns2", "overlay/sn2"): {
294309
gcnode(ResourceSnapshot, "ns2", "overlay/sn1"),
295310
},
311+
gcnode(ResourceSnapshot, "ns2", "overlay/sn3"): {
312+
gcnode(ResourceContent, "ns2", dgst(1).String()),
313+
gcnode(ResourceContent, "ns2", dgst(6).String()),
314+
},
296315
gcnode(ResourceIngest, "ns1", "ingest-1"): nil,
297316
gcnode(ResourceIngest, "ns2", "ingest-2"): {
298317
gcnode(ResourceContent, "ns2", dgst(8).String()),

0 commit comments

Comments
 (0)