News for hackers. Stuff that matters.
Re:In-Memory Filesystems in Rust by adastra22 on Sunday August 24, 2025 @04:00AM (#45002291)
I no mention of fsync/sync_all. That’s why your disk file system is acting as fast as your in memory file system (for small tests). Both are effectively in-memory.
Re:In-Memory Filesystems in Rust by maxbond on Monday August 25, 2025 @02:20AM (#45010795)
A Rust-specific danger is that, if you don't explicitly sync a file before dropping it, any errors from syncing are ignored. So if you care about atomicity, call eg `File::sync_all()`.
Re:In-Memory Filesystems in Rust by dezgeg on Monday August 25, 2025 @02:34AM (#45010888)
Is that really rust-specific? I would be really surprised if any other languages do fsync() in their destructor either
Re:In-Memory Filesystems in Rust by maxbond on Monday August 25, 2025 @02:42AM (#45010957)
To be clear `File::drop()` does sync, it just ignores errors (because `drop()` doesn't have a way of returning an error). It's not really Rust specific I guess, I just don't know off the top of my head what other languages behave this way.
Re:In-Memory Filesystems in Rust by aw1621107 on Monday August 25, 2025 @04:38AM (#45011641)
I believe C++'s fstreams also ignore errors on destruction for similar reasons.

I've wondered for a while what it'd take to eliminate such pitfalls in the "traditional" RAII approach. Something equivalent to deleting the "normal" RAII destructor and forcing consumption via a close() could be interesting, but I don't know how easy/hard that would be to pull off.

Re:In-Memory Filesystems in Rust by vbezhenar on Monday August 25, 2025 @07:18AM (#45012602)
There's no reason that throwing exceptions in finalisers must be prohibited. It's just bad design.

Modern Java provides the concept of suppressed exceptions. Basically an exception can maintain the list of suppressed exceptions.

When stack unwinds, just allow finaliser to throw an exception. If it threw an exception, either propagate it to the handler, unwinding stack as necessary, or add it to the current exception as a suppressed exception. Exception handler can inspect the suppressed exceptions, if necessary. Exception print routine will print all suppressed exceptions for log visibility.

Java does not do it properly for finally blocks, instead overwriting current exception, probably because the concept of suppressed exception was introduced in the later versions and they wanted to keep the compatibility.

But it can be done properly.

Re:In-Memory Filesystems in Rust by aw1621107 on Monday August 25, 2025 @05:59PM (#45019593)
IIRC C++ and Rust don't technically prohibit throwing exceptions out of destructors; it's triggering unwinding during unwinding that's the main problem.

Does make me wonder about the specifics behind that. I had assumed that there are some kind of soundness issues that force that particular approach (e.g., https://github.com/rust-lang/rust/pull/110975, "Any panics while the panic hook is executing will force an immediate abort. This is necessary to avoid potential deadlocks like rustc hangs after ICEing due to memory limit #110771 where a panic happens while holding the backtrace lock."; alternatively, some other kind of soundness issue?), but I don't have the knowledge to say whether this is a fundamental limitation or "just" an implementation quirk that basically got standardized. Rust' first public release was after Java 7, so in principle the precedent was there, for what it's worth.

Re:In-Memory Filesystems in Rust by the8472 on Monday August 25, 2025 @05:30AM (#45011958)
> To be clear `File::drop()` does sync

It does not. BufWriter<File> flushes its userspace buffer (but doesn't fsync either). If you have a bare File then drop really just closes the file descriptor, that's it.

https://github.com/rust-lang/rust/blob/ee361e8fca1c30e13e7a3...

Re:In-Memory Filesystems in Rust by maxbond on Monday August 25, 2025 @09:11AM (#45013472)
My bad, thanks for the correction.
Re:In-Memory Filesystems in Rust by silon42 on Monday August 25, 2025 @03:26AM (#45011236)
I'd almost never want do to fsync in normal code (unless implementing something transactional)... but I'd want an explicit close almost always (or drop should panic/abort).
Re:In-Memory Filesystems in Rust by maxbond on Monday August 25, 2025 @09:39AM (#45013735)
I use transactional file operations when for instance when I write tools that change their own human-readable configuration files. If something is important enough to write to disk, then it's probably important enough that you can't tolerate torn writes.
Re:In-Memory Filesystems in Rust by adastra22 on Monday August 25, 2025 @03:33PM (#45017980)
Why? The explicit close does almost nothing.
Re:In-Memory Filesystems in Rust by 01HNNWZ0MV43FF on Monday August 25, 2025 @03:05AM (#45011105)
For context - cppreference.com doesn't say anything about `fstream` syncing on drop, but it does have an explicit `sync` function. `QFile` from Qt doesn't even have a sync function, which I find odd.
Re:In-Memory Filesystems in Rust by aw1621107 on Monday August 25, 2025 @05:04AM (#45011812)
I had always assumed that fstream flushes on destruction, but after digging through the standard all I can conclude is that I'm confused.

According to the standard, fstream doesn't have an explicit destructor, but the standard says "It uses a basic_filebuf<charT, traits> object to control the associated sequences." ~basic_filebuf(), in turn, is defined to call close() (which I think flushes to disk?) and swallow exceptions.

However, I can't seem to find anything that explicitly ties the lifetime of the fstream to the corresponding basic_filebuf. fstream doesn't have an explicitly declared destructor and the standard doesn't require that the basic_filebuf is a member of fstream, so the obvious ways the file would be closed don't seem to be explicitly required. In addition, all of fstream's parents' destructors are specified to perform no operations on the underlying rdbuf(). Which leaves... I don't know?

cppreference says the underlying file is closed, though, which should flush it. And that's what I would expect for an RAII class! But I just can't seem to find the requirement...

Re:In-Memory Filesystems in Rust by znpy on Monday August 25, 2025 @03:55AM (#45011389)
so the good old `sync; sync; sync;` ?
Re:In-Memory Filesystems in Rust by goodpoint on Monday August 25, 2025 @04:44AM (#45011682)
This is not correct. Programming languages do not and should not call sync automatically.
Re:In-Memory Filesystems in Rust by the8472 on Monday August 25, 2025 @05:26AM (#45011922)
On most filesystems close(2) is nearly a noop, so even if you surfaced errors from close it returning successfully would not guarantee an absence of errors.

close without fsync (or direct IO) essentially is telling the OS that you don't need immediate durability and prefer performance instead.

Re:In-Memory Filesystems in Rust by cyphar on Monday August 25, 2025 @09:00AM (#45013371)
This is actually true for all programs (on Linux at least) because closing a file does not mean it will be synced and so close(2) may not return an error even if the later sync will error out.

The more general issue (not checking close(2) errors) is mostly true for most programming languages. I can count on one hand how many C programs I've seen that attempt to check the return value from close(2) consistently, let alone programs in languages like Go where handling it is far more effort than ignoring it.

Also, close(2) doesn't consistently return errors. Because filesystem errors are often a property of the whole filesystem and data written during sync has been disassociated from the filesystem, the error usually can't be linked to a particular file descriptor. Most filesystems instead just return EIO if the filesystem had an error at all. This is arguably less useful than not returning an error at all because the error might be triggered by a completely unrelated process and (as above) you might not receive errors that you do care about.

Filesystems also have different approaches to which close(2) calls will get filesystem errors. Some only return the error to the first close(2) call, which means another thread or process could clear the error bit. Other filesystems keep the error bit set until a remount, which means that any program checking close(2) will get lots of spurious errors. From memory there was a data corruption bug in PostgreSQL a few years ago because they were relying on close(2) error semantics that didn't work for all filesystems.

Re:In-Memory Filesystems in Rust by indirect on Monday August 25, 2025 @03:18AM (#45011197)
I guess I wasn't sufficiently clear in the post, but the part I think is interesting is not that tmpfs and SSD bench at the same speed. I am aware of in-memory filesystem caches, and explicitly mention them twice in the last few paragraphs.

The interesting part, to me, was that using the vfs crate or the rsfs crate didn't produce any differences from using tmpfs or an SSD. In theory, those crates completely cut out the actual filesystem and the OS entirely. Somehow, avoiding all those syscalls didn't make it any faster? Not what I expected.

Anyway, if you have examples of in-process filesystem mocks that run faster than the in-memory filesystem cache, I'd love to hear about them.

Re:In-Memory Filesystems in Rust by eumon on Monday August 25, 2025 @03:23AM (#45011218)
you may try /dev/shm for the testing purpose, which is effectively an in memory filesystem that linux provides, it is very performant
Re:In-Memory Filesystems in Rust by j1elo on Monday August 25, 2025 @04:36AM (#45011632)
> It turns out the intended primary use case of the crate is to store files inside Rust binaries but still have an API sort of like the filesystem API to interact with them. Unfortunately, that information is hidden away in a comment on a random GitHub issue, rather than included in the project readme.

A+ on technical prowess,

F- on being able to articulate a couple words about it on a text file.

Re:In-Memory Filesystems in Rust by kolektiv on Monday August 25, 2025 @04:55AM (#45011755)
It always surprised me somewhat that there isn't a set of traits covering some kind of `fs` like surface. It's not a trivial surface, but it's not huge either, and I've also found myself in a position of wanting to have multiple implementations of a filesystem-like structure (not even for the same reasons).

Tricky to make that kind of change to std lib now I appreciate, but it seems like an odd gap.

Re:In-Memory Filesystems in Rust by ozgrakkurt on Monday August 25, 2025 @06:27AM (#45012325)
Mocking file system or network seems counter productive.

Complicated logic can be in pure functions and not be intertwined with IO if it needs to be tested.

Mocking IO seems like it won’t really capture the problems you might encounter in reality anyway.

Re:In-Memory Filesystems in Rust by kolektiv on Monday August 25, 2025 @06:30AM (#45012355)
It's not always about mocking (in my cases it hasn't been). Sometimes it is about multiple "real" implementations - a filesystem is itself an abstraction, and a very common one, it seems like it would at least sometimes be useful to be able to leverage that more flexibly.
Re:In-Memory Filesystems in Rust by eru on Monday August 25, 2025 @06:40AM (#45012402)
I have a little system that takes a .git and mounts it as a fuse filesystem. Every commit becomes a directory with a snapshot of the project at that point in time.

You could read the whole .git in at once, and then you'd have an in-memory file-system, if you wanted to.

In any case, I agree with you: it's not about mocking.

Re:In-Memory Filesystems in Rust by kryptiskt on Monday August 25, 2025 @07:16AM (#45012595)
Some examples where it would be useful: Exposing a zip file or exe-embedded data as a filesystem, or making an FS backed by 9P, WebDAV or SFTP.
Re:In-Memory Filesystems in Rust by stingraycharles on Monday August 25, 2025 @07:20AM (#45012611)
Same like mocking databases; yes they make your tests run faster and more “pure”, but you’re suddenly not really testing reality anymore.
Re:In-Memory Filesystems in Rust by boomlinde on Monday August 25, 2025 @08:55AM (#45013331)
Sure, but they're not mutually exclusive approaches. Having tests that run in a couple of seconds thanks to low I/O and cheap scaffolding setup/teardown can be a valuable addition to slower, comprehensive system and integration test suites.
Re:In-Memory Filesystems in Rust by actionfromafar on Monday August 25, 2025 @10:09AM (#45014041)
And you can spot differences between your understanding of reality (test mockups) and how it behaves on the real filesystem. (In this case.)
Re:In-Memory Filesystems in Rust by Arch-TK on Monday August 25, 2025 @08:30AM (#45013137)
Fault injection is much easier if you can mock IO. And you aren't really testing your software if you're not injecting faults.
Re:In-Memory Filesystems in Rust by ozgrakkurt on Tuesday August 26, 2025 @11:50PM (#45035276)
My point is, you can give gibberish data to a processing function if it just takes in-memory data instead of being parameterized by “IO”.

If you parameterize everything by IO then you have to mock the IO

Re:In-Memory Filesystems in Rust by Arch-TK on Thursday August 28, 2025 @10:47AM (#45052874)
It's not just about gibberish data. It's read failures, write failures, open failures, for a variety of reasons including permission errors, disk errors, space errors, etc.

You basically want to test your code does something sensical with either every possible combination of errors, or with some random subset of combinations of errors. This can be automated and can verify the behaviour of your program in the edge cases. It's actually not usually that helpful to only test "we read corrupt garbage from the file" which is the thing you're describing here.

Re:In-Memory Filesystems in Rust by Joker_vD on Monday August 25, 2025 @08:36AM (#45013177)
See David R. Hanson's "A Portable File Directory System" [0][1], for example: a 700 lines long implementation of early UNIX's filesystem API that piggy-backs on some sort of pre-existing (block-oriented) I/O primitives, which means you can do it entirely in-memory, with about another 300 lines of code or so.

I suspect that with OSes becoming much more UNIX-like the demand for such abstraction layers shrank almost to nothing.

[0] https://drh.github.io/documents/pds-spe.pdf

[1] https://drh.github.io/documents/pds.pdf

Re:In-Memory Filesystems in Rust by lenkite on Monday August 25, 2025 @08:44AM (#45013234)
Go has a basic FS abstraction in the standard library: https://dev.to/rezmoss/gos-fs-package-modern-file-system-abs...

But the stdlib one is a bit barebones. So people created: https://github.com/spf13/afero

Re:In-Memory Filesystems in Rust by tayo42 on Monday August 25, 2025 @10:03AM (#45013969)
This is one nice thing about go.

I think was trying to test something in Rust and I was surprised by how many people were OK with using real file's for unit testing.

It seems like a massive oversight for being able to use rust in a corporate environment.

Re:In-Memory Filesystems in Rust by jen20 on Monday August 25, 2025 @01:52PM (#45016663)
> It seems like a massive oversight for being able to use rust in a corporate environment.

Why does being in a corporate environment matter?

Re:In-Memory Filesystems in Rust by tayo42 on Monday August 25, 2025 @03:40PM (#45018067)
Permissions are usually more strict then a hobby projects. So you can't just be writing and leaving things all over the file system without the possibility of failure.

Or maybe your using drives over a network and randomly your tests will now fail becasue of things outside your control. Things like that.

That's why when writing tests you always want them to actually do io like that.

Re:In-Memory Filesystems in Rust by bccdee on Monday August 25, 2025 @07:38PM (#45020536)
Seems like you could just put your test files in a tmpfs, if leaving files laying around is an issue.
Re:In-Memory Filesystems in Rust by tayo42 on Monday August 25, 2025 @08:09PM (#45020730)
You need to mount and unmount fikesystems to do that.

Take a look at the library mentioned,afero, and you'll see how nice it handles working with the file system in tests.

You can have everything in memory, and a whole new fs in each test

Re:In-Memory Filesystems in Rust by jen20 on Tuesday August 26, 2025 @11:26AM (#45027909)
The problem is it only tests trivial properties of the API. That might be enough for some things, but it’s not a panacea.
Re:In-Memory Filesystems in Rust by hansvm on Monday August 25, 2025 @11:46AM (#45015140)
This is something I'm hopeful will fall out accidentally from Zig's new IO interface. If everyone doing IO has the implementation injected, mocks (fault injection, etc) become trivial, along with any other sort of feature you might want like checking S3 if you don't have a sufficiently recent local copy.
Re:In-Memory Filesystems in Rust by Arnavion on Monday August 25, 2025 @11:58AM (#45015255)
Having traits in the stdlib would be nice, but there's also the type parameter pollution that results from mocking which I think is also a turn-off, as TFA says about rsfs.

I have a Rust library to implement the UAPI config spec (a spec that describes which files and directories a service should look for config files in), and initally wanted to test it with filesystem mocks. After making some effort to implement the mock types and traits, plus wrappers around the `<F = StdFs>` types to hide the `<F>` parameter because I didn't want to expose it in the public API, I realized it was much easier to not bother and just create all the directory trees I needed for the tests.

Re:In-Memory Filesystems in Rust by vpanyam on Monday August 25, 2025 @01:31PM (#45016399)
Yeah having traits for this in the stdlib would be nice.

You might find Lunchbox [1] interesting. I needed an async virtual filesystem interface for a project a few years ago (and didn't find an existing library that fit my needs) so I built one:

> Lunchbox provides a common interface that can be used to interact with any filesystem (e.g. a local FS, in-memory FS, zip filesystem, etc). This interface closely matches `tokio::fs::` ...

It includes a few traits (`ReadableFileSystem`, `WritableFileSystem`) along with an implementation for local filesystems. I also used those traits to build libraries that enable things like read-only filesystems backed by zip files [2] and remote filesystems over a transport (e.g. TCP, UDS, etc) [3].

[1] https://crates.io/crates/lunchbox

[2] https://crates.io/crates/zipfs

[3] https://github.com/VivekPanyam/carton/tree/main/source/anywh...

Re:In-Memory Filesystems in Rust by the8472 on Monday August 25, 2025 @05:54AM (#45012123)
> but all my benchmarks seem to disagree.

Well, benchmarks could be wrong or misleading. Did you make sure that the IO actually happens and that it dominates the process execution time?

Re:In-Memory Filesystems in Rust by IshKebab on Monday August 25, 2025 @06:04AM (#45012194)
I guess the overhead from the syscalls simply wasn't that significant. Syscalls aren't that slow (~0.5us). This never says how many you were doing.
Re:In-Memory Filesystems in Rust by ozgrakkurt on Monday August 25, 2025 @06:28AM (#45012334)
Also kernel code is probably more optimized than a mock library
Re:In-Memory Filesystems in Rust by jitl on Monday August 25, 2025 @11:44AM (#45015115)
wat. a write to address in memory + a context switch is not going to beat a write to an address in memory
Re:In-Memory Filesystems in Rust by bhawks on Monday August 25, 2025 @07:37AM (#45012748)
Posix file system semantics are very complex. An in memory implementation is likely to have quality gaps that make it sub optimal. If you want fast tests /tmp is likely to be backed by tmpfs in memory. If you are paranoid you can use /dev/shm to be explicit about your desire.

Going this route means you're going to leverage all the well tested Linux VFS code and your tests will execute with higher fidelity.

Re:In-Memory Filesystems in Rust by mpweiher on Monday August 25, 2025 @07:42AM (#45012779)
Yeah, SSDs are really fast. Have been for a while now, so fast that system call and other kernel overheads easily dominate unless you take care:

https://blog.metaobject.com/2017/02/mkfile8-is-severely-sysc...

That was 8 years ago, and even then mkfile needed a 512K buffer size to saturate the hardware. With the 512 byte default buffer it was 8x slower than the hardware.

In addition, as others have pointed out, if you are not doing something extra to ensure things are flushed to disk, you are just measuring the buffer cache in the first place.

Re:In-Memory Filesystems in Rust by mncalc7 on Monday August 25, 2025 @08:58AM (#45013362)
Why not just use tmpfs?
Re:In-Memory Filesystems in Rust by jelder on Monday August 25, 2025 @09:24AM (#45013597)
Linux supports two different in-memory filesystems, ramfs and tmpfs. It should be easy enough to set up tests to use paths on such a mount point. Wonder why OP didn't mention these.
Re:In-Memory Filesystems in Rust by tayo42 on Monday August 25, 2025 @10:12AM (#45014066)
>Eat trash, be free, test directly against the filesystem. Why not.

You might run into weird environment or permission issues when you run your tests in a ci job.

Omg, the comment about getting lectured. Relatable about anything testing related. It's happening this comment section. Someone hand waving testing away with pure functions, I'm sure someone will say pattern matching will solve all the problems thanks to the compiler.

Re:In-Memory Filesystems in Rust by tannhaeuser on Monday August 25, 2025 @10:37AM (#45014343)
In memoriam Filesystems in Rust, is what I read ;)
Re:In-Memory Filesystems in Rust by cbondurant on Monday August 25, 2025 @10:41AM (#45014381)
The thing that finally made me realize just how fast file IO is today, is when I was looking into doing my own impl of 1brc in rust for practice.

I had expected that without the ramdisk, that file IO would have been the bottleneck for my testing, but in fact found that even with regular file IO my cpu was still the bottleneck, and multi-threading provided a massive performance boost. Completely decimating my expectations.

Re:In-Memory Filesystems in Rust by jitl on Monday August 25, 2025 @11:47AM (#45015150)
You can’t ask Rust people to make things simple or easy. Rust culture prioritizes making things complex & hard because it’s Correct for life to be complex & hard.
Re:In-Memory Filesystems in Rust by mirekrusin on Monday August 25, 2025 @11:50AM (#45015176)
i/o codepaths are heavily optimized with multiple layers of cache, you're probably hitting OS in memory one in your tests?