@claude-flow/memory 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agentic-flow/intelligence.json +16 -0
- package/README.md +249 -0
- package/__tests__/coverage/base.css +224 -0
- package/__tests__/coverage/block-navigation.js +87 -0
- package/__tests__/coverage/coverage-final.json +19 -0
- package/__tests__/coverage/favicon.png +0 -0
- package/__tests__/coverage/index.html +206 -0
- package/__tests__/coverage/lcov-report/base.css +224 -0
- package/__tests__/coverage/lcov-report/block-navigation.js +87 -0
- package/__tests__/coverage/lcov-report/favicon.png +0 -0
- package/__tests__/coverage/lcov-report/index.html +206 -0
- package/__tests__/coverage/lcov-report/prettify.css +1 -0
- package/__tests__/coverage/lcov-report/prettify.js +2 -0
- package/__tests__/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/__tests__/coverage/lcov-report/sorter.js +210 -0
- package/__tests__/coverage/lcov-report/src/agentdb-adapter.ts.html +2737 -0
- package/__tests__/coverage/lcov-report/src/agentdb-backend.ts.html +3130 -0
- package/__tests__/coverage/lcov-report/src/application/commands/delete-memory.command.ts.html +601 -0
- package/__tests__/coverage/lcov-report/src/application/commands/index.html +131 -0
- package/__tests__/coverage/lcov-report/src/application/commands/store-memory.command.ts.html +394 -0
- package/__tests__/coverage/lcov-report/src/application/queries/index.html +116 -0
- package/__tests__/coverage/lcov-report/src/application/queries/search-memory.query.ts.html +796 -0
- package/__tests__/coverage/lcov-report/src/application/services/index.html +116 -0
- package/__tests__/coverage/lcov-report/src/application/services/memory-application-service.ts.html +793 -0
- package/__tests__/coverage/lcov-report/src/cache-manager.ts.html +1633 -0
- package/__tests__/coverage/lcov-report/src/database-provider.ts.html +1618 -0
- package/__tests__/coverage/lcov-report/src/domain/entities/index.html +116 -0
- package/__tests__/coverage/lcov-report/src/domain/entities/memory-entry.ts.html +952 -0
- package/__tests__/coverage/lcov-report/src/domain/services/index.html +116 -0
- package/__tests__/coverage/lcov-report/src/domain/services/memory-domain-service.ts.html +1294 -0
- package/__tests__/coverage/lcov-report/src/hnsw-index.ts.html +3124 -0
- package/__tests__/coverage/lcov-report/src/hybrid-backend.ts.html +2167 -0
- package/__tests__/coverage/lcov-report/src/index.html +266 -0
- package/__tests__/coverage/lcov-report/src/infrastructure/repositories/hybrid-memory-repository.ts.html +1633 -0
- package/__tests__/coverage/lcov-report/src/infrastructure/repositories/index.html +116 -0
- package/__tests__/coverage/lcov-report/src/migration.ts.html +2092 -0
- package/__tests__/coverage/lcov-report/src/query-builder.ts.html +1711 -0
- package/__tests__/coverage/lcov-report/src/sqlite-backend.ts.html +2281 -0
- package/__tests__/coverage/lcov-report/src/sqljs-backend.ts.html +2374 -0
- package/__tests__/coverage/lcov-report/src/types.ts.html +2266 -0
- package/__tests__/coverage/lcov.info +10238 -0
- package/__tests__/coverage/prettify.css +1 -0
- package/__tests__/coverage/prettify.js +2 -0
- package/__tests__/coverage/sort-arrow-sprite.png +0 -0
- package/__tests__/coverage/sorter.js +210 -0
- package/__tests__/coverage/src/agentdb-adapter.ts.html +2737 -0
- package/__tests__/coverage/src/agentdb-backend.ts.html +3130 -0
- package/__tests__/coverage/src/application/commands/delete-memory.command.ts.html +601 -0
- package/__tests__/coverage/src/application/commands/index.html +131 -0
- package/__tests__/coverage/src/application/commands/store-memory.command.ts.html +394 -0
- package/__tests__/coverage/src/application/queries/index.html +116 -0
- package/__tests__/coverage/src/application/queries/search-memory.query.ts.html +796 -0
- package/__tests__/coverage/src/application/services/index.html +116 -0
- package/__tests__/coverage/src/application/services/memory-application-service.ts.html +793 -0
- package/__tests__/coverage/src/cache-manager.ts.html +1633 -0
- package/__tests__/coverage/src/database-provider.ts.html +1618 -0
- package/__tests__/coverage/src/domain/entities/index.html +116 -0
- package/__tests__/coverage/src/domain/entities/memory-entry.ts.html +952 -0
- package/__tests__/coverage/src/domain/services/index.html +116 -0
- package/__tests__/coverage/src/domain/services/memory-domain-service.ts.html +1294 -0
- package/__tests__/coverage/src/hnsw-index.ts.html +3124 -0
- package/__tests__/coverage/src/hybrid-backend.ts.html +2167 -0
- package/__tests__/coverage/src/index.html +266 -0
- package/__tests__/coverage/src/infrastructure/repositories/hybrid-memory-repository.ts.html +1633 -0
- package/__tests__/coverage/src/infrastructure/repositories/index.html +116 -0
- package/__tests__/coverage/src/migration.ts.html +2092 -0
- package/__tests__/coverage/src/query-builder.ts.html +1711 -0
- package/__tests__/coverage/src/sqlite-backend.ts.html +2281 -0
- package/__tests__/coverage/src/sqljs-backend.ts.html +2374 -0
- package/__tests__/coverage/src/types.ts.html +2266 -0
- package/benchmarks/cache-hit-rate.bench.ts +535 -0
- package/benchmarks/hnsw-indexing.bench.ts +552 -0
- package/benchmarks/memory-write.bench.ts +469 -0
- package/benchmarks/vector-search.bench.ts +449 -0
- package/dist/agentdb-adapter.d.ts +146 -0
- package/dist/agentdb-adapter.d.ts.map +1 -0
- package/dist/agentdb-adapter.js +679 -0
- package/dist/agentdb-adapter.js.map +1 -0
- package/dist/agentdb-backend.d.ts +214 -0
- package/dist/agentdb-backend.d.ts.map +1 -0
- package/dist/agentdb-backend.js +827 -0
- package/dist/agentdb-backend.js.map +1 -0
- package/dist/agentdb-backend.test.d.ts +7 -0
- package/dist/agentdb-backend.test.d.ts.map +1 -0
- package/dist/agentdb-backend.test.js +258 -0
- package/dist/agentdb-backend.test.js.map +1 -0
- package/dist/application/commands/delete-memory.command.d.ts +65 -0
- package/dist/application/commands/delete-memory.command.d.ts.map +1 -0
- package/dist/application/commands/delete-memory.command.js +129 -0
- package/dist/application/commands/delete-memory.command.js.map +1 -0
- package/dist/application/commands/store-memory.command.d.ts +48 -0
- package/dist/application/commands/store-memory.command.d.ts.map +1 -0
- package/dist/application/commands/store-memory.command.js +72 -0
- package/dist/application/commands/store-memory.command.js.map +1 -0
- package/dist/application/index.d.ts +12 -0
- package/dist/application/index.d.ts.map +1 -0
- package/dist/application/index.js +15 -0
- package/dist/application/index.js.map +1 -0
- package/dist/application/queries/search-memory.query.d.ts +72 -0
- package/dist/application/queries/search-memory.query.d.ts.map +1 -0
- package/dist/application/queries/search-memory.query.js +143 -0
- package/dist/application/queries/search-memory.query.js.map +1 -0
- package/dist/application/services/memory-application-service.d.ts +121 -0
- package/dist/application/services/memory-application-service.d.ts.map +1 -0
- package/dist/application/services/memory-application-service.js +190 -0
- package/dist/application/services/memory-application-service.js.map +1 -0
- package/dist/cache-manager.d.ts +134 -0
- package/dist/cache-manager.d.ts.map +1 -0
- package/dist/cache-manager.js +407 -0
- package/dist/cache-manager.js.map +1 -0
- package/dist/database-provider.d.ts +86 -0
- package/dist/database-provider.d.ts.map +1 -0
- package/dist/database-provider.js +385 -0
- package/dist/database-provider.js.map +1 -0
- package/dist/database-provider.test.d.ts +7 -0
- package/dist/database-provider.test.d.ts.map +1 -0
- package/dist/database-provider.test.js +285 -0
- package/dist/database-provider.test.js.map +1 -0
- package/dist/domain/entities/memory-entry.d.ts +143 -0
- package/dist/domain/entities/memory-entry.d.ts.map +1 -0
- package/dist/domain/entities/memory-entry.js +226 -0
- package/dist/domain/entities/memory-entry.js.map +1 -0
- package/dist/domain/index.d.ts +11 -0
- package/dist/domain/index.d.ts.map +1 -0
- package/dist/domain/index.js +12 -0
- package/dist/domain/index.js.map +1 -0
- package/dist/domain/repositories/memory-repository.interface.d.ts +102 -0
- package/dist/domain/repositories/memory-repository.interface.d.ts.map +1 -0
- package/dist/domain/repositories/memory-repository.interface.js +11 -0
- package/dist/domain/repositories/memory-repository.interface.js.map +1 -0
- package/dist/domain/services/memory-domain-service.d.ts +105 -0
- package/dist/domain/services/memory-domain-service.d.ts.map +1 -0
- package/dist/domain/services/memory-domain-service.js +297 -0
- package/dist/domain/services/memory-domain-service.js.map +1 -0
- package/dist/hnsw-index.d.ts +111 -0
- package/dist/hnsw-index.d.ts.map +1 -0
- package/dist/hnsw-index.js +781 -0
- package/dist/hnsw-index.js.map +1 -0
- package/dist/hybrid-backend.d.ts +217 -0
- package/dist/hybrid-backend.d.ts.map +1 -0
- package/dist/hybrid-backend.js +491 -0
- package/dist/hybrid-backend.js.map +1 -0
- package/dist/hybrid-backend.test.d.ts +8 -0
- package/dist/hybrid-backend.test.d.ts.map +1 -0
- package/dist/hybrid-backend.test.js +320 -0
- package/dist/hybrid-backend.test.js.map +1 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +345 -0
- package/dist/index.js.map +1 -0
- package/dist/infrastructure/index.d.ts +17 -0
- package/dist/infrastructure/index.d.ts.map +1 -0
- package/dist/infrastructure/index.js +16 -0
- package/dist/infrastructure/index.js.map +1 -0
- package/dist/infrastructure/repositories/hybrid-memory-repository.d.ts +66 -0
- package/dist/infrastructure/repositories/hybrid-memory-repository.d.ts.map +1 -0
- package/dist/infrastructure/repositories/hybrid-memory-repository.js +409 -0
- package/dist/infrastructure/repositories/hybrid-memory-repository.js.map +1 -0
- package/dist/migration.d.ts +68 -0
- package/dist/migration.d.ts.map +1 -0
- package/dist/migration.js +513 -0
- package/dist/migration.js.map +1 -0
- package/dist/query-builder.d.ts +211 -0
- package/dist/query-builder.d.ts.map +1 -0
- package/dist/query-builder.js +438 -0
- package/dist/query-builder.js.map +1 -0
- package/dist/sqlite-backend.d.ts +121 -0
- package/dist/sqlite-backend.d.ts.map +1 -0
- package/dist/sqlite-backend.js +564 -0
- package/dist/sqlite-backend.js.map +1 -0
- package/dist/sqljs-backend.d.ts +128 -0
- package/dist/sqljs-backend.d.ts.map +1 -0
- package/dist/sqljs-backend.js +598 -0
- package/dist/sqljs-backend.js.map +1 -0
- package/dist/types.d.ts +481 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +58 -0
- package/dist/types.js.map +1 -0
- package/docs/AGENTDB-INTEGRATION.md +388 -0
- package/docs/CROSS_PLATFORM.md +505 -0
- package/docs/WINDOWS_SUPPORT.md +422 -0
- package/examples/agentdb-example.ts +345 -0
- package/examples/cross-platform-usage.ts +326 -0
- package/framework/benchmark.ts +112 -0
- package/package.json +31 -0
- package/src/agentdb-adapter.ts +884 -0
- package/src/agentdb-backend.test.ts +339 -0
- package/src/agentdb-backend.ts +1016 -0
- package/src/application/commands/delete-memory.command.ts +172 -0
- package/src/application/commands/store-memory.command.ts +103 -0
- package/src/application/index.ts +36 -0
- package/src/application/queries/search-memory.query.ts +237 -0
- package/src/application/services/memory-application-service.ts +236 -0
- package/src/cache-manager.ts +516 -0
- package/src/database-provider.test.ts +364 -0
- package/src/database-provider.ts +511 -0
- package/src/domain/entities/memory-entry.ts +289 -0
- package/src/domain/index.ts +35 -0
- package/src/domain/repositories/memory-repository.interface.ts +120 -0
- package/src/domain/services/memory-domain-service.ts +403 -0
- package/src/hnsw-index.ts +1013 -0
- package/src/hybrid-backend.test.ts +399 -0
- package/src/hybrid-backend.ts +694 -0
- package/src/index.ts +515 -0
- package/src/infrastructure/index.ts +23 -0
- package/src/infrastructure/repositories/hybrid-memory-repository.ts +516 -0
- package/src/migration.ts +669 -0
- package/src/query-builder.ts +542 -0
- package/src/sqlite-backend.ts +732 -0
- package/src/sqljs-backend.ts +763 -0
- package/src/types.ts +727 -0
- package/tsconfig.json +9 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/verify-cross-platform.ts +170 -0
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Write Benchmark
|
|
3
|
+
*
|
|
4
|
+
* Target: <5ms (10x faster than current ~50ms)
|
|
5
|
+
*
|
|
6
|
+
* Measures memory write operations including key-value stores,
|
|
7
|
+
* structured data, and vector embeddings.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { benchmark, BenchmarkRunner, formatTime, meetsTarget } from '../framework/benchmark.js';
|
|
11
|
+
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Memory Store Implementations
|
|
14
|
+
// ============================================================================
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Simple in-memory key-value store
|
|
18
|
+
*/
|
|
19
|
+
class SimpleMemoryStore {
|
|
20
|
+
private data = new Map<string, unknown>();
|
|
21
|
+
|
|
22
|
+
set(key: string, value: unknown): void {
|
|
23
|
+
this.data.set(key, value);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
get(key: string): unknown {
|
|
27
|
+
return this.data.get(key);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
delete(key: string): boolean {
|
|
31
|
+
return this.data.delete(key);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
clear(): void {
|
|
35
|
+
this.data.clear();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
get size(): number {
|
|
39
|
+
return this.data.size;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Typed array store for vectors
|
|
45
|
+
*/
|
|
46
|
+
class VectorStore {
|
|
47
|
+
private vectors: Map<string, Float32Array> = new Map();
|
|
48
|
+
private metadata: Map<string, object> = new Map();
|
|
49
|
+
|
|
50
|
+
set(key: string, vector: Float32Array, meta?: object): void {
|
|
51
|
+
this.vectors.set(key, vector);
|
|
52
|
+
if (meta) {
|
|
53
|
+
this.metadata.set(key, meta);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
get(key: string): { vector: Float32Array; metadata?: object } | undefined {
|
|
58
|
+
const vector = this.vectors.get(key);
|
|
59
|
+
if (!vector) return undefined;
|
|
60
|
+
return { vector, metadata: this.metadata.get(key) };
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
delete(key: string): boolean {
|
|
64
|
+
this.metadata.delete(key);
|
|
65
|
+
return this.vectors.delete(key);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
get size(): number {
|
|
69
|
+
return this.vectors.size;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Write-ahead log for durability
|
|
75
|
+
*/
|
|
76
|
+
class WriteAheadLog {
|
|
77
|
+
private entries: Array<{ timestamp: number; operation: string; key: string; value: unknown }> = [];
|
|
78
|
+
private maxEntries = 10000;
|
|
79
|
+
|
|
80
|
+
append(operation: string, key: string, value: unknown): number {
|
|
81
|
+
const entry = {
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
operation,
|
|
84
|
+
key,
|
|
85
|
+
value,
|
|
86
|
+
};
|
|
87
|
+
this.entries.push(entry);
|
|
88
|
+
|
|
89
|
+
// Compact if needed
|
|
90
|
+
if (this.entries.length > this.maxEntries) {
|
|
91
|
+
this.entries = this.entries.slice(-this.maxEntries / 2);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return this.entries.length;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get length(): number {
|
|
98
|
+
return this.entries.length;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Batched memory store for bulk operations
|
|
104
|
+
*/
|
|
105
|
+
class BatchedMemoryStore {
|
|
106
|
+
private data = new Map<string, unknown>();
|
|
107
|
+
private pendingWrites: Array<{ key: string; value: unknown }> = [];
|
|
108
|
+
private batchSize = 100;
|
|
109
|
+
|
|
110
|
+
queue(key: string, value: unknown): void {
|
|
111
|
+
this.pendingWrites.push({ key, value });
|
|
112
|
+
if (this.pendingWrites.length >= this.batchSize) {
|
|
113
|
+
this.flush();
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
flush(): void {
|
|
118
|
+
for (const { key, value } of this.pendingWrites) {
|
|
119
|
+
this.data.set(key, value);
|
|
120
|
+
}
|
|
121
|
+
this.pendingWrites = [];
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
get(key: string): unknown {
|
|
125
|
+
return this.data.get(key);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
get size(): number {
|
|
129
|
+
return this.data.size;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
get pendingCount(): number {
|
|
133
|
+
return this.pendingWrites.length;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ============================================================================
|
|
138
|
+
// Helper Functions
|
|
139
|
+
// ============================================================================
|
|
140
|
+
|
|
141
|
+
function generateVector(dim: number): Float32Array {
|
|
142
|
+
const v = new Float32Array(dim);
|
|
143
|
+
for (let i = 0; i < dim; i++) {
|
|
144
|
+
v[i] = Math.random() * 2 - 1;
|
|
145
|
+
}
|
|
146
|
+
return v;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function generateTestData(count: number): Array<{ key: string; value: object }> {
|
|
150
|
+
return Array.from({ length: count }, (_, i) => ({
|
|
151
|
+
key: `key-${i}`,
|
|
152
|
+
value: {
|
|
153
|
+
id: i,
|
|
154
|
+
name: `Item ${i}`,
|
|
155
|
+
timestamp: Date.now(),
|
|
156
|
+
tags: ['tag1', 'tag2', 'tag3'],
|
|
157
|
+
metadata: { source: 'benchmark', priority: i % 10 },
|
|
158
|
+
},
|
|
159
|
+
}));
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// Benchmark Suite
|
|
164
|
+
// ============================================================================
|
|
165
|
+
|
|
166
|
+
export async function runMemoryWriteBenchmarks(): Promise<void> {
|
|
167
|
+
const runner = new BenchmarkRunner('Memory Write');
|
|
168
|
+
|
|
169
|
+
console.log('\n--- Memory Write Benchmarks ---\n');
|
|
170
|
+
|
|
171
|
+
const store = new SimpleMemoryStore();
|
|
172
|
+
const vectorStore = new VectorStore();
|
|
173
|
+
const wal = new WriteAheadLog();
|
|
174
|
+
const batchedStore = new BatchedMemoryStore();
|
|
175
|
+
|
|
176
|
+
// Benchmark 1: Single Key-Value Write
|
|
177
|
+
const singleWriteResult = await runner.run(
|
|
178
|
+
'single-kv-write',
|
|
179
|
+
async () => {
|
|
180
|
+
store.set(`key-${Date.now()}`, { data: 'test value' });
|
|
181
|
+
},
|
|
182
|
+
{ iterations: 10000 }
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
console.log(`Single K-V Write: ${formatTime(singleWriteResult.mean)}`);
|
|
186
|
+
const kvTarget = meetsTarget('memory-write', singleWriteResult.mean);
|
|
187
|
+
console.log(` Target (<5ms): ${kvTarget.met ? 'PASS' : 'FAIL'}`);
|
|
188
|
+
|
|
189
|
+
// Benchmark 2: Batch Write (100 items)
|
|
190
|
+
const testData = generateTestData(100);
|
|
191
|
+
|
|
192
|
+
const batch100Result = await runner.run(
|
|
193
|
+
'batch-write-100',
|
|
194
|
+
async () => {
|
|
195
|
+
for (const { key, value } of testData) {
|
|
196
|
+
store.set(key, value);
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
{ iterations: 500 }
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
console.log(`Batch Write (100 items): ${formatTime(batch100Result.mean)}`);
|
|
203
|
+
console.log(` Per item: ${formatTime(batch100Result.mean / 100)}`);
|
|
204
|
+
|
|
205
|
+
// Benchmark 3: Vector Write
|
|
206
|
+
const vectorWriteResult = await runner.run(
|
|
207
|
+
'vector-write',
|
|
208
|
+
async () => {
|
|
209
|
+
const vector = generateVector(384);
|
|
210
|
+
vectorStore.set(`vec-${Date.now()}`, vector, { source: 'test' });
|
|
211
|
+
},
|
|
212
|
+
{ iterations: 5000 }
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
console.log(`Vector Write (384d): ${formatTime(vectorWriteResult.mean)}`);
|
|
216
|
+
|
|
217
|
+
// Benchmark 4: Batch Vector Write (100 vectors)
|
|
218
|
+
const batchVectorResult = await runner.run(
|
|
219
|
+
'batch-vector-write-100',
|
|
220
|
+
async () => {
|
|
221
|
+
for (let i = 0; i < 100; i++) {
|
|
222
|
+
const vector = generateVector(384);
|
|
223
|
+
vectorStore.set(`vec-${i}`, vector, { index: i });
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
{ iterations: 100 }
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
console.log(`Batch Vector Write (100x 384d): ${formatTime(batchVectorResult.mean)}`);
|
|
230
|
+
console.log(` Per vector: ${formatTime(batchVectorResult.mean / 100)}`);
|
|
231
|
+
|
|
232
|
+
// Benchmark 5: Write-Ahead Log Append
|
|
233
|
+
const walAppendResult = await runner.run(
|
|
234
|
+
'wal-append',
|
|
235
|
+
async () => {
|
|
236
|
+
wal.append('SET', 'key', { data: 'value' });
|
|
237
|
+
},
|
|
238
|
+
{ iterations: 10000 }
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
console.log(`WAL Append: ${formatTime(walAppendResult.mean)}`);
|
|
242
|
+
|
|
243
|
+
// Benchmark 6: Batched Store Queue
|
|
244
|
+
const batchedQueueResult = await runner.run(
|
|
245
|
+
'batched-store-queue',
|
|
246
|
+
async () => {
|
|
247
|
+
batchedStore.queue(`key-${Date.now()}`, { data: 'test' });
|
|
248
|
+
},
|
|
249
|
+
{ iterations: 10000 }
|
|
250
|
+
);
|
|
251
|
+
|
|
252
|
+
console.log(`Batched Store Queue: ${formatTime(batchedQueueResult.mean)}`);
|
|
253
|
+
|
|
254
|
+
// Benchmark 7: Batched Store Flush
|
|
255
|
+
// Queue up items first
|
|
256
|
+
for (let i = 0; i < 100; i++) {
|
|
257
|
+
batchedStore.queue(`flush-key-${i}`, { data: i });
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
const batchedFlushResult = await runner.run(
|
|
261
|
+
'batched-store-flush-100',
|
|
262
|
+
async () => {
|
|
263
|
+
// Queue and flush 100 items
|
|
264
|
+
for (let i = 0; i < 100; i++) {
|
|
265
|
+
batchedStore.queue(`key-${i}`, { data: i });
|
|
266
|
+
}
|
|
267
|
+
batchedStore.flush();
|
|
268
|
+
},
|
|
269
|
+
{ iterations: 500 }
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
console.log(`Batched Flush (100 items): ${formatTime(batchedFlushResult.mean)}`);
|
|
273
|
+
|
|
274
|
+
// Benchmark 8: Object Serialization (JSON)
|
|
275
|
+
const testObject = {
|
|
276
|
+
id: 'test-123',
|
|
277
|
+
name: 'Test Object',
|
|
278
|
+
nested: { level1: { level2: { value: 42 } } },
|
|
279
|
+
array: Array.from({ length: 100 }, (_, i) => i),
|
|
280
|
+
timestamp: new Date().toISOString(),
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
const jsonSerializeResult = await runner.run(
|
|
284
|
+
'json-serialize',
|
|
285
|
+
async () => {
|
|
286
|
+
JSON.stringify(testObject);
|
|
287
|
+
},
|
|
288
|
+
{ iterations: 10000 }
|
|
289
|
+
);
|
|
290
|
+
|
|
291
|
+
console.log(`JSON Serialize: ${formatTime(jsonSerializeResult.mean)}`);
|
|
292
|
+
|
|
293
|
+
// Benchmark 9: Object Cloning (for immutability)
|
|
294
|
+
const cloneResult = await runner.run(
|
|
295
|
+
'object-clone',
|
|
296
|
+
async () => {
|
|
297
|
+
const clone = structuredClone(testObject);
|
|
298
|
+
void clone;
|
|
299
|
+
},
|
|
300
|
+
{ iterations: 5000 }
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
console.log(`Object Clone: ${formatTime(cloneResult.mean)}`);
|
|
304
|
+
|
|
305
|
+
// Benchmark 10: Concurrent Writes
|
|
306
|
+
const concurrentWriteResult = await runner.run(
|
|
307
|
+
'concurrent-writes-10',
|
|
308
|
+
async () => {
|
|
309
|
+
await Promise.all(
|
|
310
|
+
Array.from({ length: 10 }, (_, i) =>
|
|
311
|
+
Promise.resolve(store.set(`concurrent-${i}`, { index: i }))
|
|
312
|
+
)
|
|
313
|
+
);
|
|
314
|
+
},
|
|
315
|
+
{ iterations: 1000 }
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
console.log(`Concurrent Writes (10): ${formatTime(concurrentWriteResult.mean)}`);
|
|
319
|
+
|
|
320
|
+
// Benchmark 11: Large Value Write
|
|
321
|
+
const largeValue = {
|
|
322
|
+
data: 'x'.repeat(10000),
|
|
323
|
+
nested: Array.from({ length: 100 }, (_, i) => ({
|
|
324
|
+
id: i,
|
|
325
|
+
content: 'content'.repeat(10),
|
|
326
|
+
})),
|
|
327
|
+
};
|
|
328
|
+
|
|
329
|
+
const largeWriteResult = await runner.run(
|
|
330
|
+
'large-value-write',
|
|
331
|
+
async () => {
|
|
332
|
+
store.set('large-key', largeValue);
|
|
333
|
+
},
|
|
334
|
+
{ iterations: 1000 }
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
console.log(`Large Value Write (~100KB): ${formatTime(largeWriteResult.mean)}`);
|
|
338
|
+
|
|
339
|
+
// Summary
|
|
340
|
+
console.log('\n--- Summary ---');
|
|
341
|
+
console.log(`Single write: ${formatTime(singleWriteResult.mean)}`);
|
|
342
|
+
console.log(`Batched (100): ${formatTime(batch100Result.mean)} (${formatTime(batch100Result.mean / 100)}/item)`);
|
|
343
|
+
console.log(`Vector (384d): ${formatTime(vectorWriteResult.mean)}`);
|
|
344
|
+
console.log(`WAL append: ${formatTime(walAppendResult.mean)}`);
|
|
345
|
+
console.log(`Batch queue: ${formatTime(batchedQueueResult.mean)} (${(batchedQueueResult.opsPerSecond).toFixed(0)} ops/sec)`);
|
|
346
|
+
|
|
347
|
+
// Print full results
|
|
348
|
+
runner.printResults();
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// ============================================================================
|
|
352
|
+
// Memory Write Optimization Strategies
|
|
353
|
+
// ============================================================================
|
|
354
|
+
|
|
355
|
+
export const memoryWriteOptimizations = {
|
|
356
|
+
/**
|
|
357
|
+
* Write batching: Batch multiple writes together
|
|
358
|
+
*/
|
|
359
|
+
writeBatching: {
|
|
360
|
+
description: 'Batch multiple writes and flush periodically',
|
|
361
|
+
expectedImprovement: '5-10x',
|
|
362
|
+
implementation: `
|
|
363
|
+
class BatchedWriter {
|
|
364
|
+
private batch: Write[] = [];
|
|
365
|
+
private batchSize = 100;
|
|
366
|
+
private flushInterval = 100; // ms
|
|
367
|
+
|
|
368
|
+
write(key: string, value: unknown): void {
|
|
369
|
+
this.batch.push({ key, value });
|
|
370
|
+
if (this.batch.length >= this.batchSize) {
|
|
371
|
+
this.flush();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
private flush(): void {
|
|
376
|
+
const writes = this.batch;
|
|
377
|
+
this.batch = [];
|
|
378
|
+
for (const { key, value } of writes) {
|
|
379
|
+
this.store.set(key, value);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
`,
|
|
384
|
+
},
|
|
385
|
+
|
|
386
|
+
/**
|
|
387
|
+
* Object pooling: Reuse objects to avoid allocation
|
|
388
|
+
*/
|
|
389
|
+
objectPooling: {
|
|
390
|
+
description: 'Pool and reuse objects to reduce GC pressure',
|
|
391
|
+
expectedImprovement: '20-40%',
|
|
392
|
+
implementation: `
|
|
393
|
+
class ObjectPool<T> {
|
|
394
|
+
private pool: T[] = [];
|
|
395
|
+
|
|
396
|
+
acquire(): T {
|
|
397
|
+
return this.pool.pop() || this.create();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
release(obj: T): void {
|
|
401
|
+
this.reset(obj);
|
|
402
|
+
this.pool.push(obj);
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
`,
|
|
406
|
+
},
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Typed arrays: Use typed arrays for numeric data
|
|
410
|
+
*/
|
|
411
|
+
typedArrays: {
|
|
412
|
+
description: 'Use Float32Array/Int32Array for numeric data',
|
|
413
|
+
expectedImprovement: '2-4x memory, 1.5-2x speed',
|
|
414
|
+
implementation: `
|
|
415
|
+
// Instead of:
|
|
416
|
+
const vector = new Array(384).fill(0);
|
|
417
|
+
|
|
418
|
+
// Use:
|
|
419
|
+
const vector = new Float32Array(384);
|
|
420
|
+
`,
|
|
421
|
+
},
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Write-ahead logging: Append-only for durability
|
|
425
|
+
*/
|
|
426
|
+
walLogging: {
|
|
427
|
+
description: 'Use append-only WAL for crash recovery',
|
|
428
|
+
expectedImprovement: 'Durability with <10% overhead',
|
|
429
|
+
implementation: `
|
|
430
|
+
class WAL {
|
|
431
|
+
private fd: number;
|
|
432
|
+
|
|
433
|
+
async append(entry: LogEntry): Promise<void> {
|
|
434
|
+
const data = Buffer.from(JSON.stringify(entry) + '\\n');
|
|
435
|
+
await fs.write(this.fd, data);
|
|
436
|
+
await fs.fdatasync(this.fd);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
`,
|
|
440
|
+
},
|
|
441
|
+
|
|
442
|
+
/**
|
|
443
|
+
* Copy-on-write: Avoid unnecessary copying
|
|
444
|
+
*/
|
|
445
|
+
copyOnWrite: {
|
|
446
|
+
description: 'Use COW semantics for large objects',
|
|
447
|
+
expectedImprovement: '30-50% for read-heavy workloads',
|
|
448
|
+
implementation: `
|
|
449
|
+
class COWStore {
|
|
450
|
+
private data = new Map<string, { value: unknown; version: number }>();
|
|
451
|
+
|
|
452
|
+
set(key: string, value: unknown): void {
|
|
453
|
+
const existing = this.data.get(key);
|
|
454
|
+
if (existing && deepEqual(existing.value, value)) {
|
|
455
|
+
return; // No change needed
|
|
456
|
+
}
|
|
457
|
+
this.data.set(key, { value, version: (existing?.version ?? 0) + 1 });
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
`,
|
|
461
|
+
},
|
|
462
|
+
};
|
|
463
|
+
|
|
464
|
+
// Run if executed directly
|
|
465
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
466
|
+
runMemoryWriteBenchmarks().catch(console.error);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
export default runMemoryWriteBenchmarks;
|