Releases: aalhour/fractaltree
Release list
v0.4.0: Unsorted Buffer Append with Lazy Sort
What's Changed
Eliminates runtime.memmove (16% CPU) from the write path by replacing sorted buffer insertion with unsorted append and lazy sorting.
appendToBufferswitched from sorted insertion (O(B) memmove per insert) to O(1) unsorted append- Removed eager sorting from
flushNode— sorting now only happens at leaf merge time viaresolveMessages - Added linear-scan fallback in
bufferMessagesForKeyandbufferSlicefor reads on unsorted buffers (safe under RLock) - Batch leaf merge and iterator refactor
- Cross-impl benchmarks now match Google BTree node config (
WithBlockSize(63))
Benchmarks (vs v0.3.0)
| Benchmark | Delta | Meaning |
|---|---|---|
| Put (all sizes) | ~ | No change |
| Get/Hit | +9.5% | Slower (linear scan on unsorted buffer) |
| Get/Miss | +5.6% | Slower |
| Delete | +11.1% | Slower |
| Range/10 | -99.7% | Faster |
| Range/10000 | -74.7% | Faster |
| Upsert | -15.8% | Faster |
Read regressions are expected and acceptable — this is a write-optimized B^ε-tree. The write path no longer pays any sorting or memmove cost on insert. Full
comparison in benchmarks/benchstat_v0.3.0...v0.4.0.txt.
Docs
- ADR-004: design rationale, alternatives rejected, invariants
v0.3.0: Batch Leaf Merge
Performance Improvements
Three-path batch merge in applyToLeaf replaces per-message leafInsert/leafDelete loop:
| Path | When | Improvement |
|---|---|---|
| Append fast-path | Sequential inserts | -20 to -26% |
| Binary-search + chunk-copy | Interleaved puts | -23 to -33% |
| In-place compaction | Batches with deletes | -53% |
Geomean -13.9% across all benchmarks vs v0.2.1. Zero allocation regressions.
See docs/PERFORMANCE.md for full numbers and Google BTree comparison.
Documentation
docs/ADR.md— Architecture decision records for batch merge, size tracking, flush bucket reusedocs/PERFORMANCE.md— Full benchmarks, cross-implementation comparison, reproduction instructionsCONTRIBUTING.md— Development workflow, testing practices, benchmark proceduresdocs/ROADMAP.md— Completed work, profiling data, remaining optimizations
Design Details
See ADR-001 for the full decision record including alternatives benchmarked and rejected.
v0.2.1 — Reuse Flush Bucket Allocations
Performance Optimizations
P1: Reuse flush bucket allocations and compact buffer in-place
flushNode previously allocated a fresh [][]Message bucket slice and a remaining slice on every flush — producing 85.7% of all heap objects. This release:
- Adds a reusable
flushBucketsfield to internal nodes, reset via[:0]each flush - Compacts the buffer in-place instead of allocating a new
remainingslice
Benchmarks (vs v0.2.0, Apple M2 Max, Go 1.26, -count=6)
| Benchmark | Metric | Before | After | Δ |
|---|---|---|---|---|
| Put/Sequential/1M | sec/op | 139ms | 106ms | -24% |
| Put/Random/1M | sec/op | 1.70s | 1.08s | -36% |
| Put/Random/1M | B/op | 5.5Gi | 55Mi | -99.0% |
| Put/Random/1M | allocs | 11.2M | 4.8K | -99.96% |
| Put/Random/100K | B/op | 200Mi | 5.8Mi | -97% |
| Mixed | B/op | 89Mi | 21B | -100% |
| Delete | B/op | 38.5Mi | 3.3Ki | -99.99% |
| Delete | allocs | 33K | 6 | -99.98% |
Full benchstat comparison in benchmarks/benchstat_v0.2.0...v0.2.1.txt.
v0.2.0 — Performance Optimizations
Performance Optimizations
P0: Eliminate buffer scans in putLocked existence check
Replaced getFromNode (full root-to-leaf traversal with O(bufferCap) linear buffer scan per level) with existsInLeaf (leaf-only binary search) in the write path. A pendingDeletes counter triggers fallback to the full check only when buffered
deletes are in flight.
Benchmark improvements (Apple M2 Max, Go 1.26):
| Benchmark | Before | After | Δ |
|---|---|---|---|
| Put/Sequential/10K | 1070µs | 754µs | -30% |
| Put/Random/10K | 5.26ms | 4.54ms | -14% |
| Put/Sequential/100K | 17.1ms | 11.8ms | -31% |
| Put/Random/100K | 124ms | 110ms | -11% |
| Put/Sequential/1M | 198ms | 143ms | -28% |
| Put/Random/1M | 3.34s | 1.85s | -45% |
Other changes
- Fix
BenchmarkDeletetimer/setup issue (was rebuilding 100K tree inside timed loop) - Add
benchstatto tooling dependencies viatools.go
v0.1.0
fractaltree v0.1.0
Initial release of a write-optimized B-epsilon-tree (fractal tree) for Go.
Highlights
- Generic ordered key-value store (
cmp.Orderedor custom comparator) - Concurrent-safe with
sync.RWMutex(read-many / write-one) - Buffered writes with configurable epsilon and block size
iter.Seq2iterators:All,Ascend,Descend,Range,DescendRange- Stateful
CursorwithSeek/Next/Prev Upsert,PutIfAbsent,Increment,CompareAndSwapDeleteRangefor bulk key removalDiskBETreewith pluggableFlusherandCodecinterfaces- Zero runtime dependencies
- 97.8% test coverage, 159 tests, fuzz/stress/race clean
- 15 runnable examples