dmsc/device/
pool.rs

1//! Copyright © 2025-2026 Wenze Wei. All Rights Reserved.
2//!
3//! This file is part of DMSC.
4//! The DMSC project belongs to the Dunimd Team.
5//!
6//! Licensed under the Apache License, Version 2.0 (the "License");
7//! You may not use this file except in compliance with the License.
8//! You may obtain a copy of the License at
9//!
10//!     http://www.apache.org/licenses/LICENSE-2.0
11//!
12//! Unless required by applicable law or agreed to in writing, software
13//! distributed under the License is distributed on an "AS IS" BASIS,
14//! WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15//! See the License for the specific language governing permissions and
16//! limitations under the License.
17
18#![allow(non_snake_case)]
19
20//! # Resource Pool Management
21//! 
22//! This file implements resource pool management for the DMSC framework, providing a way to group
23//! similar devices together for efficient resource allocation and management. It includes both
24//! single resource pools and a resource pool manager for handling multiple pools.
25//! 
26//! ## Key Components
27//! 
28//! - **DMSCResourcePool**: Manages a pool of similar devices
29//! - **DMSCResourcePoolConfig**: Configuration for resource pools
30//! - **DMSCResourcePoolStatistics**: Statistics for monitoring resource pools
31//! - **DMSCResourcePoolManager**: Manages multiple resource pools
32//! 
33//! ## Design Principles
34//! 
35//! 1. **Resource Grouping**: Groups similar devices together for efficient management
36//! 2. **Capacity Tracking**: Tracks total, available, and allocated capacity
37//! 3. **Statistics Collection**: Collects comprehensive statistics for monitoring
38//! 4. **Device Filtering**: Filters devices by availability and allocation status
39//! 5. **Health Monitoring**: Monitors pool health based on available devices
40//! 6. **Utilization Tracking**: Tracks resource utilization rates
41//! 7. **Multi-Pool Management**: Supports managing multiple pools through a central manager
42//! 8. **Device Type Segregation**: Each pool contains devices of a single type
43//! 9. **Arc-Based Sharing**: Uses Arc for safe concurrent access to devices
44//! 10. **Serialization Support**: All structures support serialization/deserialization
45//! 11. **Builder Pattern**: Configurable through DMSCResourcePoolConfig
46//! 12. **Resource Optimization**: Calculates total compute, memory, storage, and bandwidth
47//! 
48//! ## Usage
49//! 
50//! ```rust,ignore
51//! use dmsc::device::{DMSCResourcePoolManager, DMSCResourcePoolConfig, DMSCDeviceType};
52//! use dmsc::core::DMSCResult;
53//! 
54//! fn example() -> DMSCResult<()> {
55//!     // Create a resource pool manager
56//!     let mut manager = DMSCResourcePoolManager::new();
57//!     
58//!     // Create a resource pool configuration
59//!     let config = DMSCResourcePoolConfig {
60//!         name: "cpu-pool-1".to_string(),
61//!         device_type: DMSCDeviceType::CPU,
62//!         max_concurrent_allocations: 10,
63//!         allocation_timeout_secs: 60,
64//!         health_check_interval_secs: 30,
65//!     };
66//!     
67//!     // Create a resource pool
68//!     let pool = manager.create_pool(config);
69//!     
70//!     // Get pool statistics
71//!     let stats = pool.get_statistics();
72//!     println!("Pool has {} devices, utilization: {:.2}%", 
73//!              stats.total_devices, stats.utilization_rate * 100.0);
74//!     
75//!     // Get all pools by device type
76//!     let cpu_pools = manager.get_pools_by_type(DMSCDeviceType::CPU);
77//!     println!("Found {} CPU pools", cpu_pools.len());
78//!     
79//!     // Get overall statistics
80//!     let overall_stats = manager.get_overall_statistics();
81//!     println!("Total devices across all pools: {}", overall_stats.total_devices);
82//!     
83//!     Ok(())
84//! }
85//! ```
86
87use std::sync::{Arc, RwLock};
88use std::collections::HashMap;
89use std::time::Duration;
90use serde::{Serialize, Deserialize};
91
92use super::core::{DMSCDevice, DMSCDeviceType, DMSCDeviceStatus};
93
94
95/// Resource pool for managing multiple similar devices
96/// 
97/// This struct manages a pool of devices of the same type, tracking their availability,
98/// allocation status, and capacity. It provides methods for adding/removing devices,
99/// allocating/releasing devices, and collecting statistics.
100#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
101pub struct DMSCResourcePool {
102    /// Name of the resource pool
103    name: String,
104    /// Type of devices in the pool
105    device_type: DMSCDeviceType,
106    /// Map of device IDs to device instances
107    devices: HashMap<String, Arc<DMSCDevice>>,
108    /// Total capacity of the pool (number of devices)
109    total_capacity: usize,
110    /// Available capacity (number of devices not allocated)
111    available_capacity: usize,
112    /// Allocated capacity (number of devices currently allocated)
113    allocated_capacity: usize,
114    /// Number of pending requests for devices
115    pending_requests: usize,
116    /// Total compute units across all devices in the pool
117    total_compute_units: usize,
118    /// Total memory in GB across all devices in the pool
119    total_memory_gb: f64,
120    /// Total storage in GB across all devices in the pool
121    total_storage_gb: f64,
122    /// Total bandwidth in Gbps across all devices in the pool
123    total_bandwidth_gbps: f64,
124    /// Available compute units (not allocated)
125    available_compute_units: usize,
126    /// Available memory in GB (not allocated)
127    available_memory_gb: f64,
128    /// Available storage in GB (not allocated)
129    available_storage_gb: f64,
130    /// Available bandwidth in Gbps (not allocated)
131    available_bandwidth_gbps: f64,
132    /// Connection pool state for lifecycle management
133    connection_pool: Arc<RwLock<DMSCConnectionPool>>,
134}
135
136/// Configuration for a resource pool
137/// 
138/// This struct defines the configuration options for creating a resource pool, including
139/// name, device type, and various operational parameters.
140#[derive(Debug, Clone, Serialize, Deserialize)]
141#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
142pub struct DMSCResourcePoolConfig {
143    /// Name of the resource pool
144    pub name: String,
145    /// Type of devices that will be in the pool
146    pub device_type: DMSCDeviceType,
147    /// Maximum number of concurrent allocations allowed
148    pub max_concurrent_allocations: usize,
149    /// Timeout for device allocation in seconds
150    pub allocation_timeout_secs: u64,
151    /// Interval for health checks in seconds
152    pub health_check_interval_secs: u64,
153}
154
155impl Default for DMSCResourcePoolConfig {
156    fn default() -> Self {
157        Self {
158            name: "default_pool".to_string(),
159            device_type: DMSCDeviceType::CPU,
160            max_concurrent_allocations: 10,
161            allocation_timeout_secs: 60,
162            health_check_interval_secs: 30,
163        }
164    }
165}
166
167impl DMSCResourcePool {
168    /// Creates a new resource pool with the given configuration
169    /// 
170    /// # Parameters
171    /// 
172    /// - `config`: The configuration for the resource pool
173    /// 
174    /// # Returns
175    /// 
176    /// A new `DMSCResourcePool` instance with the specified configuration
177    pub fn new(config: DMSCResourcePoolConfig) -> Self {
178        let connection_pool = Arc::new(RwLock::new(DMSCConnectionPool::new(
179            config.max_concurrent_allocations,
180            Duration::from_secs(config.allocation_timeout_secs),
181            Duration::from_secs(config.health_check_interval_secs),
182        )));
183        
184        Self {
185            name: config.name,
186            device_type: config.device_type,
187            devices: HashMap::with_capacity(16),
188            total_capacity: 0,
189            available_capacity: 0,
190            allocated_capacity: 0,
191            pending_requests: 0,
192            total_compute_units: 0,
193            total_memory_gb: 0.0,
194            total_storage_gb: 0.0,
195            total_bandwidth_gbps: 0.0,
196            available_compute_units: 0,
197            available_memory_gb: 0.0,
198            available_storage_gb: 0.0,
199            available_bandwidth_gbps: 0.0,
200            connection_pool,
201        }
202    }
203    
204    /// Adds a device to the pool
205    /// 
206    /// This method adds a device to the pool if it matches the pool's device type
207    /// and is not already in the pool.
208    /// 
209    /// # Parameters
210    /// 
211    /// - `device`: The device to add to the pool
212    /// 
213    /// # Returns
214    /// 
215    /// `true` if the device was successfully added, `false` otherwise
216    pub fn add_device(&mut self, device: Arc<DMSCDevice>) -> bool {
217        // Check if device type matches pool device type
218        if device.device_type() != self.device_type {
219            return false;
220        }
221        
222        let device_id = device.id().to_string();
223        // Check if device is already in the pool
224        if self.devices.contains_key(&device_id) {
225            return false;
226        }
227        
228        // Get device capabilities and extract values before inserting the device
229        let compute_units = device.capabilities().compute_units.unwrap_or(0);
230        let memory_gb = device.capabilities().memory_gb.unwrap_or(0.0);
231        let storage_gb = device.capabilities().storage_gb.unwrap_or(0.0);
232        let bandwidth_gbps = device.capabilities().bandwidth_gbps.unwrap_or(0.0);
233        
234        // Add device to the pool
235        self.devices.insert(device_id, device);
236        
237        // Update capacity counters
238        self.total_capacity += 1;
239        self.available_capacity += 1;
240        
241        // Update total resource counters
242        self.total_compute_units += compute_units;
243        self.total_memory_gb += memory_gb;
244        self.total_storage_gb += storage_gb;
245        self.total_bandwidth_gbps += bandwidth_gbps;
246        
247        // Update available resource counters (device is available initially)
248        self.available_compute_units += compute_units;
249        self.available_memory_gb += memory_gb;
250        self.available_storage_gb += storage_gb;
251        self.available_bandwidth_gbps += bandwidth_gbps;
252        
253        true
254    }
255    
256    /// Removes a device from the pool
257    /// 
258    /// This method removes a device from the pool by its ID, updating capacity counters
259    /// based on the device's status.
260    /// 
261    /// # Parameters
262    /// 
263    /// - `device_id`: The ID of the device to remove
264    /// 
265    /// # Returns
266    /// 
267    /// `true` if the device was successfully removed, `false` otherwise
268    pub fn remove_device(&mut self, device_id: &str) -> bool {
269        if let Some(device) = self.devices.remove(device_id) {
270            // Get device capabilities
271            let capabilities = device.capabilities();
272            
273            // Decrement total capacity
274            self.total_capacity -= 1;
275            
276            // Update available or allocated capacity based on device status
277            if device.is_available() {
278                self.available_capacity -= 1;
279                
280                // Update available resource counters
281                self.available_compute_units -= capabilities.compute_units.unwrap_or(0);
282                self.available_memory_gb -= capabilities.memory_gb.unwrap_or(0.0);
283                self.available_storage_gb -= capabilities.storage_gb.unwrap_or(0.0);
284                self.available_bandwidth_gbps -= capabilities.bandwidth_gbps.unwrap_or(0.0);
285            } else if device.is_allocated() {
286                self.allocated_capacity -= 1;
287                
288                // Update allocated resource counters indirectly by updating total
289                // Available resources don't change when removing an allocated device
290            }
291            
292            // Update total resource counters
293            self.total_compute_units -= capabilities.compute_units.unwrap_or(0);
294            self.total_memory_gb -= capabilities.memory_gb.unwrap_or(0.0);
295            self.total_storage_gb -= capabilities.storage_gb.unwrap_or(0.0);
296            self.total_bandwidth_gbps -= capabilities.bandwidth_gbps.unwrap_or(0.0);
297            
298            true
299        } else {
300            false
301        }
302    }
303    
304    /// Allocates a device from the pool
305    /// 
306    /// This method allocates the first available device from the pool, updating capacity counters.
307    /// 
308    /// # Parameters
309    /// 
310    /// - `_allocation_id`: The ID of the allocation (currently unused)
311    /// 
312    /// # Returns
313    /// 
314    /// An `Option<Arc<DMSCDevice>>` containing the allocated device if successful, `None` otherwise
315    pub fn allocate(&mut self, _allocation_id: &str) -> Option<Arc<DMSCDevice>> {
316        // Check if there's available capacity
317        if self.available_capacity == 0 {
318            return None;
319        }
320        
321        // Find the first available device
322        for device in self.devices.values() {
323            // This is a simplified allocation - in a real implementation, 
324            // we'd need to lock the device and check its status atomically
325            if device.is_available() {
326                // Get device capabilities
327                let capabilities = device.capabilities();
328                
329                // Note: In a real implementation, we'd need to modify the device
330                // to mark it as allocated. This is simplified for demonstration.
331                self.available_capacity -= 1;
332                self.allocated_capacity += 1;
333                
334                // Update available resource counters
335                self.available_compute_units -= capabilities.compute_units.unwrap_or(0);
336                self.available_memory_gb -= capabilities.memory_gb.unwrap_or(0.0);
337                self.available_storage_gb -= capabilities.storage_gb.unwrap_or(0.0);
338                self.available_bandwidth_gbps -= capabilities.bandwidth_gbps.unwrap_or(0.0);
339                
340                // Add connection to pool
341                let mut pool = match self.connection_pool.write() {
342                    Ok(pool) => pool,
343                    Err(e) => {
344                        log::error!("Failed to acquire connection pool lock: {}", e);
345                        return None;
346                    }
347                };
348                pool.add_connection(device.id().to_string(), device.id().to_string());
349                
350                return Some(device.clone());
351            }
352        }
353        
354        None
355    }
356    
357    /// Releases a device back to the pool
358    /// 
359    /// This method releases a device back to the pool by its allocation ID, updating capacity counters.
360    /// 
361    /// # Parameters
362    /// 
363    /// - `allocation_id`: The ID of the allocation to release
364    /// 
365    /// # Returns
366    /// 
367    /// `true` if the device was successfully released, `false` otherwise
368    pub fn release(&mut self, allocation_id: &str) -> bool {
369        // Find the allocated device by allocation ID
370        for device in self.devices.values() {
371            if let Some(current_allocation) = device.get_allocation_id() {
372                if current_allocation == allocation_id {
373                    // Get device capabilities
374                    let capabilities = device.capabilities();
375                    
376                    // Note: In a real implementation, we'd need to modify the device
377                    // to mark it as released. This is simplified for demonstration.
378                    self.allocated_capacity -= 1;
379                    self.available_capacity += 1;
380                    
381                    // Update available resource counters
382                    self.available_compute_units += capabilities.compute_units.unwrap_or(0);
383                    self.available_memory_gb += capabilities.memory_gb.unwrap_or(0.0);
384                    self.available_storage_gb += capabilities.storage_gb.unwrap_or(0.0);
385                    self.available_bandwidth_gbps += capabilities.bandwidth_gbps.unwrap_or(0.0);
386                    
387                    // Remove connection from pool
388                    match self.connection_pool.write() {
389                        Ok(mut pool) => {
390                            pool.remove_connection(device.id());
391                        }
392                        Err(e) => {
393                            log::error!("Failed to acquire connection pool lock for removal: {}", e);
394                            // Continue with release even if we can't update the pool
395                        }
396                    }
397                    
398                    return true;
399                }
400            }
401        }
402        
403        false
404    }
405    
406    /// Gets the current status of the pool
407    /// 
408    /// This method returns a DMSCResourcePoolStatus struct containing information about the pool's
409    /// capacity, allocation, and utilization.
410    /// 
411    /// # Returns
412    /// 
413    /// A `DMSCResourcePoolStatus` struct with the current pool status
414    pub fn get_status(&self) -> super::DMSCResourcePoolStatus {
415        super::DMSCResourcePoolStatus {
416            total_capacity: self.total_capacity,
417            available_capacity: self.available_capacity,
418            allocated_capacity: self.allocated_capacity,
419            pending_requests: self.pending_requests,
420            utilization_rate: if self.total_capacity > 0 {
421                (self.allocated_capacity as f64 / self.total_capacity as f64) * 100.0
422            } else {
423                0.0
424            },
425        }
426    }
427    
428    /// Gets the name of the pool
429    /// 
430    /// # Returns
431    /// 
432    /// The pool name as a string slice
433    #[inline]
434    pub fn name(&self) -> &str {
435        &self.name
436    }
437    
438    /// Gets the device type of the pool
439    /// 
440    /// # Returns
441    /// 
442    /// The device type as a `DMSCDeviceType` enum
443    #[inline]
444    pub fn device_type(&self) -> DMSCDeviceType {
445        self.device_type
446    }
447    
448    /// Gets all devices in the pool
449    /// 
450    /// # Returns
451    /// 
452    /// A vector of `Arc<DMSCDevice>` containing all devices in the pool
453    #[inline]
454    pub fn get_devices(&self) -> Vec<Arc<DMSCDevice>> {
455        self.devices.values().cloned().collect()
456    }
457    
458    /// Gets available devices in the pool
459    /// 
460    /// # Returns
461    /// 
462    /// A vector of `Arc<DMSCDevice>` containing only available devices
463    pub fn get_available_devices(&self) -> Vec<Arc<DMSCDevice>> {
464        self.devices.values()
465            .filter(|device| device.is_available())
466            .cloned()
467            .collect()
468    }
469    
470    /// Gets allocated devices in the pool
471    /// 
472    /// # Returns
473    /// 
474    /// A vector of `Arc<DMSCDevice>` containing only allocated devices
475    pub fn get_allocated_devices(&self) -> Vec<Arc<DMSCDevice>> {
476        self.devices.values()
477            .filter(|device| device.is_allocated())
478            .cloned()
479            .collect()
480    }
481    
482    /// Checks if the pool has available capacity
483    /// 
484    /// # Returns
485    /// 
486    /// `true` if the pool has available devices, `false` otherwise
487    #[inline]
488    pub fn has_available_capacity(&self) -> bool {
489        self.available_capacity > 0
490    }
491    
492    /// Gets the utilization rate of the pool (0.0 - 1.0)
493    /// 
494    /// # Returns
495    /// 
496    /// The utilization rate as a floating-point number between 0.0 and 1.0
497    #[inline]
498    pub fn utilization_rate(&self) -> f64 {
499        if self.total_capacity > 0 {
500            self.allocated_capacity as f64 / self.total_capacity as f64
501        } else {
502            0.0
503        }
504    }
505    
506    /// Checks if the pool is healthy
507    /// 
508    /// A pool is considered healthy if it has available devices or allocated devices.
509    /// 
510    /// # Returns
511    /// 
512    /// `true` if the pool is healthy, `false` otherwise
513    pub fn is_healthy(&self) -> bool {
514        self.available_capacity > 0 || self.allocated_capacity > 0
515    }
516    
517    /// Gets comprehensive statistics for the pool
518    /// 
519    /// This method calculates and returns comprehensive statistics for the pool, including
520    /// device counts, utilization, total compute units, memory, storage, bandwidth, and average health score.
521    /// 
522    /// # Returns
523    /// 
524    /// A `DMSCResourcePoolStatistics` struct with comprehensive pool statistics
525    pub fn get_statistics(&self) -> DMSCResourcePoolStatistics {
526        let devices = self.get_devices();
527        let available_devices = self.get_available_devices();
528        let allocated_devices = self.get_allocated_devices();
529
530        // Calculate total compute units across all devices
531        let total_compute_units: usize = devices.iter()
532            .filter_map(|d| d.capabilities().compute_units)
533            .sum();
534
535        // Calculate total memory across all devices
536        let total_memory_gb: f64 = devices.iter()
537            .filter_map(|d| d.capabilities().memory_gb)
538            .sum();
539
540        // Calculate total storage across all devices
541        let total_storage_gb: f64 = devices.iter()
542            .filter_map(|d| d.capabilities().storage_gb)
543            .sum();
544
545        // Calculate total bandwidth across all devices
546        let total_bandwidth_gbps: f64 = devices.iter()
547            .filter_map(|d| d.capabilities().bandwidth_gbps)
548            .sum();
549
550        // Calculate average health score across all devices
551        let average_health_score: f64 = if !devices.is_empty() {
552            devices.iter()
553                .map(|d| d.health_score() as f64)
554                .sum::<f64>() / devices.len() as f64
555        } else {
556            0.0
557        };
558
559        // Get connection pool statistics
560        let connection_pool_stats = match self.connection_pool.read() {
561            Ok(pool) => Some(pool.get_statistics()),
562            Err(e) => {
563                log::error!("Failed to acquire connection pool read lock: {}", e);
564                None
565            }
566        };
567        
568        // Calculate device status distribution
569        let mut status_distribution = HashMap::with_capacity(4);
570        for device in &devices {
571            *status_distribution.entry(device.status()).or_insert(0) += 1;
572        }
573        
574        // Calculate average health metrics
575        let mut total_response_time_ms = 0.0;
576        let mut total_network_latency_ms = 0.0;
577        let mut total_disk_iops = 0.0;
578        let mut total_battery_level_percent = 0.0;
579        let mut total_cpu_usage_percent = 0.0;
580        let mut total_memory_usage_percent = 0.0;
581        let mut total_temperature_celsius = 0.0;
582        let mut total_error_count = 0u32;
583        let mut total_throughput = 0.0;
584        let mut total_uptime_seconds = 0.0;
585        
586        for device in &devices {
587            let health_metrics = device.health_metrics();
588            total_response_time_ms += health_metrics.response_time_ms;
589            total_network_latency_ms += health_metrics.network_latency_ms;
590            total_disk_iops += health_metrics.disk_iops as f64;
591            total_battery_level_percent += health_metrics.battery_level_percent;
592            total_cpu_usage_percent += health_metrics.cpu_usage_percent;
593            total_memory_usage_percent += health_metrics.memory_usage_percent;
594            total_temperature_celsius += health_metrics.temperature_celsius;
595            total_error_count += health_metrics.error_count;
596            total_throughput += health_metrics.throughput as f64;
597            total_uptime_seconds += health_metrics.uptime_seconds as f64;
598        }
599        
600        let device_count = devices.len() as f64;
601        
602        DMSCResourcePoolStatistics {
603            total_devices: devices.len(),
604            available_devices: available_devices.len(),
605            allocated_devices: allocated_devices.len(),
606            utilization_rate: self.utilization_rate(),
607            total_compute_units,
608            total_memory_gb,
609            total_storage_gb,
610            total_bandwidth_gbps,
611            average_health_score,
612            device_type: self.device_type,
613            connection_pool_stats,
614            
615            status_distribution,
616            average_response_time_ms: if device_count > 0.0 { total_response_time_ms / device_count } else { 0.0 },
617            average_network_latency_ms: if device_count > 0.0 { total_network_latency_ms / device_count } else { 0.0 },
618            average_disk_iops: if device_count > 0.0 { total_disk_iops / device_count } else { 0.0 },
619            average_battery_level_percent: if device_count > 0.0 { total_battery_level_percent / device_count } else { 0.0 },
620            average_cpu_usage_percent: if device_count > 0.0 { total_cpu_usage_percent / device_count } else { 0.0 },
621            average_memory_usage_percent: if device_count > 0.0 { total_memory_usage_percent / device_count } else { 0.0 },
622            average_temperature_celsius: if device_count > 0.0 { total_temperature_celsius / device_count } else { 0.0 },
623            total_error_count,
624            average_throughput: if device_count > 0.0 { total_throughput / device_count } else { 0.0 },
625            average_uptime_seconds: if device_count > 0.0 { total_uptime_seconds / device_count } else { 0.0 },
626        }
627    }
628}
629
630/// Connection pool for managing device connections with lifecycle and health monitoring
631#[derive(Debug, Clone)]
632#[allow(dead_code)]
633pub struct DMSCConnectionPool {
634    /// Active connections with their metadata
635    connections: HashMap<String, DMSCConnectionInfo>,
636    /// Maximum number of connections allowed
637    max_connections: usize,
638    /// Connection timeout duration
639    connection_timeout: Duration,
640    /// Health check interval
641    health_check_interval: Duration,
642    /// Last health check timestamp (seconds since Unix epoch)
643    last_health_check_secs: u64,
644    /// Number of active connections
645    pub active_connections: usize,
646    /// Number of failed connections
647    pub failed_connections: usize,
648    /// Total number of errors
649    pub total_errors: usize,
650}
651
652/// Connection information for tracking individual connections
653#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct DMSCConnectionInfo {
655    /// Connection ID
656    pub connection_id: String,
657    /// Device ID this connection is associated with
658    pub device_id: String,
659    /// Remote address or endpoint
660    pub address: String,
661    /// Connection establishment timestamp (seconds since Unix epoch)
662    pub established_at_secs: u64,
663    /// Last activity timestamp (seconds since Unix epoch)
664    pub last_activity_secs: u64,
665    /// Connection state
666    pub state: DMSCConnectionState,
667    /// Connection health metrics
668    pub health_metrics: DMSCConnectionHealthMetrics,
669}
670
671/// Connection state enumeration
672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
673pub enum DMSCConnectionState {
674    /// Connection is establishing
675    Connecting,
676    /// Connection is active and healthy
677    Active,
678    /// Connection is idle (no recent activity)
679    Idle,
680    /// Connection is unhealthy
681    Unhealthy,
682    /// Connection is being closed
683    Closing,
684    /// Connection is closed
685    Closed,
686}
687
688/// Connection health metrics
689#[derive(Debug, Clone, Default, Serialize, Deserialize)]
690pub struct DMSCConnectionHealthMetrics {
691    /// Number of successful operations
692    pub successful_operations: u64,
693    /// Number of failed operations
694    pub failed_operations: u64,
695    /// Average response time in milliseconds
696    pub average_response_time_ms: f64,
697    /// Last error timestamp (seconds since Unix epoch)
698    pub last_error_secs: Option<u64>,
699    /// Connection uptime percentage
700    pub uptime_percentage: f64,
701}
702
703#[allow(dead_code)]
704impl DMSCConnectionPool {
705    /// Creates a new connection pool
706    pub fn new(max_connections: usize, connection_timeout: Duration, health_check_interval: Duration) -> Self {
707        Self {
708            connections: HashMap::with_capacity(max_connections),
709            max_connections,
710            connection_timeout,
711            health_check_interval,
712            last_health_check_secs: std::time::SystemTime::now()
713                .duration_since(std::time::UNIX_EPOCH)
714                .unwrap_or(Duration::from_secs(0))
715                .as_secs(),
716            active_connections: 0,
717            failed_connections: 0,
718            total_errors: 0,
719        }
720    }
721    
722    /// Adds a new connection to the pool
723    pub fn add_connection(&mut self, device_id: String, address: String) {
724        let connection_info = DMSCConnectionInfo {
725            connection_id: device_id.clone(),
726            device_id: device_id.clone(),
727            address,
728            established_at_secs: std::time::SystemTime::now()
729                .duration_since(std::time::UNIX_EPOCH)
730                .unwrap_or_default()
731                .as_secs(),
732            last_activity_secs: std::time::SystemTime::now()
733                .duration_since(std::time::UNIX_EPOCH)
734                .unwrap_or_default()
735                .as_secs(),
736            state: DMSCConnectionState::Active,
737            health_metrics: DMSCConnectionHealthMetrics::default(),
738        };
739        
740        self.connections.insert(device_id, connection_info);
741        self.active_connections += 1;
742    }
743    
744    /// Removes a connection from the pool
745    pub fn remove_connection(&mut self, connection_id: &str) -> bool {
746        self.connections.remove(connection_id).is_some()
747    }
748    
749    /// Gets connection information
750    pub fn get_connection(&self, connection_id: &str) -> Option<&DMSCConnectionInfo> {
751        self.connections.get(connection_id)
752    }
753    
754    /// Updates connection activity
755    pub fn update_activity(&mut self, connection_id: &str) -> bool {
756        if let Some(connection) = self.connections.get_mut(connection_id) {
757            connection.last_activity_secs = std::time::SystemTime::now()
758                .duration_since(std::time::UNIX_EPOCH)
759                .unwrap_or(Duration::from_secs(0))
760                .as_secs();
761            if connection.state == DMSCConnectionState::Idle {
762                connection.state = DMSCConnectionState::Active;
763            }
764            true
765        } else {
766            false
767        }
768    }
769    
770    /// Updates connection health metrics
771    pub fn update_health_metrics(&mut self, connection_id: &str, success: bool, response_time_ms: f64) -> bool {
772        if let Some(connection) = self.connections.get_mut(connection_id) {
773            if success {
774                connection.health_metrics.successful_operations += 1;
775            } else {
776                connection.health_metrics.failed_operations += 1;
777                connection.health_metrics.last_error_secs = Some(
778                    std::time::SystemTime::now()
779                        .duration_since(std::time::UNIX_EPOCH)
780                        .unwrap_or(Duration::from_secs(0))
781                        .as_secs()
782                );
783            }
784            
785            // Update average response time
786            let total_ops = connection.health_metrics.successful_operations + connection.health_metrics.failed_operations;
787            connection.health_metrics.average_response_time_ms = 
788                (connection.health_metrics.average_response_time_ms * (total_ops - 1) as f64 + response_time_ms) / total_ops as f64;
789            
790            // Update uptime percentage
791            let total_ops = connection.health_metrics.successful_operations + connection.health_metrics.failed_operations;
792            connection.health_metrics.uptime_percentage = 
793                (connection.health_metrics.successful_operations as f64 / total_ops as f64) * 100.0;
794            
795            true
796        } else {
797            false
798        }
799    }
800    
801    /// Performs health check on all connections
802    pub fn perform_health_check(&mut self) {
803        self.last_health_check_secs = std::time::SystemTime::now()
804            .duration_since(std::time::UNIX_EPOCH)
805            .unwrap_or(Duration::from_secs(0))
806            .as_secs();
807        
808        for connection in self.connections.values_mut() {
809            // Check for idle connections
810            let current_time = std::time::SystemTime::now()
811                .duration_since(std::time::UNIX_EPOCH)
812                .unwrap_or_default()
813                .as_secs();
814            let elapsed_secs = current_time.saturating_sub(connection.last_activity_secs);
815            
816            if connection.state == DMSCConnectionState::Active && elapsed_secs > self.connection_timeout.as_secs() {
817                connection.state = DMSCConnectionState::Idle;
818            }
819            
820            // Check for unhealthy connections
821            if connection.health_metrics.uptime_percentage < 90.0 {
822                connection.state = DMSCConnectionState::Unhealthy;
823            } else if let Some(last_error_secs) = connection.health_metrics.last_error_secs {
824                let current_secs = std::time::SystemTime::now()
825                    .duration_since(std::time::UNIX_EPOCH)
826                    .unwrap_or(Duration::from_secs(0))
827                    .as_secs();
828                if current_secs.saturating_sub(last_error_secs) < 60 {
829                    connection.state = DMSCConnectionState::Unhealthy;
830                }
831            }
832            
833            // Close connections that have been unhealthy for too long
834            if connection.state == DMSCConnectionState::Unhealthy &&
835               connection.health_metrics.failed_operations > 10 {
836                connection.state = DMSCConnectionState::Closing;
837            }
838        }
839        
840        // Remove closed connections
841        self.connections.retain(|_, conn| conn.state != DMSCConnectionState::Closed);
842    }
843    
844    /// Gets the number of active connections
845    pub fn active_connections(&self) -> usize {
846        self.connections.values()
847            .filter(|conn| conn.state == DMSCConnectionState::Active)
848            .count()
849    }
850    
851    /// Gets the number of idle connections
852    pub fn idle_connections(&self) -> usize {
853        self.connections.values()
854            .filter(|conn| conn.state == DMSCConnectionState::Idle)
855            .count()
856    }
857    
858    /// Gets the number of unhealthy connections
859    pub fn unhealthy_connections(&self) -> usize {
860        self.connections.values()
861            .filter(|conn| conn.state == DMSCConnectionState::Unhealthy)
862            .count()
863    }
864    
865    /// Gets overall connection pool statistics
866    pub fn get_statistics(&self) -> DMSCConnectionPoolStatistics {
867        let total_connections = self.connections.len();
868        let active_connections = self.active_connections();
869        let idle_connections = self.idle_connections();
870        let unhealthy_connections = self.unhealthy_connections();
871        
872        let total_successful_ops: u64 = self.connections.values()
873            .map(|conn| conn.health_metrics.successful_operations)
874            .sum();
875        let total_failed_ops: u64 = self.connections.values()
876            .map(|conn| conn.health_metrics.failed_operations)
877            .sum();
878        
879        let avg_response_time = if !self.connections.is_empty() {
880            let total_response_time: f64 = self.connections.values()
881                .map(|conn| conn.health_metrics.average_response_time_ms)
882                .sum();
883            total_response_time / self.connections.len() as f64
884        } else {
885            0.0
886        };
887        
888        let last_health_check_secs = self.last_health_check_secs;
889        
890        DMSCConnectionPoolStatistics {
891            total_connections,
892            active_connections,
893            idle_connections,
894            unhealthy_connections,
895            available_slots: self.max_connections.saturating_sub(total_connections),
896            total_successful_operations: total_successful_ops,
897            total_failed_operations: total_failed_ops,
898            average_response_time_ms: avg_response_time,
899            health_check_interval_secs: self.health_check_interval.as_secs(),
900            last_health_check_secs,
901        }
902    }
903}
904
905/// Connection pool statistics
906#[derive(Debug, Clone, Serialize, Deserialize)]
907#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
908pub struct DMSCConnectionPoolStatistics {
909    /// Total number of connections
910    pub total_connections: usize,
911    /// Number of active connections
912    pub active_connections: usize,
913    /// Number of idle connections
914    pub idle_connections: usize,
915    /// Number of unhealthy connections
916    pub unhealthy_connections: usize,
917    /// Number of available connection slots
918    pub available_slots: usize,
919    /// Total successful operations across all connections
920    pub total_successful_operations: u64,
921    /// Total failed operations across all connections
922    pub total_failed_operations: u64,
923    /// Average response time across all connections
924    pub average_response_time_ms: f64,
925    /// Health check interval in seconds
926    pub health_check_interval_secs: u64,
927    /// Last health check timestamp (seconds since Unix epoch)
928    pub last_health_check_secs: u64,
929}
930
931impl Default for DMSCConnectionPoolStatistics {
932    fn default() -> Self {
933        Self {
934            total_connections: 0,
935            active_connections: 0,
936            idle_connections: 0,
937            unhealthy_connections: 0,
938            available_slots: 0,
939            total_successful_operations: 0,
940            total_failed_operations: 0,
941            average_response_time_ms: 0.0,
942            health_check_interval_secs: 0,
943            last_health_check_secs: 0,
944        }
945    }
946}
947
948/// Resource pool statistics structure
949/// 
950/// This struct contains comprehensive statistics for a resource pool, including device counts,
951/// utilization, total resources, and detailed health metrics.
952#[derive(Debug, Clone, Serialize, Deserialize)]
953#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass(get_all, set_all))]
954pub struct DMSCResourcePoolStatistics {
955    /// Total number of devices in the pool
956    pub total_devices: usize,
957    /// Number of available devices in the pool
958    pub available_devices: usize,
959    /// Number of allocated devices in the pool
960    pub allocated_devices: usize,
961    /// Utilization rate of the pool (0.0 - 1.0)
962    pub utilization_rate: f64,
963    /// Total compute units across all devices
964    pub total_compute_units: usize,
965    /// Total memory in gigabytes across all devices
966    pub total_memory_gb: f64,
967    /// Total storage in gigabytes across all devices
968    pub total_storage_gb: f64,
969    /// Total bandwidth in gigabits per second across all devices
970    pub total_bandwidth_gbps: f64,
971    /// Average health score across all devices
972    pub average_health_score: f64,
973    /// Type of devices in the pool
974    pub device_type: DMSCDeviceType,
975    /// Connection pool statistics
976    pub connection_pool_stats: Option<DMSCConnectionPoolStatistics>,
977    
978    /// Device status distribution
979    pub status_distribution: HashMap<DMSCDeviceStatus, usize>,
980    /// Average response time in milliseconds
981    pub average_response_time_ms: f64,
982    /// Average network latency in milliseconds (for network devices)
983    pub average_network_latency_ms: f64,
984    /// Average disk IOPS (for storage devices)
985    pub average_disk_iops: f64,
986    /// Average battery level percentage (for battery-powered devices)
987    pub average_battery_level_percent: f64,
988    /// Average CPU usage percentage
989    pub average_cpu_usage_percent: f64,
990    /// Average memory usage percentage
991    pub average_memory_usage_percent: f64,
992    /// Average temperature in Celsius
993    pub average_temperature_celsius: f64,
994    /// Total error count across all devices
995    pub total_error_count: u32,
996    /// Average throughput across all devices
997    pub average_throughput: f64,
998    /// Average uptime in seconds
999    pub average_uptime_seconds: f64,
1000}
1001
1002impl Default for DMSCResourcePoolStatistics {
1003    fn default() -> Self {
1004        Self {
1005            total_devices: 0,
1006            available_devices: 0,
1007            allocated_devices: 0,
1008            utilization_rate: 0.0,
1009            total_compute_units: 0,
1010            total_memory_gb: 0.0,
1011            total_storage_gb: 0.0,
1012            total_bandwidth_gbps: 0.0,
1013            average_health_score: 0.0,
1014            device_type: DMSCDeviceType::CPU,
1015            connection_pool_stats: None,
1016            status_distribution: HashMap::with_capacity(4),
1017            average_response_time_ms: 0.0,
1018            average_network_latency_ms: 0.0,
1019            average_disk_iops: 0.0,
1020            average_battery_level_percent: 0.0,
1021            average_cpu_usage_percent: 0.0,
1022            average_memory_usage_percent: 0.0,
1023            average_temperature_celsius: 0.0,
1024            total_error_count: 0,
1025            average_throughput: 0.0,
1026            average_uptime_seconds: 0.0,
1027        }
1028    }
1029}
1030
1031/// Resource pool manager for managing multiple resource pools
1032/// 
1033/// This struct manages multiple resource pools, providing methods for creating, retrieving,
1034/// and removing pools, as well as getting overall statistics.
1035#[cfg_attr(feature = "pyo3", pyo3::prelude::pyclass)]
1036pub struct DMSCResourcePoolManager {
1037    /// Map of pool names to resource pools
1038    pools: HashMap<String, Arc<DMSCResourcePool>>,
1039}
1040
1041impl Default for DMSCResourcePoolManager {
1042    fn default() -> Self {
1043        Self::new()
1044    }
1045}
1046
1047impl DMSCResourcePoolManager {
1048    /// Creates a new resource pool manager
1049    /// 
1050    /// # Returns
1051    /// 
1052    /// A new `DMSCResourcePoolManager` instance
1053    pub fn new() -> Self {
1054        Self {
1055            pools: HashMap::with_capacity(8),
1056        }
1057    }
1058    
1059    /// Creates a new resource pool
1060    /// 
1061    /// This method creates a new resource pool with the given configuration and adds it to the manager.
1062    /// 
1063    /// # Parameters
1064    /// 
1065    /// - `config`: The configuration for the new resource pool
1066    /// 
1067    /// # Returns
1068    /// 
1069    /// An `Arc<DMSCResourcePool>` to the newly created pool
1070    pub fn create_pool(&mut self, config: DMSCResourcePoolConfig) -> Arc<DMSCResourcePool> {
1071        let pool = Arc::new(DMSCResourcePool::new(config));
1072        self.pools.insert(pool.name().to_string(), pool.clone());
1073        pool
1074    }
1075    
1076    /// Gets a resource pool by name
1077    /// 
1078    /// # Parameters
1079    /// 
1080    /// - `name`: The name of the resource pool to get
1081    /// 
1082    /// # Returns
1083    /// 
1084    /// An `Option<Arc<DMSCResourcePool>>` containing the pool if found, `None` otherwise
1085    pub fn get_pool(&self, name: &str) -> Option<Arc<DMSCResourcePool>> {
1086        self.pools.get(name).cloned()
1087    }
1088    
1089    /// Removes a resource pool by name
1090    /// 
1091    /// # Parameters
1092    /// 
1093    /// - `name`: The name of the resource pool to remove
1094    /// 
1095    /// # Returns
1096    /// 
1097    /// An `Option<Arc<DMSCResourcePool>>` containing the removed pool if found, `None` otherwise
1098    pub fn remove_pool(&mut self, name: &str) -> Option<Arc<DMSCResourcePool>> {
1099        self.pools.remove(name)
1100    }
1101    
1102    /// Gets all resource pools
1103    /// 
1104    /// # Returns
1105    /// 
1106    /// A vector of `Arc<DMSCResourcePool>` containing all resource pools
1107    pub fn get_all_pools(&self) -> Vec<Arc<DMSCResourcePool>> {
1108        self.pools.values().cloned().collect()
1109    }
1110    
1111    /// Gets all resource pools of a specific device type
1112    /// 
1113    /// # Parameters
1114    /// 
1115    /// - `device_type`: The device type to filter pools by
1116    /// 
1117    /// # Returns
1118    /// 
1119    /// A vector of `Arc<DMSCResourcePool>` containing all pools of the specified device type
1120    pub fn get_pools_by_type(&self, device_type: DMSCDeviceType) -> Vec<Arc<DMSCResourcePool>> {
1121        self.pools.values()
1122            .filter(|pool| pool.device_type() == device_type)
1123            .cloned()
1124            .collect()
1125    }
1126    
1127    /// Gets overall statistics for all resource pools
1128    /// 
1129    /// This method calculates and returns overall statistics for all resource pools, including
1130    /// total devices, utilization, and total resources across all pools.
1131    /// 
1132    /// # Returns
1133    /// 
1134    /// A `DMSCResourcePoolStatistics` struct with overall statistics for all pools
1135    pub fn get_overall_statistics(&self) -> DMSCResourcePoolStatistics {
1136        let pools = self.get_all_pools();
1137        
1138        // Calculate total devices and allocated devices across all pools
1139        let total_devices: usize = pools.iter().map(|p| p.get_statistics().total_devices).sum();
1140        let allocated_devices: usize = pools.iter().map(|p| p.get_statistics().allocated_devices).sum();
1141        
1142        // Calculate total compute units across all devices in all pools
1143        let total_compute_units: usize = pools.iter()
1144            .flat_map(|p| p.get_devices())
1145            .filter_map(|d| d.capabilities().compute_units)
1146            .sum();
1147        
1148        // Calculate total memory across all devices in all pools
1149        let total_memory_gb: f64 = pools.iter()
1150            .flat_map(|p| p.get_devices())
1151            .filter_map(|d| d.capabilities().memory_gb)
1152            .sum();
1153        
1154        // Calculate total storage across all devices in all pools
1155        let total_storage_gb: f64 = pools.iter()
1156            .flat_map(|p| p.get_devices())
1157            .filter_map(|d| d.capabilities().storage_gb)
1158            .sum();
1159        
1160        // Calculate total bandwidth across all devices in all pools
1161        let total_bandwidth_gbps: f64 = pools.iter()
1162            .flat_map(|p| p.get_devices())
1163            .filter_map(|d| d.capabilities().bandwidth_gbps)
1164            .sum();
1165        
1166        // Calculate overall utilization rate
1167        let overall_utilization = if total_devices > 0 {
1168            allocated_devices as f64 / total_devices as f64
1169        } else {
1170            0.0
1171        };
1172        
1173        // Calculate average health score across all pools
1174        let total_health_score: f64 = pools.iter()
1175            .map(|p| p.get_statistics().average_health_score)
1176            .sum();
1177        let average_health_score = if !pools.is_empty() {
1178            total_health_score / pools.len() as f64
1179        } else {
1180            0.0
1181        };
1182        
1183        DMSCResourcePoolStatistics {
1184            total_devices,
1185            available_devices: total_devices - allocated_devices,
1186            allocated_devices,
1187            utilization_rate: overall_utilization,
1188            total_compute_units,
1189            total_memory_gb,
1190            total_storage_gb,
1191            total_bandwidth_gbps,
1192            average_health_score,
1193            device_type: DMSCDeviceType::Custom, // Multiple device types across pools
1194            connection_pool_stats: None, // No aggregated connection stats at manager level
1195            
1196            status_distribution: HashMap::with_capacity(4),
1197            average_response_time_ms: 0.0,
1198            average_network_latency_ms: 0.0,
1199            average_disk_iops: 0.0,
1200            average_battery_level_percent: 0.0,
1201            average_cpu_usage_percent: 0.0,
1202            average_memory_usage_percent: 0.0,
1203            average_temperature_celsius: 0.0,
1204            total_error_count: 0,
1205            average_throughput: 0.0,
1206            average_uptime_seconds: 0.0,
1207        }
1208    }
1209}
1210
1211#[cfg(feature = "pyo3")]
1212#[pyo3::prelude::pymethods]
1213impl DMSCResourcePoolConfig {
1214    #[new]
1215    fn py_new() -> Self {
1216        Self::default()
1217    }
1218    
1219    #[staticmethod]
1220    fn py_new_with_name(name: String, device_type: DMSCDeviceType) -> Self {
1221        Self {
1222            name,
1223            device_type,
1224            max_concurrent_allocations: 10,
1225            allocation_timeout_secs: 60,
1226            health_check_interval_secs: 30,
1227        }
1228    }
1229}
1230
1231#[cfg(feature = "pyo3")]
1232#[pyo3::prelude::pymethods]
1233impl DMSCResourcePoolStatistics {
1234    #[new]
1235    fn py_new() -> Self {
1236        Self::default()
1237    }
1238}
1239
1240#[cfg(feature = "pyo3")]
1241#[pyo3::prelude::pymethods]
1242impl DMSCResourcePoolManager {
1243    #[new]
1244    fn py_new() -> Self {
1245        Self::new()
1246    }
1247}