@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.
Files changed (70) hide show
  1. package/dist/core/EntityManager.d.ts +2 -0
  2. package/dist/core/EntityManager.d.ts.map +1 -1
  3. package/dist/core/EntityManager.js +14 -9
  4. package/dist/core/RelationManager.d.ts.map +1 -1
  5. package/dist/core/RelationManager.js +5 -4
  6. package/dist/features/CompressionManager.d.ts +3 -1
  7. package/dist/features/CompressionManager.d.ts.map +1 -1
  8. package/dist/features/CompressionManager.js +14 -5
  9. package/dist/search/BM25Search.d.ts +148 -0
  10. package/dist/search/BM25Search.d.ts.map +1 -0
  11. package/dist/search/BM25Search.js +339 -0
  12. package/dist/search/EarlyTerminationManager.d.ts +140 -0
  13. package/dist/search/EarlyTerminationManager.d.ts.map +1 -0
  14. package/dist/search/EarlyTerminationManager.js +279 -0
  15. package/dist/search/EmbeddingCache.d.ts +175 -0
  16. package/dist/search/EmbeddingCache.d.ts.map +1 -0
  17. package/dist/search/EmbeddingCache.js +246 -0
  18. package/dist/search/EmbeddingService.d.ts +108 -9
  19. package/dist/search/EmbeddingService.d.ts.map +1 -1
  20. package/dist/search/EmbeddingService.js +187 -15
  21. package/dist/search/HybridScorer.d.ts +181 -0
  22. package/dist/search/HybridScorer.d.ts.map +1 -0
  23. package/dist/search/HybridScorer.js +257 -0
  24. package/dist/search/IncrementalIndexer.d.ts +201 -0
  25. package/dist/search/IncrementalIndexer.d.ts.map +1 -0
  26. package/dist/search/IncrementalIndexer.js +342 -0
  27. package/dist/search/OptimizedInvertedIndex.d.ts +163 -0
  28. package/dist/search/OptimizedInvertedIndex.d.ts.map +1 -0
  29. package/dist/search/OptimizedInvertedIndex.js +358 -0
  30. package/dist/search/ParallelSearchExecutor.d.ts +172 -0
  31. package/dist/search/ParallelSearchExecutor.d.ts.map +1 -0
  32. package/dist/search/ParallelSearchExecutor.js +309 -0
  33. package/dist/search/QuantizedVectorStore.d.ts +171 -0
  34. package/dist/search/QuantizedVectorStore.d.ts.map +1 -0
  35. package/dist/search/QuantizedVectorStore.js +307 -0
  36. package/dist/search/QueryCostEstimator.d.ts +135 -2
  37. package/dist/search/QueryCostEstimator.d.ts.map +1 -1
  38. package/dist/search/QueryCostEstimator.js +298 -1
  39. package/dist/search/QueryPlanCache.d.ts +220 -0
  40. package/dist/search/QueryPlanCache.d.ts.map +1 -0
  41. package/dist/search/QueryPlanCache.js +379 -0
  42. package/dist/search/ReflectionManager.d.ts +49 -0
  43. package/dist/search/ReflectionManager.d.ts.map +1 -1
  44. package/dist/search/ReflectionManager.js +113 -6
  45. package/dist/search/index.d.ts +12 -3
  46. package/dist/search/index.d.ts.map +1 -1
  47. package/dist/search/index.js +20 -2
  48. package/dist/types/index.d.ts +1 -1
  49. package/dist/types/index.d.ts.map +1 -1
  50. package/dist/types/types.d.ts +41 -2
  51. package/dist/types/types.d.ts.map +1 -1
  52. package/dist/utils/BatchProcessor.d.ts +271 -0
  53. package/dist/utils/BatchProcessor.d.ts.map +1 -0
  54. package/dist/utils/BatchProcessor.js +376 -0
  55. package/dist/utils/MemoryMonitor.d.ts +176 -0
  56. package/dist/utils/MemoryMonitor.d.ts.map +1 -0
  57. package/dist/utils/MemoryMonitor.js +305 -0
  58. package/dist/utils/WorkerPoolManager.d.ts +233 -0
  59. package/dist/utils/WorkerPoolManager.d.ts.map +1 -0
  60. package/dist/utils/WorkerPoolManager.js +420 -0
  61. package/dist/utils/compressedCache.d.ts +29 -0
  62. package/dist/utils/compressedCache.d.ts.map +1 -1
  63. package/dist/utils/compressedCache.js +39 -0
  64. package/dist/utils/entityUtils.d.ts +25 -0
  65. package/dist/utils/entityUtils.d.ts.map +1 -1
  66. package/dist/utils/entityUtils.js +33 -0
  67. package/dist/utils/index.d.ts +4 -1
  68. package/dist/utils/index.d.ts.map +1 -1
  69. package/dist/utils/index.js +8 -0
  70. 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;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;IACrB,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qCAAqC;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,sCAAsC;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAsC;IACvD,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAS;IAChD,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAU;IAGvC,OAAO,CAAC,IAAI,CAAa;IACzB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,cAAc,CAAa;gBAEvB,OAAO,GAAE,sBAA2B;IAMhD;;;;;;;;OAQG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IA6BrC;;;;;;;;OAQG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAgBvC;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI1B;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI7B;;OAEG;IACH,KAAK,IAAI,IAAI;IAKb;;OAEG;IACH,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;OAEG;IACH,IAAI,IAAI,gBAAgB,CAAC,MAAM,CAAC;IAIhC;;;;OAIG;IACH,QAAQ,IAAI,oBAAoB;IA+BhC;;;;;;;OAOG;IACH,kBAAkB,IAAI,MAAM;IAI5B;;;;;OAKG;IACH,OAAO,CAAC,uBAAuB;IA2D/B;;;;;;OAMG;IACH,aAAa,IAAI,MAAM;IAsBvB;;;;OAIG;IACH,cAAc,IAAI,MAAM,EAAE;IAa1B;;;;;;OAMG;IACF,OAAO,IAAI,gBAAgB,CAAC;QAC3B,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,OAAO,CAAC;QACpB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CAUH"}
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) {