1use super::allocation::AllocationError;
4use super::codec::DecodedPageShape;
5use super::persistent_btree::{self, Child, Format, Page, PageRef};
6use super::tree::{
7 encode_tree_internal_children, encode_tree_leaf_entries, tree_page_decode_shape,
8};
9use super::{
10 CanonicalDecodeError, DecodeLimits, LogicalName, TreeEntry, TreePage, decode_tree_page,
11};
12use crate::foundation::FileId;
13use crate::performance::{OperationFailure, WorkBudget, WorkCounters, WorkError};
14use crate::storage::{ObjectId, ObjectKind, ObjectStoreError};
15use thiserror::Error;
16
17pub(crate) struct TreeFormat;
18
19impl Format for TreeFormat {
20 type Key = LogicalName;
21 type Value = TreeEntry;
22
23 fn kind() -> ObjectKind {
24 ObjectKind::TreePage
25 }
26
27 fn key(value: &Self::Value) -> &Self::Key {
28 &value.name
29 }
30
31 fn decode(bytes: &[u8], limits: DecodeLimits) -> Result<Page<Self>, CanonicalDecodeError> {
32 Ok(match decode_tree_page(bytes, limits)? {
33 TreePage::Leaf(entries) => Page::Leaf(entries),
34 TreePage::Internal(children) => Page::Internal(
35 children
36 .into_iter()
37 .map(|child| Child {
38 first: child.first_name,
39 page: child.page,
40 })
41 .collect(),
42 ),
43 })
44 }
45
46 fn decode_shape(
47 bytes: &[u8],
48 limits: DecodeLimits,
49 ) -> Result<DecodedPageShape, CanonicalDecodeError> {
50 tree_page_decode_shape(bytes, limits)
51 }
52
53 fn encode(
54 page: &PageRef<'_, Self>,
55 maximum_items: u32,
56 ) -> Result<Vec<u8>, CanonicalDecodeError> {
57 match page {
58 PageRef::Leaf(entries) => encode_tree_leaf_entries(entries, maximum_items),
59 PageRef::Internal(children) => encode_tree_internal_children(
60 children.iter().map(|child| (&child.first, child.page)),
61 maximum_items,
62 ),
63 }
64 }
65
66 fn page_encoded_length(
67 page: &PageRef<'_, Self>,
68 maximum_items: u32,
69 ) -> Result<usize, CanonicalDecodeError> {
70 let count = match page {
71 PageRef::Leaf(entries) => entries.len(),
72 PageRef::Internal(children) => children.len(),
73 };
74 if u32::try_from(count).unwrap_or(u32::MAX) > maximum_items {
75 return Err(CanonicalDecodeError::LengthOverflow);
76 }
77 let mut bytes = 8_usize + 2 + 1 + 4;
78 match page {
79 PageRef::Leaf(entries) => {
80 for entry in *entries {
81 bytes = bytes
82 .checked_add(Self::leaf_item_encoded_length(entry)?)
83 .ok_or(CanonicalDecodeError::LengthOverflow)?;
84 }
85 }
86 PageRef::Internal(children) => {
87 for child in *children {
88 bytes = bytes
89 .checked_add(Self::internal_item_encoded_length(&child.first)?)
90 .ok_or(CanonicalDecodeError::LengthOverflow)?;
91 }
92 }
93 }
94 Ok(bytes)
95 }
96
97 fn leaf_item_encoded_length(value: &Self::Value) -> Result<usize, CanonicalDecodeError> {
98 value
99 .name
100 .as_bytes()
101 .len()
102 .checked_add(1 + 4 + 16 + 1)
103 .ok_or(CanonicalDecodeError::LengthOverflow)
104 }
105
106 fn internal_item_encoded_length(key: &Self::Key) -> Result<usize, CanonicalDecodeError> {
107 key.as_bytes()
108 .len()
109 .checked_add(1 + 4 + 32)
110 .ok_or(CanonicalDecodeError::LengthOverflow)
111 }
112
113 fn key_nested_bytes(key: &Self::Key) -> u64 {
114 u64::try_from(key.as_bytes().len()).unwrap_or(u64::MAX)
115 }
116
117 fn value_nested_bytes(value: &Self::Value) -> u64 {
118 Self::key_nested_bytes(&value.name)
119 }
120
121 fn try_clone_key(
122 key: &Self::Key,
123 maximum_bytes: u32,
124 ) -> Result<Self::Key, CanonicalDecodeError> {
125 let mut bytes = Vec::new();
126 bytes
127 .try_reserve_exact(key.as_bytes().len())
128 .map_err(|_| CanonicalDecodeError::AllocationFailed)?;
129 bytes.extend_from_slice(key.as_bytes());
130 LogicalName::new(key.encoding(), bytes, maximum_bytes)
131 .map_err(|error| CanonicalDecodeError::Invariant(error.to_string()))
132 }
133
134 fn try_clone_value(
135 value: &Self::Value,
136 maximum_bytes: u32,
137 ) -> Result<Self::Value, CanonicalDecodeError> {
138 Ok(TreeEntry {
139 name: Self::try_clone_key(&value.name, maximum_bytes)?,
140 file_id: value.file_id,
141 kind: value.kind,
142 })
143 }
144}
145
146#[derive(Clone, Debug, Eq, PartialEq)]
148pub enum TreeMutation {
149 Insert(TreeEntry),
151 Remove {
153 name: LogicalName,
155 expected_file_id: Option<FileId>,
157 },
158 Replace {
160 entry: TreeEntry,
162 expected_file_id: FileId,
164 },
165}
166
167impl persistent_btree::Mutation<TreeFormat> for TreeMutation {
168 type Error = TreeSemanticError;
169
170 fn key(&self) -> &LogicalName {
171 match self {
172 Self::Insert(entry) | Self::Replace { entry, .. } => &entry.name,
173 Self::Remove { name, .. } => name,
174 }
175 }
176
177 fn changes_cardinality(&self) -> bool {
178 matches!(self, Self::Insert(_) | Self::Remove { .. })
179 }
180
181 fn apply_current(&self, current: &mut Option<TreeEntry>) -> Result<(), Self::Error> {
182 match self {
183 Self::Insert(_) if current.is_some() => Err(TreeSemanticError::AlreadyExists),
184 Self::Insert(entry) => {
185 *current = Some(entry.clone());
186 Ok(())
187 }
188 Self::Remove { .. } | Self::Replace { .. } if current.is_none() => {
189 Err(TreeSemanticError::Missing)
190 }
191 Self::Remove {
192 expected_file_id, ..
193 } => {
194 let existing = current.as_ref().ok_or(TreeSemanticError::Missing)?;
195 if expected_file_id.is_some_and(|expected| existing.file_id != expected) {
196 return Err(TreeSemanticError::FileIdentityConflict);
197 }
198 *current = None;
199 Ok(())
200 }
201 Self::Replace {
202 entry,
203 expected_file_id,
204 } => {
205 let existing = current.as_ref().ok_or(TreeSemanticError::Missing)?;
206 if existing.file_id != *expected_file_id {
207 return Err(TreeSemanticError::FileIdentityConflict);
208 }
209 *current = Some(entry.clone());
210 Ok(())
211 }
212 }
213 }
214}
215
216#[derive(Clone, Debug, Eq, PartialEq)]
218pub struct TreeMutationReceipt {
219 pub root: ObjectId,
221 pub work: WorkCounters,
223}
224
225pub type TreeMutationFailure = OperationFailure<TreeMutationError>;
227
228pub fn apply_tree_mutations<S: crate::ImmediateObjectStore>(
240 store: &S,
241 root: ObjectId,
242 mutations: Vec<TreeMutation>,
243 maximum_mutations: u32,
244 limits: DecodeLimits,
245 budget: WorkBudget,
246) -> Result<TreeMutationReceipt, TreeMutationFailure> {
247 let receipt = persistent_btree::apply::<S, TreeFormat, TreeMutation>(
248 store,
249 root,
250 mutations,
251 maximum_mutations,
252 limits,
253 budget,
254 )
255 .map_err(|failure| OperationFailure::new(map_error(failure.error), *failure.work))?;
256 Ok(TreeMutationReceipt {
257 root: receipt.root,
258 work: receipt.work,
259 })
260}
261
262pub async fn apply_tree_mutations_async<S: crate::AsyncObjectStore>(
272 store: &S,
273 root: ObjectId,
274 mutations: Vec<TreeMutation>,
275 maximum_mutations: u32,
276 limits: DecodeLimits,
277 budget: WorkBudget,
278 cancellation: &crate::CancellationToken,
279) -> Result<TreeMutationReceipt, TreeMutationFailure> {
280 let receipt = persistent_btree::apply_async::<S, TreeFormat, TreeMutation>(
281 store,
282 root,
283 mutations,
284 maximum_mutations,
285 limits,
286 budget,
287 cancellation,
288 )
289 .await
290 .map_err(|failure| OperationFailure::new(map_error(failure.error), *failure.work))?;
291 Ok(TreeMutationReceipt {
292 root: receipt.root,
293 work: receipt.work,
294 })
295}
296
297fn map_error(error: persistent_btree::Error<TreeSemanticError>) -> TreeMutationError {
298 match error {
299 persistent_btree::Error::Empty => TreeMutationError::Empty,
300 persistent_btree::Error::TooManyMutations => TreeMutationError::TooManyMutations,
301 persistent_btree::Error::WrongRootKind => TreeMutationError::WrongRootKind,
302 persistent_btree::Error::InvalidLimits => TreeMutationError::InvalidLimits,
303 persistent_btree::Error::PageItemTooLarge => TreeMutationError::PageItemTooLarge,
304 persistent_btree::Error::HeightExceeded => TreeMutationError::HeightExceeded,
305 persistent_btree::Error::CycleOrAlias => TreeMutationError::CycleOrAlias,
306 persistent_btree::Error::ChildBoundsMismatch => TreeMutationError::ChildBoundsMismatch,
307 persistent_btree::Error::MutationContract => TreeMutationError::MutationContract,
308 persistent_btree::Error::Allocation(AllocationError::Work(error)) => {
309 TreeMutationError::Work(error)
310 }
311 persistent_btree::Error::AllocationFailed | persistent_btree::Error::Allocation(_) => {
312 TreeMutationError::AllocationFailed
313 }
314 persistent_btree::Error::Semantic(error) => error.into(),
315 persistent_btree::Error::Storage(error) => TreeMutationError::Storage(error),
316 persistent_btree::Error::Decode(error) => TreeMutationError::Decode(error),
317 persistent_btree::Error::Work(error) => TreeMutationError::Work(error),
318 }
319}
320
321#[derive(Clone, Copy, Debug, Eq, Error, PartialEq)]
322pub(crate) enum TreeSemanticError {
323 #[error("tree mutation name already exists")]
324 AlreadyExists,
325 #[error("tree mutation name is absent")]
326 Missing,
327 #[error("tree mutation file identity precondition failed")]
328 FileIdentityConflict,
329}
330
331#[derive(Debug, Error)]
333pub enum TreeMutationError {
334 #[error("tree mutation batch is empty")]
336 Empty,
337 #[error("tree mutation count exceeds its admitted bound")]
339 TooManyMutations,
340 #[error("tree mutation root is not a tree page")]
342 WrongRootKind,
343 #[error("tree mutation limits are invalid")]
345 InvalidLimits,
346 #[error("tree mutation item exceeds its page byte bound")]
348 PageItemTooLarge,
349 #[error("tree mutation exceeds its admitted height")]
351 HeightExceeded,
352 #[error("tree mutation encountered a cycle or page alias")]
354 CycleOrAlias,
355 #[error("tree mutation child bounds mismatch")]
357 ChildBoundsMismatch,
358 #[error("tree mutation violated its physical-plan contract")]
360 MutationContract,
361 #[error("tree mutation scratch allocation failed")]
363 AllocationFailed,
364 #[error("tree mutation name already exists")]
366 AlreadyExists,
367 #[error("tree mutation name is absent")]
369 Missing,
370 #[error("tree mutation file identity precondition failed")]
372 FileIdentityConflict,
373 #[error(transparent)]
375 Storage(#[from] ObjectStoreError),
376 #[error(transparent)]
378 Decode(#[from] CanonicalDecodeError),
379 #[error(transparent)]
381 Work(#[from] WorkError),
382}
383
384impl From<TreeSemanticError> for TreeMutationError {
385 fn from(value: TreeSemanticError) -> Self {
386 match value {
387 TreeSemanticError::AlreadyExists => Self::AlreadyExists,
388 TreeSemanticError::Missing => Self::Missing,
389 TreeSemanticError::FileIdentityConflict => Self::FileIdentityConflict,
390 }
391 }
392}
393
394#[cfg(all(test, feature = "memory"))]
395#[path = "tests/tree_mutation.rs"]
396mod tests;