@danielsimonjr/memory-mcp 9.9.0 → 10.0.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/dist/core/EntityManager.d.ts +2 -0
- package/dist/core/EntityManager.d.ts.map +1 -1
- package/dist/core/EntityManager.js +14 -9
- package/dist/core/RelationManager.d.ts.map +1 -1
- package/dist/core/RelationManager.js +5 -4
- package/dist/features/CompressionManager.d.ts +3 -1
- package/dist/features/CompressionManager.d.ts.map +1 -1
- package/dist/features/CompressionManager.js +14 -5
- package/dist/search/BM25Search.d.ts +148 -0
- package/dist/search/BM25Search.d.ts.map +1 -0
- package/dist/search/BM25Search.js +339 -0
- package/dist/search/EarlyTerminationManager.d.ts +140 -0
- package/dist/search/EarlyTerminationManager.d.ts.map +1 -0
- package/dist/search/EarlyTerminationManager.js +279 -0
- package/dist/search/EmbeddingCache.d.ts +175 -0
- package/dist/search/EmbeddingCache.d.ts.map +1 -0
- package/dist/search/EmbeddingCache.js +246 -0
- package/dist/search/EmbeddingService.d.ts +108 -9
- package/dist/search/EmbeddingService.d.ts.map +1 -1
- package/dist/search/EmbeddingService.js +187 -15
- package/dist/search/HybridScorer.d.ts +181 -0
- package/dist/search/HybridScorer.d.ts.map +1 -0
- package/dist/search/HybridScorer.js +257 -0
- package/dist/search/IncrementalIndexer.d.ts +201 -0
- package/dist/search/IncrementalIndexer.d.ts.map +1 -0
- package/dist/search/IncrementalIndexer.js +342 -0
- package/dist/search/OptimizedInvertedIndex.d.ts +163 -0
- package/dist/search/OptimizedInvertedIndex.d.ts.map +1 -0
- package/dist/search/OptimizedInvertedIndex.js +358 -0
- package/dist/search/ParallelSearchExecutor.d.ts +172 -0
- package/dist/search/ParallelSearchExecutor.d.ts.map +1 -0
- package/dist/search/ParallelSearchExecutor.js +309 -0
- package/dist/search/QuantizedVectorStore.d.ts +171 -0
- package/dist/search/QuantizedVectorStore.d.ts.map +1 -0
- package/dist/search/QuantizedVectorStore.js +307 -0
- package/dist/search/QueryCostEstimator.d.ts +135 -2
- package/dist/search/QueryCostEstimator.d.ts.map +1 -1
- package/dist/search/QueryCostEstimator.js +298 -1
- package/dist/search/QueryPlanCache.d.ts +220 -0
- package/dist/search/QueryPlanCache.d.ts.map +1 -0
- package/dist/search/QueryPlanCache.js +379 -0
- package/dist/search/ReflectionManager.d.ts +49 -0
- package/dist/search/ReflectionManager.d.ts.map +1 -1
- package/dist/search/ReflectionManager.js +113 -6
- package/dist/search/index.d.ts +12 -3
- package/dist/search/index.d.ts.map +1 -1
- package/dist/search/index.js +20 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/types.d.ts +41 -2
- package/dist/types/types.d.ts.map +1 -1
- package/dist/utils/BatchProcessor.d.ts +271 -0
- package/dist/utils/BatchProcessor.d.ts.map +1 -0
- package/dist/utils/BatchProcessor.js +376 -0
- package/dist/utils/MemoryMonitor.d.ts +176 -0
- package/dist/utils/MemoryMonitor.d.ts.map +1 -0
- package/dist/utils/MemoryMonitor.js +305 -0
- package/dist/utils/WorkerPoolManager.d.ts +233 -0
- package/dist/utils/WorkerPoolManager.d.ts.map +1 -0
- package/dist/utils/WorkerPoolManager.js +420 -0
- package/dist/utils/compressedCache.d.ts +29 -0
- package/dist/utils/compressedCache.d.ts.map +1 -1
- package/dist/utils/compressedCache.js +39 -0
- package/dist/utils/entityUtils.d.ts +25 -0
- package/dist/utils/entityUtils.d.ts.map +1 -1
- package/dist/utils/entityUtils.js +33 -0
- package/dist/utils/index.d.ts +4 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +8 -0
- package/package.json +1 -1
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker Pool Manager
|
|
3
|
+
*
|
|
4
|
+
* Phase 12 Sprint 2: Unified worker pool management for all parallelizable operations.
|
|
5
|
+
* Provides centralized lifecycle management, configuration, and statistics.
|
|
6
|
+
*
|
|
7
|
+
* @module utils/WorkerPoolManager
|
|
8
|
+
*/
|
|
9
|
+
import workerpool from '@danielsimonjr/workerpool';
|
|
10
|
+
/**
|
|
11
|
+
* Default configuration values.
|
|
12
|
+
*/
|
|
13
|
+
const DEFAULT_CONFIG = {
|
|
14
|
+
maxWorkers: Math.max(1, workerpool.cpus - 1),
|
|
15
|
+
workerType: 'thread',
|
|
16
|
+
workerPath: '',
|
|
17
|
+
minParallelSize: 200,
|
|
18
|
+
defaultTimeout: 30000,
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* WorkerPoolManager - Unified worker pool management
|
|
22
|
+
*
|
|
23
|
+
* Provides centralized management of worker pools for parallel processing.
|
|
24
|
+
* Features:
|
|
25
|
+
* - Named pool registration with automatic lifecycle management
|
|
26
|
+
* - Pool cleanup on process exit
|
|
27
|
+
* - Statistics tracking per pool
|
|
28
|
+
* - Event callbacks for monitoring
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* const manager = WorkerPoolManager.getInstance();
|
|
33
|
+
*
|
|
34
|
+
* // Get or create a pool
|
|
35
|
+
* const pool = manager.getPool('fuzzySearch', {
|
|
36
|
+
* maxWorkers: 4,
|
|
37
|
+
* workerPath: '/path/to/worker.js'
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* // Execute task
|
|
41
|
+
* const result = await pool.exec('searchEntities', [data]);
|
|
42
|
+
*
|
|
43
|
+
* // Get statistics
|
|
44
|
+
* const stats = manager.getPoolStats('fuzzySearch');
|
|
45
|
+
*
|
|
46
|
+
* // Shutdown all pools on exit
|
|
47
|
+
* await manager.shutdownAll();
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export class WorkerPoolManager {
|
|
51
|
+
static instance = null;
|
|
52
|
+
pools = new Map();
|
|
53
|
+
eventCallbacks = [];
|
|
54
|
+
isShuttingDown = false;
|
|
55
|
+
shutdownRegistered = false;
|
|
56
|
+
/**
|
|
57
|
+
* Private constructor for singleton pattern.
|
|
58
|
+
*/
|
|
59
|
+
constructor() {
|
|
60
|
+
this.registerShutdownHandlers();
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get the singleton instance of WorkerPoolManager.
|
|
64
|
+
*
|
|
65
|
+
* @returns The WorkerPoolManager instance
|
|
66
|
+
*/
|
|
67
|
+
static getInstance() {
|
|
68
|
+
if (!WorkerPoolManager.instance) {
|
|
69
|
+
WorkerPoolManager.instance = new WorkerPoolManager();
|
|
70
|
+
}
|
|
71
|
+
return WorkerPoolManager.instance;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Reset the singleton instance (primarily for testing).
|
|
75
|
+
*/
|
|
76
|
+
static resetInstance() {
|
|
77
|
+
if (WorkerPoolManager.instance) {
|
|
78
|
+
WorkerPoolManager.instance.shutdownAll().catch(() => {
|
|
79
|
+
// Ignore errors during reset
|
|
80
|
+
});
|
|
81
|
+
WorkerPoolManager.instance = null;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Register process exit handlers for cleanup.
|
|
86
|
+
*/
|
|
87
|
+
registerShutdownHandlers() {
|
|
88
|
+
if (this.shutdownRegistered)
|
|
89
|
+
return;
|
|
90
|
+
this.shutdownRegistered = true;
|
|
91
|
+
const shutdownHandler = () => {
|
|
92
|
+
if (!this.isShuttingDown) {
|
|
93
|
+
this.shutdownAllSync();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
// Register for various exit signals
|
|
97
|
+
process.on('exit', shutdownHandler);
|
|
98
|
+
process.on('SIGINT', () => {
|
|
99
|
+
this.shutdownAll().then(() => process.exit(0)).catch(() => process.exit(1));
|
|
100
|
+
});
|
|
101
|
+
process.on('SIGTERM', () => {
|
|
102
|
+
this.shutdownAll().then(() => process.exit(0)).catch(() => process.exit(1));
|
|
103
|
+
});
|
|
104
|
+
process.on('uncaughtException', (err) => {
|
|
105
|
+
console.error('Uncaught exception:', err);
|
|
106
|
+
this.shutdownAllSync();
|
|
107
|
+
process.exit(1);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get or create a named worker pool.
|
|
112
|
+
*
|
|
113
|
+
* If a pool with the given ID exists, returns the existing pool.
|
|
114
|
+
* Otherwise, creates a new pool with the provided configuration.
|
|
115
|
+
*
|
|
116
|
+
* @param poolId - Unique identifier for the pool
|
|
117
|
+
* @param config - Pool configuration options
|
|
118
|
+
* @returns The worker pool instance
|
|
119
|
+
*/
|
|
120
|
+
getPool(poolId, config = {}) {
|
|
121
|
+
const existing = this.pools.get(poolId);
|
|
122
|
+
if (existing) {
|
|
123
|
+
return existing.pool;
|
|
124
|
+
}
|
|
125
|
+
return this.createPool(poolId, config);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a new worker pool with the given ID.
|
|
129
|
+
*
|
|
130
|
+
* @param poolId - Unique identifier for the pool
|
|
131
|
+
* @param config - Pool configuration options
|
|
132
|
+
* @returns The newly created worker pool
|
|
133
|
+
* @throws Error if a pool with the same ID already exists
|
|
134
|
+
*/
|
|
135
|
+
createPool(poolId, config = {}) {
|
|
136
|
+
if (this.pools.has(poolId)) {
|
|
137
|
+
throw new Error(`Pool with ID '${poolId}' already exists`);
|
|
138
|
+
}
|
|
139
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
140
|
+
// Create pool options with inline type definition
|
|
141
|
+
// Using inline type since WorkerPoolOptions is not directly exported
|
|
142
|
+
const poolOptions = {
|
|
143
|
+
maxWorkers: mergedConfig.maxWorkers,
|
|
144
|
+
workerType: mergedConfig.workerType,
|
|
145
|
+
};
|
|
146
|
+
// Add worker thread options for ESM support
|
|
147
|
+
if (mergedConfig.workerType === 'thread') {
|
|
148
|
+
poolOptions.workerThreadOpts = { type: 'module' };
|
|
149
|
+
}
|
|
150
|
+
// Create pool with or without worker script
|
|
151
|
+
let pool;
|
|
152
|
+
if (mergedConfig.workerPath) {
|
|
153
|
+
pool = workerpool.pool(mergedConfig.workerPath, poolOptions);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
pool = workerpool.pool(poolOptions);
|
|
157
|
+
}
|
|
158
|
+
const entry = {
|
|
159
|
+
pool,
|
|
160
|
+
config: mergedConfig,
|
|
161
|
+
createdAt: Date.now(),
|
|
162
|
+
totalTasksExecuted: 0,
|
|
163
|
+
totalExecutionTime: 0,
|
|
164
|
+
};
|
|
165
|
+
this.pools.set(poolId, entry);
|
|
166
|
+
this.emitEvent(poolId, 'created');
|
|
167
|
+
return pool;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Check if a pool with the given ID exists.
|
|
171
|
+
*
|
|
172
|
+
* @param poolId - Pool identifier to check
|
|
173
|
+
* @returns True if pool exists
|
|
174
|
+
*/
|
|
175
|
+
hasPool(poolId) {
|
|
176
|
+
return this.pools.has(poolId);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Get the configuration for a pool.
|
|
180
|
+
*
|
|
181
|
+
* @param poolId - Pool identifier
|
|
182
|
+
* @returns Pool configuration or undefined if not found
|
|
183
|
+
*/
|
|
184
|
+
getPoolConfig(poolId) {
|
|
185
|
+
const entry = this.pools.get(poolId);
|
|
186
|
+
return entry ? { ...entry.config } : undefined;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Get extended statistics for a pool.
|
|
190
|
+
*
|
|
191
|
+
* @param poolId - Pool identifier
|
|
192
|
+
* @returns Extended pool statistics or undefined if not found
|
|
193
|
+
*/
|
|
194
|
+
getPoolStats(poolId) {
|
|
195
|
+
const entry = this.pools.get(poolId);
|
|
196
|
+
if (!entry)
|
|
197
|
+
return undefined;
|
|
198
|
+
const baseStats = entry.pool.stats();
|
|
199
|
+
return {
|
|
200
|
+
...baseStats,
|
|
201
|
+
poolId,
|
|
202
|
+
createdAt: entry.createdAt,
|
|
203
|
+
totalTasksExecuted: entry.totalTasksExecuted,
|
|
204
|
+
totalExecutionTime: entry.totalExecutionTime,
|
|
205
|
+
averageExecutionTime: entry.totalTasksExecuted > 0
|
|
206
|
+
? entry.totalExecutionTime / entry.totalTasksExecuted
|
|
207
|
+
: 0,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get statistics for all pools.
|
|
212
|
+
*
|
|
213
|
+
* @returns Map of pool IDs to their statistics
|
|
214
|
+
*/
|
|
215
|
+
getAllPoolStats() {
|
|
216
|
+
const stats = new Map();
|
|
217
|
+
for (const poolId of this.pools.keys()) {
|
|
218
|
+
const poolStats = this.getPoolStats(poolId);
|
|
219
|
+
if (poolStats) {
|
|
220
|
+
stats.set(poolId, poolStats);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return stats;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Record task execution for statistics tracking.
|
|
227
|
+
*
|
|
228
|
+
* @param poolId - Pool identifier
|
|
229
|
+
* @param executionTimeMs - Task execution time in milliseconds
|
|
230
|
+
*/
|
|
231
|
+
recordTaskExecution(poolId, executionTimeMs) {
|
|
232
|
+
const entry = this.pools.get(poolId);
|
|
233
|
+
if (entry) {
|
|
234
|
+
entry.totalTasksExecuted++;
|
|
235
|
+
entry.totalExecutionTime += executionTimeMs;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Execute a task on a pool with automatic statistics tracking.
|
|
240
|
+
*
|
|
241
|
+
* @template T - Result type
|
|
242
|
+
* @param poolId - Pool identifier
|
|
243
|
+
* @param method - Method name to execute (for worker script pools) or inline function
|
|
244
|
+
* @param args - Arguments to pass to the method/function
|
|
245
|
+
* @param timeout - Optional timeout in milliseconds
|
|
246
|
+
* @returns Promise resolving to the task result
|
|
247
|
+
*/
|
|
248
|
+
async executeTask(poolId, method, args = [], timeout) {
|
|
249
|
+
const entry = this.pools.get(poolId);
|
|
250
|
+
if (!entry) {
|
|
251
|
+
throw new Error(`Pool '${poolId}' not found`);
|
|
252
|
+
}
|
|
253
|
+
const effectiveTimeout = timeout ?? entry.config.defaultTimeout ?? DEFAULT_CONFIG.defaultTimeout;
|
|
254
|
+
const startTime = Date.now();
|
|
255
|
+
try {
|
|
256
|
+
let result;
|
|
257
|
+
if (typeof method === 'string') {
|
|
258
|
+
// Execute named method from worker script
|
|
259
|
+
result = await entry.pool.exec(method, args).timeout(effectiveTimeout);
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
// Execute inline function
|
|
263
|
+
result = await entry.pool.exec(method, args).timeout(effectiveTimeout);
|
|
264
|
+
}
|
|
265
|
+
const executionTime = Date.now() - startTime;
|
|
266
|
+
this.recordTaskExecution(poolId, executionTime);
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
catch (error) {
|
|
270
|
+
const executionTime = Date.now() - startTime;
|
|
271
|
+
this.recordTaskExecution(poolId, executionTime);
|
|
272
|
+
throw error;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Shutdown a specific pool.
|
|
277
|
+
*
|
|
278
|
+
* @param poolId - Pool identifier
|
|
279
|
+
* @param force - If true, forcefully terminate workers (default: false)
|
|
280
|
+
* @returns Promise resolving when shutdown is complete
|
|
281
|
+
*/
|
|
282
|
+
async shutdownPool(poolId, force = false) {
|
|
283
|
+
const entry = this.pools.get(poolId);
|
|
284
|
+
if (!entry)
|
|
285
|
+
return;
|
|
286
|
+
try {
|
|
287
|
+
await entry.pool.terminate(force);
|
|
288
|
+
this.emitEvent(poolId, 'shutdown');
|
|
289
|
+
}
|
|
290
|
+
catch (error) {
|
|
291
|
+
this.emitEvent(poolId, 'error', error);
|
|
292
|
+
throw error;
|
|
293
|
+
}
|
|
294
|
+
finally {
|
|
295
|
+
this.pools.delete(poolId);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Shutdown all pools asynchronously.
|
|
300
|
+
*
|
|
301
|
+
* @param force - If true, forcefully terminate workers (default: false)
|
|
302
|
+
* @returns Promise resolving when all pools are shut down
|
|
303
|
+
*/
|
|
304
|
+
async shutdownAll(force = false) {
|
|
305
|
+
if (this.isShuttingDown)
|
|
306
|
+
return;
|
|
307
|
+
this.isShuttingDown = true;
|
|
308
|
+
const shutdownPromises = [];
|
|
309
|
+
for (const poolId of this.pools.keys()) {
|
|
310
|
+
shutdownPromises.push(this.shutdownPool(poolId, force));
|
|
311
|
+
}
|
|
312
|
+
try {
|
|
313
|
+
await Promise.allSettled(shutdownPromises);
|
|
314
|
+
}
|
|
315
|
+
finally {
|
|
316
|
+
this.pools.clear();
|
|
317
|
+
this.isShuttingDown = false;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Synchronous shutdown for process exit handlers.
|
|
322
|
+
* Forces immediate termination of all pools.
|
|
323
|
+
*/
|
|
324
|
+
shutdownAllSync() {
|
|
325
|
+
if (this.isShuttingDown)
|
|
326
|
+
return;
|
|
327
|
+
this.isShuttingDown = true;
|
|
328
|
+
for (const [poolId, entry] of this.pools) {
|
|
329
|
+
try {
|
|
330
|
+
entry.pool.terminate(true);
|
|
331
|
+
this.emitEvent(poolId, 'shutdown');
|
|
332
|
+
}
|
|
333
|
+
catch {
|
|
334
|
+
// Ignore errors during sync shutdown
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
this.pools.clear();
|
|
338
|
+
this.isShuttingDown = false;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Register an event callback for pool events.
|
|
342
|
+
*
|
|
343
|
+
* @param callback - Callback function to invoke on events
|
|
344
|
+
* @returns Unsubscribe function
|
|
345
|
+
*/
|
|
346
|
+
onEvent(callback) {
|
|
347
|
+
this.eventCallbacks.push(callback);
|
|
348
|
+
return () => {
|
|
349
|
+
const index = this.eventCallbacks.indexOf(callback);
|
|
350
|
+
if (index >= 0) {
|
|
351
|
+
this.eventCallbacks.splice(index, 1);
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Emit an event to all registered callbacks.
|
|
357
|
+
*/
|
|
358
|
+
emitEvent(poolId, event, data) {
|
|
359
|
+
for (const callback of this.eventCallbacks) {
|
|
360
|
+
try {
|
|
361
|
+
callback(poolId, event, data);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
// Ignore callback errors
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/**
|
|
369
|
+
* Get the number of active pools.
|
|
370
|
+
*
|
|
371
|
+
* @returns Number of pools currently managed
|
|
372
|
+
*/
|
|
373
|
+
get poolCount() {
|
|
374
|
+
return this.pools.size;
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Get all pool IDs.
|
|
378
|
+
*
|
|
379
|
+
* @returns Array of pool identifiers
|
|
380
|
+
*/
|
|
381
|
+
getPoolIds() {
|
|
382
|
+
return Array.from(this.pools.keys());
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Check if the minimum parallel size threshold is met.
|
|
386
|
+
*
|
|
387
|
+
* @param poolId - Pool identifier
|
|
388
|
+
* @param size - Size of the data to process
|
|
389
|
+
* @returns True if size meets or exceeds minimum threshold
|
|
390
|
+
*/
|
|
391
|
+
shouldUseParallel(poolId, size) {
|
|
392
|
+
const entry = this.pools.get(poolId);
|
|
393
|
+
const minSize = entry?.config.minParallelSize ?? DEFAULT_CONFIG.minParallelSize;
|
|
394
|
+
return size >= minSize;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Get the default configuration values.
|
|
398
|
+
*
|
|
399
|
+
* @returns Copy of default configuration
|
|
400
|
+
*/
|
|
401
|
+
static getDefaultConfig() {
|
|
402
|
+
return { ...DEFAULT_CONFIG };
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Get the CPU count available for workers.
|
|
406
|
+
*
|
|
407
|
+
* @returns Number of CPUs
|
|
408
|
+
*/
|
|
409
|
+
static getCpuCount() {
|
|
410
|
+
return workerpool.cpus;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* Convenience function to get the WorkerPoolManager instance.
|
|
415
|
+
*
|
|
416
|
+
* @returns The WorkerPoolManager singleton
|
|
417
|
+
*/
|
|
418
|
+
export function getWorkerPoolManager() {
|
|
419
|
+
return WorkerPoolManager.getInstance();
|
|
420
|
+
}
|
|
@@ -34,6 +34,20 @@ export interface CompressedCacheOptions {
|
|
|
34
34
|
* @default true
|
|
35
35
|
*/
|
|
36
36
|
autoCompress?: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Minimum entry size in bytes before compression is applied.
|
|
39
|
+
* Entries smaller than this are not compressed (overhead exceeds benefit).
|
|
40
|
+
* Phase 12 Sprint 6: Adaptive compression.
|
|
41
|
+
* @default 256
|
|
42
|
+
*/
|
|
43
|
+
minCompressionSize?: number;
|
|
44
|
+
/**
|
|
45
|
+
* Minimum compression ratio to keep entry compressed.
|
|
46
|
+
* If compression achieves less than this ratio, entry stays uncompressed.
|
|
47
|
+
* Phase 12 Sprint 6: Adaptive compression.
|
|
48
|
+
* @default 0.7 (30% reduction minimum)
|
|
49
|
+
*/
|
|
50
|
+
minCompressionRatio?: number;
|
|
37
51
|
}
|
|
38
52
|
/**
|
|
39
53
|
* Statistics about the cache state.
|
|
@@ -49,6 +63,8 @@ export interface CompressedCacheStats {
|
|
|
49
63
|
memorySaved: number;
|
|
50
64
|
/** Total original size of all entries in bytes */
|
|
51
65
|
totalOriginalSize: number;
|
|
66
|
+
/** Total compressed size in bytes */
|
|
67
|
+
totalCompressedSize: number;
|
|
52
68
|
/** Cache hit count since creation */
|
|
53
69
|
hits: number;
|
|
54
70
|
/** Cache miss count since creation */
|
|
@@ -57,6 +73,14 @@ export interface CompressedCacheStats {
|
|
|
57
73
|
compressions: number;
|
|
58
74
|
/** Number of decompressions performed */
|
|
59
75
|
decompressions: number;
|
|
76
|
+
/** Phase 12 Sprint 6: Number of entries skipped due to size */
|
|
77
|
+
skippedSmallEntries: number;
|
|
78
|
+
/** Phase 12 Sprint 6: Number of entries skipped due to poor ratio */
|
|
79
|
+
skippedPoorRatio: number;
|
|
80
|
+
/** Phase 12 Sprint 6: Average compression ratio (0-1) */
|
|
81
|
+
avgCompressionRatio: number;
|
|
82
|
+
/** Phase 12 Sprint 6: Estimated memory usage in bytes */
|
|
83
|
+
estimatedMemoryBytes: number;
|
|
60
84
|
}
|
|
61
85
|
/**
|
|
62
86
|
* LRU cache with automatic compression of old entries.
|
|
@@ -88,10 +112,15 @@ export declare class CompressedCache {
|
|
|
88
112
|
private readonly maxUncompressed;
|
|
89
113
|
private readonly compressionThresholdMs;
|
|
90
114
|
private readonly autoCompress;
|
|
115
|
+
private readonly minCompressionSize;
|
|
116
|
+
private readonly minCompressionRatio;
|
|
91
117
|
private hits;
|
|
92
118
|
private misses;
|
|
93
119
|
private compressions;
|
|
94
120
|
private decompressions;
|
|
121
|
+
private skippedSmallEntries;
|
|
122
|
+
private skippedPoorRatio;
|
|
123
|
+
private compressionRatios;
|
|
95
124
|
constructor(options?: CompressedCacheOptions);
|
|
96
125
|
/**
|
|
97
126
|
* Get an entity from the cache.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compressedCache.d.ts","sourceRoot":"","sources":["../../src/utils/compressedCache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAmBhD;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"compressedCache.d.ts","sourceRoot":"","sources":["../../src/utils/compressedCache.ts"],"names":[],"mappings":"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"}
|
|
@@ -43,15 +43,25 @@ export class CompressedCache {
|
|
|
43
43
|
maxUncompressed;
|
|
44
44
|
compressionThresholdMs;
|
|
45
45
|
autoCompress;
|
|
46
|
+
// Phase 12 Sprint 6: Adaptive compression options
|
|
47
|
+
minCompressionSize;
|
|
48
|
+
minCompressionRatio;
|
|
46
49
|
// Statistics
|
|
47
50
|
hits = 0;
|
|
48
51
|
misses = 0;
|
|
49
52
|
compressions = 0;
|
|
50
53
|
decompressions = 0;
|
|
54
|
+
// Phase 12 Sprint 6: Adaptive compression stats
|
|
55
|
+
skippedSmallEntries = 0;
|
|
56
|
+
skippedPoorRatio = 0;
|
|
57
|
+
compressionRatios = [];
|
|
51
58
|
constructor(options = {}) {
|
|
52
59
|
this.maxUncompressed = options.maxUncompressed ?? 1000;
|
|
53
60
|
this.compressionThresholdMs = options.compressionThresholdMs ?? 5 * 60 * 1000;
|
|
54
61
|
this.autoCompress = options.autoCompress ?? true;
|
|
62
|
+
// Phase 12 Sprint 6: Adaptive compression defaults
|
|
63
|
+
this.minCompressionSize = options.minCompressionSize ?? 256;
|
|
64
|
+
this.minCompressionRatio = options.minCompressionRatio ?? 0.7;
|
|
55
65
|
}
|
|
56
66
|
/**
|
|
57
67
|
* Get an entity from the cache.
|
|
@@ -156,27 +166,42 @@ export class CompressedCache {
|
|
|
156
166
|
let uncompressed = 0;
|
|
157
167
|
let memorySaved = 0;
|
|
158
168
|
let totalOriginalSize = 0;
|
|
169
|
+
let totalCompressedSize = 0;
|
|
170
|
+
let estimatedMemoryBytes = 0;
|
|
159
171
|
for (const entry of this._entryMap.values()) {
|
|
160
172
|
totalOriginalSize += entry.originalSize;
|
|
161
173
|
if (entry.compressed && entry.compressedData) {
|
|
162
174
|
compressed++;
|
|
175
|
+
totalCompressedSize += entry.compressedData.length;
|
|
176
|
+
estimatedMemoryBytes += entry.compressedData.length;
|
|
163
177
|
// Memory saved = original size - compressed size
|
|
164
178
|
memorySaved += entry.originalSize - entry.compressedData.length;
|
|
165
179
|
}
|
|
166
180
|
else {
|
|
167
181
|
uncompressed++;
|
|
182
|
+
estimatedMemoryBytes += entry.originalSize;
|
|
168
183
|
}
|
|
169
184
|
}
|
|
185
|
+
// Calculate average compression ratio
|
|
186
|
+
const avgCompressionRatio = this.compressionRatios.length > 0
|
|
187
|
+
? this.compressionRatios.reduce((a, b) => a + b, 0) / this.compressionRatios.length
|
|
188
|
+
: 0;
|
|
170
189
|
return {
|
|
171
190
|
total: this._entryMap.size,
|
|
172
191
|
compressed,
|
|
173
192
|
uncompressed,
|
|
174
193
|
memorySaved: Math.max(0, memorySaved),
|
|
175
194
|
totalOriginalSize,
|
|
195
|
+
totalCompressedSize,
|
|
176
196
|
hits: this.hits,
|
|
177
197
|
misses: this.misses,
|
|
178
198
|
compressions: this.compressions,
|
|
179
199
|
decompressions: this.decompressions,
|
|
200
|
+
// Phase 12 Sprint 6: Adaptive compression stats
|
|
201
|
+
skippedSmallEntries: this.skippedSmallEntries,
|
|
202
|
+
skippedPoorRatio: this.skippedPoorRatio,
|
|
203
|
+
avgCompressionRatio,
|
|
204
|
+
estimatedMemoryBytes,
|
|
180
205
|
};
|
|
181
206
|
}
|
|
182
207
|
/**
|
|
@@ -226,6 +251,11 @@ export class CompressedCache {
|
|
|
226
251
|
}
|
|
227
252
|
// Compress the entry
|
|
228
253
|
if (entry.entity) {
|
|
254
|
+
// Phase 12 Sprint 6: Skip small entries (adaptive compression)
|
|
255
|
+
if (entry.originalSize < this.minCompressionSize) {
|
|
256
|
+
this.skippedSmallEntries++;
|
|
257
|
+
continue;
|
|
258
|
+
}
|
|
229
259
|
try {
|
|
230
260
|
const jsonStr = JSON.stringify(entry.entity);
|
|
231
261
|
const compressed = brotliCompressSync(Buffer.from(jsonStr, 'utf-8'), {
|
|
@@ -233,6 +263,15 @@ export class CompressedCache {
|
|
|
233
263
|
[constants.BROTLI_PARAM_QUALITY]: COMPRESSION_CONFIG.BROTLI_QUALITY_CACHE,
|
|
234
264
|
},
|
|
235
265
|
});
|
|
266
|
+
// Phase 12 Sprint 6: Check compression ratio
|
|
267
|
+
const ratio = compressed.length / entry.originalSize;
|
|
268
|
+
if (ratio > this.minCompressionRatio) {
|
|
269
|
+
// Compression didn't achieve enough reduction
|
|
270
|
+
this.skippedPoorRatio++;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
// Track compression ratio
|
|
274
|
+
this.compressionRatios.push(ratio);
|
|
236
275
|
entry.compressedData = compressed;
|
|
237
276
|
entry.compressed = true;
|
|
238
277
|
entry.entity = null; // Free memory
|
|
@@ -11,6 +11,31 @@
|
|
|
11
11
|
* @module utils/entityUtils
|
|
12
12
|
*/
|
|
13
13
|
import type { Entity, KnowledgeGraph } from '../types/index.js';
|
|
14
|
+
/**
|
|
15
|
+
* FNV-1a hash function for fast string hashing.
|
|
16
|
+
*
|
|
17
|
+
* This is a non-cryptographic hash function that provides good distribution
|
|
18
|
+
* for bucketing and deduplication purposes. It's optimized for speed
|
|
19
|
+
* and produces a 32-bit unsigned integer.
|
|
20
|
+
*
|
|
21
|
+
* FNV-1a has the following properties:
|
|
22
|
+
* - Fast computation (single pass through string)
|
|
23
|
+
* - Good distribution for hash table use
|
|
24
|
+
* - Deterministic output for same input
|
|
25
|
+
*
|
|
26
|
+
* @param text - The string to hash
|
|
27
|
+
* @returns A 32-bit unsigned integer hash value
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const hash = fnv1aHash('hello');
|
|
32
|
+
* console.log(hash); // 1335831723
|
|
33
|
+
*
|
|
34
|
+
* // Use for bucketing similar entities
|
|
35
|
+
* const bucket = fnv1aHash(entity.name.toLowerCase()) % numBuckets;
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function fnv1aHash(text: string): number;
|
|
14
39
|
/**
|
|
15
40
|
* Finds an entity by name in the graph.
|
|
16
41
|
* Overloaded to provide type-safe returns based on throwIfNotFound parameter.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"entityUtils.d.ts","sourceRoot":"","sources":["../../src/utils/entityUtils.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"entityUtils.d.ts","sourceRoot":"","sources":["../../src/utils/entityUtils.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,6 +14,39 @@ import { promises as fs } from 'fs';
|
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import { fileURLToPath } from 'url';
|
|
16
16
|
import { EntityNotFoundError, FileOperationError } from './errors.js';
|
|
17
|
+
// ==================== Hash Functions ====================
|
|
18
|
+
/**
|
|
19
|
+
* FNV-1a hash function for fast string hashing.
|
|
20
|
+
*
|
|
21
|
+
* This is a non-cryptographic hash function that provides good distribution
|
|
22
|
+
* for bucketing and deduplication purposes. It's optimized for speed
|
|
23
|
+
* and produces a 32-bit unsigned integer.
|
|
24
|
+
*
|
|
25
|
+
* FNV-1a has the following properties:
|
|
26
|
+
* - Fast computation (single pass through string)
|
|
27
|
+
* - Good distribution for hash table use
|
|
28
|
+
* - Deterministic output for same input
|
|
29
|
+
*
|
|
30
|
+
* @param text - The string to hash
|
|
31
|
+
* @returns A 32-bit unsigned integer hash value
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const hash = fnv1aHash('hello');
|
|
36
|
+
* console.log(hash); // 1335831723
|
|
37
|
+
*
|
|
38
|
+
* // Use for bucketing similar entities
|
|
39
|
+
* const bucket = fnv1aHash(entity.name.toLowerCase()) % numBuckets;
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export function fnv1aHash(text) {
|
|
43
|
+
let hash = 2166136261; // FNV offset basis
|
|
44
|
+
for (let i = 0; i < text.length; i++) {
|
|
45
|
+
hash ^= text.charCodeAt(i);
|
|
46
|
+
hash = Math.imul(hash, 16777619); // FNV prime
|
|
47
|
+
}
|
|
48
|
+
return hash >>> 0; // Convert to unsigned 32-bit integer
|
|
49
|
+
}
|
|
17
50
|
export function findEntityByName(graph, name, throwIfNotFound = true) {
|
|
18
51
|
const entity = graph.entities.find(e => e.name === name);
|
|
19
52
|
if (!entity && throwIfNotFound) {
|