some tiny learning projects in Rust
some tiny learning projects in Rust, awesome!
What is Bitcask? Bitcask is a log-structured key-value storage model (originally from Riak). Instead of updating data in place, every write — set or delete — is appended to the end of a log file. An in-memory hash index (called the "keydir") maps each key to the offset/length of its most recent entry in the log. Old versions of a key just become dead space in the log until a merge (compaction) rewrites only the live entries into a fresh file and reclaims disk space. This design trades some memory (one index entry per key) for very fast, mostly-sequential writes and O(1) reads.
How it's implemented here, in the simplest way:
key_len(4B) | value_len_or_tombstone(4B) | key | value; a negative length marks a tombstone (delete).keydir: BTreeMap, (offset, length)> is rebuilt in memory by scanning the log once on startup.set/delete just append a new entry and update the keydir; get looks up the keydir then reads that one slice of the file.merge walks the current keydir (i.e. only the live keys), rewrites them into a new log file, and swaps it in — dropping tombstones and superseded versions.What is MVCC? Multi-Version Concurrency Control lets readers and writers work concurrently without blocking each other. Instead of overwriting a value, every write creates a new version tagged with a monotonically increasing version number. A transaction takes a version number when it begins and only ever sees versions that were already committed at that point (its "snapshot") — giving repeatable reads without taking read locks.
How it's implemented here, in the simplest way:
AtomicU64 counter hands out the next version number to each new transaction.(raw_key, version) -> value in one BTreeMap, so all versions of a key sit next to each other in key order.get scans a key's versions from newest to oldest and returns the first visible one; commit just drops the transaction from the active set; rollback deletes everything it wrote and drops it from the active set.A small arithmetic expression evaluator based on operator-precedence parsing: a Tokenizer turns the input string into a stream of Tokens (numbers, operators, parentheses), and Expr::compute_expr recursively evaluates left-to-right while only descending into a sub-expression when the next operator binds tighter than the current minimum precedence (min_prec). Right-associative operators (like ^) are handled by not bumping min_prec on recursion, while left-associative ones bump it by one — this one trick is what makes the whole algorithm fit in ~150 lines without a separate AST.
No open issues yet, or sync has not completed.