1mod audit;
4mod cursor;
5mod page;
6mod search;
7#[cfg(test)]
8mod tests;
9mod transaction;
10
11pub use cursor::{Entry, Range};
12use page::{Header, Node, Record};
13use std::{cmp::Ordering, fmt, ops::Bound};
14use transaction::Transaction;
15
16use crate::Memory;
17
18#[derive(Clone, Copy, Debug, Eq, PartialEq)]
20pub enum Error {
21 NotEmpty,
23 Format,
25 Configuration,
27 Corrupt,
29 TooLarge,
31 Capacity,
33 InvalidKey,
35 InvalidRange,
37}
38
39impl fmt::Display for Error {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 write!(f, "stable B-tree error: {self:?}")
42 }
43}
44impl std::error::Error for Error {}
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
48pub struct Config {
49 pub max_key_bytes: u32,
51 pub max_value_bytes: u32,
53}
54impl Default for Config {
55 fn default() -> Self {
56 Self {
57 max_key_bytes: 128 * 1024,
58 max_value_bytes: 4 * 1024 * 1024,
59 }
60 }
61}
62impl Config {
63 fn check(self) -> Result<(), Error> {
64 if self.max_key_bytes == 0
65 || self.max_key_bytes > 1024 * 1024
66 || self.max_value_bytes == 0
67 || self.max_value_bytes > 64 * 1024 * 1024
68 {
69 return Err(Error::Configuration);
70 }
71 Ok(())
72 }
73}
74
75pub trait Comparator {
82 const IDENTITY: [u8; 16];
84 fn compare(&self, left: &[u8], right: &[u8]) -> Result<Ordering, Error>;
89}
90
91#[derive(Clone, Copy, Debug, Default)]
93pub struct Lexicographic;
94impl Comparator for Lexicographic {
95 const IDENTITY: [u8; 16] = *b"ic-storage-lex01";
96 fn compare(&self, left: &[u8], right: &[u8]) -> Result<Ordering, Error> {
97 Ok(left.cmp(right))
98 }
99}
100
101pub struct BTreeMap<M, C = Lexicographic> {
108 memory: M,
109 order: C,
110 header: Header,
111}
112
113impl<M: Memory, C: Comparator> BTreeMap<M, C> {
114 pub fn create(memory: M, config: Config, order: C) -> Result<Self, Error> {
119 config.check()?;
120 if memory.size() != 0 {
121 return Err(Error::NotEmpty);
122 }
123 let mut tree = Self {
124 memory,
125 order,
126 header: Header::new(config, C::IDENTITY),
127 };
128 let mut tx = Transaction::new(&tree);
129 let root = tx.allocate()?;
130 tx.put_node(root, &Node::leaf())?;
131 tx.header.root = root;
132 tree.header = tx.commit()?;
133 Ok(tree)
134 }
135
136 pub fn open(memory: M, config: Config, order: C) -> Result<Self, Error> {
143 config.check()?;
144 let header = Header::read(&memory)?;
145 if header.config != config || header.identity != C::IDENTITY {
146 return Err(Error::Configuration);
147 }
148 let tree = Self {
149 memory,
150 order,
151 header,
152 };
153 tree.node(tree.header.root)?;
154 Ok(tree)
155 }
156
157 #[must_use]
159 pub const fn len(&self) -> u64 {
160 self.header.len
161 }
162 #[must_use]
164 pub const fn is_empty(&self) -> bool {
165 self.header.len == 0
166 }
167 #[must_use]
169 pub fn memory_bytes(&self) -> u64 {
170 self.memory.size().saturating_mul(65_536)
171 }
172 #[must_use]
174 pub fn into_memory(self) -> M {
175 self.memory
176 }
177
178 pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
182 self.check_key(key)?;
183 self.find_validated(key)?
184 .map(|(_, node, at)| self.value(node.entries[at]))
185 .transpose()
186 }
187
188 pub fn contains_key(&self, key: &[u8]) -> Result<bool, Error> {
192 self.check_key(key)?;
193 Ok(self.find_validated(key)?.is_some())
194 }
195
196 fn find_validated(&self, key: &[u8]) -> Result<Option<(u64, Node, usize)>, Error> {
198 let mut id = self.header.root;
199 for _ in 0..page::MAX_HEIGHT {
200 let node = self.node(id)?;
201 let (at, found) = self.locate(&node, key)?;
202 if found {
203 return Ok(Some((id, node, at)));
204 }
205 if node.children.is_empty() {
206 return Ok(None);
207 }
208 id = node.children[at];
209 }
210 Err(Error::Corrupt)
211 }
212
213 pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<Vec<u8>>, Error> {
218 self.check_key(key)?;
219 if value.len() > self.header.config.max_value_bytes as usize {
220 return Err(Error::TooLarge);
221 }
222 let located = self.find_validated(key)?;
223 let mut tx = Transaction::new(self);
224 let previous = if let Some((id, node, at)) = located {
225 Some(tx.replace(id, node, at, value)?)
226 } else {
227 tx.insert(key, value)?;
228 tx.header.len = tx.header.len.checked_add(1).ok_or(Error::Capacity)?;
229 None
230 };
231 self.header = tx.commit()?;
232 Ok(previous)
233 }
234
235 pub fn remove(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
239 self.check_key(key)?;
240 let mut tx = Transaction::new(self);
241 let Some(previous) = tx.remove(key)? else {
242 return Ok(None);
244 };
245 tx.header.len = tx.header.len.checked_sub(1).ok_or(Error::Corrupt)?;
246 self.header = tx.commit()?;
247 Ok(Some(previous))
248 }
249
250 pub fn range(
257 &self,
258 lower: Bound<&[u8]>,
259 upper: Bound<&[u8]>,
260 ) -> Result<Range<'_, M, C>, Error> {
261 Range::new(self, lower, upper)
262 }
263
264 #[must_use]
266 pub fn iter(&self) -> Range<'_, M, C> {
267 Range::all(self)
268 }
269
270 pub fn validate(&self) -> Result<(), Error> {
275 audit::validate(self)
276 }
277
278 fn check_key(&self, key: &[u8]) -> Result<(), Error> {
279 if key.len() > self.header.config.max_key_bytes as usize {
280 return Err(Error::TooLarge);
281 }
282 if self.order.compare(key, key)? != Ordering::Equal {
283 return Err(Error::InvalidKey);
284 }
285 Ok(())
286 }
287 fn node(&self, id: u64) -> Result<Node, Error> {
288 let mut page = [0; page::SIZE];
289 page::read_into(&self.memory, self.header.next, id, &mut page)?;
290 Node::decode(&page, self.header.next, self.header.config)
291 }
292 fn key(&self, record: Record) -> Result<Vec<u8>, Error> {
293 if record.key == 0 {
294 return Ok(record.key_inline
295 [..usize::try_from(record.key_len).map_err(|_| Error::Corrupt)?]
296 .to_vec());
297 }
298 page::blob(&self.memory, self.header.next, record.key, record.key_len)
299 }
300 fn value(&self, record: Record) -> Result<Vec<u8>, Error> {
301 if record.value == 0 {
302 return Ok(record.value_inline
303 [..usize::try_from(record.value_len).map_err(|_| Error::Corrupt)?]
304 .to_vec());
305 }
306 page::blob(
307 &self.memory,
308 self.header.next,
309 record.value,
310 record.value_len,
311 )
312 }
313 fn locate(&self, node: &Node, key: &[u8]) -> Result<(usize, bool), Error> {
314 search::locate(
315 node,
316 key,
317 &self.order,
318 |id, buffer| page::read_into(&self.memory, self.header.next, id, buffer),
319 |record| self.key(record),
320 )
321 }
322}
323
324impl<'a, M: Memory, C: Comparator> IntoIterator for &'a BTreeMap<M, C> {
325 type Item = Result<Entry<'a, M, C>, Error>;
326 type IntoIter = Range<'a, M, C>;
327 fn into_iter(self) -> Self::IntoIter {
328 self.iter()
329 }
330}