ferrum_interfaces/vnext/execution/sequence_checkpoint/
ranges.rs1use std::collections::BTreeMap;
2use std::ops::Range;
3
4use super::*;
5use crate::vnext::{CheckpointBackingRequest, CheckpointBackingRequests};
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
8pub struct SequenceCheckpointCopyRange {
9 source: Range<u64>,
10 checkpoint_offset: u64,
11}
12
13impl SequenceCheckpointCopyRange {
14 pub fn source(&self) -> Range<u64> {
15 self.source.clone()
16 }
17 pub fn checkpoint_offset(&self) -> u64 {
18 self.checkpoint_offset
19 }
20 pub fn length_bytes(&self) -> u64 {
21 self.source.end - self.source.start
22 }
23}
24
25#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
26pub struct SequenceCheckpointResourceRanges {
27 resource_id: ResourceId,
28 logical_bytes: u64,
29 ranges: Vec<SequenceCheckpointCopyRange>,
30}
31
32impl SequenceCheckpointResourceRanges {
33 pub fn resource_id(&self) -> &ResourceId {
34 &self.resource_id
35 }
36 pub fn logical_bytes(&self) -> u64 {
37 self.logical_bytes
38 }
39 pub fn ranges(&self) -> &[SequenceCheckpointCopyRange] {
40 &self.ranges
41 }
42}
43
44#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
48pub struct SequenceCheckpointBytePlan {
49 plan_hash: PlanHash,
50 layout_fingerprint: String,
51 boundary: u64,
52 logical_bytes: u64,
53 resources: Vec<SequenceCheckpointResourceRanges>,
54}
55
56impl SequenceCheckpointBytePlan {
57 pub fn plan_hash(&self) -> &PlanHash {
58 &self.plan_hash
59 }
60 pub fn layout_fingerprint(&self) -> &str {
61 &self.layout_fingerprint
62 }
63 pub fn boundary(&self) -> u64 {
64 self.boundary
65 }
66 pub fn logical_bytes(&self) -> u64 {
67 self.logical_bytes
68 }
69 pub fn resources(&self) -> &[SequenceCheckpointResourceRanges] {
70 &self.resources
71 }
72
73 pub(crate) fn backing_requests(&self) -> Result<CheckpointBackingRequests, VNextError> {
74 CheckpointBackingRequests::new(
75 self.plan_hash.clone(),
76 self.resources
77 .iter()
78 .map(|resource| {
79 CheckpointBackingRequest::new(
80 resource.resource_id.clone(),
81 resource.logical_bytes,
82 )
83 })
84 .collect::<Result<Vec<_>, _>>()?,
85 )
86 }
87}
88
89impl SequenceCheckpointState {
90 fn source_range(&self, boundary: u64) -> Result<Range<u64>, VNextError> {
91 let length = match self.layout {
92 ProviderCheckpointStateLayout::ContiguousBoundaryValue => {
93 self.tensor.minimum_storage_bytes()?
94 }
95 ProviderCheckpointStateLayout::TokenMajorPrefix => self
96 .tensor
97 .minimum_storage_bytes()?
98 .checked_mul(boundary)
99 .ok_or_else(|| invalid_plan("checkpoint prefix byte length overflows u64"))?,
100 };
101 let end = self
102 .offset_bytes
103 .checked_add(length)
104 .ok_or_else(|| invalid_plan("checkpoint byte end overflows u64"))?;
105 let capacity = self.descriptor.evaluate_logical_request_bytes_for_shape(
106 self.descriptor.demand().theoretical_maximum_shape(),
107 )?;
108 if length == 0 || end > capacity {
109 return Err(invalid_plan(
110 "checkpoint state range exceeds its proven resource capacity",
111 ));
112 }
113 Ok(self.offset_bytes..end)
114 }
115
116 fn maximum_source_range(&self) -> Result<Range<u64>, VNextError> {
117 match self.layout {
118 ProviderCheckpointStateLayout::ContiguousBoundaryValue => self.source_range(1),
119 ProviderCheckpointStateLayout::TokenMajorPrefix => {
120 let capacity = self.descriptor.evaluate_logical_request_bytes_for_shape(
121 self.descriptor.demand().theoretical_maximum_shape(),
122 )?;
123 self.source_range(capacity / self.tensor.minimum_storage_bytes()?)
124 }
125 }
126 }
127}
128
129impl SequenceCheckpointLayout {
130 pub(super) fn validate_aliases(&self) -> Result<(), VNextError> {
131 let mut groups = BTreeMap::<&ResourceId, Vec<&SequenceCheckpointState>>::new();
132 for state in &self.data.states {
133 groups.entry(&state.resource_id).or_default().push(state);
134 }
135 for states in groups.values() {
136 let mut ranges = states
137 .iter()
138 .map(|state| Ok((state.maximum_source_range()?, *state)))
139 .collect::<Result<Vec<_>, VNextError>>()?;
140 ranges.sort_by_key(|(range, _)| (range.start, range.end));
141 for pair in ranges.windows(2) {
142 let (left_range, left) = &pair[0];
143 let (right_range, right) = &pair[1];
144 if left_range.end > right_range.start
145 && !(left_range == right_range
146 && left.tensor == right.tensor
147 && left.layout == right.layout
148 && left.semantics == right.semantics
149 && left.storage == right.storage
150 && left.initialization == right.initialization)
151 {
152 return Err(invalid_plan(
153 "checkpoint state aliases do not prove identical content and ABI",
154 ));
155 }
156 }
157 }
158 Ok(())
159 }
160
161 pub(super) fn byte_plan(
164 &self,
165 plan_hash: PlanHash,
166 boundary: u64,
167 ) -> Result<SequenceCheckpointBytePlan, VNextError> {
168 if boundary == 0 {
169 return Err(invalid_plan(
170 "checkpoint requires a positive completed boundary",
171 ));
172 }
173 let mut groups = BTreeMap::<ResourceId, Vec<Range<u64>>>::new();
174 for state in &self.data.states {
175 groups
176 .entry(state.resource_id.clone())
177 .or_default()
178 .push(state.source_range(boundary)?);
179 }
180 let mut total = 0_u64;
181 let mut resources = Vec::new();
182 for (resource_id, mut ranges) in groups {
183 ranges.sort_by_key(|range| (range.start, range.end));
184 let mut merged: Vec<Range<u64>> = Vec::new();
185 for range in ranges {
186 if let Some(previous) = merged
187 .last_mut()
188 .filter(|previous| range.start <= previous.end)
189 {
190 previous.end = previous.end.max(range.end);
191 } else {
192 merged.push(range);
193 }
194 }
195 let mut logical_bytes = 0_u64;
196 let ranges = merged
197 .into_iter()
198 .map(|source| {
199 let checkpoint_offset = logical_bytes;
200 logical_bytes = logical_bytes
201 .checked_add(source.end - source.start)
202 .ok_or_else(|| {
203 invalid_plan("compact checkpoint resource size overflows u64")
204 })?;
205 Ok(SequenceCheckpointCopyRange {
206 source,
207 checkpoint_offset,
208 })
209 })
210 .collect::<Result<Vec<_>, VNextError>>()?;
211 total = total
212 .checked_add(logical_bytes)
213 .ok_or_else(|| invalid_plan("checkpoint total bytes overflow u64"))?;
214 resources.push(SequenceCheckpointResourceRanges {
215 resource_id,
216 logical_bytes,
217 ranges,
218 });
219 }
220 Ok(SequenceCheckpointBytePlan {
221 plan_hash,
222 layout_fingerprint: self.fingerprint()?,
223 boundary,
224 logical_bytes: total,
225 resources,
226 })
227 }
228}