acyclic_fs/kernel/
attribute_list.rs1use super::attribute_mutation::AttributeFormat;
4use super::persistent_pagination;
5use super::{AttributeEntry, AttributeName, CanonicalDecodeError, DecodeLimits};
6use crate::async_storage::AsyncObjectStore;
7use crate::cancellation::CancellationToken;
8use crate::performance::{OperationFailure, WorkBudget, WorkCounters, WorkError};
9use crate::speculation::{ResidencyHint, ResidencyReason};
10use crate::storage::{ObjectId, ObjectStoreError};
11use thiserror::Error;
12
13#[derive(Clone, Debug, Eq, PartialEq)]
15pub struct AttributeListing {
16 pub entries: Vec<AttributeEntry>,
18 pub has_more: bool,
20 pub next_residency: Option<ResidencyHint>,
22 pub work: WorkCounters,
24}
25
26pub fn list_attributes<S: crate::ImmediateObjectStore>(
33 store: &S,
34 root: ObjectId,
35 after: Option<&AttributeName>,
36 maximum_entries: u32,
37 limits: DecodeLimits,
38 budget: WorkBudget,
39) -> Result<AttributeListing, AttributeListFailure> {
40 persistent_pagination::paginate::<S, AttributeFormat>(
41 store,
42 root,
43 after,
44 maximum_entries,
45 limits,
46 budget,
47 )
48 .map(to_listing)
49 .map_err(map_failure)
50}
51
52pub async fn list_attributes_async<S: AsyncObjectStore>(
59 store: &S,
60 root: ObjectId,
61 after: Option<&AttributeName>,
62 maximum_entries: u32,
63 limits: DecodeLimits,
64 budget: WorkBudget,
65 cancellation: &CancellationToken,
66) -> Result<AttributeListing, AttributeListFailure> {
67 persistent_pagination::paginate_async::<S, AttributeFormat>(
68 store,
69 root,
70 after,
71 maximum_entries,
72 limits,
73 budget,
74 cancellation,
75 )
76 .await
77 .map(to_listing)
78 .map_err(map_failure)
79}
80
81fn to_listing(receipt: persistent_pagination::Receipt<AttributeEntry>) -> AttributeListing {
82 AttributeListing {
83 entries: receipt.values,
84 has_more: receipt.has_more,
85 next_residency: receipt.next_request.map(|request| ResidencyHint {
86 request,
87 reason: ResidencyReason::MetadataSuccessor,
88 }),
89 work: receipt.work,
90 }
91}
92
93pub type AttributeListFailure = OperationFailure<AttributeListError>;
95
96fn map_failure(failure: persistent_pagination::Failure) -> AttributeListFailure {
97 OperationFailure::new(map_error(failure.error), *failure.work)
98}
99
100fn map_error(error: persistent_pagination::Error) -> AttributeListError {
101 match error {
102 persistent_pagination::Error::Cancelled => AttributeListError::Cancelled,
103 persistent_pagination::Error::ZeroLimit => AttributeListError::ZeroLimit,
104 persistent_pagination::Error::LimitOverflow => AttributeListError::LimitOverflow,
105 persistent_pagination::Error::WrongRootKind => AttributeListError::WrongRootKind,
106 persistent_pagination::Error::InvalidLimits => AttributeListError::InvalidLimits,
107 persistent_pagination::Error::HeightExceeded => AttributeListError::HeightExceeded,
108 persistent_pagination::Error::CycleOrAlias => AttributeListError::CycleOrAlias,
109 persistent_pagination::Error::ChildBoundsMismatch => {
110 AttributeListError::ChildBoundsMismatch
111 }
112 persistent_pagination::Error::TraversalState => AttributeListError::TraversalState,
113 persistent_pagination::Error::AllocationFailed => AttributeListError::AllocationFailed,
114 persistent_pagination::Error::Storage(error) => error.into(),
115 persistent_pagination::Error::Decode(error) => error.into(),
116 persistent_pagination::Error::Work(error) => error.into(),
117 }
118}
119
120#[derive(Debug, Error)]
122pub enum AttributeListError {
123 #[error("attribute listing was cancelled")]
125 Cancelled,
126 #[error("attribute page limit must be non-zero")]
128 ZeroLimit,
129 #[error("attribute page limit cannot be represented")]
131 LimitOverflow,
132 #[error("attribute root is not an attribute page")]
134 WrongRootKind,
135 #[error("attribute listing limits are invalid")]
137 InvalidLimits,
138 #[error("attribute tree exceeds its admitted height")]
140 HeightExceeded,
141 #[error("attribute tree contains a cycle or alias")]
143 CycleOrAlias,
144 #[error("attribute child bounds do not match its page")]
146 ChildBoundsMismatch,
147 #[error("attribute listing transition state is invalid")]
149 TraversalState,
150 #[error("attribute listing allocation failed")]
152 AllocationFailed,
153 #[error(transparent)]
155 Storage(#[from] ObjectStoreError),
156 #[error(transparent)]
158 Decode(#[from] CanonicalDecodeError),
159 #[error(transparent)]
161 Work(#[from] WorkError),
162}
163
164#[cfg(all(test, feature = "memory"))]
165#[path = "tests/attribute_list.rs"]
166mod tests;