Skip to content

memfs-kit v1.1.0

Choose a tag to compare

@github-actions github-actions released this 25 Oct 09:08
· 16 commits to main since this release

This minor release reduces filesystem allocations and adds direct metadata and
directory-listing methods through Go's optional io/fs interfaces.

Highlights

  • *FS now implements fs.StatFS. Stat captures metadata with one tree lookup
    without constructing a file handle or enumerating and sorting a directory's
    children. Regular and virtual files retain their hook behavior.
  • *FS now implements fs.ReadDirFS. ReadDir returns a fresh, sorted entry
    snapshot, avoiding the standard helper's extra slice copy and sort. Directory
    opens construct full child paths only when a regular-file hook needs them.
  • Hooks still receive private input copies. Equal hook output reuses the stored
    immutable snapshot, while transformed output remains isolated by a copy.
    Metadata-only operations avoid copying output that they do not retain.
  • Path traversal uses strings.SplitSeq, and each file handle embeds its
    bytes.Reader, reducing allocations. Close resets the reader to release its
    reference to the content snapshot.

Measured allocation changes

The following local microbenchmark results compare the combined changes with
commit 39284834af24fe80d4b607f2746813c8b7a41ea4, using the same benchmark source
on Go 1.27.3, darwin/arm64, Apple M5, with -cpu=1. Each of the 27 cases ran
five 200 ms samples; allocation counts and bytes were consistent across samples.

  • Opening and closing a regular file: 3 to 1 allocations/op, with a
    one-component path falling from 160 to 128 B/op.
  • Reading metadata for a directory with 1,000 entries: 96,592 to 64 B/op
    and 2,004 to 1 allocations/op.
  • Listing a directory with 1,000 entries: 112,912 to 80,512 B/op and
    2,004 to 1,002 allocations/op.
  • Opening and closing a 1 MiB file with a passthrough hook: full-size content
    copies fall from 2 MiB to 1 MiB. Total allocation falls from
    2,097,328 to 1,048,704 B/op, including handle and path overhead.

These are operation-level microbenchmarks, with setup outside timed sections;
they do not establish application throughput or production latency. Transforming
hooks still require separate input and output copies when opening content.
See the performance notes
for reproduction commands, workload details, and the remaining optimization scope.

Installation

Requires Go 1.27.3 or newer, unchanged from v1.0.0.

go get github.com/soulteary/memfs-kit@v1.1.0
import memfs "github.com/soulteary/memfs-kit"

The module path and package name are unchanged. There are no third-party Go
module dependencies.

Compatibility

Existing method signatures, snapshot ownership, hook semantics, and error
behavior are preserved. Directory-entry metadata remains lazy, and each entry caches
its first metadata result or error independently. Hooks continue to execute
outside tree and handle locks and may write to the filesystem.

Standard fs.Stat and fs.ReadDir helpers now dispatch to the new optional
interfaces. A wrapper that anonymously embeds *memfs.FS and overrides Open
also promotes Stat and ReadDir; it must override those methods to preserve
its custom behavior, or expose only fs.FS when requesting the standard fallback:

info, err := fs.Stat(struct{ fs.FS }{wrapped}, name)
entries, err := fs.ReadDir(struct{ fs.FS }{wrapped}, name)

See wrapper compatibility
and the documented behavior.

Validation

CI covers Linux, macOS, and Windows, with Linux race detection and bounded path
fuzzing. The local race-enabled test suite passed with 97.9% statement
coverage
. Path validation, including the new methods, passed a 15-second,
two-worker fuzz run. Formatting, go vet, and module consistency checks passed.

Regression tests compare the optional methods with standard-library Open-only
fallbacks and cover subtree paths, error identity, retained hook slices,
independent lazy metadata caches, concurrent Info calls, reentrant hooks, and
snapshot ownership.

Licensing

The project uses Apache License 2.0. Code inherited from memfs retains its
BSD-3-Clause license and original notices. See
LICENSE,
the preserved BSD license,
and third-party notices.