kailash 0.8.4__py3-none-any.whl → 0.8.5__py3-none-any.whl

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 (79) hide show
  1. kailash/__init__.py +1 -7
  2. kailash/cli/__init__.py +11 -1
  3. kailash/cli/validation_audit.py +570 -0
  4. kailash/core/actors/supervisor.py +1 -1
  5. kailash/core/resilience/circuit_breaker.py +71 -1
  6. kailash/core/resilience/health_monitor.py +172 -0
  7. kailash/edge/compliance.py +33 -0
  8. kailash/edge/consistency.py +609 -0
  9. kailash/edge/coordination/__init__.py +30 -0
  10. kailash/edge/coordination/global_ordering.py +355 -0
  11. kailash/edge/coordination/leader_election.py +217 -0
  12. kailash/edge/coordination/partition_detector.py +296 -0
  13. kailash/edge/coordination/raft.py +485 -0
  14. kailash/edge/discovery.py +63 -1
  15. kailash/edge/migration/__init__.py +19 -0
  16. kailash/edge/migration/edge_migrator.py +832 -0
  17. kailash/edge/monitoring/__init__.py +21 -0
  18. kailash/edge/monitoring/edge_monitor.py +736 -0
  19. kailash/edge/prediction/__init__.py +10 -0
  20. kailash/edge/prediction/predictive_warmer.py +591 -0
  21. kailash/edge/resource/__init__.py +102 -0
  22. kailash/edge/resource/cloud_integration.py +796 -0
  23. kailash/edge/resource/cost_optimizer.py +949 -0
  24. kailash/edge/resource/docker_integration.py +919 -0
  25. kailash/edge/resource/kubernetes_integration.py +893 -0
  26. kailash/edge/resource/platform_integration.py +913 -0
  27. kailash/edge/resource/predictive_scaler.py +959 -0
  28. kailash/edge/resource/resource_analyzer.py +824 -0
  29. kailash/edge/resource/resource_pools.py +610 -0
  30. kailash/integrations/dataflow_edge.py +261 -0
  31. kailash/mcp_server/registry_integration.py +1 -1
  32. kailash/monitoring/__init__.py +18 -0
  33. kailash/monitoring/alerts.py +646 -0
  34. kailash/monitoring/metrics.py +677 -0
  35. kailash/nodes/__init__.py +2 -0
  36. kailash/nodes/ai/semantic_memory.py +2 -2
  37. kailash/nodes/base.py +545 -0
  38. kailash/nodes/edge/__init__.py +36 -0
  39. kailash/nodes/edge/base.py +240 -0
  40. kailash/nodes/edge/cloud_node.py +710 -0
  41. kailash/nodes/edge/coordination.py +239 -0
  42. kailash/nodes/edge/docker_node.py +825 -0
  43. kailash/nodes/edge/edge_data.py +582 -0
  44. kailash/nodes/edge/edge_migration_node.py +392 -0
  45. kailash/nodes/edge/edge_monitoring_node.py +421 -0
  46. kailash/nodes/edge/edge_state.py +673 -0
  47. kailash/nodes/edge/edge_warming_node.py +393 -0
  48. kailash/nodes/edge/kubernetes_node.py +652 -0
  49. kailash/nodes/edge/platform_node.py +766 -0
  50. kailash/nodes/edge/resource_analyzer_node.py +378 -0
  51. kailash/nodes/edge/resource_optimizer_node.py +501 -0
  52. kailash/nodes/edge/resource_scaler_node.py +397 -0
  53. kailash/nodes/ports.py +676 -0
  54. kailash/runtime/local.py +344 -1
  55. kailash/runtime/validation/__init__.py +20 -0
  56. kailash/runtime/validation/connection_context.py +119 -0
  57. kailash/runtime/validation/enhanced_error_formatter.py +202 -0
  58. kailash/runtime/validation/error_categorizer.py +164 -0
  59. kailash/runtime/validation/metrics.py +380 -0
  60. kailash/runtime/validation/performance.py +615 -0
  61. kailash/runtime/validation/suggestion_engine.py +212 -0
  62. kailash/testing/fixtures.py +2 -2
  63. kailash/workflow/builder.py +230 -4
  64. kailash/workflow/contracts.py +418 -0
  65. kailash/workflow/edge_infrastructure.py +369 -0
  66. kailash/workflow/migration.py +3 -3
  67. kailash/workflow/type_inference.py +669 -0
  68. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/METADATA +43 -27
  69. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/RECORD +73 -27
  70. kailash/nexus/__init__.py +0 -21
  71. kailash/nexus/cli/__init__.py +0 -5
  72. kailash/nexus/cli/__main__.py +0 -6
  73. kailash/nexus/cli/main.py +0 -176
  74. kailash/nexus/factory.py +0 -413
  75. kailash/nexus/gateway.py +0 -545
  76. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
  77. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
  78. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
  79. {kailash-0.8.4.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,615 @@
1
+ """
2
+ Performance optimization for connection validation.
3
+
4
+ Provides advanced caching, lazy evaluation, batch validation,
5
+ and performance benchmarking for the validation system.
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ import time
11
+ import weakref
12
+ from collections import OrderedDict, defaultdict
13
+ from dataclasses import dataclass, field
14
+ from datetime import UTC, datetime, timedelta
15
+ from threading import RLock
16
+ from typing import Any, Dict, List, Optional, Set, Tuple
17
+
18
+ from kailash.workflow.type_inference import (
19
+ ConnectionInferenceResult,
20
+ TypeCompatibilityResult,
21
+ )
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ @dataclass
27
+ class PerformanceMetrics:
28
+ """Performance metrics for validation operations."""
29
+
30
+ total_validations: int = 0
31
+ total_time_ms: float = 0.0
32
+ cache_hits: int = 0
33
+ cache_misses: int = 0
34
+ avg_validation_time_ms: float = 0.0
35
+ max_validation_time_ms: float = 0.0
36
+ min_validation_time_ms: float = float("inf")
37
+
38
+ # Cache performance
39
+ cache_hit_ratio: float = 0.0
40
+ cache_size: int = 0
41
+ cache_memory_kb: float = 0.0
42
+
43
+ # Bottlenecks
44
+ slow_validations: List[Tuple[str, float]] = field(default_factory=list)
45
+ expensive_connections: List[Tuple[str, str, float]] = field(default_factory=list)
46
+
47
+ def update_validation_time(self, time_ms: float, operation: str = "unknown"):
48
+ """Update validation timing statistics."""
49
+ self.total_validations += 1
50
+ self.total_time_ms += time_ms
51
+ self.avg_validation_time_ms = self.total_time_ms / self.total_validations
52
+
53
+ if time_ms > self.max_validation_time_ms:
54
+ self.max_validation_time_ms = time_ms
55
+
56
+ if time_ms < self.min_validation_time_ms:
57
+ self.min_validation_time_ms = time_ms
58
+
59
+ # Track slow validations (>50ms)
60
+ if time_ms > 50.0:
61
+ self.slow_validations.append((operation, time_ms))
62
+ # Keep only recent slow validations
63
+ if len(self.slow_validations) > 100:
64
+ self.slow_validations = self.slow_validations[-100:]
65
+
66
+ def update_cache_stats(self, hits: int, misses: int, size: int, memory_kb: float):
67
+ """Update cache performance statistics."""
68
+ self.cache_hits = hits
69
+ self.cache_misses = misses
70
+ self.cache_size = size
71
+ self.cache_memory_kb = memory_kb
72
+
73
+ total_requests = hits + misses
74
+ self.cache_hit_ratio = hits / total_requests if total_requests > 0 else 0.0
75
+
76
+
77
+ class LRUCache:
78
+ """Thread-safe LRU cache with memory management."""
79
+
80
+ def __init__(self, max_size: int = 1000, ttl_seconds: int = 3600):
81
+ """Initialize LRU cache.
82
+
83
+ Args:
84
+ max_size: Maximum number of items to cache
85
+ ttl_seconds: Time-to-live for cache entries
86
+ """
87
+ self.max_size = max_size
88
+ self.ttl_seconds = ttl_seconds
89
+ self._cache: OrderedDict = OrderedDict()
90
+ self._timestamps: Dict[Any, datetime] = {}
91
+ self._lock = RLock()
92
+ self._hits = 0
93
+ self._misses = 0
94
+
95
+ def get(self, key: Any) -> Optional[Any]:
96
+ """Get item from cache."""
97
+ with self._lock:
98
+ # Check if key exists and is not expired
99
+ if key in self._cache:
100
+ timestamp = self._timestamps[key]
101
+ if datetime.now(UTC) - timestamp < timedelta(seconds=self.ttl_seconds):
102
+ # Move to end (most recently used)
103
+ self._cache.move_to_end(key)
104
+ self._hits += 1
105
+ return self._cache[key]
106
+ else:
107
+ # Expired, remove
108
+ del self._cache[key]
109
+ del self._timestamps[key]
110
+
111
+ self._misses += 1
112
+ return None
113
+
114
+ def put(self, key: Any, value: Any) -> None:
115
+ """Put item in cache."""
116
+ with self._lock:
117
+ # Update existing item
118
+ if key in self._cache:
119
+ self._cache[key] = value
120
+ self._cache.move_to_end(key)
121
+ self._timestamps[key] = datetime.now(UTC)
122
+ return
123
+
124
+ # Add new item
125
+ self._cache[key] = value
126
+ self._timestamps[key] = datetime.now(UTC)
127
+
128
+ # Remove oldest if over capacity
129
+ if len(self._cache) > self.max_size:
130
+ oldest_key = next(iter(self._cache))
131
+ del self._cache[oldest_key]
132
+ del self._timestamps[oldest_key]
133
+
134
+ def clear(self) -> None:
135
+ """Clear all cache entries."""
136
+ with self._lock:
137
+ self._cache.clear()
138
+ self._timestamps.clear()
139
+ self._hits = 0
140
+ self._misses = 0
141
+
142
+ def get_stats(self) -> Dict[str, Any]:
143
+ """Get cache statistics."""
144
+ with self._lock:
145
+ total_requests = self._hits + self._misses
146
+ return {
147
+ "size": len(self._cache),
148
+ "max_size": self.max_size,
149
+ "hits": self._hits,
150
+ "misses": self._misses,
151
+ "hit_ratio": self._hits / total_requests if total_requests > 0 else 0.0,
152
+ "memory_estimate_kb": len(self._cache) * 0.1, # Rough estimate
153
+ }
154
+
155
+
156
+ class ValidationCache:
157
+ """High-performance validation result cache."""
158
+
159
+ def __init__(self, max_size: int = 5000, ttl_seconds: int = 3600):
160
+ """Initialize validation cache.
161
+
162
+ Args:
163
+ max_size: Maximum cache entries
164
+ ttl_seconds: Time-to-live for entries
165
+ """
166
+ self._compatibility_cache = LRUCache(max_size, ttl_seconds)
167
+ self._connection_cache = LRUCache(max_size, ttl_seconds)
168
+ self._schema_cache = LRUCache(
169
+ max_size // 2, ttl_seconds * 2
170
+ ) # Schemas change less often
171
+
172
+ def get_compatibility_result(
173
+ self, source_type: type, target_type: type, allow_coercion: bool
174
+ ) -> Optional[TypeCompatibilityResult]:
175
+ """Get cached compatibility result."""
176
+ key = (source_type, target_type, allow_coercion)
177
+ return self._compatibility_cache.get(key)
178
+
179
+ def cache_compatibility_result(
180
+ self,
181
+ source_type: type,
182
+ target_type: type,
183
+ allow_coercion: bool,
184
+ result: TypeCompatibilityResult,
185
+ ) -> None:
186
+ """Cache compatibility result."""
187
+ key = (source_type, target_type, allow_coercion)
188
+ self._compatibility_cache.put(key, result)
189
+
190
+ def get_connection_result(
191
+ self, source_node: str, target_node: str, mapping: Dict[str, str]
192
+ ) -> Optional[ConnectionInferenceResult]:
193
+ """Get cached connection validation result."""
194
+ # Create hashable key from mapping
195
+ mapping_key = tuple(sorted(mapping.items())) if mapping else ()
196
+ key = (source_node, target_node, mapping_key)
197
+ return self._connection_cache.get(key)
198
+
199
+ def cache_connection_result(
200
+ self,
201
+ source_node: str,
202
+ target_node: str,
203
+ mapping: Dict[str, str],
204
+ result: ConnectionInferenceResult,
205
+ ) -> None:
206
+ """Cache connection validation result."""
207
+ mapping_key = tuple(sorted(mapping.items())) if mapping else ()
208
+ key = (source_node, target_node, mapping_key)
209
+ self._connection_cache.put(key, result)
210
+
211
+ def get_schema_validation(self, schema_hash: str, data_hash: str) -> Optional[bool]:
212
+ """Get cached schema validation result."""
213
+ key = (schema_hash, data_hash)
214
+ return self._schema_cache.get(key)
215
+
216
+ def cache_schema_validation(
217
+ self, schema_hash: str, data_hash: str, is_valid: bool
218
+ ) -> None:
219
+ """Cache schema validation result."""
220
+ key = (schema_hash, data_hash)
221
+ self._schema_cache.put(key, is_valid)
222
+
223
+ def clear_all(self) -> None:
224
+ """Clear all caches."""
225
+ self._compatibility_cache.clear()
226
+ self._connection_cache.clear()
227
+ self._schema_cache.clear()
228
+
229
+ def get_stats(self) -> Dict[str, Any]:
230
+ """Get cache performance statistics."""
231
+ compatibility_stats = self._compatibility_cache.get_stats()
232
+ connection_stats = self._connection_cache.get_stats()
233
+ schema_stats = self._schema_cache.get_stats()
234
+
235
+ return {
236
+ "compatibility_cache": compatibility_stats,
237
+ "connection_cache": connection_stats,
238
+ "schema_cache": schema_stats,
239
+ "total_size": compatibility_stats["size"]
240
+ + connection_stats["size"]
241
+ + schema_stats["size"],
242
+ "total_memory_kb": (
243
+ compatibility_stats["memory_estimate_kb"]
244
+ + connection_stats["memory_estimate_kb"]
245
+ + schema_stats["memory_estimate_kb"]
246
+ ),
247
+ }
248
+
249
+
250
+ class LazyValidator:
251
+ """Lazy evaluation for validation operations."""
252
+
253
+ def __init__(self, cache: ValidationCache):
254
+ """Initialize lazy validator.
255
+
256
+ Args:
257
+ cache: Validation cache instance
258
+ """
259
+ self.cache = cache
260
+ self._pending_validations: Dict[str, Any] = {}
261
+ self._validation_futures: Dict[str, asyncio.Future] = {}
262
+
263
+ def defer_validation(
264
+ self, validation_id: str, validation_func, *args, **kwargs
265
+ ) -> str:
266
+ """Defer validation until actually needed.
267
+
268
+ Args:
269
+ validation_id: Unique identifier for validation
270
+ validation_func: Function to call for validation
271
+ *args, **kwargs: Arguments for validation function
272
+
273
+ Returns:
274
+ Validation ID for later retrieval
275
+ """
276
+ self._pending_validations[validation_id] = {
277
+ "func": validation_func,
278
+ "args": args,
279
+ "kwargs": kwargs,
280
+ "created_at": time.time(),
281
+ }
282
+ return validation_id
283
+
284
+ def get_validation_result(self, validation_id: str) -> Any:
285
+ """Get validation result, executing if needed.
286
+
287
+ Args:
288
+ validation_id: Validation identifier
289
+
290
+ Returns:
291
+ Validation result
292
+ """
293
+ if validation_id not in self._pending_validations:
294
+ raise ValueError(f"Unknown validation ID: {validation_id}")
295
+
296
+ validation = self._pending_validations[validation_id]
297
+
298
+ # Execute validation
299
+ start_time = time.time()
300
+ try:
301
+ result = validation["func"](*validation["args"], **validation["kwargs"])
302
+ execution_time = (time.time() - start_time) * 1000
303
+
304
+ logger.debug(
305
+ f"Lazy validation {validation_id} completed in {execution_time:.2f}ms"
306
+ )
307
+ return result
308
+ finally:
309
+ # Clean up
310
+ del self._pending_validations[validation_id]
311
+
312
+ def cleanup_expired(self, max_age_seconds: int = 300) -> int:
313
+ """Clean up expired pending validations.
314
+
315
+ Args:
316
+ max_age_seconds: Maximum age for pending validations
317
+
318
+ Returns:
319
+ Number of cleaned up validations
320
+ """
321
+ current_time = time.time()
322
+ expired_ids = [
323
+ validation_id
324
+ for validation_id, validation in self._pending_validations.items()
325
+ if current_time - validation["created_at"] > max_age_seconds
326
+ ]
327
+
328
+ for validation_id in expired_ids:
329
+ del self._pending_validations[validation_id]
330
+
331
+ return len(expired_ids)
332
+
333
+
334
+ class BatchValidator:
335
+ """Batch validation for improved performance."""
336
+
337
+ def __init__(self, cache: ValidationCache, batch_size: int = 50):
338
+ """Initialize batch validator.
339
+
340
+ Args:
341
+ cache: Validation cache instance
342
+ batch_size: Number of validations to batch together
343
+ """
344
+ self.cache = cache
345
+ self.batch_size = batch_size
346
+ self._batch_queue: List[Dict[str, Any]] = []
347
+ self._batch_results: Dict[str, Any] = {}
348
+
349
+ def add_validation(
350
+ self, validation_id: str, validation_type: str, **params
351
+ ) -> None:
352
+ """Add validation to batch queue.
353
+
354
+ Args:
355
+ validation_id: Unique identifier
356
+ validation_type: Type of validation (compatibility, connection, schema)
357
+ **params: Validation parameters
358
+ """
359
+ self._batch_queue.append(
360
+ {
361
+ "id": validation_id,
362
+ "type": validation_type,
363
+ "params": params,
364
+ "added_at": time.time(),
365
+ }
366
+ )
367
+
368
+ # Process batch if full
369
+ if len(self._batch_queue) >= self.batch_size:
370
+ self.process_batch()
371
+
372
+ def process_batch(self) -> Dict[str, Any]:
373
+ """Process all queued validations as a batch.
374
+
375
+ Returns:
376
+ Dictionary of validation results by ID
377
+ """
378
+ if not self._batch_queue:
379
+ return {}
380
+
381
+ start_time = time.time()
382
+ batch = self._batch_queue.copy()
383
+ self._batch_queue.clear()
384
+
385
+ # Group by validation type for optimized processing
386
+ by_type = defaultdict(list)
387
+ for validation in batch:
388
+ by_type[validation["type"]].append(validation)
389
+
390
+ results = {}
391
+
392
+ # Process each type in batch
393
+ for validation_type, validations in by_type.items():
394
+ if validation_type == "compatibility":
395
+ results.update(self._process_compatibility_batch(validations))
396
+ elif validation_type == "connection":
397
+ results.update(self._process_connection_batch(validations))
398
+ elif validation_type == "schema":
399
+ results.update(self._process_schema_batch(validations))
400
+
401
+ processing_time = (time.time() - start_time) * 1000
402
+ logger.debug(
403
+ f"Processed batch of {len(batch)} validations in {processing_time:.2f}ms"
404
+ )
405
+
406
+ self._batch_results.update(results)
407
+ return results
408
+
409
+ def _process_compatibility_batch(
410
+ self, validations: List[Dict[str, Any]]
411
+ ) -> Dict[str, Any]:
412
+ """Process compatibility validations in batch."""
413
+ results = {}
414
+
415
+ # Check cache first for all validations
416
+ for validation in validations:
417
+ params = validation["params"]
418
+ cached_result = self.cache.get_compatibility_result(
419
+ params["source_type"], params["target_type"], params["allow_coercion"]
420
+ )
421
+
422
+ if cached_result:
423
+ results[validation["id"]] = cached_result
424
+ else:
425
+ # Would need actual validation logic here
426
+ # For now, indicate cache miss
427
+ results[validation["id"]] = None
428
+
429
+ return results
430
+
431
+ def _process_connection_batch(
432
+ self, validations: List[Dict[str, Any]]
433
+ ) -> Dict[str, Any]:
434
+ """Process connection validations in batch."""
435
+ results = {}
436
+
437
+ for validation in validations:
438
+ params = validation["params"]
439
+ cached_result = self.cache.get_connection_result(
440
+ params["source_node"], params["target_node"], params["mapping"]
441
+ )
442
+
443
+ results[validation["id"]] = cached_result
444
+
445
+ return results
446
+
447
+ def _process_schema_batch(
448
+ self, validations: List[Dict[str, Any]]
449
+ ) -> Dict[str, Any]:
450
+ """Process schema validations in batch."""
451
+ results = {}
452
+
453
+ for validation in validations:
454
+ params = validation["params"]
455
+ cached_result = self.cache.get_schema_validation(
456
+ params["schema_hash"], params["data_hash"]
457
+ )
458
+
459
+ results[validation["id"]] = cached_result
460
+
461
+ return results
462
+
463
+ def get_result(self, validation_id: str) -> Optional[Any]:
464
+ """Get result for a specific validation."""
465
+ return self._batch_results.get(validation_id)
466
+
467
+ def flush(self) -> Dict[str, Any]:
468
+ """Force process any remaining validations in queue."""
469
+ return self.process_batch()
470
+
471
+
472
+ class PerformanceOptimizer:
473
+ """Main performance optimization coordinator."""
474
+
475
+ def __init__(self, cache_size: int = 5000, batch_size: int = 50):
476
+ """Initialize performance optimizer.
477
+
478
+ Args:
479
+ cache_size: Size of validation cache
480
+ batch_size: Batch size for validation operations
481
+ """
482
+ self.cache = ValidationCache(cache_size)
483
+ self.lazy_validator = LazyValidator(self.cache)
484
+ self.batch_validator = BatchValidator(self.cache, batch_size)
485
+ self.metrics = PerformanceMetrics()
486
+
487
+ # Optimization settings
488
+ self.enable_caching = True
489
+ self.enable_lazy_evaluation = True
490
+ self.enable_batch_processing = True
491
+ self.cache_cleanup_interval = 300 # 5 minutes
492
+
493
+ def optimize_validation_pipeline(
494
+ self, workflow_data: Dict[str, Any]
495
+ ) -> Dict[str, Any]:
496
+ """Optimize validation pipeline for a workflow.
497
+
498
+ Args:
499
+ workflow_data: Workflow configuration
500
+
501
+ Returns:
502
+ Optimization recommendations
503
+ """
504
+ recommendations = {
505
+ "cache_configuration": {},
506
+ "batch_settings": {},
507
+ "lazy_evaluation": {},
508
+ "performance_warnings": [],
509
+ }
510
+
511
+ # Analyze workflow complexity
512
+ node_count = len(workflow_data.get("nodes", []))
513
+ connection_count = len(workflow_data.get("connections", []))
514
+
515
+ # Cache size recommendations
516
+ if connection_count > 100:
517
+ recommendations["cache_configuration"]["size"] = min(
518
+ 10000, connection_count * 10
519
+ )
520
+ recommendations["cache_configuration"][
521
+ "ttl"
522
+ ] = 7200 # 2 hours for complex workflows
523
+ else:
524
+ recommendations["cache_configuration"]["size"] = 1000
525
+ recommendations["cache_configuration"]["ttl"] = 3600 # 1 hour
526
+
527
+ # Batch size recommendations
528
+ if connection_count > 50:
529
+ recommendations["batch_settings"]["size"] = min(100, connection_count // 2)
530
+ recommendations["batch_settings"]["enable"] = True
531
+ else:
532
+ recommendations["batch_settings"]["size"] = 10
533
+ recommendations["batch_settings"]["enable"] = False
534
+
535
+ # Lazy evaluation recommendations
536
+ recommendations["lazy_evaluation"]["enable"] = connection_count > 20
537
+
538
+ # Performance warnings
539
+ if connection_count > 200:
540
+ recommendations["performance_warnings"].append(
541
+ "Large number of connections detected. Consider workflow splitting."
542
+ )
543
+
544
+ if node_count > 50:
545
+ recommendations["performance_warnings"].append(
546
+ "Complex workflow detected. Enable all performance optimizations."
547
+ )
548
+
549
+ return recommendations
550
+
551
+ def get_performance_report(self) -> Dict[str, Any]:
552
+ """Get comprehensive performance report."""
553
+ cache_stats = self.cache.get_stats()
554
+
555
+ return {
556
+ "validation_metrics": {
557
+ "total_validations": self.metrics.total_validations,
558
+ "avg_time_ms": self.metrics.avg_validation_time_ms,
559
+ "max_time_ms": self.metrics.max_validation_time_ms,
560
+ "min_time_ms": (
561
+ self.metrics.min_validation_time_ms
562
+ if self.metrics.min_validation_time_ms != float("inf")
563
+ else 0
564
+ ),
565
+ },
566
+ "cache_performance": {
567
+ "hit_ratio": self.metrics.cache_hit_ratio,
568
+ "total_size": cache_stats["total_size"],
569
+ "memory_usage_kb": cache_stats["total_memory_kb"],
570
+ },
571
+ "bottlenecks": {
572
+ "slow_validations": self.metrics.slow_validations[-10:], # Last 10
573
+ "expensive_connections": self.metrics.expensive_connections[-10:],
574
+ },
575
+ "optimization_status": {
576
+ "caching_enabled": self.enable_caching,
577
+ "lazy_evaluation_enabled": self.enable_lazy_evaluation,
578
+ "batch_processing_enabled": self.enable_batch_processing,
579
+ },
580
+ }
581
+
582
+ def cleanup_resources(self) -> Dict[str, int]:
583
+ """Clean up resources and return statistics."""
584
+ cleanup_stats = {
585
+ "expired_lazy_validations": self.lazy_validator.cleanup_expired(),
586
+ "cache_entries_before": self.cache.get_stats()["total_size"],
587
+ }
588
+
589
+ # Optional: Clear old cache entries (could be more sophisticated)
590
+ # For now, we rely on TTL in the cache implementation
591
+
592
+ cleanup_stats["cache_entries_after"] = self.cache.get_stats()["total_size"]
593
+ cleanup_stats["cache_entries_cleaned"] = (
594
+ cleanup_stats["cache_entries_before"] - cleanup_stats["cache_entries_after"]
595
+ )
596
+
597
+ return cleanup_stats
598
+
599
+
600
+ # Global performance optimizer instance
601
+ _global_optimizer = None
602
+
603
+
604
+ def get_performance_optimizer() -> PerformanceOptimizer:
605
+ """Get global performance optimizer instance."""
606
+ global _global_optimizer
607
+ if _global_optimizer is None:
608
+ _global_optimizer = PerformanceOptimizer()
609
+ return _global_optimizer
610
+
611
+
612
+ def reset_performance_optimizer() -> None:
613
+ """Reset global performance optimizer (for testing)."""
614
+ global _global_optimizer
615
+ _global_optimizer = None