1use spark_connect_proto as proto;
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Default)]
14pub struct ExecutorResourceRequests {
15 resources: HashMap<String, proto::ExecutorResourceRequest>,
16}
17
18impl ExecutorResourceRequests {
19 pub fn new() -> Self {
21 ExecutorResourceRequests {
22 resources: HashMap::new(),
23 }
24 }
25
26 pub fn memory(mut self, memory_mb: i64) -> Self {
28 self.resources.insert(
29 "memory".to_string(),
30 proto::ExecutorResourceRequest {
31 resource_name: "memory".to_string(),
32 amount: memory_mb,
33 discovery_script: None,
34 vendor: None,
35 },
36 );
37 self
38 }
39
40 pub fn off_heap_memory(mut self, memory_mb: i64) -> Self {
42 self.resources.insert(
43 "offHeap".to_string(),
44 proto::ExecutorResourceRequest {
45 resource_name: "offHeap".to_string(),
46 amount: memory_mb,
47 discovery_script: None,
48 vendor: None,
49 },
50 );
51 self
52 }
53
54 pub fn cores(mut self, num_cores: i64) -> Self {
56 self.resources.insert(
57 "cores".to_string(),
58 proto::ExecutorResourceRequest {
59 resource_name: "cores".to_string(),
60 amount: num_cores,
61 discovery_script: None,
62 vendor: None,
63 },
64 );
65 self
66 }
67
68 pub fn resource(
76 mut self,
77 name: &str,
78 amount: i64,
79 discovery_script: Option<String>,
80 vendor: Option<String>,
81 ) -> Self {
82 self.resources.insert(
83 name.to_string(),
84 proto::ExecutorResourceRequest {
85 resource_name: name.to_string(),
86 amount,
87 discovery_script,
88 vendor,
89 },
90 );
91 self
92 }
93}
94
95#[derive(Debug, Clone, Default)]
100pub struct TaskResourceRequests {
101 resources: HashMap<String, proto::TaskResourceRequest>,
102}
103
104impl TaskResourceRequests {
105 pub fn new() -> Self {
107 TaskResourceRequests {
108 resources: HashMap::new(),
109 }
110 }
111
112 pub fn cpus(mut self, num_cpus: f64) -> Self {
114 self.resources.insert(
115 "cpus".to_string(),
116 proto::TaskResourceRequest {
117 resource_name: "cpus".to_string(),
118 amount: num_cpus,
119 },
120 );
121 self
122 }
123
124 pub fn resource(mut self, name: &str, amount: f64) -> Self {
130 self.resources.insert(
131 name.to_string(),
132 proto::TaskResourceRequest {
133 resource_name: name.to_string(),
134 amount,
135 },
136 );
137 self
138 }
139}
140
141#[derive(Debug, Clone, Default)]
146pub struct ResourceProfileBuilder {
147 executor_requests: ExecutorResourceRequests,
148 task_requests: TaskResourceRequests,
149}
150
151impl ResourceProfileBuilder {
152 pub fn new() -> Self {
154 ResourceProfileBuilder {
155 executor_requests: ExecutorResourceRequests::new(),
156 task_requests: TaskResourceRequests::new(),
157 }
158 }
159
160 pub fn executor_resources(mut self, requests: ExecutorResourceRequests) -> Self {
162 self.executor_requests = requests;
163 self
164 }
165
166 pub fn task_resources(mut self, requests: TaskResourceRequests) -> Self {
168 self.task_requests = requests;
169 self
170 }
171
172 pub fn build(self) -> ResourceProfile {
174 ResourceProfile {
175 proto_profile: proto::ResourceProfile {
176 executor_resources: self.executor_requests.resources.clone(),
177 task_resources: self.task_requests.resources.clone(),
178 },
179 profile_id: None,
180 }
181 }
182}
183
184#[derive(Debug, Clone)]
189pub struct ResourceProfile {
190 pub(crate) proto_profile: proto::ResourceProfile,
191 pub(crate) profile_id: Option<i32>,
192}
193
194impl ResourceProfile {
195 pub fn id(&self) -> Option<i32> {
197 self.profile_id
198 }
199
200 pub(crate) fn proto(&self) -> &proto::ResourceProfile {
202 &self.proto_profile
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use prost::Message;
210
211 #[test]
212 fn executor_resource_requests_encode_decode() {
213 let reqs = ExecutorResourceRequests::new()
214 .memory(2048)
215 .cores(4)
216 .resource("gpu", 2, None, Some("nvidia".to_string()));
217
218 let profile = proto::ResourceProfile {
219 executor_resources: reqs.resources.clone(),
220 task_resources: HashMap::new(),
221 };
222
223 let encoded = profile.encode_to_vec();
224 let decoded = proto::ResourceProfile::decode(encoded.as_slice()).unwrap();
225
226 assert_eq!(decoded.executor_resources.len(), 3);
227 assert_eq!(
228 decoded.executor_resources.get("memory").unwrap().amount,
229 2048
230 );
231 assert_eq!(decoded.executor_resources.get("cores").unwrap().amount, 4);
232 assert_eq!(decoded.executor_resources.get("gpu").unwrap().amount, 2);
233 assert_eq!(
234 decoded.executor_resources.get("gpu").unwrap().vendor,
235 Some("nvidia".to_string())
236 );
237 }
238
239 #[test]
240 fn task_resource_requests_encode_decode() {
241 let reqs = TaskResourceRequests::new().cpus(0.5).resource("gpu", 0.25);
242
243 let profile = proto::ResourceProfile {
244 executor_resources: HashMap::new(),
245 task_resources: reqs.resources.clone(),
246 };
247
248 let encoded = profile.encode_to_vec();
249 let decoded = proto::ResourceProfile::decode(encoded.as_slice()).unwrap();
250
251 assert_eq!(decoded.task_resources.len(), 2);
252 assert_eq!(decoded.task_resources.get("cpus").unwrap().amount, 0.5);
253 assert_eq!(decoded.task_resources.get("gpu").unwrap().amount, 0.25);
254 }
255
256 #[test]
257 fn resource_profile_builder() {
258 let executor_reqs = ExecutorResourceRequests::new().memory(4096).cores(8);
259 let task_reqs = TaskResourceRequests::new().cpus(1.0);
260
261 let profile = ResourceProfileBuilder::new()
262 .executor_resources(executor_reqs)
263 .task_resources(task_reqs)
264 .build();
265
266 assert!(profile.profile_id.is_none());
267 assert_eq!(profile.proto_profile.executor_resources.len(), 2);
268 assert_eq!(profile.proto_profile.task_resources.len(), 1);
269
270 let executor_mem = profile
271 .proto_profile
272 .executor_resources
273 .get("memory")
274 .unwrap();
275 assert_eq!(executor_mem.amount, 4096);
276
277 let task_cpus = profile.proto_profile.task_resources.get("cpus").unwrap();
278 assert_eq!(task_cpus.amount, 1.0);
279 }
280
281 #[test]
282 fn off_heap_memory_and_profile_accessors() {
283 let reqs = ExecutorResourceRequests::new()
284 .off_heap_memory(1024)
285 .cores(2);
286 assert_eq!(reqs.resources.get("offHeap").unwrap().amount, 1024);
287
288 let profile = ResourceProfileBuilder::new()
289 .executor_resources(reqs)
290 .build();
291 assert!(profile.id().is_none());
293 assert_eq!(profile.proto().executor_resources.len(), 2);
295 }
296}