perf: avoid cloning events in InMemoryEventStore::read_stream #363
Labels
No labels
adr
automated
bug
chore
dependencies
documentation
enhancement
epic
github-actions
P1-high
P2-medium
P3-low
release
research
rust
bug
duplicate
enhancement
help wanted
invalid
question
wontfix
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Slipstream/eventcore#363
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Problem
InMemoryEventStore::read_stream()clones every event during reads (event.clone()ateventcore-memory/src/lib.rs:110). For 1000 events, that's 1000 heap allocations just to read state.Benchmark: read 1000 events takes 43 µs (22M elem/sec). The cloning overhead is a portion of this.
Proposed Solution
Store events as
Arc<dyn Any + Send + Sync>instead ofBox<dyn Any + Send + Sync>. Reads would clone theArc(cheap pointer increment) rather than deep-cloning the event data.Expected Impact
Minor — estimated 43 µs → ~20 µs for reading 1000 events. The in-memory store is primarily used for testing, so this is low priority.
Caveats
The in-memory store is designed for testing and development, not production workloads. This optimization matters only if the in-memory store is used for benchmarking other components where read overhead should be minimized.
Location
eventcore-memory/src/lib.rs— storage types andread_stream()method.Benchmark Baseline
Run
cargo bench -p eventcore-bench --bench store_operations -- 'store/read_stream/memory'to measure before/after.Closing as obsoleted by #364 (streaming reads, ADR-0049).
The proposed optimization was to store events as
Arc<dyn Any>instead ofBox<dyn Any>so that reads clone a cheap pointer rather than deep-cloning event data. After #364,EventStore::read_streamyields owned events (Item = Result<E, EventStoreError>) one at a time. Producing each ownedEfrom the type-erased stored value still requires a deep clone regardless of whether it is stored behindBoxorArc—Arcwould only avoid the clone if the read API handed out shared events (Arc<E>), which we deliberately chose not to do (the streaming API yields owned events, consistent with the other backends that deserialize fresh owned events from JSON).In addition,
InMemoryEventStoreis a test/development backend, not a production workload (as the issue itself notes), and #364 already removed the up-front full-Vec materialization that was the larger memory concern.No code change delivers the intended win without changing the public read API to yield shared events, which is out of scope and undesirable. Resolving as won't-fix / obsolete.