JsonMutexDB 💾
Ridiculously simple, fast and thread safe JSON file database
Ever found yourself needing a really simple way to persist some state in a Rust application? Maybe a configuration file, some user preferences, or the results of that one calculation you don't want to run again? And did you also need multiple threads to poke at that state without setting your data on fire? 🔥
JsonMutexDB was born out of a desire for a straightforward, thread-safe mechanism to manage data stored in a single JSON file. It doesn't try to be a full-fledged database, but it's pretty handy for those "I just need to save this struct somewhere" moments.
What's Inside? ✨
- Thread-Safe Access: Uses
std::sync::Mutex(or potentiallyparking_lot::Mutexdepending on historical versions) under the hood, allowing multiple threads to safely read (get) and write (update) data. - JSON Persistence: Reads from and saves data to a JSON file you specify. Handles empty or non-existent files gracefully on startup.
- Atomic Saves: Writes are performed atomically by default (using
tempfileand rename) to prevent data corruption if your application crashes mid-save. Safety first! - Serialization Options:
- Save JSON in a compact format (default) or human-readable "pretty" format.
- Optionally use
simd-jsonfor potentially faster serialization when saving in compact mode. Speed boost! 🚀
- Optional Asynchronous Updates: For scenarios where you don't want your main threads blocked by updates, you can enable
async_updates. Updates are sent to a dedicated background thread for processing.- State Synchronization: When async mode is enabled,
get()andsave_sync()intelligently query the background thread to ensure they operate on the absolute latest state. (This involves some channel communication overhead).
- State Synchronization: When async mode is enabled,
- Asynchronous Saving: Offload the potentially slow file I/O of saving to a background thread with
save_async().
Quick Start 🚀
And get going in your code:
use ;
use ;
use json;
// Needed for storage/retrieval
// Remember to define your crate (replace with actual implementation)
Configuration Options (new) ⚙️
When creating a JsonMutexDB, you have a few choices:
path: The path to the JSON file. If it doesn't exist, it will be created.pretty: If true, the JSON will be saved in a human-readable format. If false, it will be compact. This affects bothsave_sync()andsave_async().async_updates: If true, updates are sent to a background thread. This allows the main thread to continue without waiting for the update to complete. If false, updates are synchronous and block until completed.fast_serialization: If true and pretty is false, uses thesimd-jsoncrate for faster serialization. This is only effective when saving in compact mode.
Examples 🧐
Async Updates
use JsonMutexDB;
use json;
use thread;
use Arc;
use Duration;
#
# // Shim for example
# use ; // Shim for example
Async Saving
use JsonMutexDB;
use json;
use thread;
use Duration;
#
# // Shim for example
# use ; // Shim for example
Performance Notes ⚡️
- Serialization:
simd-json(fast_serialization: true) can significantly speed up saving compact JSON. Pretty printing will always useserde_json. - I/O: Saves use
std::io::BufWriterto minimize system calls. Atomic saves add the overhead of writing to a temporary file and renaming.save_asyncoffloads serialization and I/O but involves thread spawning and fetching state (if async updates are on). - Async Updates: Enabling async_updates reduces blocking on update calls but adds overhead for channel communication on get and save_sync to maintain consistency. Choose based on whether update latency or get/save latency is more critical.
Error Handling ⚠️
Most operations return Result<_, DbError>. This enum covers:
DbError::Io(std::io::Error): Filesystem errors, invalid JSON loading, serialization errors.DbError::Sync(String): Errors related to the async background thread communication (channel errors, poisoned mutexes in sync mode). Match on the result or use ? to propagate errors.
Limitations & Considerations 🤔
Single File: This manages one JSON file. It's not designed for complex relational data or large datasets where a real database would be more appropriate. Memory Usage: The entire JSON structure is loaded into memory. Very large JSON files might consume significant RAM. Async Mode Latency: While async_updates: true makes update() non-blocking, get() and save_sync() do block while communicating with the background thread to retrieve the latest state. unsafe: Uses unsafe internally for simd-json's from_str for performance. While believed to be safe in this context, be aware if auditing for unsafe.
Contributing 🤝
Welcome!
Happy JSON juggling!
🎉