@@ -11,6 +11,7 @@ import (
11
11
"github.com/containers/image/v5/pkg/compression"
12
12
compressiontypes "github.com/containers/image/v5/pkg/compression/types"
13
13
"github.com/containers/image/v5/types"
14
+ chunkedToc "github.com/containers/storage/pkg/chunked/toc"
14
15
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
15
16
"github.com/sirupsen/logrus"
16
17
)
@@ -34,10 +35,10 @@ var (
34
35
35
36
// bpDetectCompressionStepData contains data that the copy pipeline needs about the “detect compression” step.
36
37
type bpDetectCompressionStepData struct {
37
- isCompressed bool
38
- format compressiontypes.Algorithm // Valid if isCompressed
39
- decompressor compressiontypes.DecompressorFunc // Valid if isCompressed
40
- srcCompressorName string // Compressor name to possibly record in the blob info cache for the source blob.
38
+ isCompressed bool
39
+ format compressiontypes.Algorithm // Valid if isCompressed
40
+ decompressor compressiontypes.DecompressorFunc // Valid if isCompressed
41
+ srcCompressorBaseVariantName string // Compressor name to possibly record in the blob info cache for the source blob.
41
42
}
42
43
43
44
// blobPipelineDetectCompressionStep updates *stream to detect its current compression format.
@@ -51,15 +52,25 @@ func blobPipelineDetectCompressionStep(stream *sourceStream, srcInfo types.BlobI
51
52
}
52
53
stream .reader = reader
53
54
55
+ if decompressor != nil && format .Name () == compressiontypes .ZstdAlgorithmName {
56
+ tocDigest , err := chunkedToc .GetTOCDigest (srcInfo .Annotations )
57
+ if err != nil {
58
+ return bpDetectCompressionStepData {}, err
59
+ }
60
+ if tocDigest != nil {
61
+ format = compression .ZstdChunked
62
+ }
63
+
64
+ }
54
65
res := bpDetectCompressionStepData {
55
66
isCompressed : decompressor != nil ,
56
67
format : format ,
57
68
decompressor : decompressor ,
58
69
}
59
70
if res .isCompressed {
60
- res .srcCompressorName = format .Name ()
71
+ res .srcCompressorBaseVariantName = format .BaseVariantName ()
61
72
} else {
62
- res .srcCompressorName = internalblobinfocache .Uncompressed
73
+ res .srcCompressorBaseVariantName = internalblobinfocache .Uncompressed
63
74
}
64
75
65
76
if expectedBaseFormat , known := expectedBaseCompressionFormats [stream .info .MediaType ]; known && res .isCompressed && format .BaseVariantName () != expectedBaseFormat .Name () {
@@ -70,13 +81,14 @@ func blobPipelineDetectCompressionStep(stream *sourceStream, srcInfo types.BlobI
70
81
71
82
// bpCompressionStepData contains data that the copy pipeline needs about the compression step.
72
83
type bpCompressionStepData struct {
73
- operation bpcOperation // What we are actually doing
74
- uploadedOperation types.LayerCompression // Operation to use for updating the blob metadata (matching the end state, not necessarily what we do)
75
- uploadedAlgorithm * compressiontypes.Algorithm // An algorithm parameter for the compressionOperation edits.
76
- uploadedAnnotations map [string ]string // Compression-related annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
77
- srcCompressorName string // Compressor name to record in the blob info cache for the source blob.
78
- uploadedCompressorName string // Compressor name to record in the blob info cache for the uploaded blob.
79
- closers []io.Closer // Objects to close after the upload is done, if any.
84
+ operation bpcOperation // What we are actually doing
85
+ uploadedOperation types.LayerCompression // Operation to use for updating the blob metadata (matching the end state, not necessarily what we do)
86
+ uploadedAlgorithm * compressiontypes.Algorithm // An algorithm parameter for the compressionOperation edits.
87
+ uploadedAnnotations map [string ]string // Compression-related annotations that should be set on the uploaded blob. WARNING: This is only set after the srcStream.reader is fully consumed.
88
+ srcCompressorBaseVariantName string // Compressor base variant name to record in the blob info cache for the source blob.
89
+ uploadedCompressorBaseVariantName string // Compressor base variant name to record in the blob info cache for the uploaded blob.
90
+ uploadedCompressorSpecificVariantName string // Compressor specific variant name to record in the blob info cache for the uploaded blob.
91
+ closers []io.Closer // Objects to close after the upload is done, if any.
80
92
}
81
93
82
94
type bpcOperation int
@@ -128,11 +140,12 @@ func (ic *imageCopier) bpcPreserveEncrypted(stream *sourceStream, _ bpDetectComp
128
140
// We can’t do anything with an encrypted blob unless decrypted.
129
141
logrus .Debugf ("Using original blob without modification for encrypted blob" )
130
142
return & bpCompressionStepData {
131
- operation : bpcOpPreserveOpaque ,
132
- uploadedOperation : types .PreserveOriginal ,
133
- uploadedAlgorithm : nil ,
134
- srcCompressorName : internalblobinfocache .UnknownCompression ,
135
- uploadedCompressorName : internalblobinfocache .UnknownCompression ,
143
+ operation : bpcOpPreserveOpaque ,
144
+ uploadedOperation : types .PreserveOriginal ,
145
+ uploadedAlgorithm : nil ,
146
+ srcCompressorBaseVariantName : internalblobinfocache .UnknownCompression ,
147
+ uploadedCompressorBaseVariantName : internalblobinfocache .UnknownCompression ,
148
+ uploadedCompressorSpecificVariantName : internalblobinfocache .UnknownCompression ,
136
149
}, nil
137
150
}
138
151
return nil , nil
@@ -156,14 +169,19 @@ func (ic *imageCopier) bpcCompressUncompressed(stream *sourceStream, detected bp
156
169
Digest : "" ,
157
170
Size : - 1 ,
158
171
}
172
+ specificVariantName := uploadedAlgorithm .Name ()
173
+ if specificVariantName == uploadedAlgorithm .BaseVariantName () {
174
+ specificVariantName = internalblobinfocache .UnknownCompression
175
+ }
159
176
return & bpCompressionStepData {
160
- operation : bpcOpCompressUncompressed ,
161
- uploadedOperation : types .Compress ,
162
- uploadedAlgorithm : uploadedAlgorithm ,
163
- uploadedAnnotations : annotations ,
164
- srcCompressorName : detected .srcCompressorName ,
165
- uploadedCompressorName : uploadedAlgorithm .Name (),
166
- closers : []io.Closer {reader },
177
+ operation : bpcOpCompressUncompressed ,
178
+ uploadedOperation : types .Compress ,
179
+ uploadedAlgorithm : uploadedAlgorithm ,
180
+ uploadedAnnotations : annotations ,
181
+ srcCompressorBaseVariantName : detected .srcCompressorBaseVariantName ,
182
+ uploadedCompressorBaseVariantName : uploadedAlgorithm .BaseVariantName (),
183
+ uploadedCompressorSpecificVariantName : specificVariantName ,
184
+ closers : []io.Closer {reader },
167
185
}, nil
168
186
}
169
187
return nil , nil
@@ -196,15 +214,20 @@ func (ic *imageCopier) bpcRecompressCompressed(stream *sourceStream, detected bp
196
214
Digest : "" ,
197
215
Size : - 1 ,
198
216
}
217
+ specificVariantName := ic .compressionFormat .Name ()
218
+ if specificVariantName == ic .compressionFormat .BaseVariantName () {
219
+ specificVariantName = internalblobinfocache .UnknownCompression
220
+ }
199
221
succeeded = true
200
222
return & bpCompressionStepData {
201
- operation : bpcOpRecompressCompressed ,
202
- uploadedOperation : types .PreserveOriginal ,
203
- uploadedAlgorithm : ic .compressionFormat ,
204
- uploadedAnnotations : annotations ,
205
- srcCompressorName : detected .srcCompressorName ,
206
- uploadedCompressorName : ic .compressionFormat .Name (),
207
- closers : []io.Closer {decompressed , recompressed },
223
+ operation : bpcOpRecompressCompressed ,
224
+ uploadedOperation : types .PreserveOriginal ,
225
+ uploadedAlgorithm : ic .compressionFormat ,
226
+ uploadedAnnotations : annotations ,
227
+ srcCompressorBaseVariantName : detected .srcCompressorBaseVariantName ,
228
+ uploadedCompressorBaseVariantName : ic .compressionFormat .BaseVariantName (),
229
+ uploadedCompressorSpecificVariantName : specificVariantName ,
230
+ closers : []io.Closer {decompressed , recompressed },
208
231
}, nil
209
232
}
210
233
return nil , nil
@@ -225,12 +248,13 @@ func (ic *imageCopier) bpcDecompressCompressed(stream *sourceStream, detected bp
225
248
Size : - 1 ,
226
249
}
227
250
return & bpCompressionStepData {
228
- operation : bpcOpDecompressCompressed ,
229
- uploadedOperation : types .Decompress ,
230
- uploadedAlgorithm : nil ,
231
- srcCompressorName : detected .srcCompressorName ,
232
- uploadedCompressorName : internalblobinfocache .Uncompressed ,
233
- closers : []io.Closer {s },
251
+ operation : bpcOpDecompressCompressed ,
252
+ uploadedOperation : types .Decompress ,
253
+ uploadedAlgorithm : nil ,
254
+ srcCompressorBaseVariantName : detected .srcCompressorBaseVariantName ,
255
+ uploadedCompressorBaseVariantName : internalblobinfocache .Uncompressed ,
256
+ uploadedCompressorSpecificVariantName : internalblobinfocache .UnknownCompression ,
257
+ closers : []io.Closer {s },
234
258
}, nil
235
259
}
236
260
return nil , nil
@@ -268,11 +292,15 @@ func (ic *imageCopier) bpcPreserveOriginal(_ *sourceStream, detected bpDetectCom
268
292
algorithm = nil
269
293
}
270
294
return & bpCompressionStepData {
271
- operation : bpcOp ,
272
- uploadedOperation : uploadedOp ,
273
- uploadedAlgorithm : algorithm ,
274
- srcCompressorName : detected .srcCompressorName ,
275
- uploadedCompressorName : detected .srcCompressorName ,
295
+ operation : bpcOp ,
296
+ uploadedOperation : uploadedOp ,
297
+ uploadedAlgorithm : algorithm ,
298
+ srcCompressorBaseVariantName : detected .srcCompressorBaseVariantName ,
299
+ // We only record the base variant of the format on upload; we didn’t do anything with
300
+ // the TOC, we don’t know whether it matches the blob digest, so we don’t want to trigger
301
+ // reuse of any kind between the blob digest and the TOC digest.
302
+ uploadedCompressorBaseVariantName : detected .srcCompressorBaseVariantName ,
303
+ uploadedCompressorSpecificVariantName : internalblobinfocache .UnknownCompression ,
276
304
}
277
305
}
278
306
@@ -308,6 +336,15 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
308
336
// No useful information
309
337
case bpcOpCompressUncompressed :
310
338
c .blobInfoCache .RecordDigestUncompressedPair (uploadedInfo .Digest , srcInfo .Digest )
339
+ if d .uploadedAnnotations != nil {
340
+ tocDigest , err := chunkedToc .GetTOCDigest (d .uploadedAnnotations )
341
+ if err != nil {
342
+ return fmt .Errorf ("parsing just-created compression annotations: %w" , err )
343
+ }
344
+ if tocDigest != nil {
345
+ c .blobInfoCache .RecordTOCUncompressedPair (* tocDigest , srcInfo .Digest )
346
+ }
347
+ }
311
348
case bpcOpDecompressCompressed :
312
349
c .blobInfoCache .RecordDigestUncompressedPair (srcInfo .Digest , uploadedInfo .Digest )
313
350
case bpcOpRecompressCompressed , bpcOpPreserveCompressed :
@@ -323,29 +360,27 @@ func (d *bpCompressionStepData) recordValidatedDigestData(c *copier, uploadedInf
323
360
return fmt .Errorf ("Internal error: Unexpected d.operation value %#v" , d .operation )
324
361
}
325
362
}
326
- if d .srcCompressorName == "" || d .uploadedCompressorName == "" {
327
- return fmt .Errorf ("internal error: missing compressor names (src: %q, uploaded: %q)" ,
328
- d .srcCompressorName , d .uploadedCompressorName )
363
+ if d .srcCompressorBaseVariantName == "" || d .uploadedCompressorBaseVariantName == "" || d . uploadedCompressorSpecificVariantName == "" {
364
+ return fmt .Errorf ("internal error: missing compressor names (src base : %q, uploaded base: %q, uploaded specific : %q)" ,
365
+ d .srcCompressorBaseVariantName , d .uploadedCompressorBaseVariantName , d . uploadedCompressorSpecificVariantName )
329
366
}
330
- if d .uploadedCompressorName != internalblobinfocache .UnknownCompression {
331
- if d .uploadedCompressorName != compressiontypes .ZstdChunkedAlgorithmName {
332
- // HACK: Don’t record zstd:chunked algorithms.
333
- // There is already a similar hack in internal/imagedestination/impl/helpers.CandidateMatchesTryReusingBlobOptions,
334
- // and that one prevents reusing zstd:chunked blobs, so recording the algorithm here would be mostly harmless.
335
- //
336
- // We skip that here anyway to work around the inability of blobPipelineDetectCompressionStep to differentiate
337
- // between zstd and zstd:chunked; so we could, in varying situations over time, call RecordDigestCompressorName
338
- // with the same digest and both ZstdAlgorithmName and ZstdChunkedAlgorithmName , which causes warnings about
339
- // inconsistent data to be logged.
340
- c .blobInfoCache .RecordDigestCompressorName (uploadedInfo .Digest , d .uploadedCompressorName )
341
- }
367
+ if d .uploadedCompressorBaseVariantName != internalblobinfocache .UnknownCompression {
368
+ c .blobInfoCache .RecordDigestCompressorData (uploadedInfo .Digest , internalblobinfocache.DigestCompressorData {
369
+ BaseVariantCompressor : d .uploadedCompressorBaseVariantName ,
370
+ SpecificVariantCompressor : d .uploadedCompressorSpecificVariantName ,
371
+ SpecificVariantAnnotations : d .uploadedAnnotations ,
372
+ })
342
373
}
343
374
if srcInfo .Digest != "" && srcInfo .Digest != uploadedInfo .Digest &&
344
- d .srcCompressorName != internalblobinfocache .UnknownCompression {
345
- if d .srcCompressorName != compressiontypes .ZstdChunkedAlgorithmName {
346
- // HACK: Don’t record zstd:chunked algorithms, see above.
347
- c .blobInfoCache .RecordDigestCompressorName (srcInfo .Digest , d .srcCompressorName )
348
- }
375
+ d .srcCompressorBaseVariantName != internalblobinfocache .UnknownCompression {
376
+ // If the source is already using some TOC-dependent variant, we either copied the
377
+ // blob as is, or perhaps decompressed it; either way we don’t trust the TOC digest,
378
+ // so record neither the variant name, nor the TOC digest.
379
+ c .blobInfoCache .RecordDigestCompressorData (srcInfo .Digest , internalblobinfocache.DigestCompressorData {
380
+ BaseVariantCompressor : d .srcCompressorBaseVariantName ,
381
+ SpecificVariantCompressor : internalblobinfocache .UnknownCompression ,
382
+ SpecificVariantAnnotations : nil ,
383
+ })
349
384
}
350
385
return nil
351
386
}
0 commit comments