ferrum_interfaces/model_executor/
prefix_restore.rs1use super::{KvCacheHandle, PlanRuntimePrefillAuthority, PrefixCaptureLease};
4use ferrum_types::{FerrumError, RequestId, Result, TokenId};
5use std::{fmt, sync::Arc};
6
7#[derive(Debug, serde::Serialize)]
10pub struct PrefixRestoreObservation<'a> {
11 pub request_id: &'a RequestId,
12 pub source: PrefixRestoreSource,
13 pub decision: PrefixRestoreDecision<'a>,
14}
15
16#[derive(Debug, Clone, Copy, serde::Serialize)]
17#[serde(rename_all = "snake_case")]
18pub enum PrefixRestoreSource {
19 Index,
20 Rendezvous,
21}
22
23#[derive(Debug, serde::Serialize)]
25#[serde(tag = "outcome", rename_all = "snake_case")]
26pub enum PrefixRestoreDecision<'a> {
27 NoReusableEntry,
28 SequenceCapacityNotReady {
29 candidate_prefix_tokens: usize,
30 capacity: &'a super::ExecutorExecutionCapacityDeferral,
31 },
32 RequestStateNotReady {
33 candidate_prefix_tokens: usize,
34 request_state: &'a super::ExecutorRequestStateDeferral,
35 },
36 NativeRestoreSkipped {
37 candidate_prefix_tokens: usize,
38 },
39 Restored {
40 candidate_prefix_tokens: usize,
41 },
42}
43
44#[derive(Debug, Clone, Copy)]
47pub struct PlanRuntimePrefixRestoreInput<'a> {
48 pub request_id: &'a RequestId,
49 pub input_tokens: &'a [TokenId],
50 pub maximum_sequence_tokens: usize,
51 pub checkpoint: Option<&'a dyn PrefixCaptureLease>,
54 pub retry: Option<&'a PlanRuntimePrefixRestoreDeferral>,
56}
57
58#[derive(Debug)]
62pub struct PlanRuntimePrefixRestoreDeferral {
63 capacity: super::ExecutorExecutionCapacityDeferral,
64 checkpoint: Arc<dyn PrefixCaptureLease>,
65 source: PrefixRestoreSource,
66}
67
68impl PlanRuntimePrefixRestoreDeferral {
69 pub fn new(
70 capacity: super::ExecutorExecutionCapacityDeferral,
71 checkpoint: Arc<dyn PrefixCaptureLease>,
72 source: PrefixRestoreSource,
73 ) -> Self {
74 Self {
75 capacity,
76 checkpoint,
77 source,
78 }
79 }
80
81 pub fn capacity(&self) -> &super::ExecutorExecutionCapacityDeferral {
82 &self.capacity
83 }
84
85 pub fn checkpoint(&self) -> &Arc<dyn PrefixCaptureLease> {
86 &self.checkpoint
87 }
88
89 pub fn source(&self) -> PrefixRestoreSource {
90 self.source
91 }
92}
93
94#[derive(Debug)]
95#[must_use = "restore publication or a retained capacity deferral must be handled"]
96pub enum PlanRuntimePrefixRestoreOutcome {
97 Unavailable,
98 Restored(PlanRuntimePrefixRestoreOutput),
99 Deferred(PlanRuntimePrefixRestoreDeferral),
100}
101
102#[must_use = "publish matching progress and acknowledge, or drop to cancel the restored target"]
110pub struct PlanRuntimePrefixRestoreOutput {
111 authority: PlanRuntimePrefillAuthority,
112 prompt_tokens: usize,
113 acknowledge: Box<dyn FnOnce() -> Result<()> + Send>,
114}
115
116impl PlanRuntimePrefixRestoreOutput {
117 pub fn new(
121 request_id: RequestId,
122 restored_tokens: usize,
123 prompt_tokens: usize,
124 kv_cache: Arc<dyn KvCacheHandle>,
125 acknowledge: impl FnOnce() -> Result<()> + Send + 'static,
126 ) -> Result<Self> {
127 let output = Self {
128 authority: PlanRuntimePrefillAuthority {
129 request_id,
130 committed_tokens: restored_tokens,
131 kv_cache,
132 },
133 prompt_tokens,
134 acknowledge: Box::new(acknowledge),
135 };
136 output.validate_for(output.request_id(), prompt_tokens)?;
137 Ok(output)
138 }
139
140 pub fn request_id(&self) -> &RequestId {
141 self.authority.request_id()
142 }
143
144 pub fn restored_tokens(&self) -> usize {
145 self.authority.committed_tokens()
146 }
147
148 pub fn kv_cache(&self) -> &Arc<dyn KvCacheHandle> {
149 self.authority.kv_cache()
150 }
151
152 pub fn validate_for(&self, request_id: &RequestId, prompt_tokens: usize) -> Result<()> {
153 if self.request_id() != request_id || self.prompt_tokens != prompt_tokens {
154 return Err(FerrumError::backend(
155 "prefix restore publication does not match the admitted request",
156 ));
157 }
158 let restored = self.restored_tokens();
159 if restored == 0 || restored >= prompt_tokens {
160 return Err(FerrumError::backend(
161 "prefix restore must leave a nonempty prompt suffix for execution",
162 ));
163 }
164 if self.kv_cache().num_tokens() != restored || !self.kv_cache().is_valid() {
165 return Err(FerrumError::backend(
166 "prefix restore cache authority does not match the restored extent",
167 ));
168 }
169 Ok(())
170 }
171
172 pub fn acknowledge(self) -> Result<PlanRuntimePrefillAuthority> {
176 let Self {
177 authority,
178 acknowledge,
179 ..
180 } = self;
181 acknowledge()?;
182 Ok(authority)
183 }
184}
185
186impl fmt::Debug for PlanRuntimePrefixRestoreOutput {
187 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
188 f.debug_struct("PlanRuntimePrefixRestoreOutput")
189 .field("authority", &self.authority)
190 .field("prompt_tokens", &self.prompt_tokens)
191 .finish_non_exhaustive()
192 }
193}