Skip to main content

fraiseql_server/encryption/
performance.rs

1// Phase 12.3 Cycle 9: Performance Optimization (GREEN)
2//! Performance optimization for encryption operations including batching,
3//! parallelization, caching, and metrics collection.
4
5use std::{
6    collections::HashMap,
7    sync::{
8        Arc,
9        atomic::{AtomicU64, Ordering},
10    },
11    time::Instant,
12};
13
14use chrono::{DateTime, Utc};
15
16/// Operation metrics for performance monitoring
17#[derive(Debug, Clone)]
18pub struct OperationMetrics {
19    /// Operation type (encrypt, decrypt)
20    pub operation:   String,
21    /// Latency in microseconds
22    pub latency_us:  u64,
23    /// Success indicator
24    pub success:     bool,
25    /// Timestamp
26    pub timestamp:   DateTime<Utc>,
27    /// Field count (for batch operations)
28    pub field_count: usize,
29}
30
31impl OperationMetrics {
32    /// Create new operation metrics
33    pub fn new(operation: impl Into<String>, latency_us: u64, field_count: usize) -> Self {
34        Self {
35            operation: operation.into(),
36            latency_us,
37            success: true,
38            timestamp: Utc::now(),
39            field_count,
40        }
41    }
42
43    /// Mark as failed
44    pub fn with_failure(mut self) -> Self {
45        self.success = false;
46        self
47    }
48
49    /// Get latency in milliseconds
50    pub fn latency_ms(&self) -> f64 {
51        self.latency_us as f64 / 1000.0
52    }
53}
54
55/// Batch of encryption operations
56#[derive(Debug, Clone)]
57pub struct EncryptionBatch {
58    /// Batch ID
59    pub batch_id:   String,
60    /// Fields to encrypt
61    pub fields:     Vec<(String, String)>,
62    /// Batch creation time
63    pub created_at: DateTime<Utc>,
64    /// Maximum batch size
65    pub max_size:   usize,
66}
67
68impl EncryptionBatch {
69    /// Create new batch
70    pub fn new(batch_id: impl Into<String>, max_size: usize) -> Self {
71        Self {
72            batch_id: batch_id.into(),
73            fields: Vec::new(),
74            created_at: Utc::now(),
75            max_size,
76        }
77    }
78
79    /// Add field to batch
80    pub fn add_field(
81        &mut self,
82        field_name: impl Into<String>,
83        plaintext: impl Into<String>,
84    ) -> bool {
85        if self.fields.len() >= self.max_size {
86            return false;
87        }
88        self.fields.push((field_name.into(), plaintext.into()));
89        true
90    }
91
92    /// Check if batch is full
93    pub fn is_full(&self) -> bool {
94        self.fields.len() >= self.max_size
95    }
96
97    /// Get batch size
98    pub fn size(&self) -> usize {
99        self.fields.len()
100    }
101
102    /// Clear batch
103    pub fn clear(&mut self) {
104        self.fields.clear();
105    }
106}
107
108/// Key cache with LRU eviction
109pub struct KeyCache {
110    /// Cached keys
111    cache:        HashMap<String, Vec<u8>>,
112    /// Maximum cache size
113    max_size:     usize,
114    /// Access order for LRU
115    access_order: Vec<String>,
116    /// Cache hits
117    hits:         Arc<AtomicU64>,
118    /// Cache misses
119    misses:       Arc<AtomicU64>,
120}
121
122impl KeyCache {
123    /// Create new key cache
124    pub fn new(max_size: usize) -> Self {
125        Self {
126            cache: HashMap::new(),
127            max_size,
128            access_order: Vec::new(),
129            hits: Arc::new(AtomicU64::new(0)),
130            misses: Arc::new(AtomicU64::new(0)),
131        }
132    }
133
134    /// Get key from cache
135    pub fn get(&mut self, key_path: &str) -> Option<Vec<u8>> {
136        if let Some(key) = self.cache.get(key_path) {
137            // Update access order
138            self.access_order.retain(|k| k != key_path);
139            self.access_order.push(key_path.to_string());
140            self.hits.fetch_add(1, Ordering::Relaxed);
141            Some(key.clone())
142        } else {
143            self.misses.fetch_add(1, Ordering::Relaxed);
144            None
145        }
146    }
147
148    /// Insert key into cache
149    pub fn insert(&mut self, key_path: impl Into<String>, key: Vec<u8>) {
150        let key_path = key_path.into();
151
152        // If at capacity, evict LRU entry
153        if self.cache.len() >= self.max_size && !self.cache.contains_key(&key_path) {
154            if let Some(lru_key) = self.access_order.first() {
155                let lru = lru_key.clone();
156                self.cache.remove(&lru);
157                self.access_order.remove(0);
158            }
159        }
160
161        // Insert or update
162        self.cache.insert(key_path.clone(), key);
163
164        // Update access order
165        self.access_order.retain(|k| k != &key_path);
166        self.access_order.push(key_path);
167    }
168
169    /// Get cache statistics
170    pub fn stats(&self) -> (u64, u64) {
171        (self.hits.load(Ordering::Relaxed), self.misses.load(Ordering::Relaxed))
172    }
173
174    /// Get hit rate
175    pub fn hit_rate(&self) -> f64 {
176        let hits = self.hits.load(Ordering::Relaxed) as f64;
177        let misses = self.misses.load(Ordering::Relaxed) as f64;
178        let total = hits + misses;
179        if total > 0.0 { hits / total } else { 0.0 }
180    }
181
182    /// Get cache size
183    pub fn size(&self) -> usize {
184        self.cache.len()
185    }
186
187    /// Clear cache
188    pub fn clear(&mut self) {
189        self.cache.clear();
190        self.access_order.clear();
191    }
192
193    /// Get cached entry count
194    pub fn entry_count(&self) -> usize {
195        self.cache.len()
196    }
197}
198
199impl Default for KeyCache {
200    fn default() -> Self {
201        Self::new(1000)
202    }
203}
204
205/// Performance metrics collector
206pub struct PerformanceMonitor {
207    /// Collected metrics
208    metrics:     Vec<OperationMetrics>,
209    /// Maximum metrics to retain
210    max_metrics: usize,
211    /// Performance SLOs
212    slos:        HashMap<String, u64>,
213}
214
215impl PerformanceMonitor {
216    /// Create new performance monitor
217    pub fn new(max_metrics: usize) -> Self {
218        Self {
219            metrics: Vec::new(),
220            max_metrics,
221            slos: HashMap::new(),
222        }
223    }
224
225    /// Record operation metric
226    pub fn record_metric(&mut self, metric: OperationMetrics) {
227        // Keep bounded history
228        if self.metrics.len() >= self.max_metrics {
229            self.metrics.remove(0);
230        }
231        self.metrics.push(metric);
232    }
233
234    /// Set SLO for operation
235    pub fn set_slo(&mut self, operation: impl Into<String>, latency_us: u64) {
236        self.slos.insert(operation.into(), latency_us);
237    }
238
239    /// Internal filter helper
240    fn filter_metrics<F>(&self, predicate: F) -> Vec<&OperationMetrics>
241    where
242        F: Fn(&&OperationMetrics) -> bool,
243    {
244        self.metrics.iter().filter(predicate).collect()
245    }
246
247    /// Get metrics for operation
248    pub fn metrics_for_operation(&self, operation: &str) -> Vec<&OperationMetrics> {
249        self.filter_metrics(|m| m.operation == operation)
250    }
251
252    /// Get successful metrics
253    pub fn successful_metrics(&self) -> Vec<&OperationMetrics> {
254        self.filter_metrics(|m| m.success)
255    }
256
257    /// Get failed metrics
258    pub fn failed_metrics(&self) -> Vec<&OperationMetrics> {
259        self.filter_metrics(|m| !m.success)
260    }
261
262    /// Get average latency
263    pub fn average_latency_us(&self) -> u64 {
264        if self.metrics.is_empty() {
265            return 0;
266        }
267        let sum: u64 = self.metrics.iter().map(|m| m.latency_us).sum();
268        sum / self.metrics.len() as u64
269    }
270
271    /// Get average latency for operation
272    pub fn average_latency_for_operation_us(&self, operation: &str) -> u64 {
273        let metrics = self.metrics_for_operation(operation);
274        if metrics.is_empty() {
275            return 0;
276        }
277        let sum: u64 = metrics.iter().map(|m| m.latency_us).sum();
278        sum / metrics.len() as u64
279    }
280
281    /// Get p50 latency (median)
282    pub fn p50_latency_us(&self) -> u64 {
283        if self.metrics.is_empty() {
284            return 0;
285        }
286        let mut latencies: Vec<_> = self.metrics.iter().map(|m| m.latency_us).collect();
287        latencies.sort();
288        let idx = latencies.len() / 2;
289        latencies[idx]
290    }
291
292    /// Get p99 latency
293    pub fn p99_latency_us(&self) -> u64 {
294        if self.metrics.is_empty() {
295            return 0;
296        }
297        let mut latencies: Vec<_> = self.metrics.iter().map(|m| m.latency_us).collect();
298        latencies.sort();
299        let idx = (latencies.len() as f64 * 0.99) as usize;
300        latencies[idx]
301    }
302
303    /// Get max latency
304    pub fn max_latency_us(&self) -> u64 {
305        self.metrics.iter().map(|m| m.latency_us).max().unwrap_or(0)
306    }
307
308    /// Get min latency
309    pub fn min_latency_us(&self) -> u64 {
310        self.metrics.iter().map(|m| m.latency_us).min().unwrap_or(0)
311    }
312
313    /// Get success rate
314    pub fn success_rate(&self) -> f64 {
315        if self.metrics.is_empty() {
316            return 0.0;
317        }
318        let successful = self.metrics.iter().filter(|m| m.success).count() as f64;
319        successful / self.metrics.len() as f64
320    }
321
322    /// Get error rate
323    pub fn error_rate(&self) -> f64 {
324        1.0 - self.success_rate()
325    }
326
327    /// Get total fields processed
328    pub fn total_fields_processed(&self) -> usize {
329        self.metrics.iter().map(|m| m.field_count).sum()
330    }
331
332    /// Get operations per second
333    pub fn operations_per_second(&self) -> f64 {
334        if self.metrics.is_empty() {
335            return 0.0;
336        }
337        self.metrics.len() as f64
338    }
339
340    /// Check if SLO violated
341    pub fn check_slo(&self, operation: &str) -> bool {
342        if let Some(slo) = self.slos.get(operation) {
343            let avg_latency = self.average_latency_for_operation_us(operation);
344            avg_latency <= *slo
345        } else {
346            true // No SLO defined
347        }
348    }
349
350    /// Get all SLO violations
351    pub fn check_all_slos(&self) -> Vec<(String, bool)> {
352        self.slos.iter().map(|(op, _)| (op.clone(), self.check_slo(op))).collect()
353    }
354
355    /// Get metric count
356    pub fn metric_count(&self) -> usize {
357        self.metrics.len()
358    }
359
360    /// Get count by operation
361    pub fn operation_count(&self, operation: &str) -> usize {
362        self.metrics_for_operation(operation).len()
363    }
364
365    /// Clear metrics
366    pub fn clear(&mut self) {
367        self.metrics.clear();
368    }
369}
370
371impl Default for PerformanceMonitor {
372    fn default() -> Self {
373        Self::new(10000)
374    }
375}
376
377/// Operation timing utility
378pub struct OperationTimer {
379    start: Instant,
380}
381
382impl OperationTimer {
383    /// Start operation timer
384    pub fn start() -> Self {
385        Self {
386            start: Instant::now(),
387        }
388    }
389
390    /// Get elapsed microseconds
391    pub fn elapsed_us(&self) -> u64 {
392        self.start.elapsed().as_micros() as u64
393    }
394
395    /// Get elapsed milliseconds
396    pub fn elapsed_ms(&self) -> f64 {
397        self.elapsed_us() as f64 / 1000.0
398    }
399}
400
401#[cfg(test)]
402mod tests {
403    use super::*;
404
405    #[test]
406    fn test_operation_metrics_creation() {
407        let metric = OperationMetrics::new("encrypt", 1000, 5);
408        assert_eq!(metric.operation, "encrypt");
409        assert_eq!(metric.latency_us, 1000);
410        assert_eq!(metric.field_count, 5);
411        assert!(metric.success);
412    }
413
414    #[test]
415    fn test_operation_metrics_failure() {
416        let metric = OperationMetrics::new("decrypt", 2000, 3).with_failure();
417        assert!(!metric.success);
418    }
419
420    #[test]
421    fn test_operation_metrics_latency_ms() {
422        let metric = OperationMetrics::new("encrypt", 5000, 1);
423        assert_eq!(metric.latency_ms(), 5.0);
424    }
425
426    #[test]
427    fn test_encryption_batch_creation() {
428        let batch = EncryptionBatch::new("batch1", 100);
429        assert_eq!(batch.batch_id, "batch1");
430        assert_eq!(batch.max_size, 100);
431        assert_eq!(batch.size(), 0);
432    }
433
434    #[test]
435    fn test_encryption_batch_add_field() {
436        let mut batch = EncryptionBatch::new("batch1", 10);
437        let result = batch.add_field("email", "user@example.com");
438        assert!(result);
439        assert_eq!(batch.size(), 1);
440    }
441
442    #[test]
443    fn test_encryption_batch_full() {
444        let mut batch = EncryptionBatch::new("batch1", 2);
445        batch.add_field("email", "user@example.com");
446        batch.add_field("phone", "555-1234");
447        assert!(batch.is_full());
448        let result = batch.add_field("ssn", "123-45-6789");
449        assert!(!result); // Batch full
450    }
451
452    #[test]
453    fn test_encryption_batch_clear() {
454        let mut batch = EncryptionBatch::new("batch1", 10);
455        batch.add_field("email", "user@example.com");
456        assert_eq!(batch.size(), 1);
457        batch.clear();
458        assert_eq!(batch.size(), 0);
459    }
460
461    #[test]
462    fn test_key_cache_creation() {
463        let cache = KeyCache::new(100);
464        assert_eq!(cache.size(), 0);
465        assert_eq!(cache.entry_count(), 0);
466    }
467
468    #[test]
469    fn test_key_cache_insert_and_get() {
470        let mut cache = KeyCache::new(100);
471        let key = vec![1, 2, 3, 4];
472        cache.insert("key1", key.clone());
473        let retrieved = cache.get("key1");
474        assert!(retrieved.is_some());
475        assert_eq!(retrieved.unwrap(), key);
476    }
477
478    #[test]
479    fn test_key_cache_miss() {
480        let mut cache = KeyCache::new(100);
481        let result = cache.get("nonexistent");
482        assert!(result.is_none());
483    }
484
485    #[test]
486    fn test_key_cache_lru_eviction() {
487        let mut cache = KeyCache::new(2);
488        cache.insert("key1", vec![1]);
489        cache.insert("key2", vec![2]);
490        cache.insert("key3", vec![3]); // Should evict key1
491
492        assert!(cache.get("key1").is_none());
493        assert!(cache.get("key2").is_some());
494        assert!(cache.get("key3").is_some());
495    }
496
497    #[test]
498    fn test_key_cache_hit_rate() {
499        let mut cache = KeyCache::new(100);
500        cache.insert("key1", vec![1]);
501        cache.get("key1"); // hit
502        cache.get("key1"); // hit
503        cache.get("key2"); // miss
504
505        let (hits, misses) = cache.stats();
506        assert_eq!(hits, 2);
507        assert_eq!(misses, 1);
508        assert_eq!(cache.hit_rate(), 2.0 / 3.0);
509    }
510
511    #[test]
512    fn test_key_cache_clear() {
513        let mut cache = KeyCache::new(100);
514        cache.insert("key1", vec![1]);
515        assert_eq!(cache.size(), 1);
516        cache.clear();
517        assert_eq!(cache.size(), 0);
518    }
519
520    #[test]
521    fn test_key_cache_default() {
522        let cache = KeyCache::default();
523        assert_eq!(cache.max_size, 1000);
524    }
525
526    #[test]
527    fn test_performance_monitor_record_metric() {
528        let mut monitor = PerformanceMonitor::new(100);
529        let metric = OperationMetrics::new("encrypt", 1000, 5);
530        monitor.record_metric(metric);
531        assert_eq!(monitor.metric_count(), 1);
532    }
533
534    #[test]
535    fn test_performance_monitor_average_latency() {
536        let mut monitor = PerformanceMonitor::new(100);
537        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
538        monitor.record_metric(OperationMetrics::new("encrypt", 2000, 5));
539        monitor.record_metric(OperationMetrics::new("encrypt", 3000, 5));
540        assert_eq!(monitor.average_latency_us(), 2000);
541    }
542
543    #[test]
544    fn test_performance_monitor_p99_latency() {
545        let mut monitor = PerformanceMonitor::new(100);
546        for i in 1..=100 {
547            monitor.record_metric(OperationMetrics::new("encrypt", i * 100, 1));
548        }
549        let p99 = monitor.p99_latency_us();
550        assert!(p99 >= 9900); // p99 should be high
551    }
552
553    #[test]
554    fn test_performance_monitor_success_rate() {
555        let mut monitor = PerformanceMonitor::new(100);
556        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
557        let mut metric = OperationMetrics::new("encrypt", 2000, 5);
558        metric = metric.with_failure();
559        monitor.record_metric(metric);
560        assert_eq!(monitor.success_rate(), 0.5);
561    }
562
563    #[test]
564    fn test_performance_monitor_slo() {
565        let mut monitor = PerformanceMonitor::new(100);
566        monitor.set_slo("encrypt", 2000);
567        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
568        monitor.record_metric(OperationMetrics::new("encrypt", 1500, 5));
569        assert!(monitor.check_slo("encrypt"));
570    }
571
572    #[test]
573    fn test_performance_monitor_slo_violation() {
574        let mut monitor = PerformanceMonitor::new(100);
575        monitor.set_slo("encrypt", 1400);
576        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
577        monitor.record_metric(OperationMetrics::new("encrypt", 2000, 5));
578        assert!(!monitor.check_slo("encrypt")); // Average 1500 > SLO 1400
579    }
580
581    #[test]
582    fn test_performance_monitor_clear() {
583        let mut monitor = PerformanceMonitor::new(100);
584        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
585        assert_eq!(monitor.metric_count(), 1);
586        monitor.clear();
587        assert_eq!(monitor.metric_count(), 0);
588    }
589
590    #[test]
591    fn test_operation_timer() {
592        let timer = OperationTimer::start();
593        std::thread::sleep(std::time::Duration::from_millis(10));
594        let elapsed_us = timer.elapsed_us();
595        assert!(elapsed_us >= 10000); // At least 10ms
596    }
597
598    #[test]
599    fn test_operation_timer_ms() {
600        let timer = OperationTimer::start();
601        std::thread::sleep(std::time::Duration::from_millis(10));
602        let elapsed_ms = timer.elapsed_ms();
603        assert!(elapsed_ms >= 10.0);
604    }
605
606    #[test]
607    fn test_performance_monitor_metrics_for_operation() {
608        let mut monitor = PerformanceMonitor::new(100);
609        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
610        monitor.record_metric(OperationMetrics::new("decrypt", 2000, 5));
611        monitor.record_metric(OperationMetrics::new("encrypt", 1500, 5));
612
613        let encrypt_metrics = monitor.metrics_for_operation("encrypt");
614        assert_eq!(encrypt_metrics.len(), 2);
615    }
616
617    #[test]
618    fn test_performance_monitor_successful_metrics() {
619        let mut monitor = PerformanceMonitor::new(100);
620        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
621        let mut failed = OperationMetrics::new("encrypt", 2000, 5);
622        failed = failed.with_failure();
623        monitor.record_metric(failed);
624
625        let successful = monitor.successful_metrics();
626        assert_eq!(successful.len(), 1);
627    }
628
629    #[test]
630    fn test_performance_monitor_failed_metrics() {
631        let mut monitor = PerformanceMonitor::new(100);
632        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
633        let mut failed = OperationMetrics::new("encrypt", 2000, 5);
634        failed = failed.with_failure();
635        monitor.record_metric(failed);
636
637        let failed_metrics = monitor.failed_metrics();
638        assert_eq!(failed_metrics.len(), 1);
639    }
640
641    #[test]
642    fn test_performance_monitor_p50_latency() {
643        let mut monitor = PerformanceMonitor::new(100);
644        for i in 1..=10 {
645            monitor.record_metric(OperationMetrics::new("encrypt", i * 100, 1));
646        }
647        let p50 = monitor.p50_latency_us();
648        assert_eq!(p50, 600); // Median of 100-1000 (index 5 in 0-9 range)
649    }
650
651    #[test]
652    fn test_performance_monitor_max_min_latency() {
653        let mut monitor = PerformanceMonitor::new(100);
654        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
655        monitor.record_metric(OperationMetrics::new("encrypt", 5000, 5));
656        monitor.record_metric(OperationMetrics::new("encrypt", 3000, 5));
657
658        assert_eq!(monitor.max_latency_us(), 5000);
659        assert_eq!(monitor.min_latency_us(), 1000);
660    }
661
662    #[test]
663    fn test_performance_monitor_error_rate() {
664        let mut monitor = PerformanceMonitor::new(100);
665        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
666        let mut failed = OperationMetrics::new("encrypt", 2000, 5);
667        failed = failed.with_failure();
668        monitor.record_metric(failed);
669
670        assert_eq!(monitor.error_rate(), 0.5);
671    }
672
673    #[test]
674    fn test_performance_monitor_total_fields_processed() {
675        let mut monitor = PerformanceMonitor::new(100);
676        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
677        monitor.record_metric(OperationMetrics::new("encrypt", 2000, 10));
678        monitor.record_metric(OperationMetrics::new("encrypt", 3000, 3));
679
680        assert_eq!(monitor.total_fields_processed(), 18);
681    }
682
683    #[test]
684    fn test_performance_monitor_average_latency_for_operation() {
685        let mut monitor = PerformanceMonitor::new(100);
686        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
687        monitor.record_metric(OperationMetrics::new("decrypt", 4000, 5));
688        monitor.record_metric(OperationMetrics::new("encrypt", 2000, 5));
689
690        let avg_encrypt = monitor.average_latency_for_operation_us("encrypt");
691        assert_eq!(avg_encrypt, 1500);
692    }
693
694    #[test]
695    fn test_performance_monitor_check_all_slos() {
696        let mut monitor = PerformanceMonitor::new(100);
697        monitor.set_slo("encrypt", 2000);
698        monitor.set_slo("decrypt", 3000);
699        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
700        monitor.record_metric(OperationMetrics::new("decrypt", 4000, 5));
701
702        let violations = monitor.check_all_slos();
703        assert_eq!(violations.len(), 2);
704
705        // Check that encrypt passes and decrypt fails (order-independent)
706        let encrypt_pass = violations.iter().any(|(op, passed)| op == "encrypt" && *passed);
707        let decrypt_fail = violations.iter().any(|(op, passed)| op == "decrypt" && !*passed);
708        assert!(encrypt_pass);
709        assert!(decrypt_fail);
710    }
711
712    #[test]
713    fn test_performance_monitor_operation_count() {
714        let mut monitor = PerformanceMonitor::new(100);
715        monitor.record_metric(OperationMetrics::new("encrypt", 1000, 5));
716        monitor.record_metric(OperationMetrics::new("encrypt", 2000, 5));
717        monitor.record_metric(OperationMetrics::new("decrypt", 3000, 5));
718
719        assert_eq!(monitor.operation_count("encrypt"), 2);
720        assert_eq!(monitor.operation_count("decrypt"), 1);
721    }
722}