@@ -272,8 +272,14 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
272272 return err
273273 }
274274
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+ }
277283
278284 ra , err := c .contentStore .ReaderAt (ctx , desc )
279285 if err != nil {
@@ -343,6 +349,17 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
343349
344350 state := calc .State ()
345351
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+
346363 c .mu .Lock ()
347364 c .blobMap [desc .Digest ] = state
348365 c .layerBlobs [state .diffID ] = desc
@@ -351,6 +368,40 @@ func (c *Converter) fetchBlob(ctx context.Context, desc ocispec.Descriptor) erro
351368 return nil
352369}
353370
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+
354405func (c * Converter ) schema1ManifestHistory () ([]ocispec.History , []digest.Digest , error ) {
355406 if c .pulledManifest == nil {
356407 return nil , nil , errors .New ("missing schema 1 manifest for conversion" )
0 commit comments