Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
afc5e50
Add append-only mapped file abstraction with tests and benchmark
Copilot May 14, 2026
b3bc297
Add mapped file throughput benchmark script
Copilot May 14, 2026
e3aeef7
Use @riaskov/mmap-io for true file memory mapping
Copilot May 14, 2026
531cc20
Refactor AppendOnlyMmapedFile: move write-only methods to writable su…
Copilot May 14, 2026
a99e26f
Move pageSize to writable subclass, simplify writeBufferSize expression
Copilot May 14, 2026
8f87e5e
Add mmap-backed Index implementation beside existing Index (MmapReada…
Copilot May 14, 2026
cec0c39
Address code review: remove redundant isOpen guard in close(), drop e…
Copilot May 14, 2026
291d47b
planning: file.write(size) API + bench + caching
Copilot May 14, 2026
bb1cff3
Add write(size) API, entry caching, hasPendingData flush guard, and M…
Copilot May 14, 2026
f9516f6
Split write(data) and reserve(size), add cache forward-trim, clear ma…
Copilot May 14, 2026
dabe4ff
Refactor index benchmark to shared writer/readers with scaling steps
Copilot May 14, 2026
6c9df21
Split benchmark read ranges across readers
Copilot May 14, 2026
1725a08
Implement mmap partition classes and benchmark updates
Copilot May 14, 2026
38d6c6e
Fix mmap partition exports and run storage benchmark
Copilot May 14, 2026
af109b8
Address review feedback and rerun storage benchmark
Copilot May 14, 2026
6c5711b
Replace deprecated substr usage in mmap readable partition
Copilot May 14, 2026
710e429
Fix mmap partition review issues and rerun validations
Copilot May 14, 2026
043818e
Use mmap buffer directly in mmap partition read and write paths
Copilot May 14, 2026
29d0fb3
perf(mmap): defer marker write to flush, skip fdatasync when syncOnFl…
Copilot May 14, 2026
b4b6746
perf(mmap): address review - clarify comments in flush()
Copilot May 14, 2026
a107bb4
Add forked storage benchmark script
Copilot May 14, 2026
694ef60
Add forked multi-process storage benchmark
Copilot May 14, 2026
e4ab266
Optimize mmap grow path to keep marker writes flush-driven
Copilot May 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 69 additions & 21 deletions bench/bench-index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Benchmark from 'benchmark';
import benchmarks from 'beautify-benchmark';
import fs from 'fs-extra';
import Stable from 'event-storage';
import { Index as LatestIndex } from '../index.js';
import { Index as LatestIndex, MmapIndex } from '../index.js';

const Suite = new Benchmark.Suite('index');
Suite.on('start', () => fs.emptyDirSync('data'));
Expand All @@ -11,31 +11,79 @@ Suite.on('complete', () => benchmarks.log());
Suite.on('error', (e) => console.log(e.target.error));

const WRITES = 1000;
let stableCallCount = 0;
let latestCallCount = 0;
const READER_STEPS = [1, 2, 4, 8, 16];

function bench(index) {
index.open();
for (let i = 1; i<=WRITES; i++) {
index.add(new Stable.Index.Entry(i,2,4,8));
function bench({ IndexClass, dataDirectory, id, readers }) {
const name = `${id}.index`;
const writer = new IndexClass(name, { dataDirectory });
const readIndexes = [];
const ReaderClass = IndexClass.ReadOnly || IndexClass;

for (let reader = 0; reader < readers; reader++) {
const readIndex = new ReaderClass(name, { dataDirectory });
if (typeof readIndex.range !== 'function') {
readIndexes.push(new IndexClass(name, { dataDirectory }));
continue;
}
readIndexes.push(readIndex);
}

writer.open();
for (const index of readIndexes) {
index.open();
}
index.close();

let number;
index.open();
for (let entry of index.range(-WRITES + 1)) {
number = entry.number;
for (let i = 1; i <= WRITES; i++) {
writer.add(new IndexClass.Entry(i, 2, 4, 8));
}
index.close();
if (number < WRITES) throw new Error('Not all entries were written! Last entry was '+number);
writer.flush();

for (const index of readIndexes) {
index.close();
index.open();
}

for (let reader = 0; reader < readIndexes.length; reader++) {
const index = readIndexes[reader];
const start = Math.floor((reader * WRITES) / readers) + 1;
const end = Math.floor(((reader + 1) * WRITES) / readers);
const expectedLength = end - start + 1;
let number = 0;
const entries = index.range(start, end) || [];
for (const entry of entries) {
number = entry.number;
}
if (entries.length !== expectedLength || number !== end) {
throw new Error(
'Split read range failed for reader ' + reader +
': expected [' + start + ',' + end + '] but got last=' + number +
' length=' + entries.length
);
}
}

for (const index of readIndexes) {
index.close();
}
writer.close();
}

Suite.add('index [stable]', function() {
bench(new Stable.Index((stableCallCount++) + '.index', { dataDirectory: 'data/stable' }));
});
function addBenchmarks(label, IndexClass, dataDirectory) {
let callCount = 0;
for (const readers of READER_STEPS) {
Suite.add(`index [${label}] readers=${readers}`, function() {
bench({
IndexClass,
dataDirectory,
id: callCount++,
readers
});
});
}
}

Suite.add('index [latest]', function() {
bench(new LatestIndex((latestCallCount++) + '.index', { dataDirectory: 'data/latest' }));
});
addBenchmarks('stable', Stable.Index, 'data/stable');
addBenchmarks('latest', LatestIndex, 'data/latest');
addBenchmarks('mmap', MmapIndex, 'data/mmap');

Suite.run();
Suite.run();
Loading