Skip to main content

cfdp_simplified/daemon/
segments.rs

1use std::cmp::Ordering;
2
3/// Holds a list of disjunctive [start, end) segments covering the received file
4pub struct Segments(Vec<(u64, u64)>);
5
6impl Default for Segments {
7    fn default() -> Self {
8        Self::new()
9    }
10}
11
12impl Segments {
13    pub fn new() -> Self {
14        Segments(Vec::new())
15    }
16
17    // return true if empty, false otherwise
18    pub fn is_empty(&self) -> bool {
19        self.0.is_empty()
20    }
21
22    /// return the number of disjunctive segments
23    pub fn len(&self) -> usize {
24        self.0.len()
25    }
26
27    /// return the end of the last segment or None if there is no segment
28    pub fn end(&self) -> Option<u64> {
29        self.0.last().map(|x| x.1)
30    }
31
32    /// return the end of the last segment or 0 if there is no segment
33    pub fn end_or_0(&self) -> u64 {
34        self.0.last().map(|x| x.1).unwrap_or(0)
35    }
36
37    /// return true if there is only one segment whose end is the given size
38    pub fn is_complete(&self, size: u64) -> bool {
39        self.0.len() == 1 && self.0[0].1 == size
40    }
41
42    /// update the contiguous segment list with the new segment, filling any gap (i.e. unifying segments) if required
43    /// return the number of new bytes added (e.g. if the new segment overlaps completely existing segments, return 0)
44    pub fn merge(&mut self, seg: (u64, u64)) -> u64 {
45        assert!(seg.0 < seg.1, "invalid segment");
46        let v = &mut self.0;
47
48        let len = v.len();
49        if len == 0 {
50            v.push(seg);
51            return seg.1 - seg.0;
52        }
53        let mut newly_received = 0;
54
55        let last = &mut v[len - 1];
56        match last.1.cmp(&seg.0) {
57            Ordering::Equal => {
58                //most probable case - the data fits nicely at the end
59                last.1 = seg.1;
60                newly_received = seg.1 - seg.0;
61            }
62            Ordering::Less => {
63                //the new segment comes at the end of the list after a gap
64                v.push(seg);
65                newly_received = seg.1 - seg.0
66            }
67            Ordering::Greater => {
68                // data fills some gap in the middle, use binary search to find where it should go
69                match v.binary_search_by(|x| x.0.cmp(&seg.0)) {
70                    Ok(k) => {
71                        // the segment starts at the same offset with the segment v[k]
72                        if v[k].1 < seg.1 {
73                            newly_received = seg.1 - v[k].1;
74                            v[k].1 = seg.1;
75                            newly_received -= merge(v, k);
76                        }
77                    }
78                    Err(k) => {
79                        if k == 0 {
80                            //new segment comes right at the beginning of the list
81                            if seg.1 < v[0].0 {
82                                v.insert(0, seg);
83                                newly_received = seg.1 - seg.0;
84                            } else {
85                                //overlapping with the first segment
86                                newly_received = v[0].0 - seg.0;
87                                v[0].0 = seg.0;
88                                if seg.1 > v[0].1 {
89                                    newly_received += seg.1 - v[0].1;
90                                    v[0].1 = seg.1;
91                                    merge(v, 0);
92                                }
93                            }
94                        } else {
95                            //here we know there is an element to the left
96                            if v[k - 1].1 >= seg.0 {
97                                //overlaps with the left
98                                if v[k - 1].1 < seg.1 {
99                                    newly_received = seg.1 - v[k - 1].1;
100                                    v[k - 1].1 = seg.1;
101                                    newly_received -= merge(v, k - 1);
102                                } //else seg is completely embedded in v[k-1]
103                            } else {
104                                //does not overlap with left
105                                //we know there is an element to the right (i.e. k < len),
106                                // otherwise this would be the last in the list and we have tested for that
107                                // in the match Ordering::Less above
108                                if seg.1 < v[k].0 {
109                                    //does not overlap with right either
110                                    v.insert(k, seg);
111                                    newly_received = seg.1 - seg.0;
112                                } else {
113                                    //overlaps with right, we have to extend the right to the left
114                                    newly_received = v[k].0 - seg.0;
115                                    v[k].0 = seg.0;
116                                    if v[k].1 < seg.1 {
117                                        newly_received += seg.1 - v[k].1;
118                                        v[k].1 = seg.1;
119                                        newly_received -= merge(v, k);
120                                    }
121                                }
122                            }
123                        }
124                    }
125                }
126            }
127        }
128
129        newly_received
130    }
131
132    /// return a list of gaps covering the [start, end) interval
133    pub fn gaps(&self, start: u64, end: u64) -> Vec<(u64, u64)> {
134        let v = &self.0;
135
136        let mut gaps = Vec::new();
137
138        let (idx, mut pointer) = match v.binary_search_by(|x| x.0.cmp(&start)) {
139            Ok(k) => (k + 1, v[k].1),
140            Err(k) => (
141                k,
142                if k == 0 {
143                    start
144                } else {
145                    std::cmp::max(v[k - 1].1, start)
146                },
147            ),
148        };
149
150        for (s, e) in &v[idx..] {
151            if *s >= end {
152                gaps.push((pointer, end));
153                pointer = end;
154                break;
155            }
156
157            gaps.push((pointer, *s));
158            pointer = *e;
159
160            if pointer > end {
161                break;
162            }
163        }
164
165        if pointer < end {
166            gaps.push((pointer, end));
167        }
168        gaps
169    }
170}
171
172/// v[k] has been enlarged to the right possibly overlapping with its right segments
173/// this function merges all the overlapping segments reducing the size of the list
174///
175/// return the size of overlapping data
176fn merge(v: &mut Vec<(u64, u64)>, k: usize) -> u64 {
177    // it is very unlikely this will loop more than once so no need to bother removing in bulk
178    let mut overlapping = 0;
179    while k + 1 < v.len() && v[k + 1].0 <= v[k].1 {
180        if v[k + 1].1 > v[k].1 {
181            overlapping += v[k].1 - v[k + 1].0;
182            v[k].1 = v[k + 1].1
183        } else {
184            overlapping += v[k + 1].1 - v[k + 1].0;
185        }
186
187        v.remove(k + 1);
188    }
189
190    overlapping
191}
192
193#[cfg(test)]
194mod test {
195    use super::*;
196
197    #[test]
198    fn test1() {
199        let mut s = Segments::new();
200        assert_eq!(s.gaps(0, 30), vec![(0, 30)]);
201
202        assert_eq!(10, s.merge((0, 10)));
203        assert_eq!(10, s.merge((10, 20)));
204
205        assert_eq!(s.0, vec![(0, 20)]);
206
207        assert_eq!(s.gaps(0, 20), vec![]);
208        assert_eq!(s.gaps(0, 30), vec![(20, 30)]);
209    }
210
211    #[test]
212    fn test2() {
213        let mut s = Segments::new();
214        assert_eq!(10, s.merge((10, 20)));
215
216        assert_eq!(s.gaps(0, 10), vec![(0, 10)]);
217        assert_eq!(s.gaps(0, 15), vec![(0, 10)]);
218        assert_eq!(s.gaps(0, 25), vec![(0, 10), (20, 25)]);
219
220        assert_eq!(10, s.merge((0, 10)));
221
222        assert_eq!(s.0, vec![(0, 20)]);
223    }
224
225    #[test]
226    fn test3() {
227        let mut s = Segments::new();
228
229        assert_eq!(10, s.merge((0, 10)));
230        assert_eq!(10, s.merge((20, 30)));
231        assert_eq!(2, s.len());
232
233        assert_eq!(s.gaps(10, 20), vec![(10, 20)]);
234        assert_eq!(s.gaps(5, 30), vec![(10, 20)]);
235        assert_eq!(s.gaps(5, 35), vec![(10, 20), (30, 35)]);
236
237        assert_eq!(10, s.merge((10, 20)));
238
239        assert_eq!(s.0, vec![(0, 30)]);
240    }
241
242    #[test]
243    fn test4() {
244        let mut s = Segments::new();
245
246        assert_eq!(10, s.merge((0, 10)));
247        assert_eq!(10, s.merge((20, 30)));
248        assert_eq!(2, s.len());
249
250        assert_eq!(3, s.merge((12, 15)));
251
252        assert_eq!(s.0, vec![(0, 10), (12, 15), (20, 30)]);
253    }
254
255    #[test]
256    fn test5() {
257        let mut s = Segments::new();
258
259        assert_eq!(10, s.merge((0, 10)));
260        assert_eq!(10, s.merge((20, 30)));
261        assert_eq!(2, s.len());
262
263        assert_eq!(8, s.merge((12, 20)));
264
265        assert_eq!(s.0, vec![(0, 10), (12, 30)]);
266    }
267
268    #[test]
269    fn test6() {
270        let mut s = Segments::new();
271
272        assert_eq!(10, s.merge((0, 10)));
273        assert_eq!(10, s.merge((0, 20)));
274
275        assert_eq!(s.0, vec![(0, 20)]);
276    }
277
278    #[test]
279    fn test7() {
280        let mut s = Segments::new();
281
282        assert_eq!(10, s.merge((10, 20)));
283        assert_eq!(5, s.merge((0, 5)));
284
285        assert_eq!(s.0, vec![(0, 5), (10, 20)]);
286    }
287
288    #[test]
289    fn test8() {
290        let mut s = Segments::new();
291
292        assert_eq!(10, s.merge((0, 10)));
293        assert_eq!(10, s.merge((20, 30)));
294        assert_eq!(5, s.merge((10, 15)));
295
296        assert_eq!(s.0, vec![(0, 15), (20, 30)]);
297    }
298
299    #[test]
300    fn test9() {
301        let mut s = Segments::new();
302
303        assert_eq!(30, s.merge((0, 30)));
304        assert_eq!(0, s.merge((10, 20)));
305
306        assert_eq!(s.0, vec![(0, 30)]);
307    }
308
309    //these are the weird cases where a segment larger than the previous ones comes in
310
311    #[test]
312    fn test10() {
313        let mut s = Segments::new();
314
315        assert_eq!(10, s.merge((0, 10)));
316        assert_eq!(10, s.merge((0, 20)));
317        assert_eq!(s.0, vec![(0, 20)]);
318
319        assert_eq!(0, s.merge((10, 15)));
320
321        assert_eq!(s.0, vec![(0, 20)]);
322    }
323
324    #[test]
325    fn test11() {
326        let mut s = Segments::new();
327
328        assert_eq!(10, s.merge((0, 10)));
329        assert_eq!(10, s.merge((20, 30)));
330        assert_eq!(10, s.merge((40, 50)));
331
332        assert_eq!(s.0, vec![(0, 10), (20, 30), (40, 50)]);
333
334        assert_eq!(20, s.merge((5, 45)));
335
336        assert_eq!(s.0, vec![(0, 50)]);
337    }
338
339    #[test]
340    fn test12() {
341        let mut s = Segments::new();
342
343        assert_eq!(10, s.merge((0, 10)));
344        assert_eq!(10, s.merge((20, 30)));
345
346        assert_eq!(s.0, vec![(0, 10), (20, 30)]);
347
348        assert_eq!(25, s.merge((5, 45)));
349
350        assert_eq!(s.0, vec![(0, 45)]);
351    }
352
353    #[test]
354    fn test13() {
355        let mut s = Segments::new();
356
357        assert_eq!(10, s.merge((10, 20)));
358        assert_eq!(15, s.merge((5, 30)));
359
360        assert_eq!(s.0, vec![(5, 30)]);
361    }
362
363    #[test]
364    fn test14() {
365        let mut s = Segments::new();
366
367        assert_eq!(10, s.merge((0, 10)));
368        assert_eq!(10, s.merge((20, 30)));
369        assert_eq!(10, s.merge((15, 35)));
370
371        assert_eq!(s.0, vec![(0, 10), (15, 35)]);
372    }
373    #[test]
374    #[should_panic]
375    fn test_invalid_segment() {
376        let mut v = Segments::new();
377
378        v.merge((10, 10));
379    }
380}