@plures/pluresdb 1.4.0
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/LICENSE +72 -0
- package/README.md +450 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/better-sqlite3-shared.d.ts +12 -0
- package/dist/better-sqlite3-shared.d.ts.map +1 -0
- package/dist/better-sqlite3-shared.js +143 -0
- package/dist/better-sqlite3-shared.js.map +1 -0
- package/dist/better-sqlite3.d.ts +4 -0
- package/dist/better-sqlite3.d.ts.map +1 -0
- package/dist/better-sqlite3.js +8 -0
- package/dist/better-sqlite3.js.map +1 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +258 -0
- package/dist/cli.js.map +1 -0
- package/dist/node-index.d.ts +148 -0
- package/dist/node-index.d.ts.map +1 -0
- package/dist/node-index.js +665 -0
- package/dist/node-index.js.map +1 -0
- package/dist/node-wrapper.d.ts +44 -0
- package/dist/node-wrapper.d.ts.map +1 -0
- package/dist/node-wrapper.js +296 -0
- package/dist/node-wrapper.js.map +1 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/node-types.d.ts +71 -0
- package/dist/types/node-types.d.ts.map +1 -0
- package/dist/types/node-types.js +6 -0
- package/dist/types/node-types.js.map +1 -0
- package/dist/vscode/extension.d.ts +81 -0
- package/dist/vscode/extension.d.ts.map +1 -0
- package/dist/vscode/extension.js +309 -0
- package/dist/vscode/extension.js.map +1 -0
- package/examples/basic-usage.d.ts +2 -0
- package/examples/basic-usage.d.ts.map +1 -0
- package/examples/basic-usage.js +26 -0
- package/examples/basic-usage.js.map +1 -0
- package/examples/basic-usage.ts +29 -0
- package/examples/vscode-extension-example/README.md +95 -0
- package/examples/vscode-extension-example/package.json +49 -0
- package/examples/vscode-extension-example/src/extension.ts +172 -0
- package/examples/vscode-extension-example/tsconfig.json +12 -0
- package/examples/vscode-extension-integration.d.ts +31 -0
- package/examples/vscode-extension-integration.d.ts.map +1 -0
- package/examples/vscode-extension-integration.js +319 -0
- package/examples/vscode-extension-integration.js.map +1 -0
- package/examples/vscode-extension-integration.ts +41 -0
- package/legacy/benchmarks/memory-benchmarks.ts +350 -0
- package/legacy/benchmarks/run-benchmarks.ts +315 -0
- package/legacy/better-sqlite3-shared.ts +157 -0
- package/legacy/better-sqlite3.ts +4 -0
- package/legacy/cli.ts +241 -0
- package/legacy/config.ts +50 -0
- package/legacy/core/crdt.ts +107 -0
- package/legacy/core/database.ts +529 -0
- package/legacy/healthcheck.ts +162 -0
- package/legacy/http/api-server.ts +438 -0
- package/legacy/index.ts +28 -0
- package/legacy/logic/rules.ts +46 -0
- package/legacy/main.rs +3 -0
- package/legacy/main.ts +197 -0
- package/legacy/network/websocket-server.ts +115 -0
- package/legacy/node-index.ts +823 -0
- package/legacy/node-wrapper.ts +329 -0
- package/legacy/sqlite-compat.ts +633 -0
- package/legacy/sqlite3-compat.ts +55 -0
- package/legacy/storage/kv-storage.ts +73 -0
- package/legacy/tests/core.test.ts +305 -0
- package/legacy/tests/fixtures/performance-data.json +71 -0
- package/legacy/tests/fixtures/test-data.json +129 -0
- package/legacy/tests/integration/api-server.test.ts +334 -0
- package/legacy/tests/integration/mesh-network.test.ts +303 -0
- package/legacy/tests/logic.test.ts +34 -0
- package/legacy/tests/performance/load.test.ts +290 -0
- package/legacy/tests/security/input-validation.test.ts +286 -0
- package/legacy/tests/unit/core.test.ts +226 -0
- package/legacy/tests/unit/subscriptions.test.ts +135 -0
- package/legacy/tests/unit/vector-search.test.ts +173 -0
- package/legacy/tests/vscode_extension_test.ts +281 -0
- package/legacy/types/index.ts +32 -0
- package/legacy/types/node-types.ts +80 -0
- package/legacy/util/debug.ts +14 -0
- package/legacy/vector/index.ts +59 -0
- package/legacy/vscode/extension.ts +387 -0
- package/package.json +127 -0
- package/scripts/compiled-crud-verify.ts +30 -0
- package/scripts/dogfood.ts +297 -0
- package/scripts/postinstall.js +156 -0
- package/scripts/release-check.js +190 -0
- package/scripts/run-tests.ts +178 -0
- package/scripts/setup-libclang.ps1 +209 -0
- package/scripts/update-changelog.js +214 -0
- package/web/README.md +27 -0
- package/web/svelte/package.json +31 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
#!/usr/bin/env -S deno run -A
|
|
2
|
+
|
|
3
|
+
import { GunDB } from "../core/database.ts";
|
|
4
|
+
|
|
5
|
+
interface MemoryMetrics {
|
|
6
|
+
operation: string;
|
|
7
|
+
initialMemory: number;
|
|
8
|
+
finalMemory: number;
|
|
9
|
+
memoryIncrease: number;
|
|
10
|
+
recordCount: number;
|
|
11
|
+
memoryPerRecord: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class MemoryBenchmark {
|
|
15
|
+
private results: MemoryMetrics[] = [];
|
|
16
|
+
|
|
17
|
+
private getMemoryUsage(): number {
|
|
18
|
+
return (performance as any).memory?.usedJSHeapSize || 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async measureMemoryUsage(
|
|
22
|
+
operation: string,
|
|
23
|
+
recordCount: number,
|
|
24
|
+
operationFn: () => Promise<void>,
|
|
25
|
+
): Promise<MemoryMetrics> {
|
|
26
|
+
console.log(`Measuring memory usage for: ${operation}`);
|
|
27
|
+
|
|
28
|
+
// Force garbage collection if available
|
|
29
|
+
if ((globalThis as any).gc) {
|
|
30
|
+
(globalThis as any).gc();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const initialMemory = this.getMemoryUsage();
|
|
34
|
+
|
|
35
|
+
await operationFn();
|
|
36
|
+
|
|
37
|
+
// Force garbage collection if available
|
|
38
|
+
if ((globalThis as any).gc) {
|
|
39
|
+
(globalThis as any).gc();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const finalMemory = this.getMemoryUsage();
|
|
43
|
+
const memoryIncrease = finalMemory - initialMemory;
|
|
44
|
+
const memoryPerRecord = memoryIncrease / recordCount;
|
|
45
|
+
|
|
46
|
+
const metrics: MemoryMetrics = {
|
|
47
|
+
operation,
|
|
48
|
+
initialMemory,
|
|
49
|
+
finalMemory,
|
|
50
|
+
memoryIncrease,
|
|
51
|
+
recordCount,
|
|
52
|
+
memoryPerRecord,
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
this.results.push(metrics);
|
|
56
|
+
|
|
57
|
+
console.log(
|
|
58
|
+
` Initial Memory: ${(initialMemory / 1024 / 1024).toFixed(2)}MB`,
|
|
59
|
+
);
|
|
60
|
+
console.log(` Final Memory: ${(finalMemory / 1024 / 1024).toFixed(2)}MB`);
|
|
61
|
+
console.log(
|
|
62
|
+
` Memory Increase: ${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`,
|
|
63
|
+
);
|
|
64
|
+
console.log(` Memory per Record: ${memoryPerRecord.toFixed(2)} bytes`);
|
|
65
|
+
console.log();
|
|
66
|
+
|
|
67
|
+
return metrics;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
printSummary() {
|
|
71
|
+
console.log("\n" + "=".repeat(80));
|
|
72
|
+
console.log("MEMORY USAGE SUMMARY");
|
|
73
|
+
console.log("=".repeat(80));
|
|
74
|
+
|
|
75
|
+
this.results.forEach((result) => {
|
|
76
|
+
console.log(`${result.operation}:`);
|
|
77
|
+
console.log(` Records: ${result.recordCount.toLocaleString()}`);
|
|
78
|
+
console.log(
|
|
79
|
+
` Memory Increase: ${
|
|
80
|
+
(result.memoryIncrease / 1024 / 1024).toFixed(2)
|
|
81
|
+
}MB`,
|
|
82
|
+
);
|
|
83
|
+
console.log(
|
|
84
|
+
` Memory per Record: ${result.memoryPerRecord.toFixed(2)} bytes`,
|
|
85
|
+
);
|
|
86
|
+
console.log();
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function runMemoryBenchmarks() {
|
|
92
|
+
const benchmark = new MemoryBenchmark();
|
|
93
|
+
const db = new GunDB();
|
|
94
|
+
|
|
95
|
+
try {
|
|
96
|
+
const kvPath = await Deno.makeTempFile({
|
|
97
|
+
prefix: "kv_",
|
|
98
|
+
suffix: ".sqlite",
|
|
99
|
+
});
|
|
100
|
+
await db.ready(kvPath);
|
|
101
|
+
|
|
102
|
+
console.log("Starting Memory Benchmarks...\n");
|
|
103
|
+
|
|
104
|
+
// Benchmark 1: Small Records
|
|
105
|
+
await benchmark.measureMemoryUsage(
|
|
106
|
+
"Small Records (100 bytes)",
|
|
107
|
+
1000,
|
|
108
|
+
async () => {
|
|
109
|
+
for (let i = 0; i < 1000; i++) {
|
|
110
|
+
await db.put(`small:${i}`, {
|
|
111
|
+
id: i,
|
|
112
|
+
data: "x".repeat(100),
|
|
113
|
+
timestamp: Date.now(),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// Benchmark 2: Medium Records
|
|
120
|
+
await benchmark.measureMemoryUsage(
|
|
121
|
+
"Medium Records (1KB)",
|
|
122
|
+
1000,
|
|
123
|
+
async () => {
|
|
124
|
+
for (let i = 0; i < 1000; i++) {
|
|
125
|
+
await db.put(`medium:${i}`, {
|
|
126
|
+
id: i,
|
|
127
|
+
data: "x".repeat(1024),
|
|
128
|
+
timestamp: Date.now(),
|
|
129
|
+
metadata: { size: "medium", type: "test" },
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Benchmark 3: Large Records
|
|
136
|
+
await benchmark.measureMemoryUsage(
|
|
137
|
+
"Large Records (10KB)",
|
|
138
|
+
100,
|
|
139
|
+
async () => {
|
|
140
|
+
for (let i = 0; i < 100; i++) {
|
|
141
|
+
await db.put(`large:${i}`, {
|
|
142
|
+
id: i,
|
|
143
|
+
data: "x".repeat(10 * 1024),
|
|
144
|
+
timestamp: Date.now(),
|
|
145
|
+
metadata: { size: "large", type: "test" },
|
|
146
|
+
additional: "y".repeat(1024),
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
);
|
|
151
|
+
|
|
152
|
+
// Benchmark 4: Vector Data
|
|
153
|
+
await benchmark.measureMemoryUsage(
|
|
154
|
+
"Vector Data (100 dimensions)",
|
|
155
|
+
500,
|
|
156
|
+
async () => {
|
|
157
|
+
for (let i = 0; i < 500; i++) {
|
|
158
|
+
const vector = Array.from({ length: 100 }, () => Math.random());
|
|
159
|
+
await db.put(`vector:${i}`, {
|
|
160
|
+
id: i,
|
|
161
|
+
text: `Document ${i} with vector data`,
|
|
162
|
+
vector: vector,
|
|
163
|
+
timestamp: Date.now(),
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
},
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
// Benchmark 5: Nested Objects
|
|
170
|
+
await benchmark.measureMemoryUsage("Nested Objects", 500, async () => {
|
|
171
|
+
for (let i = 0; i < 500; i++) {
|
|
172
|
+
await db.put(`nested:${i}`, {
|
|
173
|
+
id: i,
|
|
174
|
+
user: {
|
|
175
|
+
name: `User ${i}`,
|
|
176
|
+
email: `user${i}@example.com`,
|
|
177
|
+
profile: {
|
|
178
|
+
age: 20 + (i % 50),
|
|
179
|
+
location: `City ${i}`,
|
|
180
|
+
preferences: {
|
|
181
|
+
theme: i % 2 === 0 ? "dark" : "light",
|
|
182
|
+
notifications: true,
|
|
183
|
+
privacy: "public",
|
|
184
|
+
},
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
metadata: {
|
|
188
|
+
created: Date.now(),
|
|
189
|
+
updated: Date.now(),
|
|
190
|
+
version: 1,
|
|
191
|
+
},
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Benchmark 6: Subscriptions Memory Usage
|
|
197
|
+
await benchmark.measureMemoryUsage("Subscriptions", 1000, async () => {
|
|
198
|
+
const subscriptions: Array<() => void> = [];
|
|
199
|
+
for (let i = 0; i < 1000; i++) {
|
|
200
|
+
const unsubscribe = db.on(`sub:${i}`, () => {});
|
|
201
|
+
subscriptions.push(unsubscribe);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Store subscriptions for cleanup
|
|
205
|
+
(globalThis as any).subscriptions = subscriptions;
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
// Clean up subscriptions
|
|
209
|
+
if ((globalThis as any).subscriptions) {
|
|
210
|
+
((globalThis as any).subscriptions as Array<() => void>).forEach((
|
|
211
|
+
unsubscribe,
|
|
212
|
+
) => unsubscribe());
|
|
213
|
+
delete (globalThis as any).subscriptions;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Benchmark 7: Type System Memory Usage
|
|
217
|
+
await benchmark.measureMemoryUsage("Type System", 1000, async () => {
|
|
218
|
+
for (let i = 0; i < 1000; i++) {
|
|
219
|
+
await db.put(`type:${i}`, { name: `Item ${i}` });
|
|
220
|
+
await db.setType(`type:${i}`, "TestItem");
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
// Benchmark 8: CRDT Operations Memory Usage
|
|
225
|
+
await benchmark.measureMemoryUsage("CRDT Operations", 1000, async () => {
|
|
226
|
+
for (let i = 0; i < 1000; i++) {
|
|
227
|
+
await db.put(`crdt:${i}`, {
|
|
228
|
+
value: i,
|
|
229
|
+
timestamp: Date.now(),
|
|
230
|
+
vectorClock: { peer1: i, peer2: i * 2 },
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
benchmark.printSummary();
|
|
236
|
+
} finally {
|
|
237
|
+
await db.close();
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
async function runMemoryLeakTests() {
|
|
242
|
+
console.log("\n" + "=".repeat(80));
|
|
243
|
+
console.log("MEMORY LEAK TESTS");
|
|
244
|
+
console.log("=".repeat(80));
|
|
245
|
+
|
|
246
|
+
const db = new GunDB();
|
|
247
|
+
try {
|
|
248
|
+
const kvPath = await Deno.makeTempFile({
|
|
249
|
+
prefix: "kv_",
|
|
250
|
+
suffix: ".sqlite",
|
|
251
|
+
});
|
|
252
|
+
await db.ready(kvPath);
|
|
253
|
+
|
|
254
|
+
// Test 1: Subscription Memory Leaks
|
|
255
|
+
console.log("Testing subscription memory leaks...");
|
|
256
|
+
|
|
257
|
+
const initialMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
258
|
+
|
|
259
|
+
// Create and destroy many subscriptions
|
|
260
|
+
for (let cycle = 0; cycle < 10; cycle++) {
|
|
261
|
+
const subscriptions: Array<() => void> = [];
|
|
262
|
+
|
|
263
|
+
for (let i = 0; i < 100; i++) {
|
|
264
|
+
subscriptions.push(db.on(`leak:${cycle}:${i}`, () => {}));
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Destroy all subscriptions
|
|
268
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
269
|
+
|
|
270
|
+
// Force garbage collection if available
|
|
271
|
+
if ((globalThis as any).gc) {
|
|
272
|
+
(globalThis as any).gc();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const finalMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
277
|
+
const memoryIncrease = finalMemory - initialMemory;
|
|
278
|
+
|
|
279
|
+
console.log(
|
|
280
|
+
`Memory increase after subscription cycles: ${
|
|
281
|
+
(memoryIncrease / 1024).toFixed(2)
|
|
282
|
+
}KB`,
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
if (memoryIncrease > 1024 * 1024) {
|
|
286
|
+
// More than 1MB
|
|
287
|
+
console.log("⚠️ Potential memory leak detected in subscriptions");
|
|
288
|
+
} else {
|
|
289
|
+
console.log("✓ No significant memory leak in subscriptions");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Test 2: CRUD Operations Memory Leaks
|
|
293
|
+
console.log("\nTesting CRUD operations memory leaks...");
|
|
294
|
+
|
|
295
|
+
const crudInitialMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
296
|
+
|
|
297
|
+
// Perform many CRUD operations
|
|
298
|
+
for (let cycle = 0; cycle < 100; cycle++) {
|
|
299
|
+
for (let i = 0; i < 100; i++) {
|
|
300
|
+
await db.put(`leak:${cycle}:${i}`, {
|
|
301
|
+
data: `Cycle ${cycle} Item ${i}`,
|
|
302
|
+
});
|
|
303
|
+
await db.get(`leak:${cycle}:${i}`);
|
|
304
|
+
await db.delete(`leak:${cycle}:${i}`);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Force garbage collection if available
|
|
308
|
+
if ((globalThis as any).gc) {
|
|
309
|
+
(globalThis as any).gc();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const crudFinalMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
314
|
+
const crudMemoryIncrease = crudFinalMemory - crudInitialMemory;
|
|
315
|
+
|
|
316
|
+
console.log(
|
|
317
|
+
`Memory increase after CRUD cycles: ${
|
|
318
|
+
(crudMemoryIncrease / 1024).toFixed(2)
|
|
319
|
+
}KB`,
|
|
320
|
+
);
|
|
321
|
+
|
|
322
|
+
if (crudMemoryIncrease > 1024 * 1024) {
|
|
323
|
+
// More than 1MB
|
|
324
|
+
console.log("⚠️ Potential memory leak detected in CRUD operations");
|
|
325
|
+
} else {
|
|
326
|
+
console.log("✓ No significant memory leak in CRUD operations");
|
|
327
|
+
}
|
|
328
|
+
} finally {
|
|
329
|
+
await db.close();
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function main() {
|
|
334
|
+
console.log("PluresDB Memory Benchmarks");
|
|
335
|
+
console.log("===========================\n");
|
|
336
|
+
|
|
337
|
+
try {
|
|
338
|
+
await runMemoryBenchmarks();
|
|
339
|
+
await runMemoryLeakTests();
|
|
340
|
+
|
|
341
|
+
console.log("\nMemory benchmarks completed successfully!");
|
|
342
|
+
} catch (error) {
|
|
343
|
+
console.error("Memory benchmark failed:", error);
|
|
344
|
+
Deno.exit(1);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
if (import.meta.main) {
|
|
349
|
+
await main();
|
|
350
|
+
}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
#!/usr/bin/env -S deno run -A
|
|
2
|
+
|
|
3
|
+
import { GunDB } from "../core/database.ts";
|
|
4
|
+
|
|
5
|
+
interface BenchmarkResult {
|
|
6
|
+
name: string;
|
|
7
|
+
operations: number;
|
|
8
|
+
totalTime: number;
|
|
9
|
+
averageTime: number;
|
|
10
|
+
operationsPerSecond: number;
|
|
11
|
+
memoryUsage?: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class BenchmarkRunner {
|
|
15
|
+
private results: BenchmarkResult[] = [];
|
|
16
|
+
|
|
17
|
+
async runBenchmark(
|
|
18
|
+
name: string,
|
|
19
|
+
operations: number,
|
|
20
|
+
operation: () => Promise<void>,
|
|
21
|
+
): Promise<BenchmarkResult> {
|
|
22
|
+
console.log(`Running benchmark: ${name} (${operations} operations)`);
|
|
23
|
+
|
|
24
|
+
const startTime = performance.now();
|
|
25
|
+
const startMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < operations; i++) {
|
|
28
|
+
await operation();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const endTime = performance.now();
|
|
32
|
+
const endMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
33
|
+
|
|
34
|
+
const totalTime = endTime - startTime;
|
|
35
|
+
const averageTime = totalTime / operations;
|
|
36
|
+
const operationsPerSecond = (operations / totalTime) * 1000;
|
|
37
|
+
const memoryUsage = endMemory - startMemory;
|
|
38
|
+
|
|
39
|
+
const result: BenchmarkResult = {
|
|
40
|
+
name,
|
|
41
|
+
operations,
|
|
42
|
+
totalTime,
|
|
43
|
+
averageTime,
|
|
44
|
+
operationsPerSecond,
|
|
45
|
+
memoryUsage,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
this.results.push(result);
|
|
49
|
+
console.log(
|
|
50
|
+
` ✓ ${operationsPerSecond.toFixed(2)} ops/sec (${
|
|
51
|
+
averageTime.toFixed(2)
|
|
52
|
+
}ms avg)`,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
printSummary() {
|
|
59
|
+
console.log("\n" + "=".repeat(80));
|
|
60
|
+
console.log("BENCHMARK SUMMARY");
|
|
61
|
+
console.log("=".repeat(80));
|
|
62
|
+
|
|
63
|
+
this.results.forEach((result) => {
|
|
64
|
+
console.log(`${result.name}:`);
|
|
65
|
+
console.log(` Operations: ${result.operations.toLocaleString()}`);
|
|
66
|
+
console.log(` Total Time: ${result.totalTime.toFixed(2)}ms`);
|
|
67
|
+
console.log(` Average Time: ${result.averageTime.toFixed(2)}ms`);
|
|
68
|
+
console.log(` Operations/sec: ${result.operationsPerSecond.toFixed(2)}`);
|
|
69
|
+
if (result.memoryUsage) {
|
|
70
|
+
console.log(
|
|
71
|
+
` Memory Usage: ${(result.memoryUsage / 1024 / 1024).toFixed(2)}MB`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
console.log();
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function runCoreBenchmarks() {
|
|
80
|
+
const runner = new BenchmarkRunner();
|
|
81
|
+
const db = new GunDB();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
const kvPath = await Deno.makeTempFile({
|
|
85
|
+
prefix: "kv_",
|
|
86
|
+
suffix: ".sqlite",
|
|
87
|
+
});
|
|
88
|
+
await db.ready(kvPath);
|
|
89
|
+
|
|
90
|
+
console.log("Starting Core Database Benchmarks...\n");
|
|
91
|
+
|
|
92
|
+
// Benchmark 1: Basic CRUD Operations
|
|
93
|
+
await runner.runBenchmark("Basic CRUD Operations", 1000, async () => {
|
|
94
|
+
const id = `crud:${Math.random()}`;
|
|
95
|
+
await db.put(id, { value: Math.random(), timestamp: Date.now() });
|
|
96
|
+
await db.get(id);
|
|
97
|
+
await db.delete(id);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Benchmark 2: Bulk Insert
|
|
101
|
+
await runner.runBenchmark("Bulk Insert", 5000, async () => {
|
|
102
|
+
const id = `bulk:${Math.random()}`;
|
|
103
|
+
await db.put(id, {
|
|
104
|
+
data: "x".repeat(100),
|
|
105
|
+
timestamp: Date.now(),
|
|
106
|
+
random: Math.random(),
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Benchmark 3: Bulk Read
|
|
111
|
+
// First populate with data
|
|
112
|
+
for (let i = 0; i < 1000; i++) {
|
|
113
|
+
await db.put(`read:${i}`, { value: i, data: `Data ${i}` });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let readCount = 0;
|
|
117
|
+
await runner.runBenchmark("Bulk Read", 1000, async () => {
|
|
118
|
+
await db.get(`read:${readCount % 1000}`);
|
|
119
|
+
readCount++;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Benchmark 4: Vector Search
|
|
123
|
+
// First populate with documents
|
|
124
|
+
for (let i = 0; i < 100; i++) {
|
|
125
|
+
await db.put(`doc:${i}`, {
|
|
126
|
+
text:
|
|
127
|
+
`Document ${i} about machine learning and artificial intelligence`,
|
|
128
|
+
content:
|
|
129
|
+
`This is document number ${i} containing information about AI and ML algorithms`,
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const searchQueries = [
|
|
134
|
+
"machine learning",
|
|
135
|
+
"artificial intelligence",
|
|
136
|
+
"neural networks",
|
|
137
|
+
"deep learning",
|
|
138
|
+
"data science",
|
|
139
|
+
];
|
|
140
|
+
|
|
141
|
+
let queryCount = 0;
|
|
142
|
+
await runner.runBenchmark("Vector Search", 100, async () => {
|
|
143
|
+
const query = searchQueries[queryCount % searchQueries.length];
|
|
144
|
+
await db.vectorSearch(query, 10);
|
|
145
|
+
queryCount++;
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Benchmark 5: Subscription Performance
|
|
149
|
+
const subscriptions: Array<() => void> = [];
|
|
150
|
+
for (let i = 0; i < 100; i++) {
|
|
151
|
+
subscriptions.push(db.on(`sub:${i}`, () => {}));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
let updateCount = 0;
|
|
155
|
+
await runner.runBenchmark("Subscription Updates", 500, async () => {
|
|
156
|
+
await db.put(`sub:${updateCount % 100}`, {
|
|
157
|
+
update: updateCount,
|
|
158
|
+
timestamp: Date.now(),
|
|
159
|
+
});
|
|
160
|
+
updateCount++;
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// Clean up subscriptions
|
|
164
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
165
|
+
|
|
166
|
+
// Benchmark 6: Type System Operations
|
|
167
|
+
await runner.runBenchmark("Type System Operations", 1000, async () => {
|
|
168
|
+
const id = `type:${Math.random()}`;
|
|
169
|
+
await db.put(id, { name: `Item ${Math.random()}` });
|
|
170
|
+
await db.setType(id, "TestItem");
|
|
171
|
+
await db.instancesOf("TestItem");
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
runner.printSummary();
|
|
175
|
+
} finally {
|
|
176
|
+
await db.close();
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
async function runNetworkBenchmarks() {
|
|
181
|
+
const runner = new BenchmarkRunner();
|
|
182
|
+
|
|
183
|
+
console.log("Starting Network Benchmarks...\n");
|
|
184
|
+
|
|
185
|
+
// Benchmark 1: WebSocket Connection Performance
|
|
186
|
+
const db = new GunDB();
|
|
187
|
+
try {
|
|
188
|
+
const kvPath = await Deno.makeTempFile({
|
|
189
|
+
prefix: "kv_",
|
|
190
|
+
suffix: ".sqlite",
|
|
191
|
+
});
|
|
192
|
+
await db.ready(kvPath);
|
|
193
|
+
|
|
194
|
+
const port = 18000 + Math.floor(Math.random() * 10000);
|
|
195
|
+
await db.serve({ port });
|
|
196
|
+
|
|
197
|
+
const serverUrl = `ws://localhost:${port}`;
|
|
198
|
+
|
|
199
|
+
await runner.runBenchmark("WebSocket Connections", 10, async () => {
|
|
200
|
+
const clientDb = new GunDB();
|
|
201
|
+
const clientKv = await Deno.makeTempFile({
|
|
202
|
+
prefix: "kv_client_",
|
|
203
|
+
suffix: ".sqlite",
|
|
204
|
+
});
|
|
205
|
+
await clientDb.ready(clientKv);
|
|
206
|
+
|
|
207
|
+
const connectionPromise = new Promise<void>((resolve, reject) => {
|
|
208
|
+
const ws = new WebSocket(serverUrl);
|
|
209
|
+
ws.onopen = () => {
|
|
210
|
+
ws.close();
|
|
211
|
+
resolve();
|
|
212
|
+
};
|
|
213
|
+
ws.onerror = reject;
|
|
214
|
+
setTimeout(() => reject(new Error("Connection timeout")), 5000);
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
await connectionPromise;
|
|
218
|
+
await clientDb.close();
|
|
219
|
+
});
|
|
220
|
+
} finally {
|
|
221
|
+
await db.close();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
runner.printSummary();
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function runMemoryBenchmarks() {
|
|
228
|
+
const runner = new BenchmarkRunner();
|
|
229
|
+
const db = new GunDB();
|
|
230
|
+
|
|
231
|
+
try {
|
|
232
|
+
const kvPath = await Deno.makeTempFile({
|
|
233
|
+
prefix: "kv_",
|
|
234
|
+
suffix: ".sqlite",
|
|
235
|
+
});
|
|
236
|
+
await db.ready(kvPath);
|
|
237
|
+
|
|
238
|
+
console.log("Starting Memory Benchmarks...\n");
|
|
239
|
+
|
|
240
|
+
// Benchmark 1: Memory Usage with Large Datasets
|
|
241
|
+
const initialMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
242
|
+
|
|
243
|
+
await runner.runBenchmark("Large Dataset Memory Usage", 1000, async () => {
|
|
244
|
+
const id = `memory:${Math.random()}`;
|
|
245
|
+
await db.put(id, {
|
|
246
|
+
data: "x".repeat(1024), // 1KB per record
|
|
247
|
+
timestamp: Date.now(),
|
|
248
|
+
random: Math.random(),
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
const finalMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
253
|
+
const memoryIncrease = finalMemory - initialMemory;
|
|
254
|
+
|
|
255
|
+
console.log(
|
|
256
|
+
`Memory Usage: ${
|
|
257
|
+
(memoryIncrease / 1024 / 1024).toFixed(2)
|
|
258
|
+
}MB for 1000 records`,
|
|
259
|
+
);
|
|
260
|
+
console.log(
|
|
261
|
+
`Memory per record: ${(memoryIncrease / 1000).toFixed(2)} bytes`,
|
|
262
|
+
);
|
|
263
|
+
|
|
264
|
+
// Benchmark 2: Subscription Memory Usage
|
|
265
|
+
const subscriptionMemory = (performance as any).memory?.usedJSHeapSize || 0;
|
|
266
|
+
|
|
267
|
+
const subscriptions: Array<() => void> = [];
|
|
268
|
+
await runner.runBenchmark("Subscription Memory Usage", 1000, async () => {
|
|
269
|
+
const id = `sub:${Math.random()}`;
|
|
270
|
+
const unsubscribe = db.on(id, () => {});
|
|
271
|
+
subscriptions.push(unsubscribe);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
const afterSubscriptionMemory =
|
|
275
|
+
(performance as any).memory?.usedJSHeapSize || 0;
|
|
276
|
+
const subscriptionMemoryIncrease = afterSubscriptionMemory -
|
|
277
|
+
subscriptionMemory;
|
|
278
|
+
|
|
279
|
+
console.log(
|
|
280
|
+
`Subscription Memory: ${
|
|
281
|
+
(subscriptionMemoryIncrease / 1024).toFixed(2)
|
|
282
|
+
}KB for 1000 subscriptions`,
|
|
283
|
+
);
|
|
284
|
+
console.log(
|
|
285
|
+
`Memory per subscription: ${
|
|
286
|
+
(subscriptionMemoryIncrease / 1000).toFixed(2)
|
|
287
|
+
} bytes`,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
// Clean up subscriptions
|
|
291
|
+
subscriptions.forEach((unsubscribe) => unsubscribe());
|
|
292
|
+
} finally {
|
|
293
|
+
await db.close();
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async function main() {
|
|
298
|
+
console.log("PluresDB Benchmark Suite");
|
|
299
|
+
console.log("========================\n");
|
|
300
|
+
|
|
301
|
+
try {
|
|
302
|
+
await runCoreBenchmarks();
|
|
303
|
+
await runNetworkBenchmarks();
|
|
304
|
+
await runMemoryBenchmarks();
|
|
305
|
+
|
|
306
|
+
console.log("All benchmarks completed successfully!");
|
|
307
|
+
} catch (error) {
|
|
308
|
+
console.error("Benchmark failed:", error);
|
|
309
|
+
Deno.exit(1);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (import.meta.main) {
|
|
314
|
+
await main();
|
|
315
|
+
}
|