Skip to content

Commit c8141a1

Browse files
authored
Merge pull request moby#32293 from moypray/save_delete
Fix delete a image while saving it, delete successfully but failed to save it
2 parents 34f1cd2 + 4a014e6 commit c8141a1

File tree

1 file changed

+67
-20
lines changed

1 file changed

+67
-20
lines changed

image/tarexport/save.go

+67-20
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@ import (
2121
)
2222

2323
type imageDescriptor struct {
24-
refs []reference.NamedTagged
25-
layers []string
24+
refs []reference.NamedTagged
25+
layers []string
26+
image *image.Image
27+
layerRef layer.Layer
2628
}
2729

2830
type saveSession struct {
@@ -39,33 +41,47 @@ func (l *tarexporter) Save(names []string, outStream io.Writer) error {
3941
return err
4042
}
4143

44+
// Release all the image top layer references
45+
defer l.releaseLayerReferences(images)
4246
return (&saveSession{tarexporter: l, images: images}).save(outStream)
4347
}
4448

45-
func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor, error) {
49+
// parseNames will parse the image names to a map which contains image.ID to *imageDescriptor.
50+
// Each imageDescriptor holds an image top layer reference named 'layerRef'. It is taken here, should be released later.
51+
func (l *tarexporter) parseNames(names []string) (desc map[image.ID]*imageDescriptor, rErr error) {
4652
imgDescr := make(map[image.ID]*imageDescriptor)
53+
defer func() {
54+
if rErr != nil {
55+
l.releaseLayerReferences(imgDescr)
56+
}
57+
}()
4758

48-
addAssoc := func(id image.ID, ref reference.Named) {
59+
addAssoc := func(id image.ID, ref reference.Named) error {
4960
if _, ok := imgDescr[id]; !ok {
50-
imgDescr[id] = &imageDescriptor{}
61+
descr := &imageDescriptor{}
62+
if err := l.takeLayerReference(id, descr); err != nil {
63+
return err
64+
}
65+
imgDescr[id] = descr
5166
}
5267

5368
if ref != nil {
5469
if _, ok := ref.(reference.Canonical); ok {
55-
return
70+
return nil
5671
}
5772
tagged, ok := reference.TagNameOnly(ref).(reference.NamedTagged)
5873
if !ok {
59-
return
74+
return nil
6075
}
6176

6277
for _, t := range imgDescr[id].refs {
6378
if tagged.String() == t.String() {
64-
return
79+
return nil
6580
}
6681
}
6782
imgDescr[id].refs = append(imgDescr[id].refs, tagged)
6883
}
84+
return nil
6985
}
7086

7187
for _, name := range names {
@@ -78,11 +94,9 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
7894
// Check if digest ID reference
7995
if digested, ok := ref.(reference.Digested); ok {
8096
id := image.IDFromDigest(digested.Digest())
81-
_, err := l.is.Get(id)
82-
if err != nil {
97+
if err := addAssoc(id, nil); err != nil {
8398
return nil, err
8499
}
85-
addAssoc(id, nil)
86100
continue
87101
}
88102
return nil, errors.Errorf("invalid reference: %v", name)
@@ -93,33 +107,70 @@ func (l *tarexporter) parseNames(names []string) (map[image.ID]*imageDescriptor,
93107
if err != nil {
94108
return nil, err
95109
}
96-
addAssoc(imgID, nil)
110+
if err := addAssoc(imgID, nil); err != nil {
111+
return nil, err
112+
}
97113
continue
98114
}
99115
if reference.IsNameOnly(namedRef) {
100116
assocs := l.rs.ReferencesByName(namedRef)
101117
for _, assoc := range assocs {
102-
addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref)
118+
if err := addAssoc(image.IDFromDigest(assoc.ID), assoc.Ref); err != nil {
119+
return nil, err
120+
}
103121
}
104122
if len(assocs) == 0 {
105123
imgID, err := l.is.Search(name)
106124
if err != nil {
107125
return nil, err
108126
}
109-
addAssoc(imgID, nil)
127+
if err := addAssoc(imgID, nil); err != nil {
128+
return nil, err
129+
}
110130
}
111131
continue
112132
}
113133
id, err := l.rs.Get(namedRef)
114134
if err != nil {
115135
return nil, err
116136
}
117-
addAssoc(image.IDFromDigest(id), namedRef)
137+
if err := addAssoc(image.IDFromDigest(id), namedRef); err != nil {
138+
return nil, err
139+
}
118140

119141
}
120142
return imgDescr, nil
121143
}
122144

145+
// takeLayerReference will take/Get the image top layer reference
146+
func (l *tarexporter) takeLayerReference(id image.ID, imgDescr *imageDescriptor) error {
147+
img, err := l.is.Get(id)
148+
if err != nil {
149+
return err
150+
}
151+
imgDescr.image = img
152+
topLayerID := img.RootFS.ChainID()
153+
if topLayerID == "" {
154+
return nil
155+
}
156+
layer, err := l.ls.Get(topLayerID)
157+
if err != nil {
158+
return err
159+
}
160+
imgDescr.layerRef = layer
161+
return nil
162+
}
163+
164+
// releaseLayerReferences will release all the image top layer references
165+
func (l *tarexporter) releaseLayerReferences(imgDescr map[image.ID]*imageDescriptor) error {
166+
for _, descr := range imgDescr {
167+
if descr.layerRef != nil {
168+
l.ls.Release(descr.layerRef)
169+
}
170+
}
171+
return nil
172+
}
173+
123174
func (s *saveSession) save(outStream io.Writer) error {
124175
s.savedLayers = make(map[string]struct{})
125176
s.diffIDPaths = make(map[layer.DiffID]string)
@@ -224,11 +275,7 @@ func (s *saveSession) save(outStream io.Writer) error {
224275
}
225276

226277
func (s *saveSession) saveImage(id image.ID) (map[layer.DiffID]distribution.Descriptor, error) {
227-
img, err := s.is.Get(id)
228-
if err != nil {
229-
return nil, err
230-
}
231-
278+
img := s.images[id].image
232279
if len(img.RootFS.DiffIDs) == 0 {
233280
return nil, fmt.Errorf("empty export - not implemented")
234281
}

0 commit comments

Comments
 (0)