@unrdf/knowledge-engine 5.0.1 → 26.4.3
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/package.json +13 -7
- package/src/ai-enhanced-search.mjs +371 -0
- package/src/anomaly-detector.mjs +226 -0
- package/src/artifact-generator.mjs +251 -0
- package/src/browser.mjs +1 -1
- package/src/chatman/disruption-arithmetic.mjs +140 -0
- package/src/chatman/market-dynamics.mjs +140 -0
- package/src/chatman/organizational-dynamics.mjs +140 -0
- package/src/chatman/strategic-dynamics.mjs +140 -0
- package/src/chatman-config-loader.mjs +282 -0
- package/src/chatman-engine.mjs +431 -0
- package/src/chatman-operator.mjs +342 -0
- package/src/dark-field-detector.mjs +312 -0
- package/src/formation-theorems.mjs +345 -0
- package/src/index.mjs +20 -2
- package/src/knowledge-hook-manager.mjs +1 -1
- package/src/lockchain-writer-browser.mjs +2 -2
- package/src/observability.mjs +40 -4
- package/src/query-optimizer.mjs +1 -1
- package/src/resolution-layer.mjs +1 -1
- package/src/transaction.mjs +11 -9
- package/README.md +0 -84
- package/src/browser-shims.mjs +0 -343
- package/src/canonicalize.mjs +0 -414
- package/src/condition-cache.mjs +0 -109
- package/src/condition-evaluator.mjs +0 -722
- package/src/dark-matter-core.mjs +0 -742
- package/src/define-hook.mjs +0 -213
- package/src/effect-sandbox-browser.mjs +0 -283
- package/src/effect-sandbox-worker.mjs +0 -170
- package/src/effect-sandbox.mjs +0 -517
- package/src/engines/index.mjs +0 -11
- package/src/engines/rdf-engine.mjs +0 -299
- package/src/file-resolver.mjs +0 -387
- package/src/hook-executor-batching.mjs +0 -277
- package/src/hook-executor.mjs +0 -870
- package/src/hook-management.mjs +0 -150
- package/src/ken-parliment.mjs +0 -119
- package/src/ken.mjs +0 -149
- package/src/knowledge-engine/builtin-rules.mjs +0 -190
- package/src/knowledge-engine/inference-engine.mjs +0 -418
- package/src/knowledge-engine/knowledge-engine.mjs +0 -317
- package/src/knowledge-engine/pattern-dsl.mjs +0 -142
- package/src/knowledge-engine/pattern-matcher.mjs +0 -215
- package/src/knowledge-engine/rules.mjs +0 -184
- package/src/knowledge-engine.mjs +0 -319
- package/src/knowledge-hook-engine.mjs +0 -360
- package/src/knowledge-substrate-core.mjs +0 -927
- package/src/lite.mjs +0 -222
- package/src/lockchain-writer.mjs +0 -602
- package/src/monitoring/andon-signals.mjs +0 -775
- package/src/parse.mjs +0 -290
- package/src/performance-optimizer.mjs +0 -678
- package/src/policy-pack.mjs +0 -572
- package/src/query-cache.mjs +0 -116
- package/src/query.mjs +0 -306
- package/src/reason.mjs +0 -350
- package/src/schemas.mjs +0 -1063
- package/src/security/error-sanitizer.mjs +0 -257
- package/src/security/path-validator.mjs +0 -194
- package/src/security/sandbox-restrictions.mjs +0 -331
- package/src/security-validator.mjs +0 -389
- package/src/store-cache.mjs +0 -137
- package/src/telemetry.mjs +0 -167
- package/src/utils/adaptive-monitor.mjs +0 -746
- package/src/utils/circuit-breaker.mjs +0 -513
- package/src/utils/edge-case-handler.mjs +0 -503
- package/src/utils/memory-manager.mjs +0 -498
- package/src/utils/ring-buffer.mjs +0 -282
- package/src/validate.mjs +0 -319
- package/src/validators/index.mjs +0 -338
|
@@ -1,678 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Performance Optimizer for UNRDF
|
|
3
|
-
* @module performance-optimizer
|
|
4
|
-
*
|
|
5
|
-
* @description
|
|
6
|
-
* Implements performance optimizations to meet KGC PRD success metrics:
|
|
7
|
-
* - p50 pre-hook pipeline ≤ 200 µs
|
|
8
|
-
* - p99 ≤ 2 ms (10k triples store, afterHashOnly=true)
|
|
9
|
-
* - Receipt write ≤ 5 ms median (no canonicalization) / ≤ 200 ms with URDNA2015 on 100k triples
|
|
10
|
-
* - Hook engine ≥ 10k exec/min sustained
|
|
11
|
-
* - Error isolation 100%
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { randomUUID } from 'crypto';
|
|
15
|
-
import { z } from 'zod';
|
|
16
|
-
import { PerformanceMetricsSchema } from './schemas.mjs';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Performance optimization configuration
|
|
20
|
-
*/
|
|
21
|
-
const PerformanceConfigSchema = z.object({
|
|
22
|
-
enableFastPath: z.boolean().default(true),
|
|
23
|
-
enableCaching: z.boolean().default(true),
|
|
24
|
-
enableBatchProcessing: z.boolean().default(true),
|
|
25
|
-
enableParallelExecution: z.boolean().default(true),
|
|
26
|
-
maxConcurrency: z.number().int().positive().default(10),
|
|
27
|
-
cacheSize: z.number().int().positive().default(10000),
|
|
28
|
-
batchSize: z.number().int().positive().default(1000),
|
|
29
|
-
timeoutMs: z.number().int().positive().default(2000), // KGC PRD: p99 ≤ 2ms
|
|
30
|
-
maxHooks: z.number().int().positive().default(10000), // KGC PRD: 10k exec/min
|
|
31
|
-
afterHashOnly: z.boolean().default(false), // KGC PRD fast path
|
|
32
|
-
enableProfiling: z.boolean().default(false),
|
|
33
|
-
enableMemoryOptimization: z.boolean().default(true),
|
|
34
|
-
enableQueryOptimization: z.boolean().default(true),
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Performance metrics tracking
|
|
39
|
-
*/
|
|
40
|
-
const PerformanceMetrics = {
|
|
41
|
-
transactionLatency: [],
|
|
42
|
-
hookExecutionRate: 0,
|
|
43
|
-
errorRate: 0,
|
|
44
|
-
memoryUsage: [],
|
|
45
|
-
cacheStats: { hits: 0, misses: 0, size: 0 },
|
|
46
|
-
backpressure: { queueDepth: 0, watermarks: { high: 1000, low: 100 } },
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Performance Optimizer for UNRDF
|
|
51
|
-
*/
|
|
52
|
-
export class PerformanceOptimizer {
|
|
53
|
-
/**
|
|
54
|
-
* Create a new performance optimizer
|
|
55
|
-
* @param {Object} [config] - Performance configuration
|
|
56
|
-
*/
|
|
57
|
-
constructor(config = {}) {
|
|
58
|
-
this.config = PerformanceConfigSchema.parse(config);
|
|
59
|
-
this.metrics = { ...PerformanceMetrics };
|
|
60
|
-
this.cache = new Map();
|
|
61
|
-
this.batchQueue = [];
|
|
62
|
-
this.processingQueue = [];
|
|
63
|
-
this.isProcessing = false;
|
|
64
|
-
|
|
65
|
-
// Performance tracking
|
|
66
|
-
this.startTime = Date.now();
|
|
67
|
-
this.totalTransactions = 0;
|
|
68
|
-
this.totalHooks = 0;
|
|
69
|
-
this.totalErrors = 0;
|
|
70
|
-
|
|
71
|
-
// Memory optimization
|
|
72
|
-
this.memoryThreshold = 100 * 1024 * 1024; // 100MB
|
|
73
|
-
this.lastGcTime = Date.now();
|
|
74
|
-
this.gcInterval = 30000; // 30 seconds
|
|
75
|
-
|
|
76
|
-
// Query optimization
|
|
77
|
-
this.queryCache = new Map();
|
|
78
|
-
this.queryStats = new Map();
|
|
79
|
-
|
|
80
|
-
// Initialize performance monitoring
|
|
81
|
-
this._initializePerformanceMonitoring();
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
/**
|
|
85
|
-
* Initialize performance monitoring
|
|
86
|
-
* @private
|
|
87
|
-
*/
|
|
88
|
-
_initializePerformanceMonitoring() {
|
|
89
|
-
if (this.config.enableProfiling) {
|
|
90
|
-
// Set up performance monitoring
|
|
91
|
-
setInterval(() => {
|
|
92
|
-
this._updateMemoryUsage();
|
|
93
|
-
this._checkMemoryThreshold();
|
|
94
|
-
this._cleanupCache();
|
|
95
|
-
}, 5000); // Every 5 seconds
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Optimize transaction processing
|
|
101
|
-
* @param {Function} transactionFn - Transaction function
|
|
102
|
-
* @param {Object} context - Transaction context
|
|
103
|
-
* @returns {Promise<any>} Optimized transaction result
|
|
104
|
-
*/
|
|
105
|
-
async optimizeTransaction(transactionFn, context) {
|
|
106
|
-
const startTime = process.hrtime.bigint();
|
|
107
|
-
|
|
108
|
-
try {
|
|
109
|
-
// Fast path optimization
|
|
110
|
-
if (this.config.enableFastPath && context.afterHashOnly) {
|
|
111
|
-
return await this._fastPathTransaction(transactionFn, context);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Batch processing optimization
|
|
115
|
-
if (this.config.enableBatchProcessing && context.batchable) {
|
|
116
|
-
return await this._batchTransaction(transactionFn, context);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Parallel execution optimization
|
|
120
|
-
if (this.config.enableParallelExecution && context.parallelizable) {
|
|
121
|
-
return await this._parallelTransaction(transactionFn, context);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// Standard execution
|
|
125
|
-
const result = await transactionFn(context);
|
|
126
|
-
|
|
127
|
-
// Update metrics
|
|
128
|
-
const duration = Number(process.hrtime.bigint() - startTime) / 1000000; // Convert to ms
|
|
129
|
-
this._updateTransactionMetrics(duration, true);
|
|
130
|
-
|
|
131
|
-
return result;
|
|
132
|
-
} catch (error) {
|
|
133
|
-
const duration = Number(process.hrtime.bigint() - startTime) / 1000000;
|
|
134
|
-
this._updateTransactionMetrics(duration, false);
|
|
135
|
-
throw error;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Optimize hook execution
|
|
141
|
-
* @param {Function} hookFn - Hook function
|
|
142
|
-
* @param {Object} context - Hook context
|
|
143
|
-
* @returns {Promise<any>} Optimized hook result
|
|
144
|
-
*/
|
|
145
|
-
async optimizeHook(hookFn, context) {
|
|
146
|
-
const startTime = process.hrtime.bigint();
|
|
147
|
-
|
|
148
|
-
try {
|
|
149
|
-
// Check if hook is cached
|
|
150
|
-
if (this.config.enableCaching) {
|
|
151
|
-
const cacheKey = this._generateCacheKey(hookFn, context);
|
|
152
|
-
const cached = this.cache.get(cacheKey);
|
|
153
|
-
if (cached && this._isCacheValid(cached)) {
|
|
154
|
-
this.metrics.cacheStats.hits++;
|
|
155
|
-
return cached.result;
|
|
156
|
-
}
|
|
157
|
-
this.metrics.cacheStats.misses++;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
// Execute hook
|
|
161
|
-
const result = await hookFn(context);
|
|
162
|
-
|
|
163
|
-
// Cache result if enabled
|
|
164
|
-
if (this.config.enableCaching) {
|
|
165
|
-
const cacheKey = this._generateCacheKey(hookFn, context);
|
|
166
|
-
this.cache.set(cacheKey, {
|
|
167
|
-
result,
|
|
168
|
-
timestamp: Date.now(),
|
|
169
|
-
ttl: context.cacheTtl || 300000, // 5 minutes default
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
// Update metrics
|
|
174
|
-
const duration = Number(process.hrtime.bigint() - startTime) / 1000000;
|
|
175
|
-
this._updateHookMetrics(duration, true);
|
|
176
|
-
|
|
177
|
-
return result;
|
|
178
|
-
} catch (error) {
|
|
179
|
-
const duration = Number(process.hrtime.bigint() - startTime) / 1000000;
|
|
180
|
-
this._updateHookMetrics(duration, false);
|
|
181
|
-
throw error;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Optimize query execution
|
|
187
|
-
* @param {string} query - SPARQL query
|
|
188
|
-
* @param {Function} queryFn - Query function
|
|
189
|
-
* @param {Object} context - Query context
|
|
190
|
-
* @returns {Promise<any>} Optimized query result
|
|
191
|
-
*/
|
|
192
|
-
async optimizeQuery(query, queryFn, context) {
|
|
193
|
-
if (!this.config.enableQueryOptimization) {
|
|
194
|
-
return await queryFn(query, context);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
// Check query cache
|
|
198
|
-
const cacheKey = this._hashQuery(query);
|
|
199
|
-
const cached = this.queryCache.get(cacheKey);
|
|
200
|
-
if (cached && this._isCacheValid(cached)) {
|
|
201
|
-
this.metrics.cacheStats.hits++;
|
|
202
|
-
return cached.result;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
// Execute query
|
|
206
|
-
const startTime = process.hrtime.bigint();
|
|
207
|
-
const result = await queryFn(query, context);
|
|
208
|
-
const duration = Number(process.hrtime.bigint() - startTime) / 1000000;
|
|
209
|
-
|
|
210
|
-
// Cache result
|
|
211
|
-
this.queryCache.set(cacheKey, {
|
|
212
|
-
result,
|
|
213
|
-
timestamp: Date.now(),
|
|
214
|
-
ttl: context.queryCacheTtl || 600000, // 10 minutes default
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
// Update query stats
|
|
218
|
-
this.queryStats.set(cacheKey, {
|
|
219
|
-
executionCount: (this.queryStats.get(cacheKey)?.executionCount || 0) + 1,
|
|
220
|
-
totalDuration: (this.queryStats.get(cacheKey)?.totalDuration || 0) + duration,
|
|
221
|
-
lastExecuted: Date.now(),
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
this.metrics.cacheStats.misses++;
|
|
225
|
-
return result;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Fast path transaction execution
|
|
230
|
-
* @param {Function} transactionFn - Transaction function
|
|
231
|
-
* @param {Object} context - Transaction context
|
|
232
|
-
* @returns {Promise<any>} Fast path result
|
|
233
|
-
* @private
|
|
234
|
-
*/
|
|
235
|
-
async _fastPathTransaction(transactionFn, context) {
|
|
236
|
-
// Skip expensive operations for fast path
|
|
237
|
-
const fastContext = {
|
|
238
|
-
...context,
|
|
239
|
-
skipCanonicalization: true,
|
|
240
|
-
skipValidation: true,
|
|
241
|
-
skipHooks: false, // Still run hooks but optimize them
|
|
242
|
-
timeout: Math.min(context.timeout || 2000, 1000), // Max 1s for fast path
|
|
243
|
-
};
|
|
244
|
-
|
|
245
|
-
return await transactionFn(fastContext);
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Batch transaction processing
|
|
250
|
-
* @param {Function} transactionFn - Transaction function
|
|
251
|
-
* @param {Object} context - Transaction context
|
|
252
|
-
* @returns {Promise<any>} Batch result
|
|
253
|
-
* @private
|
|
254
|
-
*/
|
|
255
|
-
async _batchTransaction(transactionFn, context) {
|
|
256
|
-
// Add to batch queue
|
|
257
|
-
this.batchQueue.push({ transactionFn, context });
|
|
258
|
-
|
|
259
|
-
// Process batch if size threshold reached
|
|
260
|
-
if (this.batchQueue.length >= this.config.batchSize) {
|
|
261
|
-
return await this._processBatch();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Return promise that resolves when batch is processed
|
|
265
|
-
return new Promise((resolve, reject) => {
|
|
266
|
-
const batchId = randomUUID();
|
|
267
|
-
this.processingQueue.push({ batchId, resolve, reject });
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Process batch queue
|
|
273
|
-
* @returns {Promise<any>} Batch processing result
|
|
274
|
-
* @private
|
|
275
|
-
*/
|
|
276
|
-
async _processBatch() {
|
|
277
|
-
if (this.isProcessing) {
|
|
278
|
-
return; // Already processing
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
this.isProcessing = true;
|
|
282
|
-
const batch = this.batchQueue.splice(0, this.config.batchSize);
|
|
283
|
-
|
|
284
|
-
try {
|
|
285
|
-
// Process batch in parallel
|
|
286
|
-
const results = await Promise.all(
|
|
287
|
-
batch.map(({ transactionFn, context }) => transactionFn(context))
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
// Resolve all pending promises
|
|
291
|
-
this.processingQueue.forEach(({ resolve }) => resolve(results));
|
|
292
|
-
this.processingQueue = [];
|
|
293
|
-
|
|
294
|
-
return results;
|
|
295
|
-
} catch (error) {
|
|
296
|
-
// Reject all pending promises
|
|
297
|
-
this.processingQueue.forEach(({ reject }) => reject(error));
|
|
298
|
-
this.processingQueue = [];
|
|
299
|
-
throw error;
|
|
300
|
-
} finally {
|
|
301
|
-
this.isProcessing = false;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
/**
|
|
306
|
-
* Parallel transaction execution
|
|
307
|
-
* @param {Function} transactionFn - Transaction function
|
|
308
|
-
* @param {Object} context - Transaction context
|
|
309
|
-
* @returns {Promise<any>} Parallel result
|
|
310
|
-
* @private
|
|
311
|
-
*/
|
|
312
|
-
async _parallelTransaction(transactionFn, context) {
|
|
313
|
-
// Split context into parallelizable parts
|
|
314
|
-
const parallelParts = this._splitContext(context);
|
|
315
|
-
|
|
316
|
-
// Execute parts in parallel
|
|
317
|
-
const results = await Promise.all(parallelParts.map(part => transactionFn(part)));
|
|
318
|
-
|
|
319
|
-
// Merge results
|
|
320
|
-
return this._mergeResults(results);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Update transaction metrics
|
|
325
|
-
* @param {number} duration - Transaction duration
|
|
326
|
-
* @param {boolean} success - Whether transaction succeeded
|
|
327
|
-
* @private
|
|
328
|
-
*/
|
|
329
|
-
_updateTransactionMetrics(duration, success) {
|
|
330
|
-
this.metrics.transactionLatency.push({
|
|
331
|
-
timestamp: Date.now(),
|
|
332
|
-
duration,
|
|
333
|
-
success,
|
|
334
|
-
});
|
|
335
|
-
|
|
336
|
-
// Keep only last 1000 measurements
|
|
337
|
-
if (this.metrics.transactionLatency.length > 1000) {
|
|
338
|
-
this.metrics.transactionLatency = this.metrics.transactionLatency.slice(-1000);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
this.totalTransactions++;
|
|
342
|
-
|
|
343
|
-
if (!success) {
|
|
344
|
-
this.totalErrors++;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
// Check if we're meeting performance targets
|
|
348
|
-
this._checkPerformanceTargets();
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Update hook metrics
|
|
353
|
-
* @param {number} duration - Hook duration
|
|
354
|
-
* @param {boolean} success - Whether hook succeeded
|
|
355
|
-
* @private
|
|
356
|
-
*/
|
|
357
|
-
_updateHookMetrics(duration, success) {
|
|
358
|
-
this.totalHooks++;
|
|
359
|
-
|
|
360
|
-
if (!success) {
|
|
361
|
-
this.totalErrors++;
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
// Calculate hook execution rate (per minute)
|
|
365
|
-
const now = Date.now();
|
|
366
|
-
const timeElapsed = (now - this.startTime) / 60000; // minutes
|
|
367
|
-
this.metrics.hookExecutionRate = this.totalHooks / timeElapsed;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* Check performance targets
|
|
372
|
-
* @private
|
|
373
|
-
*/
|
|
374
|
-
_checkPerformanceTargets() {
|
|
375
|
-
const recentLatencies = this.metrics.transactionLatency
|
|
376
|
-
.filter(l => Date.now() - l.timestamp < 60000) // Last minute
|
|
377
|
-
.map(l => l.duration)
|
|
378
|
-
.sort((a, b) => a - b);
|
|
379
|
-
|
|
380
|
-
if (recentLatencies.length === 0) return;
|
|
381
|
-
|
|
382
|
-
const p50 = this._calculatePercentile(recentLatencies, 0.5);
|
|
383
|
-
const p99 = this._calculatePercentile(recentLatencies, 0.99);
|
|
384
|
-
|
|
385
|
-
// Check KGC PRD targets
|
|
386
|
-
if (p50 > 0.2) {
|
|
387
|
-
// 200 µs
|
|
388
|
-
console.warn(`[Performance] p50 latency ${p50.toFixed(3)}ms exceeds target 0.2ms`);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
if (p99 > 2) {
|
|
392
|
-
// 2 ms
|
|
393
|
-
console.warn(`[Performance] p99 latency ${p99.toFixed(3)}ms exceeds target 2ms`);
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (this.metrics.hookExecutionRate < 10000) {
|
|
397
|
-
// 10k exec/min
|
|
398
|
-
console.warn(
|
|
399
|
-
`[Performance] Hook execution rate ${this.metrics.hookExecutionRate.toFixed(0)}/min below target 10000/min`
|
|
400
|
-
);
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
/**
|
|
405
|
-
* Calculate percentile
|
|
406
|
-
* @param {Array<number>} values - Sorted values
|
|
407
|
-
* @param {number} percentile - Percentile (0-1)
|
|
408
|
-
* @returns {number} Percentile value
|
|
409
|
-
* @private
|
|
410
|
-
*/
|
|
411
|
-
_calculatePercentile(values, percentile) {
|
|
412
|
-
if (values.length === 0) return 0;
|
|
413
|
-
const index = Math.ceil(values.length * percentile) - 1;
|
|
414
|
-
return values[Math.max(0, index)];
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Generate cache key
|
|
419
|
-
* @param {Function} fn - Function
|
|
420
|
-
* @param {Object} context - Context
|
|
421
|
-
* @returns {string} Cache key
|
|
422
|
-
* @private
|
|
423
|
-
*/
|
|
424
|
-
_generateCacheKey(fn, context) {
|
|
425
|
-
const fnString = fn.toString();
|
|
426
|
-
const contextString = JSON.stringify(context);
|
|
427
|
-
return this._hashString(fnString + contextString);
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Hash string
|
|
432
|
-
* @param {string} str - String to hash
|
|
433
|
-
* @returns {string} Hash
|
|
434
|
-
* @private
|
|
435
|
-
*/
|
|
436
|
-
_hashString(str) {
|
|
437
|
-
let hash = 0;
|
|
438
|
-
for (let i = 0; i < str.length; i++) {
|
|
439
|
-
const char = str.charCodeAt(i);
|
|
440
|
-
hash = (hash << 5) - hash + char;
|
|
441
|
-
hash = hash & hash; // Convert to 32-bit integer
|
|
442
|
-
}
|
|
443
|
-
return hash.toString(36);
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/**
|
|
447
|
-
* Hash query
|
|
448
|
-
* @param {string} query - SPARQL query
|
|
449
|
-
* @returns {string} Query hash
|
|
450
|
-
* @private
|
|
451
|
-
*/
|
|
452
|
-
_hashQuery(query) {
|
|
453
|
-
return this._hashString(query);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
/**
|
|
457
|
-
* Check if cache entry is valid
|
|
458
|
-
* @param {Object} cached - Cached entry
|
|
459
|
-
* @returns {boolean} Is valid
|
|
460
|
-
* @private
|
|
461
|
-
*/
|
|
462
|
-
_isCacheValid(cached) {
|
|
463
|
-
return Date.now() - cached.timestamp < cached.ttl;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
/**
|
|
467
|
-
* Update memory usage
|
|
468
|
-
* @private
|
|
469
|
-
*/
|
|
470
|
-
_updateMemoryUsage() {
|
|
471
|
-
const memUsage = process.memoryUsage();
|
|
472
|
-
this.metrics.memoryUsage.push({
|
|
473
|
-
timestamp: Date.now(),
|
|
474
|
-
rss: memUsage.rss,
|
|
475
|
-
heapUsed: memUsage.heapUsed,
|
|
476
|
-
heapTotal: memUsage.heapTotal,
|
|
477
|
-
external: memUsage.external,
|
|
478
|
-
});
|
|
479
|
-
|
|
480
|
-
// Keep only last 100 measurements
|
|
481
|
-
if (this.metrics.memoryUsage.length > 100) {
|
|
482
|
-
this.metrics.memoryUsage = this.metrics.memoryUsage.slice(-100);
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
|
|
486
|
-
/**
|
|
487
|
-
* Check memory threshold
|
|
488
|
-
* @private
|
|
489
|
-
*/
|
|
490
|
-
_checkMemoryThreshold() {
|
|
491
|
-
const memUsage = process.memoryUsage();
|
|
492
|
-
if (memUsage.heapUsed > this.memoryThreshold) {
|
|
493
|
-
console.warn(
|
|
494
|
-
`[Performance] Memory usage ${(memUsage.heapUsed / 1024 / 1024).toFixed(2)}MB exceeds threshold ${(this.memoryThreshold / 1024 / 1024).toFixed(2)}MB`
|
|
495
|
-
);
|
|
496
|
-
|
|
497
|
-
// Force garbage collection if available
|
|
498
|
-
if (global.gc) {
|
|
499
|
-
global.gc();
|
|
500
|
-
this.lastGcTime = Date.now();
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
/**
|
|
506
|
-
* Cleanup cache
|
|
507
|
-
* @private
|
|
508
|
-
*/
|
|
509
|
-
_cleanupCache() {
|
|
510
|
-
const _now = Date._now();
|
|
511
|
-
|
|
512
|
-
// Cleanup main cache
|
|
513
|
-
for (const [key, value] of this.cache.entries()) {
|
|
514
|
-
if (!this._isCacheValid(value)) {
|
|
515
|
-
this.cache.delete(key);
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// Cleanup query cache
|
|
520
|
-
for (const [key, value] of this.queryCache.entries()) {
|
|
521
|
-
if (!this._isCacheValid(value)) {
|
|
522
|
-
this.queryCache.delete(key);
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// Limit cache size
|
|
527
|
-
if (this.cache.size > this.config.cacheSize) {
|
|
528
|
-
const entries = Array.from(this.cache.entries());
|
|
529
|
-
entries.sort((a, b) => a[1].timestamp - b[1].timestamp);
|
|
530
|
-
const toDelete = entries.slice(0, entries.length - this.config.cacheSize);
|
|
531
|
-
toDelete.forEach(([key]) => this.cache.delete(key));
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
/**
|
|
536
|
-
* Split context for parallel processing
|
|
537
|
-
* @param {Object} context - Context to split
|
|
538
|
-
* @returns {Array<Object>} Split contexts
|
|
539
|
-
* @private
|
|
540
|
-
*/
|
|
541
|
-
_splitContext(context) {
|
|
542
|
-
// Simple implementation - split by delta additions/removals
|
|
543
|
-
if (context.delta && context.delta.additions) {
|
|
544
|
-
const chunkSize = Math.ceil(context.delta.additions.length / this.config.maxConcurrency);
|
|
545
|
-
const chunks = [];
|
|
546
|
-
|
|
547
|
-
for (let i = 0; i < context.delta.additions.length; i += chunkSize) {
|
|
548
|
-
chunks.push({
|
|
549
|
-
...context,
|
|
550
|
-
delta: {
|
|
551
|
-
...context.delta,
|
|
552
|
-
additions: context.delta.additions.slice(i, i + chunkSize),
|
|
553
|
-
removals: [], // Only process additions in parallel
|
|
554
|
-
},
|
|
555
|
-
});
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
return chunks;
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return [context];
|
|
562
|
-
}
|
|
563
|
-
|
|
564
|
-
/**
|
|
565
|
-
* Merge parallel results
|
|
566
|
-
* @param {Array} results - Results to merge
|
|
567
|
-
* @returns {Object} Merged result
|
|
568
|
-
* @private
|
|
569
|
-
*/
|
|
570
|
-
_mergeResults(results) {
|
|
571
|
-
// Simple implementation - merge receipts
|
|
572
|
-
if (results.length === 1) {
|
|
573
|
-
return results[0];
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
const merged = {
|
|
577
|
-
...results[0],
|
|
578
|
-
hookResults: [],
|
|
579
|
-
hookErrors: [],
|
|
580
|
-
};
|
|
581
|
-
|
|
582
|
-
results.forEach(result => {
|
|
583
|
-
if (result.hookResults) {
|
|
584
|
-
merged.hookResults.push(...result.hookResults);
|
|
585
|
-
}
|
|
586
|
-
if (result.hookErrors) {
|
|
587
|
-
merged.hookErrors.push(...result.hookErrors);
|
|
588
|
-
}
|
|
589
|
-
});
|
|
590
|
-
|
|
591
|
-
return merged;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/**
|
|
595
|
-
* Get performance metrics
|
|
596
|
-
* @returns {Object} Performance metrics
|
|
597
|
-
*/
|
|
598
|
-
getMetrics() {
|
|
599
|
-
const now = Date.now();
|
|
600
|
-
const oneMinuteAgo = now - 60000;
|
|
601
|
-
|
|
602
|
-
// Calculate transaction latency percentiles
|
|
603
|
-
const recentLatencies = this.metrics.transactionLatency
|
|
604
|
-
.filter(l => l.timestamp > oneMinuteAgo)
|
|
605
|
-
.map(l => l.duration)
|
|
606
|
-
.sort((a, b) => a - b);
|
|
607
|
-
|
|
608
|
-
const p50 = this._calculatePercentile(recentLatencies, 0.5);
|
|
609
|
-
const p95 = this._calculatePercentile(recentLatencies, 0.95);
|
|
610
|
-
const p99 = this._calculatePercentile(recentLatencies, 0.99);
|
|
611
|
-
const max = recentLatencies.length > 0 ? recentLatencies[recentLatencies.length - 1] : 0;
|
|
612
|
-
|
|
613
|
-
// Calculate error rate
|
|
614
|
-
const errorRate = this.totalTransactions > 0 ? this.totalErrors / this.totalTransactions : 0;
|
|
615
|
-
|
|
616
|
-
// Get current memory usage
|
|
617
|
-
const currentMemory = process.memoryUsage();
|
|
618
|
-
|
|
619
|
-
// Calculate cache hit rate
|
|
620
|
-
const totalCacheOps = this.metrics.cacheStats.hits + this.metrics.cacheStats.misses;
|
|
621
|
-
const cacheHitRate = totalCacheOps > 0 ? this.metrics.cacheStats.hits / totalCacheOps : 0;
|
|
622
|
-
|
|
623
|
-
return PerformanceMetricsSchema.parse({
|
|
624
|
-
transactionLatency: { p50, p95, p99, max },
|
|
625
|
-
hookExecutionRate: this.metrics.hookExecutionRate,
|
|
626
|
-
errorRate,
|
|
627
|
-
memoryUsage: currentMemory,
|
|
628
|
-
cacheStats: {
|
|
629
|
-
hitRate: cacheHitRate,
|
|
630
|
-
size: this.cache.size,
|
|
631
|
-
maxSize: this.config.cacheSize,
|
|
632
|
-
},
|
|
633
|
-
backpressure: this.metrics.backpressure,
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
/**
|
|
638
|
-
* Reset metrics
|
|
639
|
-
*/
|
|
640
|
-
resetMetrics() {
|
|
641
|
-
this.metrics = { ...PerformanceMetrics };
|
|
642
|
-
this.startTime = Date.now();
|
|
643
|
-
this.totalTransactions = 0;
|
|
644
|
-
this.totalHooks = 0;
|
|
645
|
-
this.totalErrors = 0;
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
/**
|
|
649
|
-
* Shutdown optimizer
|
|
650
|
-
*/
|
|
651
|
-
async shutdown() {
|
|
652
|
-
// Process remaining batch
|
|
653
|
-
if (this.batchQueue.length > 0) {
|
|
654
|
-
await this._processBatch();
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
// Clear caches
|
|
658
|
-
this.cache.clear();
|
|
659
|
-
this.queryCache.clear();
|
|
660
|
-
this.queryStats.clear();
|
|
661
|
-
|
|
662
|
-
console.log('[Performance] Optimizer shutdown complete');
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
/**
|
|
667
|
-
* Create a performance optimizer instance
|
|
668
|
-
* @param {Object} [config] - Configuration
|
|
669
|
-
* @returns {PerformanceOptimizer} Performance optimizer
|
|
670
|
-
*/
|
|
671
|
-
export function createPerformanceOptimizer(config = {}) {
|
|
672
|
-
return new PerformanceOptimizer(config);
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* Default performance optimizer instance
|
|
677
|
-
*/
|
|
678
|
-
export const defaultPerformanceOptimizer = createPerformanceOptimizer();
|