sehawq.db 3.0.0 → 4.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.
@@ -0,0 +1,496 @@
1
+ /**
2
+ * MemoryManager - Keeps your memory usage in check like a financial advisor 💰
3
+ *
4
+ * Monitors, optimizes, and prevents memory leaks
5
+ * Because crashing from out-of-memory is so 1990s 😅
6
+ */
7
+
8
+ const { performance } = require('perf_hooks');
9
+
10
+ class MemoryManager {
11
+ constructor(options = {}) {
12
+ this.options = {
13
+ maxMemoryMB: 100, // 100MB default limit
14
+ checkInterval: 30000, // Check every 30 seconds
15
+ gcAggressiveness: 'medium', // low, medium, high
16
+ leakDetection: true,
17
+ ...options
18
+ };
19
+
20
+ this.components = new Map(); // Track memory by component
21
+ this.snapshots = []; // Memory usage history
22
+ this.alerts = []; // Memory alerts
23
+
24
+ this.stats = {
25
+ totalChecks: 0,
26
+ optimizations: 0,
27
+ leaksDetected: 0,
28
+ gcCalls: 0,
29
+ memorySaved: 0
30
+ };
31
+
32
+ this._startMonitoring();
33
+ }
34
+
35
+ /**
36
+ * Register a component for memory tracking
37
+ */
38
+ registerComponent(name, component) {
39
+ this.components.set(name, {
40
+ instance: component,
41
+ baselineMemory: this._getComponentMemory(component),
42
+ lastCheck: Date.now(),
43
+ leaks: 0
44
+ });
45
+
46
+ if (this.options.debug) {
47
+ console.log(`📝 Registered component for memory tracking: ${name}`);
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Start memory monitoring
53
+ */
54
+ _startMonitoring() {
55
+ setInterval(() => {
56
+ this._performMemoryCheck();
57
+ }, this.options.checkInterval);
58
+
59
+ if (this.options.debug) {
60
+ console.log('🔍 Memory monitoring started');
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Perform comprehensive memory check
66
+ */
67
+ _performMemoryCheck() {
68
+ this.stats.totalChecks++;
69
+
70
+ const memoryUsage = process.memoryUsage();
71
+ const currentMemoryMB = memoryUsage.heapUsed / 1024 / 1024;
72
+
73
+ // Take snapshot for trend analysis
74
+ this._takeMemorySnapshot(memoryUsage);
75
+
76
+ // Check for memory leaks
77
+ if (this.options.leakDetection) {
78
+ this._checkForLeaks();
79
+ }
80
+
81
+ // Check if we're approaching memory limit
82
+ if (currentMemoryMB > this.options.maxMemoryMB * 0.8) {
83
+ this._handleHighMemoryUsage(currentMemoryMB);
84
+ }
85
+
86
+ // Aggressive GC if configured
87
+ if (this.options.gcAggressiveness === 'high') {
88
+ this._forceGarbageCollection();
89
+ }
90
+
91
+ if (this.options.debug) {
92
+ console.log(`🧠 Memory: ${currentMemoryMB.toFixed(2)}MB / ${this.options.maxMemoryMB}MB`);
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Take memory snapshot for trend analysis
98
+ */
99
+ _takeMemorySnapshot(memoryUsage) {
100
+ const snapshot = {
101
+ timestamp: Date.now(),
102
+ heapUsed: memoryUsage.heapUsed,
103
+ heapTotal: memoryUsage.heapTotal,
104
+ external: memoryUsage.external,
105
+ rss: memoryUsage.rss,
106
+ components: {}
107
+ };
108
+
109
+ // Track memory by component
110
+ for (const [name, component] of this.components) {
111
+ snapshot.components[name] = this._getComponentMemory(component.instance);
112
+ }
113
+
114
+ this.snapshots.push(snapshot);
115
+
116
+ // Keep only last 100 snapshots
117
+ if (this.snapshots.length > 100) {
118
+ this.snapshots.shift();
119
+ }
120
+ }
121
+
122
+ /**
123
+ * Check for memory leaks in components
124
+ */
125
+ _checkForLeaks() {
126
+ for (const [name, component] of this.components) {
127
+ const currentMemory = this._getComponentMemory(component.instance);
128
+ const memoryIncrease = currentMemory - component.baselineMemory;
129
+
130
+ // If memory increased by more than 50% since baseline, potential leak
131
+ if (memoryIncrease > component.baselineMemory * 0.5) {
132
+ component.leaks++;
133
+ this.stats.leaksDetected++;
134
+
135
+ this._alert('leak', `Potential memory leak in ${name}: +${(memoryIncrease / 1024 / 1024).toFixed(2)}MB`);
136
+
137
+ if (this.options.debug) {
138
+ console.log(`🚨 Potential memory leak in ${name}`);
139
+ }
140
+ }
141
+
142
+ component.lastCheck = Date.now();
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Handle high memory usage situations
148
+ */
149
+ _handleHighMemoryUsage(currentMemoryMB) {
150
+ const severity = currentMemoryMB > this.options.maxMemoryMB * 0.9 ? 'critical' : 'warning';
151
+
152
+ this._alert(severity,
153
+ `High memory usage: ${currentMemoryMB.toFixed(2)}MB / ${this.options.maxMemoryMB}MB`
154
+ );
155
+
156
+ // Trigger memory optimization
157
+ this.optimizeMemory(severity);
158
+ }
159
+
160
+ /**
161
+ * Optimize memory usage based on severity
162
+ */
163
+ optimizeMemory(severity = 'medium') {
164
+ this.stats.optimizations++;
165
+
166
+ const strategies = {
167
+ low: ['clearCaches', 'mildGC'],
168
+ medium: ['clearCaches', 'aggressiveGC', 'unloadChunks'],
169
+ high: ['clearCaches', 'forceGC', 'unloadAllChunks', 'compressData'],
170
+ critical: ['emergencyMeasures']
171
+ };
172
+
173
+ const strategy = strategies[severity] || strategies.medium;
174
+
175
+ if (this.options.debug) {
176
+ console.log(`🔄 Memory optimization (${severity}): ${strategy.join(', ')}`);
177
+ }
178
+
179
+ for (const action of strategy) {
180
+ this._executeOptimization(action);
181
+ }
182
+
183
+ this._alert('info', `Memory optimization completed (${severity})`);
184
+ }
185
+
186
+ /**
187
+ * Execute specific optimization action
188
+ */
189
+ _executeOptimization(action) {
190
+ switch (action) {
191
+ case 'clearCaches':
192
+ this._clearAllCaches();
193
+ break;
194
+ case 'mildGC':
195
+ this._suggestGarbageCollection();
196
+ break;
197
+ case 'aggressiveGC':
198
+ this._forceGarbageCollection();
199
+ break;
200
+ case 'unloadChunks':
201
+ this._unloadNonCriticalChunks();
202
+ break;
203
+ case 'unloadAllChunks':
204
+ this._unloadAllChunks();
205
+ break;
206
+ case 'compressData':
207
+ this._compressMemoryData();
208
+ break;
209
+ case 'emergencyMeasures':
210
+ this._emergencyMemoryReduction();
211
+ break;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Clear all registered caches
217
+ */
218
+ _clearAllCaches() {
219
+ for (const [name, component] of this.components) {
220
+ if (component.instance.clearCache) {
221
+ const before = this._getComponentMemory(component.instance);
222
+ component.instance.clearCache();
223
+ const after = this._getComponentMemory(component.instance);
224
+
225
+ this.stats.memorySaved += (before - after);
226
+
227
+ if (this.options.debug) {
228
+ console.log(`🧹 Cleared cache for ${name}: saved ${((before - after) / 1024 / 1024).toFixed(2)}MB`);
229
+ }
230
+ }
231
+ }
232
+ }
233
+
234
+ /**
235
+ * Suggest garbage collection (if available)
236
+ */
237
+ _suggestGarbageCollection() {
238
+ if (global.gc) {
239
+ const before = process.memoryUsage().heapUsed;
240
+ global.gc();
241
+ const after = process.memoryUsage().heapUsed;
242
+
243
+ this.stats.gcCalls++;
244
+ this.stats.memorySaved += (before - after);
245
+
246
+ if (this.options.debug) {
247
+ console.log(`♻️ GC freed ${((before - after) / 1024 / 1024).toFixed(2)}MB`);
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Force garbage collection more aggressively
254
+ */
255
+ _forceGarbageCollection() {
256
+ if (global.gc) {
257
+ // Call multiple times for more aggressive collection
258
+ for (let i = 0; i < 3; i++) {
259
+ global.gc();
260
+ }
261
+ this.stats.gcCalls += 3;
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Unload non-critical data chunks
267
+ */
268
+ _unloadNonCriticalChunks() {
269
+ for (const [name, component] of this.components) {
270
+ if (component.instance.unloadChunks) {
271
+ component.instance.unloadChunks();
272
+
273
+ if (this.options.debug) {
274
+ console.log(`📦 Unloaded chunks for ${name}`);
275
+ }
276
+ }
277
+ }
278
+ }
279
+
280
+ /**
281
+ * Unload all possible chunks
282
+ */
283
+ _unloadAllChunks() {
284
+ for (const [name, component] of this.components) {
285
+ if (component.instance.clear) {
286
+ component.instance.clear();
287
+
288
+ if (this.options.debug) {
289
+ console.log(`🗑️ Cleared all data for ${name}`);
290
+ }
291
+ }
292
+ }
293
+ }
294
+
295
+ /**
296
+ * Compress in-memory data
297
+ */
298
+ _compressMemoryData() {
299
+ // This would implement actual compression logic
300
+ // For now, it's a placeholder for future implementation
301
+ if (this.options.debug) {
302
+ console.log('🗜️ Memory compression would run here');
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Emergency measures for critical memory situations
308
+ */
309
+ _emergencyMemoryReduction() {
310
+ this._clearAllCaches();
311
+ this._unloadAllChunks();
312
+ this._forceGarbageCollection();
313
+
314
+ // Reset component baselines
315
+ for (const [name, component] of this.components) {
316
+ component.baselineMemory = this._getComponentMemory(component.instance);
317
+ }
318
+
319
+ this._alert('critical', 'Emergency memory reduction completed');
320
+ }
321
+
322
+ /**
323
+ * Get memory usage for a component
324
+ */
325
+ _getComponentMemory(component) {
326
+ // Try to get memory stats from component
327
+ if (component.getStats && component.getStats().memoryUsage) {
328
+ return component.getStats().memoryUsage;
329
+ }
330
+
331
+ // Fallback: estimate from internal state
332
+ return this._estimateObjectSize(component);
333
+ }
334
+
335
+ /**
336
+ * Estimate memory size of an object
337
+ */
338
+ _estimateObjectSize(obj) {
339
+ const seen = new WeakSet();
340
+
341
+ function sizeOf(obj) {
342
+ if (obj === null || obj === undefined) return 0;
343
+ if (seen.has(obj)) return 0;
344
+
345
+ seen.add(obj);
346
+
347
+ switch (typeof obj) {
348
+ case 'number':
349
+ return 8;
350
+ case 'string':
351
+ return obj.length * 2;
352
+ case 'boolean':
353
+ return 4;
354
+ case 'object':
355
+ if (Array.isArray(obj)) {
356
+ return obj.reduce((size, item) => size + sizeOf(item), 0);
357
+ } else if (obj instanceof Map) {
358
+ let size = 0;
359
+ for (const [key, value] of obj) {
360
+ size += sizeOf(key) + sizeOf(value);
361
+ }
362
+ return size;
363
+ } else if (obj instanceof Set) {
364
+ let size = 0;
365
+ for (const value of obj) {
366
+ size += sizeOf(value);
367
+ }
368
+ return size;
369
+ } else {
370
+ let size = 0;
371
+ for (const key in obj) {
372
+ if (obj.hasOwnProperty(key)) {
373
+ size += sizeOf(key) + sizeOf(obj[key]);
374
+ }
375
+ }
376
+ return size;
377
+ }
378
+ default:
379
+ return 0;
380
+ }
381
+ }
382
+
383
+ return sizeOf(obj);
384
+ }
385
+
386
+ /**
387
+ * Create memory alert
388
+ */
389
+ _alert(level, message) {
390
+ const alert = {
391
+ level,
392
+ message,
393
+ timestamp: Date.now(),
394
+ memoryUsage: process.memoryUsage().heapUsed
395
+ };
396
+
397
+ this.alerts.push(alert);
398
+
399
+ // Keep only last 50 alerts
400
+ if (this.alerts.length > 50) {
401
+ this.alerts.shift();
402
+ }
403
+
404
+ // Emit alert event if available
405
+ if (this.emit) {
406
+ this.emit('alert', alert);
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Get memory usage trends
412
+ */
413
+ getMemoryTrend() {
414
+ if (this.snapshots.length < 2) {
415
+ return 'insufficient_data';
416
+ }
417
+
418
+ const recent = this.snapshots.slice(-5);
419
+ const oldest = recent[0].heapUsed;
420
+ const newest = recent[recent.length - 1].heapUsed;
421
+
422
+ const change = newest - oldest;
423
+ const percentageChange = (change / oldest) * 100;
424
+
425
+ if (percentageChange > 10) return 'increasing';
426
+ if (percentageChange < -10) return 'decreasing';
427
+ return 'stable';
428
+ }
429
+
430
+ /**
431
+ * Get comprehensive memory report
432
+ */
433
+ getReport() {
434
+ const currentMemory = process.memoryUsage();
435
+ const trend = this.getMemoryTrend();
436
+
437
+ return {
438
+ current: {
439
+ heapUsed: `${(currentMemory.heapUsed / 1024 / 1024).toFixed(2)}MB`,
440
+ heapTotal: `${(currentMemory.heapTotal / 1024 / 1024).toFixed(2)}MB`,
441
+ external: `${(currentMemory.external / 1024 / 1024).toFixed(2)}MB`,
442
+ rss: `${(currentMemory.rss / 1024 / 1024).toFixed(2)}MB`
443
+ },
444
+ limits: {
445
+ maxMemory: `${this.options.maxMemoryMB}MB`,
446
+ usagePercentage: `${((currentMemory.heapUsed / 1024 / 1024) / this.options.maxMemoryMB * 100).toFixed(1)}%`
447
+ },
448
+ trends: {
449
+ direction: trend,
450
+ snapshots: this.snapshots.length
451
+ },
452
+ components: Array.from(this.components.entries()).map(([name, component]) => ({
453
+ name,
454
+ memory: `${(this._getComponentMemory(component.instance) / 1024 / 1024).toFixed(2)}MB`,
455
+ leaks: component.leaks
456
+ })),
457
+ stats: this.stats,
458
+ recentAlerts: this.alerts.slice(-5)
459
+ };
460
+ }
461
+
462
+ /**
463
+ * Set new memory limit
464
+ */
465
+ setMemoryLimit(mb) {
466
+ this.options.maxMemoryMB = mb;
467
+
468
+ if (this.options.debug) {
469
+ console.log(`📏 Memory limit set to ${mb}MB`);
470
+ }
471
+ }
472
+
473
+ /**
474
+ * Get optimization suggestions
475
+ */
476
+ getOptimizationSuggestions() {
477
+ const suggestions = [];
478
+ const currentMB = process.memoryUsage().heapUsed / 1024 / 1024;
479
+
480
+ if (currentMB > this.options.maxMemoryMB * 0.8) {
481
+ suggestions.push('Consider increasing maxMemoryMB or optimizing data structures');
482
+ }
483
+
484
+ if (this.stats.leaksDetected > 0) {
485
+ suggestions.push('Investigate potential memory leaks in registered components');
486
+ }
487
+
488
+ if (this.getMemoryTrend() === 'increasing') {
489
+ suggestions.push('Memory usage is trending upward - consider proactive optimization');
490
+ }
491
+
492
+ return suggestions;
493
+ }
494
+ }
495
+
496
+ module.exports = MemoryManager;