Skip to main content

stormdl_segment/
splitter.rs

1use std::time::Duration;
2
3#[derive(Debug, Clone, Copy)]
4pub enum SplitStrategy {
5    Static(usize),
6    Adaptive,
7}
8
9pub fn optimal_segments(file_size: u64, measured_bw: f64, rtt: Duration) -> usize {
10    let bdp = measured_bw * rtt.as_secs_f64();
11    let tcp_window = 65536.0;
12    let min_connections = (bdp / tcp_window).ceil() as usize;
13
14    let max_connections = match file_size {
15        0..=1_000_000 => 1,
16        1_000_001..=10_000_000 => 4,
17        10_000_001..=100_000_000 => 8,
18        100_000_001..=1_000_000_000 => 16,
19        _ => 32,
20    };
21
22    min_connections.clamp(1, max_connections)
23}
24
25pub fn initial_segments(file_size: u64) -> usize {
26    match file_size {
27        0..=1_000_000 => 1,
28        1_000_001..=10_000_000 => 4,
29        _ => 8,
30    }
31}
32
33pub fn turbo_segments(file_size: u64) -> usize {
34    match file_size {
35        0..=1_000_000 => 1,
36        1_000_001..=10_000_000 => 8,
37        _ => 16,
38    }
39}
40
41pub fn split_range(total_size: u64, num_segments: usize) -> Vec<stormdl_core::ByteRange> {
42    if num_segments == 0 || total_size == 0 {
43        return vec![];
44    }
45
46    let segment_size = total_size / num_segments as u64;
47    let remainder = total_size % num_segments as u64;
48
49    let mut ranges = Vec::with_capacity(num_segments);
50    let mut offset = 0;
51
52    for i in 0..num_segments {
53        let extra = if i < remainder as usize { 1 } else { 0 };
54        let size = segment_size + extra;
55        ranges.push(stormdl_core::ByteRange::new(offset, offset + size));
56        offset += size;
57    }
58
59    ranges
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65
66    #[test]
67    fn test_split_range_even() {
68        let ranges = split_range(100, 4);
69        assert_eq!(ranges.len(), 4);
70        assert_eq!(ranges[0], stormdl_core::ByteRange::new(0, 25));
71        assert_eq!(ranges[1], stormdl_core::ByteRange::new(25, 50));
72        assert_eq!(ranges[2], stormdl_core::ByteRange::new(50, 75));
73        assert_eq!(ranges[3], stormdl_core::ByteRange::new(75, 100));
74    }
75
76    #[test]
77    fn test_split_range_uneven() {
78        let ranges = split_range(10, 3);
79        assert_eq!(ranges.len(), 3);
80        assert_eq!(ranges[0].len() + ranges[1].len() + ranges[2].len(), 10);
81    }
82}