From 2a452d538aae533d304f4516c428438223eda01f Mon Sep 17 00:00:00 2001 From: mojatter Date: Mon, 6 Apr 2026 13:35:24 +0900 Subject: [PATCH] memfs: document MemFile write/close/sync semantics MemFile buffers writes locally and only publishes them on Close, while osfs makes writes visible immediately. Sync is a no-op on memfs and in particular does NOT publish buffered bytes. These differences can trip up callers porting code between backends, so spell them out on the MemFile type doc and on each of Write, Close, and Sync. --- memfs/memfs.go | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/memfs/memfs.go b/memfs/memfs.go index f215763..2ffd98f 100644 --- a/memfs/memfs.go +++ b/memfs/memfs.go @@ -317,7 +317,22 @@ func (fsys *MemFS) RemoveAll(path string) error { } // MemFile represents an in-memory file. -// MemFile implements fs.File, fs.ReadDirFile and wfs.WriterFile. +// MemFile implements fs.File, fs.ReadDirFile, wfs.WriterFile and +// wfs.SyncWriterFile. +// +// Write semantics differ from osfs and may surprise callers porting code +// between backends: +// +// - Writes are buffered locally on the *MemFile. They are NOT visible to +// other Open/Read/ReadFile calls until Close returns successfully. +// - Sync is a no-op. It exists only so that wfs.SyncWriterFile-aware +// callers (atomic-write helpers, for example) can share a single code +// path across osfs and memfs; on memfs the durability guarantee is +// vacuously satisfied because there is no underlying storage, but a +// successful Sync still does NOT publish the buffered bytes — only +// Close does. +// - Concurrent writers to the same name each operate on independent +// buffers; whichever calls Close last wins. type MemFile struct { fsys *MemFS name string @@ -349,7 +364,10 @@ func (f *MemFile) Stat() (fs.FileInfo, error) { return f.fsys.Stat(f.name) } -// Close closes streams. +// Close closes the file. If any Write calls were made, Close commits the +// buffered bytes to the filesystem; until Close returns successfully the +// written content is not visible to other readers. See the MemFile type +// docs for the full semantics. func (f *MemFile) Close() error { if f.wrote { var err error @@ -389,15 +407,18 @@ func (f *MemFile) ReadDir(n int) ([]fs.DirEntry, error) { return f.dirEntries[f.dirIndex:end], nil } -// Write writes the specified bytes to this file. +// Write appends the specified bytes to this file's local buffer. The +// bytes are not published to the filesystem until Close is called. See +// the MemFile type docs. func (f *MemFile) Write(p []byte) (int, error) { f.wrote = true return f.buf.Write(p) } -// Sync is a no-op for in-memory files. It exists to satisfy -// wfs.SyncWriterFile so that callers writing for crash safety on osfs can -// share the same code path on memfs. +// Sync is a no-op for in-memory files. It exists so that callers using +// wfs.SyncWriterFile to flush osfs files for crash safety can share the +// same code path on memfs. Note that Sync does NOT publish buffered +// writes — only Close does. See the MemFile type docs. func (f *MemFile) Sync() error { return nil }