Fix reverse-scan off-by-one and replace index data array with fixed-size ring buffer#255
Fix reverse-scan off-by-one and replace index data array with fixed-size ring buffer#255
Conversation
…dableIndex - Replace `this.data` (sparse Array, grows without bound) with `this.cache` (ring buffer of `cacheSize` slots) and `this._length` (total entry count). - The ring buffer window is always [_length - cacheSize, _length - 1]; entries outside that window are read from disk on demand without consuming memory. - New `cacheSize` option (default 1024) configures how many of the most-recent entries are kept in memory, bounding memory use regardless of index size. - WritableIndex.add() stores new entries in the ring buffer and increments _length; truncate() clears stale ring buffer slots for removed entries. - ReadOnlyIndex.onChange() manages _length directly and clears stale cache slots when the underlying file is truncated by the writer. - readRange() handles out-of-window reads (disk-only, no cache) separately from in-window reads (disk + ring buffer), with explanatory comments showing why in-window slots can never hold stale data. - 5 new tests validate: memory-bounding after cycling, disk fallback for out-of-window entries, cross-boundary range reads, stale-slot safety after truncation + re-add, and correctness after full ring cycles. Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/58a8bfd7-606c-4d78-86e4-713c830c84be
Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/883111c6-3b9d-4839-a829-5e2c1f265c4e
|
Given the benchmark result I would refrain from merging this. The penalty is not worth the potential gain for write cases and overall reduced memory consumption. However @copilot please add the test |
The test and the one-line fix have been committed to a local branch Since I'm unable to open new PRs directly, you can create the PR by cherry-picking those two file changes from |
|
Closing this as of the benchmark results. The bug and test case is handled in #258 |
|
With the performance fix in #262 this should be reconsidered, as the performance degradation was not caused by this change |
|
@copilot rebase this PR then run the benchmark again |
…ata support Co-authored-by: albe <4259532+albe@users.noreply.github.com>
…partitionMetadata) Co-authored-by: albe <4259532+albe@users.noreply.github.com>
Co-authored-by: albe <4259532+albe@users.noreply.github.com>
Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/a3d29880-0ef1-4485-b1f8-3b3405a5feab
Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/3995bf0a-704b-4c73-8c31-acebe87c88ba
Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/72e4073d-8177-4078-89fe-5f8b88c97876
…ner and streamMetadata fallback paths Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/d1ba14e3-fb46-42f3-88fc-05ecf508f745
…recreation and emit calls Co-authored-by: albe <4259532+albe@users.noreply.github.com> Agent-Logs-Url: https://github.com/albe/node-event-storage/sessions/30186b59-6016-4170-a527-bc2a9e7c36bb
Rebased onto main (commit
All 335 tests pass. |
|
Closing in favor of #267 |
Fixes a pre-existing off-by-one in reverse batch iteration and replaces the unbounded index data array with a fixed-size ring buffer to bound memory usage. The bench+fix were landed separately in #258; this PR (rebased onto main after the performance regression fix in #262) contains the ring buffer implementation.
Benchmark results (
bench/bench-read-scenarios.js) — after rebase onto main (#262)The ring buffer variant is now within ~4–7% of stable (the original −3.5× penalty was caused by an unrelated regression fixed in #262).
Changes
src/Index/ReadableIndex.js– replacesthis.data(sparseArray, grows without bound) withthis.cache(ring buffer ofcacheSizeslots) andthis._length(total entry count). The ring buffer window is always[_length − cacheSize, _length − 1]; entries outside that window are read from disk on demand without consuming memory. NewcacheSizeoption (default 1024) configures how many of the most-recent entries are kept in memory.src/Index/WritableIndex.js–add()stores new entries in the ring buffer and increments_length;truncate()clears stale ring buffer slots for removed entries.src/Index/ReadOnlyIndex.js–onChange()manages_lengthdirectly and clears stale cache slots when the underlying file is truncated by the writer.test/Index.spec.js– 5 new tests validate: memory-bounding after cycling, disk fallback for out-of-window entries, cross-boundary range reads, stale-slot safety after truncation + re-add, and correctness after full ring cycles.Original prompt
⚡ Quickly spin up Copilot coding agent tasks from anywhere on your macOS or Windows machine with Raycast.