diff --git a/core/content/content.go b/core/content/content.go index 2dc7bf8b5..66b42a9cb 100644 --- a/core/content/content.go +++ b/core/content/content.go @@ -165,6 +165,11 @@ type Writer interface { Truncate(size int64) error } +type Syncer interface { + // Sync flushes the in-flight writes to the disk (when applicable) + Sync() error +} + // Opt is used to alter the mutable properties of content type Opt func(*Info) error diff --git a/core/metadata/content.go b/core/metadata/content.go index 3c990cb1e..2877fa665 100644 --- a/core/metadata/content.go +++ b/core/metadata/content.go @@ -574,6 +574,13 @@ func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected dig var innerErr error + // We pre-sync the in-flight writes to the disk. This avoids the [subsequent fp.Sync() call] + // (https://github.com/containerd/containerd/blob/c4c3c6ea568ce0cfbcf754863abadeea37d77c8f/plugins/content/local/writer.go#L95) + // from taking too long (10s+) while holding the metadata database lock as in the following + // `update` transaction. We intentionally ignore any error on Sync() because it will be + // handled by the subsequent `fp.Sync` anyway. + nw.Sync() + if err := update(ctx, nw.db, func(tx *bolt.Tx) error { dgst, err := nw.commit(ctx, tx, size, expected, opts...) if err != nil { @@ -599,6 +606,13 @@ func (nw *namespacedWriter) Commit(ctx context.Context, size int64, expected dig return innerErr } +func (nw *namespacedWriter) Sync() error { + if syncer, ok := nw.w.(content.Syncer); ok { + return syncer.Sync() + } + return nil +} + func (nw *namespacedWriter) commit(ctx context.Context, tx *bolt.Tx, size int64, expected digest.Digest, opts ...content.Opt) (digest.Digest, error) { var base content.Info for _, opt := range opts { diff --git a/plugins/content/local/writer.go b/plugins/content/local/writer.go index 26cef0aae..38c2f1078 100644 --- a/plugins/content/local/writer.go +++ b/plugins/content/local/writer.go @@ -206,3 +206,11 @@ func (w *writer) Truncate(size int64) error { } return w.fp.Truncate(0) } + +func (w *writer) Sync() error { + if w.fp != nil { + return w.fp.Sync() + } + + return nil +}