Skip to content

Commit 4cc2aa3

Browse files
committed
overlay: add StartStagingDiffToApply()
Add a function to apply the diff into a tmporary directory so we can do that unlcoked and only rename under the lock. Signed-off-by: Paul Holzinger <[email protected]>
1 parent 7418c95 commit 4cc2aa3

File tree

3 files changed

+66
-8
lines changed

3 files changed

+66
-8
lines changed

storage/drivers/driver.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,15 @@ type DriverWithDiffer interface {
299299
DifferTarget(id string) (string, error)
300300
}
301301

302+
// ApplyDiffStaging is an interface for driver who can apply the diff without holding the main storage lock.
303+
// This API is experimental and can be changed without bumping the major version number.
304+
type ApplyDiffStaging interface {
305+
// StartStagingDiffToApply applies the layer in a temporary directory. This can be done without holding the storage lock.
306+
StartStagingDiffToApply(id, parent string, options ApplyDiffOpts) (tempdir.CleanupTempDirFunc, tempdir.CommitFunc, int64, error)
307+
// CommitStagedLayer commits the staged layer from StartStagingDiffToApply(). This must be done while the storage lock.
308+
CommitStagedLayer(id string, commit tempdir.CommitFunc) error
309+
}
310+
302311
// Capabilities defines a list of capabilities a driver may implement.
303312
// These capabilities are not required; however, they do determine how a
304313
// graphdriver can be used.

storage/drivers/overlay/overlay.go

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2369,21 +2369,67 @@ func (d *Driver) DifferTarget(id string) (string, error) {
23692369
return d.getDiffPath(id)
23702370
}
23712371

2372-
// ApplyDiff applies the new layer into a root
2373-
func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) (size int64, err error) {
2374-
idMappings := options.Mappings
2375-
if idMappings == nil {
2376-
idMappings = &idtools.IDMappings{}
2372+
// StartStagingDiffToApply applies the new layer into a temporary directory.
2373+
// It returns a CleanupTempDirFunc which can nil or set regardless if the function return an error or not.
2374+
// CommitFunc is only set when there is no error returned and the int64 value returns the size of the layer.
2375+
//
2376+
// This API is experimental and can be changed without bumping the major version number.
2377+
func (d *Driver) StartStagingDiffToApply(id, parent string, options graphdriver.ApplyDiffOpts) (tempdir.CleanupTempDirFunc, tempdir.CommitFunc, int64, error) {
2378+
tempDirRoot := d.getTempDirRoot(id)
2379+
t, err := tempdir.NewTempDir(tempDirRoot)
2380+
if err != nil {
2381+
return nil, nil, -1, err
2382+
}
2383+
2384+
var size int64
2385+
sa, err := t.StageDirectoryAddition(func(path string) error {
2386+
size, err = d.applyDiff(id, path, options)
2387+
return err
2388+
})
2389+
if err != nil {
2390+
return t.Cleanup, nil, -1, err
2391+
}
2392+
2393+
return t.Cleanup, sa.Commit, size, nil
2394+
}
2395+
2396+
// CommitStagedLayer that was created with StartStagingDiffToApply().
2397+
//
2398+
// This API is experimental and can be changed without bumping the major version number.
2399+
func (d *Driver) CommitStagedLayer(id string, commit tempdir.CommitFunc) error {
2400+
applyDir, err := d.getDiffPath(id)
2401+
if err != nil {
2402+
return err
23772403
}
23782404

2405+
// The os.Rename() function used by CommitFunc errors when the target directory already
2406+
// exists, as such delete the dir if it already exists.
2407+
if err := os.Remove(applyDir); err != nil && !errors.Is(err, fs.ErrNotExist) {
2408+
return err
2409+
}
2410+
2411+
return commit(applyDir)
2412+
}
2413+
2414+
// ApplyDiff applies the new layer into a root
2415+
func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) (size int64, err error) {
23792416
applyDir, err := d.getDiffPath(id)
23802417
if err != nil {
23812418
return 0, err
23822419
}
2420+
return d.applyDiff(id, applyDir, options)
2421+
}
2422+
2423+
// ApplyDiff applies the new layer into a root
2424+
func (d *Driver) applyDiff(id, target string, options graphdriver.ApplyDiffOpts) (size int64, err error) {
2425+
idMappings := options.Mappings
2426+
if idMappings == nil {
2427+
idMappings = &idtools.IDMappings{}
2428+
}
23832429

2384-
logrus.Debugf("Applying tar in %s", applyDir)
2430+
logrus.Debugf("Applying tar in %s", target)
23852431
// Overlay doesn't need the parent id to apply the diff
2386-
if err := untar(options.Diff, applyDir, &archive.TarOptions{
2432+
if err := untar(options.Diff, target, &archive.TarOptions{
23872433
UIDMaps: idMappings.UIDs(),
23882434
GIDMaps: idMappings.GIDs(),
23892435
IgnoreChownErrors: d.options.ignoreChownErrors,
@@ -2394,7 +2440,7 @@ func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts)
23942440
return 0, err
23952441
}
23962442

2397-
return directory.Size(applyDir)
2443+
return directory.Size(target)
23982444
}
23992445

24002446
func (d *Driver) getComposefsData(id string) string {

storage/drivers/overlay/overlay_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import (
1717

1818
const driverName = "overlay"
1919

20+
// check that Driver correctly implements the ApplyDiffTemporary interface
21+
var _ graphdriver.ApplyDiffStaging = &Driver{}
22+
2023
func init() {
2124
// Do not sure chroot to speed run time and allow archive
2225
// errors or hangs to be debugged directly from the test process.

0 commit comments

Comments
 (0)