Skip to main content

micromegas_object_cache/
blocks.rs

1use bytes::Bytes;
2use std::ops::Range;
3
4pub fn blocks_for_range(start: u64, end: u64, block_size: u64) -> Range<u64> {
5    debug_assert!(start < end);
6    let first = start / block_size;
7    let last = (end - 1) / block_size;
8    first..last + 1
9}
10
11pub fn block_byte_range(block_idx: u64, block_size: u64, file_size: u64) -> Range<u64> {
12    let start = block_idx * block_size;
13    let end = (start + block_size).min(file_size);
14    start..end
15}
16
17/// Group sorted, deduplicated, *owned* missing block indices into maximal
18/// contiguous runs, splitting any run whose byte span would exceed
19/// `max_coalesced_get_bytes` at block boundaries. Each returned block-index
20/// range becomes one `origin.get_range` call.
21pub fn coalesce_runs(
22    sorted_missing_owned: &[u64],
23    block_size: u64,
24    max_coalesced_get_bytes: u64,
25) -> Vec<Range<u64>> {
26    let max_blocks_per_run = (max_coalesced_get_bytes / block_size).max(1);
27    let mut runs = Vec::new();
28    let mut i = 0;
29    while i < sorted_missing_owned.len() {
30        let mut j = i;
31        while j + 1 < sorted_missing_owned.len()
32            && sorted_missing_owned[j + 1] == sorted_missing_owned[j] + 1
33            && sorted_missing_owned[j + 1] - sorted_missing_owned[i] < max_blocks_per_run
34        {
35            j += 1;
36        }
37        runs.push(sorted_missing_owned[i]..sorted_missing_owned[j] + 1);
38        i = j + 1;
39    }
40    runs
41}
42
43pub fn assemble_range(
44    blocks: &[(u64, Bytes)],
45    block_size: u64,
46    req_start: u64,
47    req_end: u64,
48) -> Bytes {
49    if req_start >= req_end || blocks.is_empty() {
50        return Bytes::new();
51    }
52    let mut result = Vec::with_capacity((req_end - req_start) as usize);
53    for (block_idx, block_data) in blocks {
54        let blk_start = block_idx * block_size;
55        let blk_end = blk_start + block_data.len() as u64;
56        let clip_start = req_start.max(blk_start);
57        let clip_end = req_end.min(blk_end);
58        if clip_start < clip_end {
59            let local_start = (clip_start - blk_start) as usize;
60            let local_end = (clip_end - blk_start) as usize;
61            result.extend_from_slice(&block_data[local_start..local_end]);
62        }
63    }
64    Bytes::from(result)
65}