@@ -199,8 +199,26 @@ type DiffOptions struct {
199199// stagedLayerOptions are the options passed to .create to populate a staged
200200// layer
201201type stagedLayerOptions struct {
202+ // These are used via the zstd:chunked pull paths
202203 DiffOutput * drivers.DriverWithDifferOutput
203204 DiffOptions * drivers.ApplyDiffWithDifferOpts
205+
206+ // stagedLayerExtraction is used by the normal tar layer extraction.
207+ stagedLayerExtraction * maybeStagedLayerExtraction
208+ }
209+
210+ // maybeStagedLayerExtraction is a helper to encapsulate details around extracting
211+ // a layer potentially before we even take a look if the driver implements the
212+ // ApplyDiffStaging interface.
213+ type maybeStagedLayerExtraction struct {
214+ // diff contains the tar archive, can be compressed
215+ diff io.Reader
216+ staging drivers.ApplyDiffStaging
217+ result * applyDiffResult
218+
219+ cleanupFuncs []tempdir.CleanupTempDirFunc
220+ stagedTarSplit * tempdir.StageAddition
221+ stagedLayer * tempdir.StageAddition
204222}
205223
206224type applyDiffResult struct {
@@ -300,7 +318,7 @@ type rwLayerStore interface {
300318 // underlying drivers do not themselves distinguish between writeable
301319 // and read-only layers. Returns the new layer structure and the size of the
302320 // diff which was applied to its parent to initialize its contents.
303- create (id string , parent * Layer , names []string , mountLabel string , options map [string ]string , moreOptions * LayerOptions , writeable bool , diff io. Reader , slo * stagedLayerOptions ) (* Layer , int64 , error )
321+ create (id string , parent * Layer , names []string , mountLabel string , options map [string ]string , moreOptions * LayerOptions , writeable bool , slo * stagedLayerOptions ) (* Layer , int64 , error )
304322
305323 // updateNames modifies names associated with a layer based on (op, names).
306324 updateNames (id string , names []string , op updateNameOperation ) error
@@ -1391,7 +1409,7 @@ func (r *layerStore) pickStoreLocation(volatile, writeable bool) layerLocations
13911409}
13921410
13931411// Requires startWriting.
1394- func (r * layerStore ) create (id string , parentLayer * Layer , names []string , mountLabel string , options map [string ]string , moreOptions * LayerOptions , writeable bool , diff io. Reader , slo * stagedLayerOptions ) (layer * Layer , size int64 , err error ) {
1412+ func (r * layerStore ) create (id string , parentLayer * Layer , names []string , mountLabel string , options map [string ]string , moreOptions * LayerOptions , writeable bool , slo * stagedLayerOptions ) (layer * Layer , size int64 , err error ) {
13951413 if moreOptions == nil {
13961414 moreOptions = & LayerOptions {}
13971415 }
@@ -1580,15 +1598,28 @@ func (r *layerStore) create(id string, parentLayer *Layer, names []string, mount
15801598 }
15811599
15821600 size = - 1
1583- if diff != nil {
1584- if size , err = r .applyDiffWithOptions (layer .ID , moreOptions , diff ); err != nil {
1585- cleanupFailureContext = "applying layer diff"
1586- return nil , - 1 , err
1587- }
1588- } else if slo != nil {
1589- if err := r .applyDiffFromStagingDirectory (layer .ID , slo .DiffOutput , slo .DiffOptions ); err != nil {
1590- cleanupFailureContext = "applying staged directory diff"
1591- return nil , - 1 , err
1601+ if slo != nil {
1602+ if slo .stagedLayerExtraction != nil {
1603+ if slo .stagedLayerExtraction .result != nil {
1604+ // The layer is staged, just commit it and update the metadata.
1605+ if err := slo .stagedLayerExtraction .commitLayer (r , layer .ID ); err != nil {
1606+ cleanupFailureContext = "commiting staged layer diff"
1607+ return nil , - 1 , err
1608+ }
1609+ applyDiffResultToLayer (r , layer , moreOptions , slo .stagedLayerExtraction .result )
1610+ } else {
1611+ // The diff was not staged, apply it now here instead.
1612+ if size , err = r .applyDiffWithOptions (layer .ID , moreOptions , slo .stagedLayerExtraction .diff ); err != nil {
1613+ cleanupFailureContext = "applying layer diff"
1614+ return nil , - 1 , err
1615+ }
1616+ }
1617+ } else {
1618+ // staging logic for the chunked pull path
1619+ if err := r .applyDiffFromStagingDirectory (layer .ID , slo .DiffOutput , slo .DiffOptions ); err != nil {
1620+ cleanupFailureContext = "applying staged directory diff"
1621+ return nil , - 1 , err
1622+ }
15921623 }
15931624 } else {
15941625 // applyDiffWithOptions() would have updated r.bycompressedsum
@@ -2417,6 +2448,78 @@ func createTarSplitFile(r *layerStore, layerID string) (*os.File, error) {
24172448 return os .OpenFile (r .tspath (layerID ), os .O_CREATE | os .O_WRONLY | os .O_TRUNC , 0o600 )
24182449}
24192450
2451+ // newMaybeStagedLayerExtraction initlaizes a new maybeStagedLayerExtraction. The caller
2452+ // must call .cleanup() to remove any temporary files.
2453+ func newMaybeStagedLayerExtraction (diff io.Reader , driver drivers.Driver ) * maybeStagedLayerExtraction {
2454+ m := & maybeStagedLayerExtraction {
2455+ diff : diff ,
2456+ }
2457+ if d , ok := driver .(drivers.ApplyDiffStaging ); ok {
2458+ m .staging = d
2459+ }
2460+ return m
2461+ }
2462+
2463+ func (sl * maybeStagedLayerExtraction ) cleanup () error {
2464+ return tempdir .CleanupTemporaryDirectories (sl .cleanupFuncs ... )
2465+ }
2466+
2467+ // stageWithUnlockedStore stages the layer content without needing the store locked.
2468+ // If the driver does not support stage addition then this is a NOP and does nothing.
2469+ func (sl * maybeStagedLayerExtraction ) stageWithUnlockedStore (r * layerStore , layerOptions * LayerOptions ) error {
2470+ if sl .staging == nil {
2471+ // driver does not implement stage addition
2472+ return nil
2473+ }
2474+ td , err := tempdir .NewTempDir (filepath .Join (r .layerdir , tempDirPath ))
2475+ if err != nil {
2476+ return err
2477+ }
2478+ sl .cleanupFuncs = append (sl .cleanupFuncs , td .Cleanup )
2479+
2480+ stageTarSplit , err := td .StageAddition ()
2481+ if err != nil {
2482+ return err
2483+ }
2484+ sl .stagedTarSplit = stageTarSplit
2485+
2486+ f , err := os .OpenFile (stageTarSplit .Path , os .O_CREATE | os .O_WRONLY | os .O_TRUNC , 0o600 )
2487+ if err != nil {
2488+ return err
2489+ }
2490+ defer f .Close ()
2491+
2492+ result , err := applyDiff (layerOptions , sl .diff , f , func (payload io.Reader ) (int64 , error ) {
2493+ cleanup , stageLayer , size , err := sl .staging .StartStagingDiffToApply (drivers.ApplyDiffOpts {
2494+ Diff : payload ,
2495+ Mappings : idtools .NewIDMappingsFromMaps (layerOptions .UIDMap , layerOptions .GIDMap ),
2496+ // FIXME: What to do here? We have no lock and assigned label yet.
2497+ // Overlayfs should not need it anyway so this seems fine for now.
2498+ MountLabel : "" ,
2499+ })
2500+ sl .cleanupFuncs = append (sl .cleanupFuncs , cleanup )
2501+ sl .stagedLayer = stageLayer
2502+ return size , err
2503+ })
2504+ if err != nil {
2505+ return err
2506+ }
2507+
2508+ sl .result = result
2509+ return nil
2510+ }
2511+
2512+ // commitLayer() commits the content that was staged in stageWithUnlockedStore()
2513+ //
2514+ // Requires startWriting.
2515+ func (sl * maybeStagedLayerExtraction ) commitLayer (r * layerStore , layerID string ) error {
2516+ err := sl .stagedTarSplit .Commit (r .tspath (layerID ))
2517+ if err != nil {
2518+ return err
2519+ }
2520+ return sl .staging .CommitStagedLayer (layerID , sl .stagedLayer )
2521+ }
2522+
24202523func applyDiff (layerOptions * LayerOptions , diff io.Reader , tarSplitFile * os.File , applyDriverFunc func (io.Reader ) (int64 , error )) (* applyDiffResult , error ) {
24212524 header := make ([]byte , 10240 )
24222525 n , err := diff .Read (header )
0 commit comments