1use crate::error::{RuntimeError, RuntimeResult};
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
8pub struct ResourceQuota {
9 pub cpu_cores: f64,
11
12 pub memory_bytes: u64,
14
15 pub network_bandwidth_bps: u64,
17
18 pub disk_io_bps: u64,
20}
21
22impl Default for ResourceQuota {
23 fn default() -> Self {
24 Self {
25 cpu_cores: 1.0,
26 memory_bytes: 1024 * 1024 * 1024, network_bandwidth_bps: 100 * 1024 * 1024, disk_io_bps: 100 * 1024 * 1024, }
30 }
31}
32
33#[derive(Debug, Clone, Default, Serialize, Deserialize)]
35pub struct ResourceUsage {
36 pub cpu_usage: f64,
38
39 pub memory_used_bytes: u64,
41
42 pub network_usage_bps: u64,
44
45 pub disk_io_bps: u64,
47}
48
49#[derive(Debug, Clone)]
51pub struct ResourceConfig {
52 pub enable_limits: bool,
54
55 pub monitoring_interval_seconds: u64,
57
58 pub warning_threshold: f64,
60
61 pub limit_threshold: f64,
63}
64
65impl Default for ResourceConfig {
66 fn default() -> Self {
67 Self {
68 enable_limits: true,
69 monitoring_interval_seconds: 5,
70 warning_threshold: 0.8,
71 limit_threshold: 0.95,
72 }
73 }
74}
75
76pub struct ResourceManager {
78 config: ResourceConfig,
79 quota: ResourceQuota,
80 current_usage: ResourceUsage,
81}
82
83impl ResourceManager {
84 pub fn new(config: ResourceConfig, quota: ResourceQuota) -> Self {
86 Self {
87 config,
88 quota,
89 current_usage: ResourceUsage::default(),
90 }
91 }
92
93 pub fn check_resource_availability(&self, required: &ResourceUsage) -> RuntimeResult<bool> {
95 if !self.config.enable_limits {
96 return Ok(true);
97 }
98
99 let cpu_available =
101 self.quota.cpu_cores - (self.current_usage.cpu_usage * self.quota.cpu_cores);
102 if required.cpu_usage * self.quota.cpu_cores > cpu_available {
103 return Ok(false);
104 }
105
106 let memory_available = self.quota.memory_bytes - self.current_usage.memory_used_bytes;
108 if required.memory_used_bytes > memory_available {
109 return Ok(false);
110 }
111
112 Ok(true)
113 }
114
115 pub fn allocate_resources(&mut self, usage: &ResourceUsage) -> RuntimeResult<()> {
117 if !self.check_resource_availability(usage)? {
118 return Err(RuntimeError::Unavailable {
119 message: "Insufficient resources available".to_string(),
120 target: None,
121 });
122 }
123
124 self.current_usage.cpu_usage += usage.cpu_usage;
125 self.current_usage.memory_used_bytes += usage.memory_used_bytes;
126 self.current_usage.network_usage_bps += usage.network_usage_bps;
127 self.current_usage.disk_io_bps += usage.disk_io_bps;
128
129 Ok(())
130 }
131
132 pub fn release_resources(&mut self, usage: &ResourceUsage) -> RuntimeResult<()> {
134 self.current_usage.cpu_usage = (self.current_usage.cpu_usage - usage.cpu_usage).max(0.0);
135 self.current_usage.memory_used_bytes = self
136 .current_usage
137 .memory_used_bytes
138 .saturating_sub(usage.memory_used_bytes);
139 self.current_usage.network_usage_bps = self
140 .current_usage
141 .network_usage_bps
142 .saturating_sub(usage.network_usage_bps);
143 self.current_usage.disk_io_bps = self
144 .current_usage
145 .disk_io_bps
146 .saturating_sub(usage.disk_io_bps);
147
148 Ok(())
149 }
150
151 pub fn get_usage(&self) -> &ResourceUsage {
153 &self.current_usage
154 }
155
156 pub fn get_quota(&self) -> &ResourceQuota {
158 &self.quota
159 }
160
161 pub fn calculate_usage_ratio(&self) -> ResourceUsageRatio {
163 ResourceUsageRatio {
164 cpu_ratio: self.current_usage.cpu_usage,
165 memory_ratio: self.current_usage.memory_used_bytes as f64
166 / self.quota.memory_bytes as f64,
167 network_ratio: self.current_usage.network_usage_bps as f64
168 / self.quota.network_bandwidth_bps as f64,
169 disk_ratio: self.current_usage.disk_io_bps as f64 / self.quota.disk_io_bps as f64,
170 }
171 }
172}
173
174#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct ResourceUsageRatio {
177 pub cpu_ratio: f64,
179
180 pub memory_ratio: f64,
182
183 pub network_ratio: f64,
185
186 pub disk_ratio: f64,
188}