1mod cursor;
4mod page;
5#[cfg(test)]
6mod tests;
7mod transaction;
8
9pub use cursor::{Entry, Range};
10use page::{Header, Node, Record};
11use std::{cmp::Ordering, fmt, ops::Bound};
12use transaction::Transaction;
13
14use crate::Memory;
15
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
18pub enum Error {
19 NotEmpty,
21 Format,
23 Configuration,
25 Corrupt,
27 TooLarge,
29 Capacity,
31 InvalidKey,
33 InvalidRange,
35}
36
37impl fmt::Display for Error {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 write!(f, "stable B-tree error: {self:?}")
40 }
41}
42impl std::error::Error for Error {}
43
44#[derive(Clone, Copy, Debug, Eq, PartialEq)]
46pub struct Config {
47 pub max_key_bytes: u32,
49 pub max_value_bytes: u32,
51}
52impl Default for Config {
53 fn default() -> Self {
54 Self {
55 max_key_bytes: 128 * 1024,
56 max_value_bytes: 4 * 1024 * 1024,
57 }
58 }
59}
60impl Config {
61 fn check(self) -> Result<(), Error> {
62 if self.max_key_bytes == 0
63 || self.max_key_bytes > 1024 * 1024
64 || self.max_value_bytes == 0
65 || self.max_value_bytes > 64 * 1024 * 1024
66 {
67 return Err(Error::Configuration);
68 }
69 Ok(())
70 }
71}
72
73pub trait Comparator {
80 const IDENTITY: [u8; 16];
82 fn compare(&self, left: &[u8], right: &[u8]) -> Result<Ordering, Error>;
87}
88
89#[derive(Clone, Copy, Debug, Default)]
91pub struct Lexicographic;
92impl Comparator for Lexicographic {
93 const IDENTITY: [u8; 16] = *b"ic-storage-lex01";
94 fn compare(&self, left: &[u8], right: &[u8]) -> Result<Ordering, Error> {
95 Ok(left.cmp(right))
96 }
97}
98
99pub struct BTreeMap<M, C = Lexicographic> {
106 memory: M,
107 order: C,
108 header: Header,
109}
110
111impl<M: Memory, C: Comparator> BTreeMap<M, C> {
112 pub fn create(memory: M, config: Config, order: C) -> Result<Self, Error> {
117 config.check()?;
118 if memory.size() != 0 {
119 return Err(Error::NotEmpty);
120 }
121 let mut tree = Self {
122 memory,
123 order,
124 header: Header::new(config, C::IDENTITY),
125 };
126 let mut tx = Transaction::new(&tree);
127 let root = tx.allocate()?;
128 tx.put_node(root, &Node::leaf())?;
129 tx.header.root = root;
130 tree.header = tx.commit()?;
131 Ok(tree)
132 }
133
134 pub fn open(memory: M, config: Config, order: C) -> Result<Self, Error> {
141 config.check()?;
142 let header = Header::read(&memory)?;
143 if header.config != config || header.identity != C::IDENTITY {
144 return Err(Error::Configuration);
145 }
146 let tree = Self {
147 memory,
148 order,
149 header,
150 };
151 tree.node(tree.header.root)?;
152 Ok(tree)
153 }
154
155 #[must_use]
157 pub const fn len(&self) -> u64 {
158 self.header.len
159 }
160 #[must_use]
162 pub const fn is_empty(&self) -> bool {
163 self.header.len == 0
164 }
165 #[must_use]
167 pub fn memory_bytes(&self) -> u64 {
168 self.memory.size().saturating_mul(65_536)
169 }
170 #[must_use]
172 pub fn into_memory(self) -> M {
173 self.memory
174 }
175
176 pub fn get(&self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
180 self.find(key)?
181 .map(|(_, node, at)| self.value(node.entries[at]))
182 .transpose()
183 }
184
185 pub fn contains_key(&self, key: &[u8]) -> Result<bool, Error> {
189 Ok(self.find(key)?.is_some())
190 }
191
192 fn find(&self, key: &[u8]) -> Result<Option<(u64, Node, usize)>, Error> {
193 self.check_key(key)?;
194 let mut id = self.header.root;
195 for _ in 0..page::MAX_HEIGHT {
196 let node = self.node(id)?;
197 let (at, found) = self.locate(&node, key)?;
198 if found {
199 return Ok(Some((id, node, at)));
200 }
201 if node.children.is_empty() {
202 return Ok(None);
203 }
204 id = node.children[at];
205 }
206 Err(Error::Corrupt)
207 }
208
209 pub fn insert(&mut self, key: &[u8], value: &[u8]) -> Result<Option<Vec<u8>>, Error> {
214 self.check_key(key)?;
215 if value.len() > self.header.config.max_value_bytes as usize {
216 return Err(Error::TooLarge);
217 }
218 let located = self.find(key)?;
219 let mut tx = Transaction::new(self);
220 let previous = if let Some((id, node, at)) = located {
221 Some(tx.replace(id, node, at, value)?)
222 } else {
223 tx.insert(key, value)?;
224 tx.header.len = tx.header.len.checked_add(1).ok_or(Error::Capacity)?;
225 None
226 };
227 self.header = tx.commit()?;
228 Ok(previous)
229 }
230
231 pub fn remove(&mut self, key: &[u8]) -> Result<Option<Vec<u8>>, Error> {
235 self.check_key(key)?;
236 let mut tx = Transaction::new(self);
237 let Some(previous) = tx.remove(key)? else {
238 return Ok(None);
240 };
241 tx.header.len = tx.header.len.checked_sub(1).ok_or(Error::Corrupt)?;
242 self.header = tx.commit()?;
243 Ok(Some(previous))
244 }
245
246 pub fn range(
253 &self,
254 lower: Bound<&[u8]>,
255 upper: Bound<&[u8]>,
256 ) -> Result<Range<'_, M, C>, Error> {
257 Range::new(self, lower, upper)
258 }
259
260 #[must_use]
262 pub fn iter(&self) -> Range<'_, M, C> {
263 Range::all(self)
264 }
265
266 pub fn validate(&self) -> Result<(), Error> {
271 transaction::validate(self)
272 }
273
274 fn check_key(&self, key: &[u8]) -> Result<(), Error> {
275 if key.len() > self.header.config.max_key_bytes as usize {
276 return Err(Error::TooLarge);
277 }
278 if self.order.compare(key, key)? != Ordering::Equal {
279 return Err(Error::InvalidKey);
280 }
281 Ok(())
282 }
283 fn node(&self, id: u64) -> Result<Node, Error> {
284 let mut page = [0; page::SIZE];
285 page::read_into(&self.memory, self.header.next, id, &mut page)?;
286 Node::decode(&page, self.header.next, self.header.config)
287 }
288 fn key(&self, record: Record) -> Result<Vec<u8>, Error> {
289 if record.key == 0 {
290 return Ok(record.key_inline
291 [..usize::try_from(record.key_len).map_err(|_| Error::Corrupt)?]
292 .to_vec());
293 }
294 page::blob(&self.memory, self.header.next, record.key, record.key_len)
295 }
296 fn value(&self, record: Record) -> Result<Vec<u8>, Error> {
297 if record.value == 0 {
298 return Ok(record.value_inline
299 [..usize::try_from(record.value_len).map_err(|_| Error::Corrupt)?]
300 .to_vec());
301 }
302 page::blob(
303 &self.memory,
304 self.header.next,
305 record.value,
306 record.value_len,
307 )
308 }
309 fn locate(&self, node: &Node, key: &[u8]) -> Result<(usize, bool), Error> {
310 let (mut lo, mut hi) = (0, node.entries.len());
311 while lo < hi {
312 let mid = lo + (hi - lo) / 2;
313 let record = node.entries[mid];
314 let order = if record.key != 0 && record.key_len <= page::PAYLOAD as u64 {
315 let mut buffer = [0; page::SIZE];
316 page::read_into(&self.memory, self.header.next, record.key, &mut buffer)?;
317 self.order
318 .compare(page::single_blob(&buffer, record.key_len)?, key)?
319 } else {
320 self.order.compare(&self.key(record)?, key)?
321 };
322 match order {
323 Ordering::Less => lo = mid + 1,
324 Ordering::Equal => return Ok((mid, true)),
325 Ordering::Greater => hi = mid,
326 }
327 }
328 Ok((lo, false))
329 }
330}
331
332impl<'a, M: Memory, C: Comparator> IntoIterator for &'a BTreeMap<M, C> {
333 type Item = Result<Entry<'a, M, C>, Error>;
334 type IntoIter = Range<'a, M, C>;
335 fn into_iter(self) -> Self::IntoIter {
336 self.iter()
337 }
338}