1use std::sync::Arc;
2use std::sync::atomic::{AtomicU32, Ordering};
3use tracing::debug;
4
5use crate::constants;
6use crate::selector::server_stat_man::ServerStatMan;
7use crate::selector::uri_selector::UriSelector;
8
9#[derive(Debug, Clone, PartialEq)]
10pub enum SegmentStatus {
11 Pending,
12 Downloading,
13 Done,
14 Failed,
15}
16
17#[derive(Debug)]
18pub struct Segment {
19 pub index: u32,
20 pub offset: u64,
21 pub length: u64,
22 pub status: SegmentStatus,
23 pub data: Option<bytes::Bytes>, pub assigned_mirror: Option<usize>,
25 pub retry_count: u32,
26}
27
28impl Segment {
29 fn new(index: u32, offset: u64, length: u64) -> Self {
30 Self {
31 index,
32 offset,
33 length,
34 status: SegmentStatus::Pending,
35 data: None,
36 assigned_mirror: None,
37 retry_count: 0,
38 }
39 }
40}
41
42#[derive(Debug)]
43pub struct MirrorState {
44 pub url: String,
45 pub speed: f64,
46 pub active_segments: usize,
47 pub max_connections: usize,
48 pub consecutive_failures: usize,
49 pub disabled: bool,
50}
51
52impl MirrorState {
53 fn new(url: String) -> Self {
54 Self {
55 url,
56 speed: 0.0,
57 active_segments: 0,
58 max_connections: constants::DEFAULT_MAX_CONNECTIONS_PER_MIRROR,
59 consecutive_failures: 0,
60 disabled: false,
61 }
62 }
63
64 pub fn is_available(&self) -> bool {
65 !self.disabled && self.active_segments < self.max_connections
66 }
67
68 pub fn can_accept_more(&self) -> bool {
69 !self.disabled && self.active_segments < self.max_connections
70 }
71}
72
73pub struct ConcurrentSegmentManager {
74 total_size: u64,
75 segments: Vec<Segment>,
76 mirrors: Vec<MirrorState>,
77 mirror_urls: Vec<String>,
79 completed_bytes: u64,
80 max_retries_per_segment: u32,
81 max_mirror_failures: usize,
82 stat_man: Option<Arc<ServerStatMan>>,
84 uri_selector: Option<Box<dyn UriSelector>>,
86 next_segment_idx: AtomicU32,
94}
95
96impl ConcurrentSegmentManager {
97 pub fn new(total_size: u64, urls: Vec<String>, segment_size: Option<u64>) -> Self {
103 let seg_size = segment_size.unwrap_or(constants::DEFAULT_SEGMENT_SIZE as u64);
104 let num_segments = if total_size == 0 {
105 0
106 } else {
107 total_size.div_ceil(seg_size) as usize
108 };
109
110 let mut segments = Vec::with_capacity(num_segments);
111 for i in 0..num_segments {
112 let offset = (i as u64) * seg_size;
113 let remaining = total_size.saturating_sub(offset);
114 let length = seg_size.min(remaining);
115 segments.push(Segment::new(i as u32, offset, length));
116 }
117
118 let mirrors = urls.iter().cloned().map(MirrorState::new).collect();
119
120 Self {
121 total_size,
122 segments,
123 mirrors,
124 mirror_urls: urls,
125 completed_bytes: 0,
126 max_retries_per_segment: constants::MAX_RETRIES_PER_SEGMENT,
127 max_mirror_failures: constants::MAX_MIRROR_FAILURES as usize,
128 stat_man: None,
129 uri_selector: None,
130 next_segment_idx: AtomicU32::new(0),
131 }
132 }
133
134 pub fn new_with_selector(
168 total_size: u64,
169 urls: Vec<String>,
170 segment_size: Option<u64>,
171 stat_man: Arc<ServerStatMan>,
172 uri_selector: Box<dyn UriSelector>,
173 ) -> Self {
174 let seg_size = segment_size.unwrap_or(constants::DEFAULT_SEGMENT_SIZE as u64);
175 let num_segments = if total_size == 0 {
176 0
177 } else {
178 total_size.div_ceil(seg_size) as usize
179 };
180
181 let mut segments = Vec::with_capacity(num_segments);
182 for i in 0..num_segments {
183 let offset = (i as u64) * seg_size;
184 let remaining = total_size.saturating_sub(offset);
185 let length = seg_size.min(remaining);
186 segments.push(Segment::new(i as u32, offset, length));
187 }
188
189 let mirrors = urls.iter().cloned().map(MirrorState::new).collect();
190
191 Self {
192 total_size,
193 segments,
194 mirrors,
195 mirror_urls: urls,
196 completed_bytes: 0,
197 max_retries_per_segment: constants::MAX_RETRIES_PER_SEGMENT,
198 max_mirror_failures: constants::MAX_MIRROR_FAILURES as usize,
199 stat_man: Some(stat_man),
200 uri_selector: Some(uri_selector),
201 next_segment_idx: AtomicU32::new(0),
202 }
203 }
204
205 pub fn allocate_segments(&mut self) {
206 for mirror_idx in 0..self.mirrors.len() {
207 while self.mirrors[mirror_idx].can_accept_more() {
208 if let Some(seg) = self.find_pending_segment() {
209 seg.status = SegmentStatus::Downloading;
210 seg.assigned_mirror = Some(mirror_idx);
211 self.mirrors[mirror_idx].active_segments += 1;
212 } else {
213 break;
214 }
215 }
216 }
217 }
218
219 fn find_pending_segment(&mut self) -> Option<&mut Segment> {
220 let len = self.segments.len();
221 if len == 0 {
222 return None;
223 }
224 let start = (self.next_segment_idx.load(Ordering::Relaxed) as usize) % len;
227 for i in 0..len {
228 let idx = (start + i) % len;
229 if self.segments[idx].status == SegmentStatus::Pending {
230 self.next_segment_idx
233 .store((idx + 1) as u32, Ordering::Relaxed);
234 return Some(&mut self.segments[idx]);
235 }
236 }
237 None
238 }
239
240 pub fn next_pending_segment_for_mirror(
241 &mut self,
242 mirror_idx: usize,
243 ) -> Option<(u32, u64, u64)> {
244 if !self
245 .mirrors
246 .get(mirror_idx)
247 .is_some_and(|m| m.can_accept_more())
248 {
249 return None;
250 }
251
252 let len = self.segments.len();
253 if len == 0 {
254 return None;
255 }
256 let start = (self.next_segment_idx.load(Ordering::Relaxed) as usize) % len;
260 for i in 0..len {
261 let idx = (start + i) % len;
262 let seg = &mut self.segments[idx];
263 if seg.status == SegmentStatus::Pending {
264 seg.status = SegmentStatus::Downloading;
265 seg.assigned_mirror = Some(mirror_idx);
266 self.next_segment_idx
267 .store((idx + 1) as u32, Ordering::Relaxed);
268 if let Some(m) = self.mirrors.get_mut(mirror_idx) {
269 m.active_segments += 1;
270 }
271 return Some((seg.index, seg.offset, seg.length));
272 }
273 }
274 None
275 }
276
277 pub fn next_pending_segment(&mut self) -> Option<(u32, u64, u64)> {
278 self.next_pending_segment_for_mirror(0)
279 }
280
281 pub fn allocate_next_index(&self) -> Option<u32> {
297 let idx = self.next_segment_idx.fetch_add(1, Ordering::Relaxed);
298 if (idx as usize) < self.segments.len() {
299 Some(idx)
300 } else {
301 None
302 }
303 }
304
305 pub fn reset_allocation_index(&self) {
316 self.next_segment_idx.store(0, Ordering::Relaxed);
317 }
318
319 pub fn complete_segment(&mut self, index: u32, data: bytes::Bytes) -> bool {
320 if let Some(seg) = self.segments.get_mut(index as usize) {
321 seg.status = SegmentStatus::Done;
322 seg.data = Some(data);
323
324 if let Some(mi) = seg.assigned_mirror
325 && let Some(m) = self.mirrors.get_mut(mi)
326 {
327 m.active_segments = m.active_segments.saturating_sub(1);
328 m.consecutive_failures = 0;
329 }
330
331 self.completed_bytes += seg.length;
332 true
333 } else {
334 false
335 }
336 }
337
338 pub fn fail_segment(&mut self, index: u32) -> Option<usize> {
339 let (prev_mirror, new_retry) = {
340 let seg = self.segments.get(index as usize)?;
341 (seg.assigned_mirror, seg.retry_count + 1)
342 };
343
344 if let Some(mi) = prev_mirror
345 && let Some(m) = self.mirrors.get_mut(mi)
346 {
347 m.active_segments = m.active_segments.saturating_sub(1);
348 m.consecutive_failures += 1;
349 if m.consecutive_failures >= self.max_mirror_failures {
350 m.disabled = true;
351 }
352 }
353
354 if new_retry >= self.max_retries_per_segment {
355 if let Some(seg) = self.segments.get_mut(index as usize) {
356 seg.status = SegmentStatus::Failed;
357 seg.retry_count = new_retry;
358 }
359 None
360 } else {
361 let reassign = self.find_available_mirror_for_reassignment(prev_mirror.unwrap_or(0));
362 if let Some(seg) = self.segments.get_mut(index as usize) {
363 seg.status = SegmentStatus::Pending;
364 seg.assigned_mirror = reassign;
365 seg.retry_count = new_retry;
366 }
367 reassign
368 }
369 }
370
371 fn find_available_mirror_for_reassignment(&self, exclude: usize) -> Option<usize> {
372 self.mirrors
373 .iter()
374 .enumerate()
375 .filter(|(i, m)| *i != exclude && m.is_available())
376 .map(|(i, _)| i)
377 .next()
378 }
379
380 pub fn is_complete(&self) -> bool {
381 self.segments
382 .iter()
383 .all(|s| s.status == SegmentStatus::Done)
384 }
385
386 pub fn has_failed_segments(&self) -> bool {
387 self.segments
388 .iter()
389 .any(|s| s.status == SegmentStatus::Failed)
390 }
391
392 pub fn has_pending_segments(&self) -> bool {
393 self.segments
394 .iter()
395 .any(|s| s.status == SegmentStatus::Pending)
396 }
397
398 pub fn assemble(&self) -> Option<Vec<u8>> {
399 if !self.is_complete() || self.total_size == 0 {
400 return None;
401 }
402
403 let mut result = Vec::with_capacity(self.total_size as usize);
404 for seg in &self.segments {
405 let data = seg.data.as_ref()?;
406 result.extend_from_slice(data);
407 }
408 Some(result)
409 }
410
411 pub fn progress(&self) -> f64 {
412 if self.total_size == 0 {
413 return 100.0;
414 }
415 let done = self
416 .segments
417 .iter()
418 .filter(|s| s.status == SegmentStatus::Done)
419 .count();
420 done as f64 / self.segments.len() as f64 * 100.0
421 }
422
423 pub fn num_segments(&self) -> usize {
424 self.segments.len()
425 }
426 pub fn segment_status(&self, index: usize) -> Option<SegmentStatus> {
427 self.segments.get(index).map(|s| s.status.clone())
428 }
429 pub fn num_mirrors(&self) -> usize {
430 self.mirrors.len()
431 }
432 pub fn total_size(&self) -> u64 {
433 self.total_size
434 }
435 pub fn completed_bytes(&self) -> u64 {
436 self.completed_bytes
437 }
438
439 pub fn mirror_url(&self, index: usize) -> Option<&str> {
440 self.mirrors.get(index).map(|m| m.url.as_str())
441 }
442
443 pub fn available_mirrors(&self) -> Vec<usize> {
444 self.mirrors
445 .iter()
446 .enumerate()
447 .filter(|(_, m)| m.is_available())
448 .map(|(i, _)| i)
449 .collect()
450 }
451
452 pub fn any_mirror_available(&self) -> bool {
453 self.mirrors.iter().any(|m| m.is_available())
454 }
455
456 pub fn set_max_connections_per_mirror(&mut self, max: usize) {
457 for m in &mut self.mirrors {
458 m.max_connections = max;
459 }
460 }
461
462 pub fn set_mirror_max_connections(&mut self, mirror_idx: usize, max: usize) {
471 if let Some(mirror) = self.mirrors.get_mut(mirror_idx) {
472 mirror.max_connections = max;
473 }
474 }
475
476 pub fn get_mirror_max_connections(&self, mirror_idx: usize) -> Option<usize> {
482 self.mirrors.get(mirror_idx).map(|m| m.max_connections)
483 }
484
485 pub fn set_max_retries(&mut self, retries: u32) {
486 self.max_retries_per_segment = retries;
487 }
488
489 pub fn segment_retry_count(&self, seg_idx: u32) -> u32 {
490 self.segments
491 .iter()
492 .find(|s| s.index == seg_idx)
493 .map(|s| s.retry_count)
494 .unwrap_or(0)
495 }
496
497 pub fn has_permanently_failed_segments(&self) -> bool {
498 self.segments.iter().any(|s| {
499 s.status == SegmentStatus::Failed && s.retry_count >= self.max_retries_per_segment
500 })
501 }
502
503 pub fn mark_completed_up_to(&mut self, offset: u64, length: u64) {
504 let end_offset = offset + length;
505 for segment in &mut self.segments {
506 if segment.offset + segment.length <= offset {
507 if segment.status != SegmentStatus::Done {
508 segment.status = SegmentStatus::Done;
509 self.completed_bytes += segment.length;
510 }
511 } else if segment.offset < end_offset {
512 let overlap_start = std::cmp::max(segment.offset, offset);
513 let overlap_end = std::cmp::min(segment.offset + segment.length, end_offset);
514 if overlap_end > overlap_start {
515 debug!(
516 "段 {} 部分已完成: {}/{} bytes",
517 segment.index,
518 overlap_end - segment.offset,
519 segment.length
520 );
521 }
522 }
523 }
524 }
525
526 pub fn segment_info(&self, index: usize) -> Option<(u64, u64, &SegmentStatus)> {
527 self.segments
528 .get(index)
529 .map(|s| (s.offset, s.length, &s.status))
530 }
531
532 pub fn select_mirror_for_next_segment(&mut self) -> Option<(usize, (u32, u64, u64))> {
545 let pending_seg = self
547 .segments
548 .iter()
549 .find(|s| s.status == SegmentStatus::Pending)?;
550
551 let seg_index = pending_seg.index;
552
553 if let Some(ref selector) = self.uri_selector {
555 let used_hosts: Vec<(usize, String)> = self
557 .segments
558 .iter()
559 .filter(|s| s.status == SegmentStatus::Downloading)
560 .filter_map(|s| {
561 s.assigned_mirror.and_then(|idx| {
562 self.mirror_urls.get(idx).map(|url| {
563 let host = extract_host_from_url(url);
565 (idx, host)
566 })
567 })
568 })
569 .collect();
570
571 if let Some(mirror_idx) = selector.select(&self.mirror_urls, &used_hosts) {
573 if self
575 .mirrors
576 .get(mirror_idx)
577 .is_some_and(|m| m.can_accept_more())
578 {
579 if let Some(seg) = self.segments.get_mut(seg_index as usize) {
581 seg.status = SegmentStatus::Downloading;
582 seg.assigned_mirror = Some(mirror_idx);
583 if let Some(m) = self.mirrors.get_mut(mirror_idx) {
584 m.active_segments += 1;
585 }
586 return Some((mirror_idx, (seg.index, seg.offset, seg.length)));
587 }
588 }
589 }
590 }
591
592 for mirror_idx in 0..self.mirrors.len() {
594 if self.mirrors[mirror_idx].can_accept_more()
595 && let Some(seg) = self.segments.get_mut(seg_index as usize)
596 {
597 seg.status = SegmentStatus::Downloading;
598 seg.assigned_mirror = Some(mirror_idx);
599 self.mirrors[mirror_idx].active_segments += 1;
600 return Some((mirror_idx, (seg.index, seg.offset, seg.length)));
601 }
602 }
603
604 None
605 }
606
607 pub fn report_segment_complete(
624 &mut self,
625 seg_idx: u32,
626 data: bytes::Bytes,
627 bytes_per_sec: u64,
628 is_multi_connection: bool,
629 ) -> bool {
630 let mirror_idx = self
632 .segments
633 .get(seg_idx as usize)
634 .and_then(|s| s.assigned_mirror);
635
636 let success = self.complete_segment(seg_idx, data);
638
639 if success {
641 if let (Some(idx), Some(stat_man)) = (mirror_idx, &self.stat_man)
642 && let Some(url) = self.mirror_urls.get(idx)
643 {
644 let host = extract_host_from_url(url);
645 stat_man.update(&host, bytes_per_sec, is_multi_connection);
646
647 if let Some(stat) = stat_man.find_stat(&host) {
649 stat.reset_status();
650 }
651 }
652
653 if let Some(ref selector) = self.uri_selector {
655 selector.tune_command(&self.mirror_urls, bytes_per_sec);
656 }
657 }
658
659 success
660 }
661
662 pub fn report_segment_failed(&mut self, seg_idx: u32, error_code: u16) -> Option<usize> {
678 let mirror_idx = self
680 .segments
681 .get(seg_idx as usize)
682 .and_then(|s| s.assigned_mirror);
683
684 let reassign = self.fail_segment(seg_idx);
686
687 if let (Some(idx), Some(stat_man)) = (mirror_idx, &self.stat_man)
689 && let Some(url) = self.mirror_urls.get(idx)
690 {
691 let host = extract_host_from_url(url);
692 stat_man.get_or_create(&host);
694 stat_man.mark_failure(&host, error_code);
695
696 if let Some(stat) = stat_man.find_stat(&host)
698 && !stat.is_available()
699 {
700 if let Some(m) = self.mirrors.get_mut(idx) {
702 m.disabled = true;
703 }
704 }
705 }
706
707 reassign
708 }
709
710 pub fn get_mirror_url(&self, mirror_idx: usize) -> Option<&str> {
712 self.mirror_urls.get(mirror_idx).map(|s| s.as_str())
713 }
714
715 pub fn mirror_active_segments(&self, mirror_idx: usize) -> usize {
717 self.mirrors
718 .get(mirror_idx)
719 .map(|m| m.active_segments)
720 .unwrap_or(0)
721 }
722
723 pub fn has_intelligent_selection(&self) -> bool {
725 self.uri_selector.is_some() && self.stat_man.is_some()
726 }
727}
728
729fn extract_host_from_url(url: &str) -> String {
731 let url = url.trim();
732 if !url.contains("://") {
733 return url.to_string();
734 }
735 let after_scheme = &url[url.find("://").unwrap() + 3..];
736 let host_part = if let Some(slash_idx) = after_scheme.find('/') {
737 &after_scheme[..slash_idx]
738 } else {
739 after_scheme
740 };
741 host_part.to_string()
742}
743
744#[cfg(test)]
745mod tests {
746 use super::*;
747
748 #[test]
749 fn test_manager_creation_small_file() {
750 let mgr = ConcurrentSegmentManager::new(1024, vec!["http://a.com/f".to_string()], None);
751 assert_eq!(mgr.num_segments(), 1);
752 assert_eq!(mgr.num_mirrors(), 1);
753 assert_eq!(mgr.total_size(), 1024);
754 assert!(!mgr.is_complete());
755 assert!(mgr.has_pending_segments());
756 }
757
758 #[test]
759 fn test_manager_large_file_multi_segment() {
760 let mgr = ConcurrentSegmentManager::new(
761 3_000_000,
762 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
763 Some(1_000_000),
764 );
765 assert_eq!(mgr.num_segments(), 3);
766 assert_eq!(mgr.num_mirrors(), 2);
767 }
768
769 #[test]
770 fn test_allocate_segments_round_robin() {
771 let mut mgr = ConcurrentSegmentManager::new(
772 3_000_000,
773 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
774 Some(1_000_000),
775 );
776
777 mgr.allocate_segments();
778
779 let assigned_a: Vec<_> = mgr
780 .segments
781 .iter()
782 .filter(|s| s.assigned_mirror == Some(0))
783 .map(|s| s.index)
784 .collect();
785 let assigned_b: Vec<_> = mgr
786 .segments
787 .iter()
788 .filter(|s| s.assigned_mirror == Some(1))
789 .map(|s| s.index)
790 .collect();
791
792 assert!(!assigned_a.is_empty());
793 assert!(!assigned_b.is_empty());
794 assert_eq!(assigned_a.len() + assigned_b.len(), 3);
795 }
796
797 #[test]
798 fn test_complete_and_assemble() {
799 let mut mgr =
800 ConcurrentSegmentManager::new(200, vec!["http://x.com/f".to_string()], Some(100));
801
802 mgr.allocate_segments();
803 assert_eq!(mgr.progress(), 0.0);
804
805 mgr.complete_segment(0, bytes::Bytes::from(vec![0xAB; 100]));
806 assert!(!mgr.is_complete());
807 assert!((mgr.progress() - 50.0).abs() < 0.01);
808
809 mgr.complete_segment(1, bytes::Bytes::from(vec![0xCD; 100]));
810 assert!(mgr.is_complete());
811 assert!((mgr.progress() - 100.0).abs() < 0.01);
812
813 let assembled = mgr.assemble().unwrap();
814 assert_eq!(assembled.len(), 200);
815 assert_eq!(&assembled[..100], &[0xAB; 100][..]);
816 assert_eq!(&assembled[100..], &[0xCD; 100][..]);
817 }
818
819 #[test]
820 fn test_fail_and_reassign() {
821 let mut mgr = ConcurrentSegmentManager::new(
822 200,
823 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
824 Some(100),
825 );
826
827 mgr.allocate_segments();
828
829 let reassign = mgr.fail_segment(0);
830 assert!(reassign.is_some());
831
832 let seg = &mgr.segments[0];
833 assert_eq!(seg.status, SegmentStatus::Pending);
834 assert_eq!(seg.assigned_mirror, reassign);
835 assert_eq!(seg.retry_count, 1);
836 }
837
838 #[test]
839 fn test_max_retries_exhausted() {
840 let mut mgr =
841 ConcurrentSegmentManager::new(100, vec!["http://a.com/f".to_string()], Some(100));
842 mgr.set_max_retries(2);
843
844 mgr.fail_segment(0);
845 assert!(mgr.has_pending_segments());
846
847 mgr.fail_segment(0);
848 assert!(mgr.has_failed_segments());
849 assert!(!mgr.has_pending_segments());
850 }
851
852 #[test]
853 fn test_empty_file() {
854 let mgr = ConcurrentSegmentManager::new(0, vec!["http://x.com/f".to_string()], None);
855 assert_eq!(mgr.num_segments(), 0);
856 assert!(mgr.is_complete());
857 assert!(mgr.assemble().is_none());
858 }
859
860 #[test]
861 fn test_next_pending_for_specific_mirror() {
862 let mut mgr = ConcurrentSegmentManager::new(
863 300,
864 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
865 Some(100),
866 );
867
868 let r = mgr.next_pending_segment_for_mirror(0);
869 assert!(r.is_some());
870 let (idx, off, len) = r.unwrap();
871 assert_eq!(idx, 0);
872 assert_eq!(off, 0);
873 assert_eq!(len, 100);
874
875 let r2 = mgr.next_pending_segment_for_mirror(1);
876 assert!(r2.is_some());
877 let (idx2, _, _) = r2.unwrap();
878 assert_eq!(idx2, 1);
879 }
880
881 #[test]
886 fn test_new_with_selector() {
887 use crate::selector::adaptive_uri_selector::AdaptiveUriSelector;
888
889 let stat_man = Arc::new(ServerStatMan::new());
890 let urls = vec![
891 "http://mirror1.com/file".to_string(),
892 "http://mirror2.com/file".to_string(),
893 ];
894 let selector = Box::new(AdaptiveUriSelector::new_with_uris(
895 Arc::clone(&stat_man),
896 urls.clone(),
897 ));
898
899 let mgr = ConcurrentSegmentManager::new_with_selector(
900 1_000_000,
901 urls,
902 Some(500_000),
903 stat_man,
904 selector,
905 );
906
907 assert_eq!(mgr.num_segments(), 2);
908 assert_eq!(mgr.num_mirrors(), 2);
909 assert!(mgr.has_intelligent_selection());
910 }
911
912 #[test]
913 fn test_select_mirror_for_next_segment_without_selector() {
914 let mut mgr = ConcurrentSegmentManager::new(
915 300,
916 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
917 Some(100),
918 );
919
920 let result = mgr.select_mirror_for_next_segment();
922 assert!(result.is_some());
923
924 let (mirror_idx, (seg_idx, offset, len)) = result.unwrap();
925 assert_eq!(seg_idx, 0);
926 assert_eq!(offset, 0);
927 assert_eq!(len, 100);
928 assert!(mirror_idx < 2);
929 }
930
931 #[test]
932 fn test_select_mirror_for_next_segment_with_selector() {
933 use crate::selector::adaptive_uri_selector::AdaptiveUriSelector;
934
935 let stat_man = Arc::new(ServerStatMan::new());
936 let urls = vec![
937 "http://fast.com/f".to_string(),
938 "http://slow.com/f".to_string(),
939 ];
940
941 stat_man.update("fast.com", 1_000_000, false);
943 stat_man.update("slow.com", 1000, false);
944 let fast_stat = stat_man.find_stat("fast.com").unwrap();
945 fast_stat.increment_counter();
946 let slow_stat = stat_man.find_stat("slow.com").unwrap();
947 slow_stat.increment_counter();
948
949 let selector = Box::new(AdaptiveUriSelector::new_with_uris(
950 Arc::clone(&stat_man),
951 urls.clone(),
952 ));
953
954 let mut mgr =
955 ConcurrentSegmentManager::new_with_selector(300, urls, Some(100), stat_man, selector);
956
957 let result = mgr.select_mirror_for_next_segment();
958 assert!(result.is_some());
959
960 let (mirror_idx, _) = result.unwrap();
961 assert_eq!(mirror_idx, 0);
963 }
964
965 #[test]
966 fn test_report_segment_complete_updates_stats() {
967 use crate::selector::adaptive_uri_selector::AdaptiveUriSelector;
968
969 let stat_man = Arc::new(ServerStatMan::new());
970 let urls = vec!["http://test.mirror.com/f".to_string()];
971
972 let selector = Box::new(AdaptiveUriSelector::new_with_uris(
973 Arc::clone(&stat_man),
974 urls.clone(),
975 ));
976
977 let mut mgr = ConcurrentSegmentManager::new_with_selector(
978 100,
979 urls,
980 Some(100),
981 stat_man.clone(),
982 selector,
983 );
984
985 mgr.allocate_segments();
986
987 let success =
989 mgr.report_segment_complete(0, bytes::Bytes::from(vec![0xAB; 100]), 1_000_000, false);
990 assert!(success);
991
992 let stat = stat_man.find_stat("test.mirror.com").unwrap();
994 assert!(stat.get_download_speed() > 0);
995 }
996
997 #[test]
998 fn test_report_segment_failed_updates_stats() {
999 use crate::selector::adaptive_uri_selector::AdaptiveUriSelector;
1000
1001 let stat_man = Arc::new(ServerStatMan::new());
1002 let urls = vec![
1003 "http://failing.mirror.com/f".to_string(),
1004 "http://backup.mirror.com/f".to_string(),
1005 ];
1006
1007 let selector = Box::new(AdaptiveUriSelector::new_with_uris(
1008 Arc::clone(&stat_man),
1009 urls.clone(),
1010 ));
1011
1012 let mut mgr = ConcurrentSegmentManager::new_with_selector(
1013 100,
1014 urls,
1015 Some(100),
1016 stat_man.clone(),
1017 selector,
1018 );
1019
1020 mgr.allocate_segments();
1021
1022 let reassign = mgr.report_segment_failed(0, 503);
1024 assert!(reassign.is_some());
1025
1026 let stat = stat_man.find_stat("failing.mirror.com").unwrap();
1028 assert_eq!(stat.get_consecutive_failures(), 1);
1029 assert_eq!(stat.get_last_error_code(), 503);
1030 }
1031
1032 #[test]
1033 fn test_extract_host_from_url() {
1034 assert_eq!(
1035 extract_host_from_url("http://example.com/path"),
1036 "example.com"
1037 );
1038 assert_eq!(
1039 extract_host_from_url("https://host:8080/file?q=1"),
1040 "host:8080"
1041 );
1042 assert_eq!(extract_host_from_url("ftp://server.com"), "server.com");
1043 assert_eq!(extract_host_from_url("not-a-url"), "not-a-url");
1044 }
1045
1046 #[test]
1047 fn test_get_mirror_url() {
1048 let mgr = ConcurrentSegmentManager::new(
1049 100,
1050 vec!["http://a.com/f".to_string(), "http://b.com/f".to_string()],
1051 Some(100),
1052 );
1053
1054 assert_eq!(mgr.get_mirror_url(0), Some("http://a.com/f"));
1055 assert_eq!(mgr.get_mirror_url(1), Some("http://b.com/f"));
1056 assert_eq!(mgr.get_mirror_url(999), None);
1057 }
1058
1059 #[test]
1060 fn test_mirror_active_segments() {
1061 let mut mgr =
1062 ConcurrentSegmentManager::new(300, vec!["http://a.com/f".to_string()], Some(100));
1063
1064 assert_eq!(mgr.mirror_active_segments(0), 0);
1065 assert_eq!(mgr.num_segments(), 3);
1066
1067 mgr.set_max_connections_per_mirror(3);
1069
1070 mgr.allocate_segments();
1071 assert_eq!(mgr.mirror_active_segments(0), 3);
1073 }
1074
1075 #[test]
1076 fn test_no_intelligent_selection_by_default() {
1077 let mgr = ConcurrentSegmentManager::new(100, vec!["http://a.com/f".to_string()], Some(100));
1078
1079 assert!(!mgr.has_intelligent_selection());
1080 }
1081
1082 #[tokio::test(flavor = "multi_thread", worker_threads = 16)]
1094 async fn test_segment_allocation_is_lock_free() {
1095 use std::collections::HashSet;
1096
1097 let manager = Arc::new(ConcurrentSegmentManager::new(
1099 16000,
1100 vec!["http://test".into()],
1101 Some(1),
1102 ));
1103 assert_eq!(manager.num_segments(), 16000);
1104
1105 let collected: Arc<tokio::sync::Mutex<Vec<u32>>> =
1106 Arc::new(tokio::sync::Mutex::new(Vec::new()));
1107
1108 let mut handles = Vec::with_capacity(16);
1109 for _ in 0..16 {
1110 let m = manager.clone();
1111 let c = collected.clone();
1112 handles.push(tokio::spawn(async move {
1113 let mut local = Vec::with_capacity(1000);
1115 for _ in 0..1000 {
1116 if let Some(idx) = m.allocate_next_index() {
1117 local.push(idx);
1118 }
1119 }
1120 c.lock().await.extend(local);
1121 }));
1122 }
1123
1124 for h in handles {
1125 h.await.unwrap();
1126 }
1127
1128 let indices = collected.lock().await.clone();
1129 assert_eq!(
1130 indices.len(),
1131 16000,
1132 "should have allocated all 16000 segments"
1133 );
1134
1135 let set: HashSet<u32> = indices.iter().copied().collect();
1137 assert_eq!(
1138 set.len(),
1139 16000,
1140 "all indices must be unique (no duplicates)"
1141 );
1142
1143 for i in 0..16000u32 {
1145 assert!(set.contains(&i), "missing index {}", i);
1146 }
1147 }
1148
1149 #[test]
1157 fn test_allocation_hint_advances_and_resets() {
1158 let mut mgr =
1159 ConcurrentSegmentManager::new(500, vec!["http://a.com/f".to_string()], Some(100));
1160 mgr.set_max_connections_per_mirror(10);
1162 assert_eq!(mgr.num_segments(), 5);
1163
1164 let mut claimed = Vec::new();
1168 while let Some((idx, _, _)) = mgr.next_pending_segment_for_mirror(0) {
1169 claimed.push(idx);
1170 }
1171 assert_eq!(claimed, vec![0, 1, 2, 3, 4]);
1172
1173 assert!(mgr.next_pending_segment_for_mirror(0).is_none());
1175
1176 mgr.segments[1].status = SegmentStatus::Pending;
1180 let next = mgr.next_pending_segment_for_mirror(0);
1181 assert!(next.is_some());
1182 assert_eq!(next.unwrap().0, 1);
1183
1184 mgr.reset_allocation_index();
1186 mgr.segments[3].status = SegmentStatus::Pending;
1189 let next = mgr.next_pending_segment_for_mirror(0);
1190 assert!(next.is_some());
1191 assert_eq!(next.unwrap().0, 3);
1192 }
1193}