Sounds interesting, though that durability tradeoff is not one that I’d think most people/applications want to make. When you save something to the DB, you generally want that to mean it’s been durably stored.
Are there specific applications you’re targeting where latency matters more than durability?
1- Session stores (can be reconstructed from auth service)
2- leaderboards/counters (recent scores/counters can be recalculated)
3- Real-time analytics/metrics (losing ~100ms of metrics is acceptable)
4- Caching layers with upstream persistence
5- High-frequency systems where latency > everything
I generally think that for KV stores, there are more use cases that can accept this _slightly_ relaxed durability model than not. of course this isn't the case for a main DB. KV stores often handle derived data, caches, or state that can be rebuilt.
That said, for cases needing stronger durability, you can call flush_all() after critical operations - gives you fsync-level guarantees. Also considering adding a "sync" or "Full ACID" mode that auto-flushes on every write for users who want strong durability.
The philosophy is: make the fast path really fast for those who need it, but provide escape hatches for stronger guarantees when needed.
This seems around the durability that most databases can reach. Aside from more specialized hardware arrangements, with a single computer, embedded database there is always a window of data loss. The durability expectation is that some in-flight window of data will be lost, but on restart, it should recover to a consistent state of the last settled operation if at all possible.
A related questions is if the code base is mature enough when configured for higher durability to work as intended. Even with Rust, there needs to be some hard systems testing and it's often not just a matter of sprinkling flushes around. Further optimization can try to close the window tighter - maybe with a transaction log, but then you obviously trade some speed for it.
When operations complete in 200ns instead of blocking for microseconds/milliseconds on fsync, you avoid thread pool exhaustion and connection queueing. Each sync operation blocks that thread until disk confirms - tying up memory, connection slots, and causing tail latency spikes.
With FeOxDB's write-behind approach:
- Operations return immediately, threads stay available
- Background workers batch writes, amortizing sync costs across many operations
- Same hardware can handle 100x more concurrent requests
- Lower cloud bills from needing fewer instances
For desktop apps, this means your KV store doesn't tie up threads that the UI needs. For servers, it means handling more users without scaling up.
The durability tradeoff makes sense when you realize most KV workloads are derived data that can be rebuilt. Why block threads and exhaust IOPS for fsync-level durability on data that doesn't need it?
Nice! On paper looks really promising!
There is actual need for embedded databases as SQLite is painful for highly concurrent programs (I actually hit this issue in rust)
Thanks! yeah, SQLite's write lock is painful for concurrent apps.
I'm comfortable with kernel development, so I brought some of those patterns here - RCU-style lock-free reads, per-CPU inspired sharded buffers, and io_uring for kernel-bypass I/O.
would love to hear your thoughts if you had the chance to give it a spin :)
Sounds interesting, though that durability tradeoff is not one that I’d think most people/applications want to make. When you save something to the DB, you generally want that to mean it’s been durably stored.
Are there specific applications you’re targeting where latency matters more than durability?
Thanks for the comment. :)
The target use cases include:
1- Session stores (can be reconstructed from auth service) 2- leaderboards/counters (recent scores/counters can be recalculated) 3- Real-time analytics/metrics (losing ~100ms of metrics is acceptable) 4- Caching layers with upstream persistence 5- High-frequency systems where latency > everything
I generally think that for KV stores, there are more use cases that can accept this _slightly_ relaxed durability model than not. of course this isn't the case for a main DB. KV stores often handle derived data, caches, or state that can be rebuilt.
That said, for cases needing stronger durability, you can call flush_all() after critical operations - gives you fsync-level guarantees. Also considering adding a "sync" or "Full ACID" mode that auto-flushes on every write for users who want strong durability.
The philosophy is: make the fast path really fast for those who need it, but provide escape hatches for stronger guarantees when needed.
This seems around the durability that most databases can reach. Aside from more specialized hardware arrangements, with a single computer, embedded database there is always a window of data loss. The durability expectation is that some in-flight window of data will be lost, but on restart, it should recover to a consistent state of the last settled operation if at all possible.
A related questions is if the code base is mature enough when configured for higher durability to work as intended. Even with Rust, there needs to be some hard systems testing and it's often not just a matter of sprinkling flushes around. Further optimization can try to close the window tighter - maybe with a transaction log, but then you obviously trade some speed for it.
Not sure I read that formula right, but isn't the data loss limited to the last 100ms (worst case)?
I don't see many single user/desktop application use cases where that kind of time range would be risky.
Maybe if you used this as the main production database with thousands of concurrent sessions. But that doesn't seem to be their main use case, is it?
Do you see any single user/desktop application that needs the kind of speed boasted in the README? The one you are trading durability for?
When operations complete in 200ns instead of blocking for microseconds/milliseconds on fsync, you avoid thread pool exhaustion and connection queueing. Each sync operation blocks that thread until disk confirms - tying up memory, connection slots, and causing tail latency spikes.
With FeOxDB's write-behind approach:
For desktop apps, this means your KV store doesn't tie up threads that the UI needs. For servers, it means handling more users without scaling up.The durability tradeoff makes sense when you realize most KV workloads are derived data that can be rebuilt. Why block threads and exhaust IOPS for fsync-level durability on data that doesn't need it?
Nice! On paper looks really promising! There is actual need for embedded databases as SQLite is painful for highly concurrent programs (I actually hit this issue in rust)
Thanks! yeah, SQLite's write lock is painful for concurrent apps. I'm comfortable with kernel development, so I brought some of those patterns here - RCU-style lock-free reads, per-CPU inspired sharded buffers, and io_uring for kernel-bypass I/O. would love to hear your thoughts if you had the chance to give it a spin :)