@@ -272,8 +272,14 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
272
272
return err
273
273
}
274
274
275
- // TODO: Check if blob -> diff id mapping already exists
276
- // TODO: Check if blob empty label exists
275
+ reuse , err := c .reuseLabelBlobState (ctx , desc )
276
+ if err != nil {
277
+ return err
278
+ }
279
+
280
+ if reuse {
281
+ return nil
282
+ }
277
283
278
284
ra , err := c .contentStore .ReaderAt (ctx , desc )
279
285
if err != nil {
@@ -343,6 +349,17 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
343
349
344
350
state := calc .State ()
345
351
352
+ cinfo := content.Info {
353
+ Digest : desc .Digest ,
354
+ Labels : map [string ]string {
355
+ "containerd.io/uncompressed" : state .diffID .String (),
356
+ },
357
+ }
358
+
359
+ if _ , err := c .contentStore .Update (ctx , cinfo , "labels.containerd.io/uncompressed" ); err != nil {
360
+ return errors .Wrap (err , "failed to update uncompressed label" )
361
+ }
362
+
346
363
c .mu .Lock ()
347
364
c .blobMap [desc .Digest ] = state
348
365
c .layerBlobs [state .diffID ] = desc
@@ -351,6 +368,40 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
351
368
return nil
352
369
}
353
370
371
+ func (c * Converter ) reuseLabelBlobState (ctx context.Context , desc ocispec.Descriptor ) (bool , error ) {
372
+ cinfo , err := c .contentStore .Info (ctx , desc .Digest )
373
+ if err != nil {
374
+ return false , errors .Wrap (err , "failed to get blob info" )
375
+ }
376
+ desc .Size = cinfo .Size
377
+
378
+ diffID , ok := cinfo .Labels ["containerd.io/uncompressed" ]
379
+ if ! ok {
380
+ return false , nil
381
+ }
382
+
383
+ bState := blobState {empty : false }
384
+
385
+ if bState .diffID , err = digest .Parse (diffID ); err != nil {
386
+ log .G (ctx ).WithField ("id" , desc .Digest ).Warnf ("failed to parse digest from label containerd.io/uncompressed: %v" , diffID )
387
+ return false , nil
388
+ }
389
+
390
+ // NOTE: there is no need to read header to get compression method
391
+ // because there are only two kinds of methods.
392
+ if bState .diffID == desc .Digest {
393
+ desc .MediaType = images .MediaTypeDockerSchema2Layer
394
+ } else {
395
+ desc .MediaType = images .MediaTypeDockerSchema2LayerGzip
396
+ }
397
+
398
+ c .mu .Lock ()
399
+ c .blobMap [desc .Digest ] = bState
400
+ c .layerBlobs [bState .diffID ] = desc
401
+ c .mu .Unlock ()
402
+ return true , nil
403
+ }
404
+
354
405
func (c * Converter ) schema1ManifestHistory () ([]ocispec.History , []digest.Digest , error ) {
355
406
if c .pulledManifest == nil {
356
407
return nil , nil , errors .New ("missing schema 1 manifest for conversion" )
0 commit comments