Rust · 24205 bytes Raw Blame History
1 //! Contribution-Based Resource Allocator
2 //!
3 //! Allocates network resources based on user contributions rather than monetary payments
4
5 use anyhow::Result;
6 use serde::{Deserialize, Serialize};
7 use std::collections::{HashMap, VecDeque};
8 use chrono::{DateTime, Utc, Duration};
9
10 use crate::economics::{UserContribution, PriorityLevel, ContributionTracker};
11
12 /// Main resource allocator using contribution ratios
13 #[derive(Debug, Clone, Serialize, Deserialize)]
14 pub struct ContributionBasedAllocator {
15 /// Allocation decisions cache
16 pub allocation_cache: HashMap<String, AllocationDecision>,
17 /// Resource availability tracking
18 pub resource_availability: ResourceAvailability,
19 /// Allocation strategies configuration
20 pub strategies: HashMap<AllocationStrategy, StrategyConfig>,
21 /// Historical allocation data
22 pub allocation_history: VecDeque<HistoricalAllocation>,
23 /// Performance metrics
24 pub performance_metrics: AllocationMetrics,
25 }
26
27 #[derive(Debug, Clone, Serialize, Deserialize)]
28 pub struct AllocationRequest {
29 pub request_id: String,
30 pub user_id: String,
31 pub resource_type: ResourceType,
32 pub amount_requested: u64,
33 pub quality_requirements: QualityRequirements,
34 pub duration: Option<Duration>,
35 pub deadline: Option<DateTime<Utc>>,
36 pub priority: RequestPriority,
37 pub requested_at: DateTime<Utc>,
38 }
39
40 #[derive(Debug, Clone, Serialize, Deserialize)]
41 pub enum ResourceType {
42 Storage {
43 size_gb: u64,
44 io_requirements: IORequirements,
45 },
46 Bandwidth {
47 mbps: u64,
48 burst_capacity: Option<u64>,
49 },
50 Compute {
51 cpu_cores: u32,
52 memory_gb: u32,
53 },
54 Network {
55 connections: u32,
56 max_latency_ms: u32,
57 },
58 }
59
60 #[derive(Debug, Clone, Serialize, Deserialize)]
61 pub struct IORequirements {
62 pub read_iops: u32,
63 pub write_iops: u32,
64 pub sequential_read_mbps: u32,
65 pub sequential_write_mbps: u32,
66 }
67
68 #[derive(Debug, Clone, Serialize, Deserialize)]
69 pub struct QualityRequirements {
70 pub reliability_level: ReliabilityLevel,
71 pub performance_tier: PerformanceTier,
72 pub availability_sla: f64, // e.g., 99.9%
73 pub max_latency_ms: Option<u32>,
74 pub redundancy_level: RedundancyLevel,
75 pub geographic_constraints: Option<GeographicConstraints>,
76 }
77
78 #[derive(Debug, Clone, Serialize, Deserialize)]
79 pub enum ReliabilityLevel {
80 Basic, // 95% uptime, basic monitoring
81 Standard, // 99% uptime, standard monitoring
82 High, // 99.9% uptime, advanced monitoring
83 Critical, // 99.99% uptime, premium monitoring
84 }
85
86 #[derive(Debug, Clone, Serialize, Deserialize)]
87 pub enum PerformanceTier {
88 Economy, // Best effort, no guarantees
89 Standard, // Baseline performance guarantees
90 Premium, // High performance guarantees
91 Enterprise, // Maximum performance guarantees
92 }
93
94 #[derive(Debug, Clone, Serialize, Deserialize)]
95 pub enum RedundancyLevel {
96 Single, // No redundancy (lowest cost)
97 Mirror, // 2x redundancy
98 Standard, // 3x redundancy
99 High, // 5x redundancy
100 Critical, // 7x redundancy
101 }
102
103 #[derive(Debug, Clone, Serialize, Deserialize)]
104 pub struct GeographicConstraints {
105 pub allowed_regions: Option<Vec<String>>,
106 pub prohibited_regions: Option<Vec<String>>,
107 pub data_sovereignty_requirements: Option<String>,
108 pub max_distance_km: Option<u32>,
109 }
110
111 #[derive(Debug, Clone, Serialize, Deserialize)]
112 pub enum RequestPriority {
113 Background, // Can wait indefinitely
114 Normal, // Standard priority
115 High, // Expedited processing
116 Urgent, // Immediate processing required
117 }
118
119 #[derive(Debug, Clone, Serialize, Deserialize)]
120 pub struct AllocationDecision {
121 pub request_id: String,
122 pub user_id: String,
123 pub decision: AllocationOutcome,
124 pub allocated_resources: Option<AllocatedResources>,
125 pub reason: String,
126 pub contribution_score_used: f64,
127 pub priority_level_used: PriorityLevel,
128 pub decided_at: DateTime<Utc>,
129 pub expires_at: Option<DateTime<Utc>>,
130 }
131
132 #[derive(Debug, Clone, Serialize, Deserialize)]
133 pub enum AllocationOutcome {
134 Approved,
135 Denied,
136 PartiallyApproved,
137 Queued,
138 Expired,
139 }
140
141 #[derive(Debug, Clone, Serialize, Deserialize)]
142 pub struct AllocatedResources {
143 pub resource_type: ResourceType,
144 pub amount_allocated: u64,
145 pub quality_level: AllocationQuality,
146 pub assigned_nodes: Vec<NodeAssignment>,
147 pub estimated_performance: PerformanceEstimate,
148 pub sla_commitments: SLACommitments,
149 }
150
151 #[derive(Debug, Clone, Serialize, Deserialize)]
152 pub struct NodeAssignment {
153 pub node_id: String,
154 pub resource_portion: f64, // 0.0-1.0
155 pub role: NodeRole,
156 pub expected_performance: NodePerformance,
157 }
158
159 #[derive(Debug, Clone, Serialize, Deserialize)]
160 pub enum NodeRole {
161 Primary, // Main storage/compute node
162 Secondary, // Backup/redundancy node
163 Cache, // Caching/acceleration node
164 Router, // Network routing node
165 }
166
167 #[derive(Debug, Clone, Serialize, Deserialize)]
168 pub struct NodePerformance {
169 pub uptime_percentage: f64,
170 pub response_time_ms: u32,
171 pub throughput_mbps: f64,
172 pub reliability_score: f64,
173 }
174
175 #[derive(Debug, Clone, Serialize, Deserialize)]
176 pub struct PerformanceEstimate {
177 pub expected_throughput_mbps: f64,
178 pub expected_latency_ms: u32,
179 pub expected_availability_percent: f64,
180 pub confidence_level: f64, // 0.0-1.0
181 }
182
183 #[derive(Debug, Clone, Serialize, Deserialize)]
184 pub struct SLACommitments {
185 pub uptime_guarantee: f64,
186 pub performance_guarantee: PerformanceGuarantee,
187 pub data_durability: f64, // e.g., 99.999999999% (11 nines)
188 pub support_level: SupportLevel,
189 }
190
191 #[derive(Debug, Clone, Serialize, Deserialize)]
192 pub struct PerformanceGuarantee {
193 pub min_throughput_mbps: f64,
194 pub max_latency_ms: u32,
195 pub response_time_percentile: PercentileGuarantee,
196 }
197
198 #[derive(Debug, Clone, Serialize, Deserialize)]
199 pub struct PercentileGuarantee {
200 pub p50_latency_ms: u32,
201 pub p95_latency_ms: u32,
202 pub p99_latency_ms: u32,
203 }
204
205 #[derive(Debug, Clone, Serialize, Deserialize)]
206 pub enum SupportLevel {
207 Community, // Community support only
208 Standard, // Business hours support
209 Premium, // 24/7 support
210 Enterprise, // Dedicated support
211 }
212
213 #[derive(Debug, Clone, Serialize, Deserialize)]
214 pub enum AllocationQuality {
215 /// Basic allocation with minimal guarantees
216 Basic,
217 /// Standard allocation with reasonable guarantees
218 Standard,
219 /// Premium allocation with strong guarantees
220 Premium,
221 /// Enterprise-grade allocation with maximum guarantees
222 Enterprise,
223 }
224
225 #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
226 pub enum AllocationStrategy {
227 /// Fair sharing based on contribution ratios
228 ContributionBased,
229 /// Priority to highest contributors
230 ContributorFirst,
231 /// Balanced approach considering multiple factors
232 Balanced,
233 /// Optimize for overall network efficiency
234 EfficiencyOptimized,
235 /// Geographic distribution optimization
236 GeographicBalanced,
237 }
238
239 #[derive(Debug, Clone, Serialize, Deserialize)]
240 pub struct StrategyConfig {
241 pub strategy: AllocationStrategy,
242 pub weight: f64, // Influence in decision making
243 pub parameters: HashMap<String, f64>,
244 pub enabled: bool,
245 }
246
247 #[derive(Debug, Clone, Serialize, Deserialize)]
248 pub enum ResourcePriority {
249 Low,
250 Normal,
251 High,
252 Critical,
253 }
254
255 #[derive(Debug, Clone, Serialize, Deserialize)]
256 pub struct ResourceAvailability {
257 pub total_storage_gb: u64,
258 pub available_storage_gb: u64,
259 pub total_bandwidth_gbps: f64,
260 pub available_bandwidth_gbps: f64,
261 pub active_nodes: u32,
262 pub node_availability: HashMap<String, NodeAvailability>,
263 pub regional_availability: HashMap<String, RegionalAvailability>,
264 pub last_updated: DateTime<Utc>,
265 }
266
267 #[derive(Debug, Clone, Serialize, Deserialize)]
268 pub struct NodeAvailability {
269 pub node_id: String,
270 pub available_storage_gb: u64,
271 pub available_bandwidth_mbps: f64,
272 pub current_load_percent: f64,
273 pub reliability_score: f64,
274 pub geographic_region: String,
275 pub last_seen: DateTime<Utc>,
276 }
277
278 #[derive(Debug, Clone, Serialize, Deserialize)]
279 pub struct RegionalAvailability {
280 pub region: String,
281 pub total_nodes: u32,
282 pub active_nodes: u32,
283 pub total_capacity_gb: u64,
284 pub available_capacity_gb: u64,
285 pub average_performance: f64,
286 pub utilization_percent: f64,
287 }
288
289 #[derive(Debug, Clone, Serialize, Deserialize)]
290 pub struct HistoricalAllocation {
291 pub timestamp: DateTime<Utc>,
292 pub user_id: String,
293 pub resource_type: ResourceType,
294 pub amount_requested: u64,
295 pub amount_allocated: u64,
296 pub decision: AllocationOutcome,
297 pub contribution_score: f64,
298 pub processing_time_ms: u32,
299 }
300
301 #[derive(Debug, Clone, Serialize, Deserialize)]
302 pub struct AllocationMetrics {
303 pub total_requests: u64,
304 pub approved_requests: u64,
305 pub denied_requests: u64,
306 pub average_processing_time_ms: u32,
307 pub resource_utilization_percent: f64,
308 pub user_satisfaction_score: f64,
309 pub fairness_index: f64, // Gini coefficient or similar
310 pub last_calculated: DateTime<Utc>,
311 }
312
313 impl ContributionBasedAllocator {
314 pub fn new() -> Self {
315 let mut strategies = HashMap::new();
316
317 strategies.insert(AllocationStrategy::ContributionBased, StrategyConfig {
318 strategy: AllocationStrategy::ContributionBased,
319 weight: 0.4,
320 parameters: {
321 let mut params = HashMap::new();
322 params.insert("min_ratio_threshold".to_string(), 1.0);
323 params.insert("bonus_multiplier".to_string(), 1.5);
324 params
325 },
326 enabled: true,
327 });
328
329 strategies.insert(AllocationStrategy::Balanced, StrategyConfig {
330 strategy: AllocationStrategy::Balanced,
331 weight: 0.3,
332 parameters: HashMap::new(),
333 enabled: true,
334 });
335
336 strategies.insert(AllocationStrategy::EfficiencyOptimized, StrategyConfig {
337 strategy: AllocationStrategy::EfficiencyOptimized,
338 weight: 0.3,
339 parameters: HashMap::new(),
340 enabled: true,
341 });
342
343 Self {
344 allocation_cache: HashMap::new(),
345 resource_availability: ResourceAvailability {
346 total_storage_gb: 0,
347 available_storage_gb: 0,
348 total_bandwidth_gbps: 0.0,
349 available_bandwidth_gbps: 0.0,
350 active_nodes: 0,
351 node_availability: HashMap::new(),
352 regional_availability: HashMap::new(),
353 last_updated: Utc::now(),
354 },
355 strategies,
356 allocation_history: VecDeque::with_capacity(10000),
357 performance_metrics: AllocationMetrics {
358 total_requests: 0,
359 approved_requests: 0,
360 denied_requests: 0,
361 average_processing_time_ms: 0,
362 resource_utilization_percent: 0.0,
363 user_satisfaction_score: 0.0,
364 fairness_index: 1.0,
365 last_calculated: Utc::now(),
366 },
367 }
368 }
369
370 /// Make allocation decision based on contribution and resource availability
371 pub async fn allocate_resources(
372 &mut self,
373 request: AllocationRequest,
374 contribution_tracker: &ContributionTracker,
375 ) -> Result<AllocationDecision> {
376 let start_time = Utc::now();
377
378 // Get user contribution data
379 let user_contribution = contribution_tracker.get_user_status(&request.user_id)
380 .ok_or_else(|| anyhow::anyhow!("User not found in contribution tracker"))?;
381
382 // Calculate allocation eligibility based on contribution
383 let allocation_eligibility = self.calculate_allocation_eligibility(user_contribution, &request)?;
384
385 // Make allocation decision
386 let decision = if allocation_eligibility.eligible {
387 self.make_allocation_decision(request.clone(), allocation_eligibility).await?
388 } else {
389 AllocationDecision {
390 request_id: request.request_id.clone(),
391 user_id: request.user_id.clone(),
392 decision: AllocationOutcome::Denied,
393 allocated_resources: None,
394 reason: allocation_eligibility.reason,
395 contribution_score_used: user_contribution.contribution_score,
396 priority_level_used: user_contribution.priority_level.clone(),
397 decided_at: start_time,
398 expires_at: None,
399 }
400 };
401
402 // Update metrics
403 self.update_allocation_metrics(&decision, start_time);
404
405 // Cache decision
406 self.allocation_cache.insert(request.request_id.clone(), decision.clone());
407
408 // Record in history
409 self.record_allocation_history(&request, &decision, start_time);
410
411 Ok(decision)
412 }
413
414 /// Calculate whether user is eligible for allocation based on contribution
415 fn calculate_allocation_eligibility(
416 &self,
417 user_contribution: &UserContribution,
418 request: &AllocationRequest,
419 ) -> Result<AllocationEligibility> {
420
421 // Check account status
422 match user_contribution.account_status {
423 crate::economics::AccountStatus::Suspended => {
424 return Ok(AllocationEligibility {
425 eligible: false,
426 max_allocation_gb: 0,
427 quality_level: AllocationQuality::Basic,
428 reason: "Account suspended due to poor contribution ratio".to_string(),
429 });
430 },
431 crate::economics::AccountStatus::Limited => {
432 // Limited accounts get minimal allocation
433 let max_allocation = (user_contribution.storage_offered_gb / 4).min(10); // Max 25% of contribution, capped at 10GB
434
435 if let ResourceType::Storage { size_gb, .. } = &request.resource_type {
436 if *size_gb > max_allocation {
437 return Ok(AllocationEligibility {
438 eligible: false,
439 max_allocation_gb: max_allocation,
440 quality_level: AllocationQuality::Basic,
441 reason: format!("Limited account. Maximum allocation: {}GB", max_allocation),
442 });
443 }
444 }
445 },
446 _ => {} // Continue with normal processing
447 }
448
449 // Calculate maximum allocation based on contribution level
450 let allocation_multiplier = match user_contribution.priority_level {
451 PriorityLevel::Deficit => 0.5,
452 PriorityLevel::Balanced => 1.0,
453 PriorityLevel::Surplus => 1.5,
454 PriorityLevel::Generous => 2.0,
455 };
456
457 let max_allocation_gb = (user_contribution.storage_offered_gb as f64 * allocation_multiplier) as u64;
458
459 // Check if request exceeds allowed allocation
460 if let ResourceType::Storage { size_gb, .. } = &request.resource_type {
461 if *size_gb > max_allocation_gb {
462 return Ok(AllocationEligibility {
463 eligible: false,
464 max_allocation_gb,
465 quality_level: self.determine_quality_level(user_contribution),
466 reason: format!("Requested {}GB exceeds maximum allowed allocation of {}GB based on contribution level", size_gb, max_allocation_gb),
467 });
468 }
469 }
470
471 Ok(AllocationEligibility {
472 eligible: true,
473 max_allocation_gb,
474 quality_level: self.determine_quality_level(user_contribution),
475 reason: "Allocation approved based on contribution level".to_string(),
476 })
477 }
478
479 /// Determine quality level based on contribution
480 fn determine_quality_level(&self, user_contribution: &UserContribution) -> AllocationQuality {
481 match user_contribution.priority_level {
482 PriorityLevel::Deficit => AllocationQuality::Basic,
483 PriorityLevel::Balanced => AllocationQuality::Standard,
484 PriorityLevel::Surplus => AllocationQuality::Premium,
485 PriorityLevel::Generous => AllocationQuality::Enterprise,
486 }
487 }
488
489 /// Make the actual allocation decision
490 async fn make_allocation_decision(
491 &mut self,
492 request: AllocationRequest,
493 eligibility: AllocationEligibility,
494 ) -> Result<AllocationDecision> {
495
496 // Find available nodes that can fulfill the request
497 let suitable_nodes = self.find_suitable_nodes(&request, &eligibility)?;
498
499 if suitable_nodes.is_empty() {
500 return Ok(AllocationDecision {
501 request_id: request.request_id.clone(),
502 user_id: request.user_id.clone(),
503 decision: AllocationOutcome::Queued,
504 allocated_resources: None,
505 reason: "No suitable nodes available at this time. Request queued.".to_string(),
506 contribution_score_used: 0.0,
507 priority_level_used: PriorityLevel::Balanced,
508 decided_at: Utc::now(),
509 expires_at: Some(Utc::now() + Duration::hours(24)),
510 });
511 }
512
513 // Create resource allocation
514 let allocated_resources = self.create_resource_allocation(&request, &suitable_nodes, &eligibility)?;
515
516 Ok(AllocationDecision {
517 request_id: request.request_id,
518 user_id: request.user_id,
519 decision: AllocationOutcome::Approved,
520 allocated_resources: Some(allocated_resources),
521 reason: "Resources allocated successfully".to_string(),
522 contribution_score_used: 0.0,
523 priority_level_used: PriorityLevel::Balanced,
524 decided_at: Utc::now(),
525 expires_at: None,
526 })
527 }
528
529 /// Find nodes suitable for the allocation request
530 fn find_suitable_nodes(
531 &self,
532 request: &AllocationRequest,
533 eligibility: &AllocationEligibility,
534 ) -> Result<Vec<NodeAssignment>> {
535
536 let mut suitable_nodes = Vec::new();
537
538 // For now, return a simple mock implementation
539 // In a real system, this would query actual node availability
540 if self.resource_availability.active_nodes > 0 {
541 suitable_nodes.push(NodeAssignment {
542 node_id: "mock_node_1".to_string(),
543 resource_portion: 1.0,
544 role: NodeRole::Primary,
545 expected_performance: NodePerformance {
546 uptime_percentage: 99.5,
547 response_time_ms: 50,
548 throughput_mbps: 100.0,
549 reliability_score: 0.95,
550 },
551 });
552 }
553
554 Ok(suitable_nodes)
555 }
556
557 /// Create the resource allocation details
558 fn create_resource_allocation(
559 &self,
560 request: &AllocationRequest,
561 nodes: &[NodeAssignment],
562 eligibility: &AllocationEligibility,
563 ) -> Result<AllocatedResources> {
564
565 Ok(AllocatedResources {
566 resource_type: request.resource_type.clone(),
567 amount_allocated: match &request.resource_type {
568 ResourceType::Storage { size_gb, .. } => *size_gb,
569 ResourceType::Bandwidth { mbps, .. } => *mbps,
570 ResourceType::Compute { cpu_cores, .. } => *cpu_cores as u64,
571 ResourceType::Network { connections, .. } => *connections as u64,
572 },
573 quality_level: eligibility.quality_level.clone(),
574 assigned_nodes: nodes.to_vec(),
575 estimated_performance: PerformanceEstimate {
576 expected_throughput_mbps: 100.0,
577 expected_latency_ms: 50,
578 expected_availability_percent: 99.5,
579 confidence_level: 0.9,
580 },
581 sla_commitments: SLACommitments {
582 uptime_guarantee: match eligibility.quality_level {
583 AllocationQuality::Basic => 95.0,
584 AllocationQuality::Standard => 99.0,
585 AllocationQuality::Premium => 99.5,
586 AllocationQuality::Enterprise => 99.9,
587 },
588 performance_guarantee: PerformanceGuarantee {
589 min_throughput_mbps: 10.0,
590 max_latency_ms: 100,
591 response_time_percentile: PercentileGuarantee {
592 p50_latency_ms: 50,
593 p95_latency_ms: 100,
594 p99_latency_ms: 200,
595 },
596 },
597 data_durability: 99.999,
598 support_level: match eligibility.quality_level {
599 AllocationQuality::Basic => SupportLevel::Community,
600 AllocationQuality::Standard => SupportLevel::Standard,
601 AllocationQuality::Premium => SupportLevel::Premium,
602 AllocationQuality::Enterprise => SupportLevel::Enterprise,
603 },
604 },
605 })
606 }
607
608 /// Update allocation performance metrics
609 fn update_allocation_metrics(&mut self, decision: &AllocationDecision, start_time: DateTime<Utc>) {
610 self.performance_metrics.total_requests += 1;
611
612 match decision.decision {
613 AllocationOutcome::Approved | AllocationOutcome::PartiallyApproved => {
614 self.performance_metrics.approved_requests += 1;
615 },
616 AllocationOutcome::Denied => {
617 self.performance_metrics.denied_requests += 1;
618 },
619 _ => {}
620 }
621
622 let processing_time_ms = (Utc::now() - start_time).num_milliseconds() as u32;
623
624 // Update running average
625 let total_requests = self.performance_metrics.total_requests;
626 let current_avg = self.performance_metrics.average_processing_time_ms;
627 self.performance_metrics.average_processing_time_ms =
628 ((current_avg as u64 * (total_requests - 1)) + processing_time_ms as u64) as u32 / total_requests as u32;
629
630 self.performance_metrics.last_calculated = Utc::now();
631 }
632
633 /// Record allocation in history
634 fn record_allocation_history(&mut self, request: &AllocationRequest, decision: &AllocationDecision, start_time: DateTime<Utc>) {
635 let amount_allocated = decision.allocated_resources.as_ref()
636 .map(|r| r.amount_allocated)
637 .unwrap_or(0);
638
639 let record = HistoricalAllocation {
640 timestamp: start_time,
641 user_id: request.user_id.clone(),
642 resource_type: request.resource_type.clone(),
643 amount_requested: match &request.resource_type {
644 ResourceType::Storage { size_gb, .. } => *size_gb,
645 ResourceType::Bandwidth { mbps, .. } => *mbps,
646 ResourceType::Compute { cpu_cores, .. } => *cpu_cores as u64,
647 ResourceType::Network { connections, .. } => *connections as u64,
648 },
649 amount_allocated,
650 decision: decision.decision.clone(),
651 contribution_score: decision.contribution_score_used,
652 processing_time_ms: (decision.decided_at - start_time).num_milliseconds() as u32,
653 };
654
655 self.allocation_history.push_back(record);
656
657 // Keep only recent history
658 if self.allocation_history.len() > 10000 {
659 self.allocation_history.pop_front();
660 }
661 }
662
663 /// Get allocation statistics
664 pub fn get_allocation_stats(&self) -> &AllocationMetrics {
665 &self.performance_metrics
666 }
667
668 /// Get resource availability
669 pub fn get_resource_availability(&self) -> &ResourceAvailability {
670 &self.resource_availability
671 }
672 }
673
674 #[derive(Debug, Clone)]
675 struct AllocationEligibility {
676 eligible: bool,
677 max_allocation_gb: u64,
678 quality_level: AllocationQuality,
679 reason: String,
680 }
681
682 impl Default for ContributionBasedAllocator {
683 fn default() -> Self {
684 Self::new()
685 }
686 }