-
Notifications
You must be signed in to change notification settings - Fork 33
WIP: Staged layer creation #378
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
a302c81
8332a27
ff03216
a6fa507
361278b
e60d339
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2369,31 +2369,91 @@ func (d *Driver) DifferTarget(id string) (string, error) { | |
| return d.getDiffPath(id) | ||
| } | ||
|
|
||
| // ApplyDiff applies the new layer into a root | ||
| func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) (size int64, err error) { | ||
| if !d.isParent(id, parent) { | ||
| if d.options.ignoreChownErrors { | ||
| options.IgnoreChownErrors = d.options.ignoreChownErrors | ||
| // StartStagingDiffToApply applies the new layer into a temporary directory. | ||
| // It returns a CleanupTempDirFunc which can nil or set regardless if the function return an error or not. | ||
| // CommitFunc is only set when there is no error returned and the int64 value returns the size of the layer. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Needs updating |
||
| // | ||
| // This API is experimental and can be changed without bumping the major version number. | ||
| func (d *Driver) StartStagingDiffToApply(options graphdriver.ApplyDiffOpts) (tempdir.CleanupTempDirFunc, *tempdir.StageAddition, int64, error) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A warning that this can run concurrently with any other operations on the driver would be nice (both here and in the interface definition). |
||
| // FIXME: how to consolidate with d.getTempDirRoot(id) if we don't have the id? | ||
| tempDirRoot := filepath.Join(d.homeDirForImageStore(), tempDirName) | ||
| t, err := tempdir.NewTempDir(tempDirRoot) | ||
| if err != nil { | ||
| return nil, nil, -1, err | ||
| } | ||
|
|
||
| sa, err := t.StageAddition() | ||
| if err != nil { | ||
| return nil, nil, -1, err | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing t.Cleanup? |
||
| } | ||
|
|
||
| size, err := d.applyDiff(sa.Path, options) | ||
| if err != nil { | ||
| return t.Cleanup, nil, -1, err | ||
| } | ||
|
|
||
| return t.Cleanup, sa, size, nil | ||
| } | ||
|
|
||
| // CommitStagedLayer that was created with StartStagingDiffToApply(). | ||
| // | ||
| // This API is experimental and can be changed without bumping the major version number. | ||
| func (d *Driver) CommitStagedLayer(id string, sa *tempdir.StageAddition) error { | ||
| applyDir, err := d.getDiffPath(id) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| // FIXME: Is there a better way to do this? | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (I agree, this suggests a refactoring might be possible and beneficial.) |
||
| stat, err := system.Stat(applyDir) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if err := os.Chmod(sa.Path, os.FileMode(stat.Mode())); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| if err := os.Chown(sa.Path, int(stat.UID()), int(stat.GID())); err != nil { | ||
| return err | ||
| } | ||
| if d.options.forceMask != nil { | ||
| st, err := idtools.GetContainersOverrideXattr(applyDir) | ||
| if err != nil { | ||
| return err | ||
| } | ||
| if d.options.forceMask != nil { | ||
| options.ForceMask = d.options.forceMask | ||
| if err := idtools.SetContainersOverrideXattr(sa.Path, st); err != nil { | ||
| return err | ||
| } | ||
| return d.naiveDiff.ApplyDiff(id, parent, options) | ||
| } | ||
|
|
||
| idMappings := options.Mappings | ||
| if idMappings == nil { | ||
| idMappings = &idtools.IDMappings{} | ||
| // The os.Rename() function used by CommitFunc errors when the target directory already | ||
| // exists, as such delete the dir. | ||
| if err := os.Remove(applyDir); err != nil { | ||
| return err | ||
| } | ||
|
|
||
| return sa.Commit(applyDir) | ||
| } | ||
|
|
||
| // ApplyDiff applies the new layer into a root | ||
| func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) (size int64, err error) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Absolutely non-blocking: BTW it seems that nothing is using the |
||
| applyDir, err := d.getDiffPath(id) | ||
| if err != nil { | ||
| return 0, err | ||
| } | ||
| return d.applyDiff(applyDir, options) | ||
| } | ||
|
|
||
| // ApplyDiff applies the new layer into a root | ||
| func (d *Driver) applyDiff(target string, options graphdriver.ApplyDiffOpts) (size int64, err error) { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A warning that this can run concurrently with any other operations on the driver would be nice. … and that might motivate auditing and documenting which fields of |
||
| idMappings := options.Mappings | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Non-blocking: So far, all callers were setting |
||
| if idMappings == nil { | ||
| idMappings = &idtools.IDMappings{} | ||
| } | ||
|
|
||
| logrus.Debugf("Applying tar in %s", applyDir) | ||
| logrus.Debugf("Applying tar in %s", target) | ||
| // Overlay doesn't need the parent id to apply the diff | ||
| if err := untar(options.Diff, applyDir, &archive.TarOptions{ | ||
| if err := untar(options.Diff, target, &archive.TarOptions{ | ||
| UIDMaps: idMappings.UIDs(), | ||
| GIDMaps: idMappings.GIDs(), | ||
| IgnoreChownErrors: d.options.ignoreChownErrors, | ||
|
|
@@ -2404,7 +2464,7 @@ func (d *Driver) ApplyDiff(id, parent string, options graphdriver.ApplyDiffOpts) | |
| return 0, err | ||
| } | ||
|
|
||
| return directory.Size(applyDir) | ||
| return directory.Size(target) | ||
| } | ||
|
|
||
| func (d *Driver) getComposefsData(id string) string { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -91,6 +91,30 @@ type TempDir struct { | |
| counter uint64 | ||
| } | ||
|
|
||
| // StageAddition is a temporary object which holds the information of where to | ||
| // put the data into and then use Commit() to move the data into the final location. | ||
| type StageAddition struct { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Maybe |
||
| // Path is the temporary path. The path is not created so caller must create | ||
| // a file or directory on it in order to use Commit(). The path is only valid | ||
| // until Commit() is called or until the TempDir instance Cleanup() method is used. | ||
| Path string | ||
| } | ||
|
|
||
| // CommitFunc is a function type that can be returned by operations | ||
| // which need to perform the commit operation later. | ||
| type CommitFunc func(destination string) error | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (Is anything using this?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, it was leftover from a previous iteration |
||
|
|
||
| // Commit the staged content into its final destination by using os.Rename(). | ||
| // That means the dest must be on the same on the same fs as the root directory | ||
| // that was given to NewTempDir() and the dest must not exist yet. | ||
| // Commit must only be called once per instance returned from the | ||
| // StageAddition() call. | ||
| func (s *StageAddition) Commit(destination string) error { | ||
| err := os.Rename(s.Path, destination) | ||
| s.Path = "" // invalidate Path to avoid reuse | ||
| return err | ||
| } | ||
|
|
||
| // CleanupTempDirFunc is a function type that can be returned by operations | ||
| // which need to perform cleanup actions later. | ||
| type CleanupTempDirFunc func() error | ||
|
|
@@ -190,6 +214,23 @@ func NewTempDir(rootDir string) (*TempDir, error) { | |
| return td, nil | ||
| } | ||
|
|
||
| // StageAddition creates a new temporary path that is returned as field in the StageAddition | ||
| // struct. The returned type has a type a the Commit() function to move the content from | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. typo |
||
| // the temporary location to the final one. | ||
| // | ||
| // The caller MUST ensure .Cleanup() is called after Commit() otherwise the staged content | ||
| // will be deleted and the move will fail. | ||
|
Comment on lines
+221
to
+222
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn’t look correct: After a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe the wording is confusing, what I tried to say is Commit() must be called before Cleanup() on the TempDir otherwise the staged content is removed and commit fails. Oh how I would love to have this written with rust lifetimes. |
||
| // If the TempDir has been cleaned up already, this method will return an error. | ||
| func (td *TempDir) StageAddition() (*StageAddition, error) { | ||
| if td.tempDirLock == nil { | ||
| return nil, fmt.Errorf("temp dir instance not initialized or already cleaned up") | ||
| } | ||
| fileName := fmt.Sprintf("%d-", td.counter) + "addition" | ||
| tmpAddPath := filepath.Join(td.tempDirPath, fileName) | ||
| td.counter++ | ||
| return &StageAddition{Path: tmpAddPath}, nil | ||
| } | ||
|
|
||
| // StageDeletion moves the specified file into the instance's temporary directory. | ||
| // The temporary directory must already exist (created during NewTempDir). | ||
| // Files are renamed with a counter-based prefix (e.g., "0-filename", "1-filename") to ensure uniqueness. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually please copy & paste the detailed description here, e.g. about the unusual
CleanupTempDirFuncreturn value.