feat(snapshots): Flush after restoring each file (#4825)

Signed-off-by: Lyndon-Li <lyonghui@vmware.com>
This commit is contained in:
lyndon-li
2025-11-13 12:59:56 +08:00
committed by GitHub
parent 06845c750b
commit 157c80e5e7
2 changed files with 17 additions and 2 deletions

View File

@@ -125,6 +125,7 @@ type commandRestore struct {
restoreIncremental bool
restoreDeleteExtra bool
restoreIgnoreErrors bool
flushFiles bool
restoreShallowAtDepth int32
minSizeForPlaceholder int32
snapshotTime string
@@ -158,6 +159,7 @@ func (c *commandRestore) setup(svc appServices, parent commandParent) {
cmd.Flag("shallow", "Shallow restore the directory hierarchy starting at this level (default is to deep restore the entire hierarchy.)").Int32Var(&c.restoreShallowAtDepth)
cmd.Flag("shallow-minsize", "When doing a shallow restore, write actual files instead of placeholders smaller than this size.").Int32Var(&c.minSizeForPlaceholder)
cmd.Flag("snapshot-time", "When using a path as the source, use the latest snapshot available before this date. Default is latest").Default("latest").StringVar(&c.snapshotTime)
cmd.Flag("flush-files", "Specifies whether or not to flush files after restore completes").Default("false").BoolVar(&c.flushFiles)
cmd.Action(svc.repositoryReaderAction(c.run))
}
@@ -269,6 +271,7 @@ func (c *commandRestore) restoreOutput(ctx context.Context, rep repo.Repository)
SkipPermissions: c.restoreSkipPermissions,
SkipTimes: c.restoreSkipTimes,
WriteSparseFiles: c.restoreWriteSparseFiles,
FlushFiles: c.flushFiles,
}
if err := o.Init(ctx); err != nil {

View File

@@ -109,6 +109,12 @@ type FilesystemOutput struct {
// copier is the StreamCopier to use for copying the actual bit stream to output.
// It is assigned at runtime based on the target filesystem and restore options.
copier streamCopier `json:"-"`
// Indicate whether or not flush files after restore.
// Varying from OS, the copier may write the file data to the system cache,
// so the data may not be written to disk when the restore to the file completes.
// This flag guarantees the file data is flushed to disk.
FlushFiles bool `json:"flushFiles"`
}
// Init initializes the internal members of the filesystem writer output.
@@ -373,7 +379,7 @@ func (o *FilesystemOutput) createDirectory(ctx context.Context, path string) err
}
}
func write(targetPath string, r fs.Reader, size int64, c streamCopier) error {
func write(targetPath string, r fs.Reader, size int64, flush bool, c streamCopier) error {
f, err := os.OpenFile(targetPath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0o600) //nolint:gosec,mnd
if err != nil {
return err //nolint:wrapcheck
@@ -391,6 +397,12 @@ func write(targetPath string, r fs.Reader, size int64, c streamCopier) error {
return errors.Wrapf(err, "cannot write data to file %q", f.Name())
}
if flush {
if err := f.Sync(); err != nil {
return errors.Wrapf(err, "cannot flush file %q", f.Name())
}
}
if err := f.Close(); err != nil {
return err //nolint:wrapcheck
}
@@ -430,7 +442,7 @@ func (o *FilesystemOutput) copyFileContent(ctx context.Context, targetPath strin
return atomicfile.Write(targetPath, rr)
}
return write(targetPath, rr, f.Size(), o.copier)
return write(targetPath, rr, f.Size(), o.FlushFiles, o.copier)
}
func isEmptyDirectory(name string) (bool, error) {