bbolt_rs/
bucket.rs

1use crate::common::bucket::{BucketHeader, BUCKET_HEADER_SIZE};
2use crate::common::cell::{Ref, RefMut};
3use crate::common::memory::{BCell, IsAligned};
4use crate::common::page::tree::branch::{MappedBranchPage, BRANCH_PAGE_ELEMENT_SIZE};
5use crate::common::page::tree::leaf::{
6  MappedLeafPage, BUCKET_LEAF_FLAG, LEAF_PAGE_ELEMENT_SIZE, LEAF_PAGE_FLAG,
7};
8use crate::common::page::tree::TreePage;
9use crate::common::page::{CoerciblePage, MutPage, PageHeader, RefPage, PAGE_HEADER_SIZE};
10use crate::common::{BVec, HashMap, PgId, SplitRef, ZERO_PGID};
11use crate::cursor::{CursorIApi, CursorImpl, CursorRwIApi, CursorRwImpl, InnerCursor, PageNode};
12use crate::iter::{BucketIter, BucketIterMut, EntryIter};
13use crate::node::NodeRwCell;
14use crate::tx::{TxCell, TxIApi, TxRwIApi};
15use crate::Error;
16use crate::Error::{
17  BucketExists, BucketNameRequired, BucketNotFound, IncompatibleValue, KeyRequired, KeyTooLarge,
18  ValueTooLarge,
19};
20use bumpalo::Bump;
21use bytemuck::{Pod, Zeroable};
22use getset::CopyGetters;
23use std::alloc::Layout;
24use std::marker::PhantomData;
25use std::ops::{AddAssign, Deref};
26use std::ptr::slice_from_raw_parts_mut;
27use std::slice::{from_raw_parts, from_raw_parts_mut};
28use std::{mem, ptr};
29
30/// Read-only Bucket API
31pub trait BucketApi<'tx>
32where
33  Self: Sized,
34{
35  /// Returns the bucket's root page id.
36  ///
37  /// ```rust
38  /// use bbolt_rs::*;
39  ///
40  /// fn main() -> Result<()> {
41  ///   let mut db = Bolt::open_mem()?;
42  ///
43  ///   db.update(|mut tx| {
44  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
45  ///     b.put("key", "value")?;
46  ///     Ok(())
47  ///   })?;
48  ///
49  ///   db.view(|tx| {
50  ///     let b = tx.bucket("test").unwrap();
51  ///     let page_id = b.root();
52  ///     let page_info = tx.page(page_id).unwrap();
53  ///     println!("{:?}", page_info);
54  ///     Ok(())
55  ///   })?;
56  ///
57  ///   Ok(())
58  /// }
59  /// ```
60  fn root(&self) -> PgId;
61
62  /// Returns whether the bucket is writable.
63  ///
64  /// ```rust
65  /// use bbolt_rs::*;
66  ///
67  /// fn main() -> Result<()> {
68  ///   let mut db = Bolt::open_mem()?;
69  ///
70  ///   db.update(|mut tx| {
71  ///     let b = tx.create_bucket_if_not_exists("test")?;
72  ///     assert_eq!(true, b.writable());
73  ///     Ok(())
74  ///   })?;
75  ///
76  ///   db.view(|tx| {
77  ///     let b = tx.bucket("test").unwrap();
78  ///     assert_eq!(false, b.writable());
79  ///     Ok(())
80  ///   })?;
81  ///
82  ///   Ok(())
83  /// }
84  /// ```
85  fn writable(&self) -> bool;
86
87  /// Creates a cursor associated with the bucket.
88  ///
89  /// ```rust
90  /// use bbolt_rs::*;
91  ///
92  /// fn main() -> Result<()> {
93  ///   let mut db = Bolt::open_mem()?;
94  ///
95  ///   db.update(|mut tx| {
96  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
97  ///     b.put("key", "value")?;
98  ///     Ok(())
99  ///   })?;
100  ///
101  ///   db.view(|tx| {
102  ///     let b = tx.bucket("test").unwrap();
103  ///     let mut c = b.cursor();
104  ///     let first = c.first();
105  ///     assert_eq!(Some((b"key".as_slice(), Some(b"value".as_slice()))), first);
106  ///     Ok(())
107  ///   })?;
108  ///
109  ///   Ok(())
110  /// }
111  /// ```
112  fn cursor<'a>(&'a self) -> CursorImpl<'tx, 'a>;
113
114  /// Retrieves a nested bucket by name.
115  ///
116  /// Returns None if the bucket does not exist.
117  ///
118  /// ```rust
119  /// use bbolt_rs::*;
120  ///
121  /// fn main() -> Result<()> {
122  ///   let mut db = Bolt::open_mem()?;
123  ///
124  ///   db.update(|mut tx| {
125  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
126  ///     let mut sub = b.create_bucket_if_not_exists("sub")?;
127  ///     sub.put("key", "value")?;
128  ///     Ok(())
129  ///   })?;
130  ///
131  ///   db.view(|tx| {
132  ///     let b = tx.bucket("test").unwrap();
133  ///     assert_eq!(true, b.bucket("sub").is_some());
134  ///     assert_eq!(false, b.bucket("no bucket").is_some());
135  ///     Ok(())
136  ///   })?;
137  ///
138  ///   Ok(())
139  /// }
140  /// ```
141  fn bucket<'a, T: AsRef<[u8]>>(&'a self, name: T) -> Option<BucketImpl<'tx, 'a>>;
142
143  /// Retrieves the value for a key in the bucket.
144  ///
145  /// Returns None if the key does not exist or if the key is a nested bucket.
146  ///
147  /// ```rust
148  /// use bbolt_rs::*;
149  ///
150  /// fn main() -> Result<()> {
151  ///   let mut db = Bolt::open_mem()?;
152  ///
153  ///   db.update(|mut tx| {
154  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
155  ///     b.put("key", "value")?;
156  ///     Ok(())
157  ///   })?;
158  ///
159  ///   db.view(|tx| {
160  ///     let b = tx.bucket("test").unwrap();
161  ///     let get = b.get("key");
162  ///     assert_eq!(Some(b"value".as_slice()), get);
163  ///     let get = b.get("no value");
164  ///     assert_eq!(None, get);
165  ///     Ok(())
166  ///   })?;
167  ///
168  ///   Ok(())
169  /// }
170  /// ```
171  fn get<T: AsRef<[u8]>>(&self, key: T) -> Option<&[u8]>;
172
173  /// Returns the current integer for the bucket without incrementing it.
174  ///
175  /// ```rust
176  /// use bbolt_rs::*;
177  ///
178  /// fn main() -> Result<()> {
179  ///   let mut db = Bolt::open_mem()?;
180  ///
181  ///   db.update(|mut tx| {
182  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
183  ///     b.put("key", "value")?;
184  ///     Ok(())
185  ///   })?;
186  ///
187  ///   db.view(|tx| {
188  ///     let b = tx.bucket("test").unwrap();
189  ///     let seq = b.sequence();
190  ///     assert_eq!(0, seq);
191  ///     Ok(())
192  ///   })?;
193  ///
194  ///   Ok(())
195  /// }
196  /// ```
197  fn sequence(&self) -> u64;
198
199  #[deprecated(since = "1.3.9", note = "please use `iter_*` methods instead")]
200  /// Executes a function for each key/value pair in a bucket.
201  /// Because this uses a [`crate::CursorApi`], the iteration over keys is in lexicographical order.
202  ///
203  /// If the provided function returns an error then the iteration is stopped and
204  /// the error is returned to the caller.
205  ///
206  /// ```rust
207  /// use bbolt_rs::*;
208  ///
209  /// fn main() -> Result<()> {
210  ///   let mut db = Bolt::open_mem()?;
211  ///
212  ///   db.update(|mut tx| {
213  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
214  ///     b.put("key1", "value1")?;
215  ///     b.put("key2", "value2")?;
216  ///     b.put("key3", "value3")?;
217  ///     Ok(())
218  ///   })?;
219  ///
220  ///   db.view(|tx| {
221  ///     let b = tx.bucket("test").unwrap();
222  ///     b.for_each(|k,v| {
223  ///      println!("{:?}, {:?}", k, v);
224  ///      Ok(())
225  ///     })?;
226  ///     Ok(())
227  ///   })?;
228  ///
229  ///   Ok(())
230  /// }
231  /// ```
232  fn for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
233    &self, f: F,
234  ) -> crate::Result<()>;
235
236  #[deprecated(since = "1.3.9", note = "please use `iter_*` methods instead")]
237  /// Executes a function for each bucket in a bucket.
238  /// Because this function uses a [`crate::CursorApi`], the iteration over keys is in lexicographical order.
239  ///
240  /// If the provided function returns an error then the iteration is stopped and
241  /// the error is returned to the caller.
242  ///
243  /// ```rust
244  /// use bbolt_rs::*;
245  ///
246  /// fn main() -> Result<()> {
247  ///   let mut db = Bolt::open_mem()?;
248  ///
249  ///   db.update(|mut tx| {
250  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
251  ///     let _ = b.create_bucket_if_not_exists("sub1")?;
252  ///     let _ = b.create_bucket_if_not_exists("sub2")?;
253  ///     let _ = b.create_bucket_if_not_exists("sub3")?;
254  ///     Ok(())
255  ///   })?;
256  ///
257  ///   db.view(|tx| {
258  ///     let b = tx.bucket("test").unwrap();
259  ///     b.for_each_bucket(|k| {
260  ///      println!("{:?}", k);
261  ///      Ok(())
262  ///     })?;
263  ///     Ok(())
264  ///   })?;
265  ///
266  ///   Ok(())
267  /// }
268  /// ```
269  fn for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(&self, f: F) -> crate::Result<()>;
270
271  /// Returns stats on a bucket.
272  ///
273  /// ```rust
274  /// use bbolt_rs::*;
275  ///
276  /// fn main() -> Result<()> {
277  ///   let mut db = Bolt::open_mem()?;
278  ///
279  ///   db.update(|mut tx| {
280  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
281  ///     b.put("key1", "value1")?;
282  ///     b.put("key2", "value2")?;
283  ///     b.put("key3", "value3")?;
284  ///     Ok(())
285  ///   })?;
286  ///
287  ///   db.view(|tx| {
288  ///     let b = tx.bucket("test").unwrap();
289  ///     let stats = b.stats();
290  ///     assert_eq!(3, stats.key_n());
291  ///     Ok(())
292  ///   })?;
293  ///
294  ///   Ok(())
295  /// }
296  /// ```
297  fn stats(&self) -> BucketStats;
298
299  fn iter_entries<'a>(&'a self) -> EntryIter<'tx, 'a>;
300
301  fn iter_buckets<'a>(&'a self) -> BucketIter<'tx, 'a>;
302}
303
304/// RW Bucket API
305pub trait BucketRwApi<'tx>: BucketApi<'tx> {
306  /// Retrieves a nested mutable bucket by name.
307  ///
308  /// Returns None if the bucket does not exist.
309  ///
310  /// ```rust
311  /// use bbolt_rs::*;
312  ///
313  /// fn main() -> Result<()> {
314  ///   let mut db = Bolt::open_mem()?;
315  ///
316  ///   db.update(|mut tx| {
317  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
318  ///     let _ = b.create_bucket_if_not_exists("sub")?;
319  ///     Ok(())
320  ///   })?;
321  ///
322  ///   db.update(|mut tx | {
323  ///     let mut b = tx.bucket_mut("test").unwrap();
324  ///     let mut sub = b.bucket_mut("sub").unwrap();
325  ///     sub.put("key1", "value1")?;
326  ///     Ok(())
327  ///   })?;
328  ///
329  ///   Ok(())
330  /// }
331  /// ```
332  fn bucket_mut<'a, T: AsRef<[u8]>>(&'a mut self, name: T) -> Option<BucketRwImpl<'tx, 'a>>;
333
334  /// Creates a new bucket at the given key and returns the new bucket.
335  ///
336  /// Returns an error if the key already exists, if the bucket name is blank, or if the bucket name is too long.
337  ///
338  /// ```rust
339  /// use bbolt_rs::*;
340  ///
341  /// fn main() -> Result<()> {
342  ///   let mut db = Bolt::open_mem()?;
343  ///
344  ///   db.update(|mut tx| {
345  ///     let mut b = tx.create_bucket("test")?;
346  ///     let _ = b.create_bucket("sub")?;
347  ///     Ok(())
348  ///   })?;
349  ///
350  ///   db.view(|tx| {
351  ///     let b = tx.bucket("test").unwrap();
352  ///     let _ = b.bucket("sub").unwrap();
353  ///     Ok(())
354  ///   })?;
355  ///
356  ///   Ok(())
357  /// }
358  /// ```
359  fn create_bucket<'a, T: AsRef<[u8]>>(
360    &'a mut self, key: T,
361  ) -> crate::Result<BucketRwImpl<'tx, 'a>>;
362
363  /// CreateBucketIfNotExists creates a new bucket if it doesn't already exist and returns a reference to it.
364  ///
365  /// Returns an error if the bucket name is blank, or if the bucket name is too long.
366  ///
367  /// ```rust
368  /// use bbolt_rs::*;
369  ///
370  /// fn main() -> Result<()> {
371  ///   let mut db = Bolt::open_mem()?;
372  ///
373  ///   db.update(|mut tx| {
374  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
375  ///     let _ = b.create_bucket_if_not_exists("sub")?;
376  ///     Ok(())
377  ///   })?;
378  ///
379  ///   db.view(|tx| {
380  ///     let b = tx.bucket("test").unwrap();
381  ///     let _ = b.bucket("sub").unwrap();
382  ///     Ok(())
383  ///   })?;
384  ///
385  ///   Ok(())
386  /// }
387  /// ```
388  fn create_bucket_if_not_exists<'a, T: AsRef<[u8]>>(
389    &'a mut self, key: T,
390  ) -> crate::Result<BucketRwImpl<'tx, 'a>>;
391
392  /// Cursor creates a cursor associated with the bucket.
393  ///
394  /// ```rust
395  /// use bbolt_rs::*;
396  ///
397  /// fn main() -> Result<()> {
398  ///   let mut db = Bolt::open_mem()?;
399  ///
400  ///   db.update(|mut tx| {
401  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
402  ///     b.put("key1", "value1")?;
403  ///     b.put("key2", "value2")?;
404  ///     b.put("key3", "value3")?;
405  ///     Ok(())
406  ///   })?;
407  ///
408  ///   db.update(|mut tx| {
409  ///     let mut b = tx.bucket_mut("test").unwrap();
410  ///     let mut c = b.cursor_mut();
411  ///     c.seek("key2");
412  ///     c.delete()?;
413  ///     Ok(())
414  ///   })?;
415  ///
416  ///   db.view(|tx| {
417  ///     let b = tx.bucket("test").unwrap();
418  ///     let mut c = b.cursor();
419  ///     let seek = c.seek("key2");
420  ///     assert_eq!(Some((b"key3".as_slice(), Some(b"value3".as_slice()))), seek);
421  ///     Ok(())
422  ///   })?;
423  ///
424  ///   Ok(())
425  /// }
426  /// ```
427  fn cursor_mut<'a>(&'a self) -> CursorRwImpl<'tx, 'a>;
428
429  /// Deletes a bucket at the given key.
430  ///
431  /// Returns an error if the bucket does not exist, or if the key represents a non-bucket value.
432  ///
433  /// ```rust
434  /// use bbolt_rs::*;
435  ///
436  /// fn main() -> Result<()> {
437  ///   let mut db = Bolt::open_mem()?;
438  ///
439  ///   db.update(|mut tx| {
440  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
441  ///     let _ = b.create_bucket_if_not_exists("sub")?;
442  ///     Ok(())
443  ///   })?;
444  ///
445  ///   db.update(|mut tx| {
446  ///     let mut b = tx.bucket_mut("test").unwrap();
447  ///     b.delete_bucket("sub")?;
448  ///     Ok(())
449  ///   })?;
450  ///
451  ///   db.view(|tx| {
452  ///     let b = tx.bucket("test").unwrap();
453  ///     assert_eq!(false, b.bucket("sub").is_some());
454  ///     Ok(())
455  ///   })?;
456  ///
457  ///   Ok(())
458  /// }
459  /// ```
460  fn delete_bucket<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()>;
461
462  /// Sets the value for a key in the bucket.
463  ///
464  /// If the key exist then its previous value will be overwritten.
465  ///
466  /// Returns an error if the key is blank, if the key is too large, or if the value is too large.
467  ///
468  /// ```rust
469  /// use bbolt_rs::*;
470  ///
471  /// fn main() -> Result<()> {
472  ///   let mut db = Bolt::open_mem()?;
473  ///
474  ///   db.update(|mut tx| {
475  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
476  ///     b.put("key1", "value1")?;
477  ///     b.put("key2", "value2")?;
478  ///     b.put("key3", "value3")?;
479  ///     Ok(())
480  ///   })?;
481  ///
482  ///   db.update(|mut tx| {
483  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
484  ///     b.put("key2", "new value")?;
485  ///     Ok(())
486  ///   })?;
487  ///
488  ///   db.view(|tx| {
489  ///     let b = tx.bucket("test").unwrap();
490  ///     let get = b.get("key1");
491  ///     assert_eq!(Some(b"value1".as_slice()), get);
492  ///     let get = b.get("key2");
493  ///     assert_eq!(Some(b"new value".as_slice()), get);
494  ///     Ok(())
495  ///   })?;
496  ///
497  ///   Ok(())
498  /// }
499  /// ```
500  fn put<T: AsRef<[u8]>, U: AsRef<[u8]>>(&mut self, key: T, data: U) -> crate::Result<()>;
501
502  /// Removes a key from the bucket.
503  ///
504  /// If the key does not exist then nothing is done.
505  ///
506  /// ```rust
507  /// use bbolt_rs::*;
508  ///
509  /// fn main() -> Result<()> {
510  ///   let mut db = Bolt::open_mem()?;
511  ///
512  ///   db.update(|mut tx| {
513  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
514  ///     b.put("key1", "value1")?;
515  ///     b.put("key2", "value2")?;
516  ///     b.put("key3", "value3")?;
517  ///     Ok(())
518  ///   })?;
519  ///
520  ///   db.update(|mut tx| {
521  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
522  ///     b.delete("key2")?;
523  ///     Ok(())
524  ///   })?;
525  ///
526  ///   db.view(|tx| {
527  ///     let b = tx.bucket("test").unwrap();
528  ///     let get = b.get("key1");
529  ///     assert_eq!(Some(b"value1".as_slice()), get);
530  ///     let get = b.get("key2");
531  ///     assert_eq!(false, get.is_some());
532  ///     Ok(())
533  ///   })?;
534  ///
535  ///   Ok(())
536  /// }
537  /// ```
538  fn delete<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()>;
539
540  /// Updates the sequence number for the bucket.
541  ///
542  /// ```rust
543  /// use bbolt_rs::*;
544  ///
545  /// fn main() -> Result<()> {
546  ///   let mut db = Bolt::open_mem()?;
547  ///
548  ///   db.update(|mut tx| {
549  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
550  ///     b.set_sequence(42)?;
551  ///     Ok(())
552  ///   })?;
553  ///
554  ///   db.view(|tx| {
555  ///     let b = tx.bucket("test").unwrap();
556  ///     assert_eq!(42, b.sequence());
557  ///     Ok(())
558  ///   })?;
559  ///
560  ///   Ok(())
561  /// }
562  /// ```
563  fn set_sequence(&mut self, v: u64) -> crate::Result<()>;
564
565  /// Returns the auto-incremented integer for the bucket.
566  ///
567  /// ```rust
568  /// use bbolt_rs::*;
569  ///
570  /// fn main() -> Result<()> {
571  ///   let mut db = Bolt::open_mem()?;
572  ///
573  ///   db.update(|mut tx| {
574  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
575  ///     b.set_sequence(42)?;
576  ///     assert_eq!(43, b.next_sequence()?);
577  ///     Ok(())
578  ///   })?;
579  ///
580  ///   Ok(())
581  /// }
582  /// ```
583  fn next_sequence(&mut self) -> crate::Result<u64>;
584
585  /// Set the fill percent of the bucket
586  ///
587  /// ```rust
588  /// use bbolt_rs::*;
589  ///
590  /// fn main() -> Result<()> {
591  ///   let mut db = Bolt::open_mem()?;
592  ///
593  ///   db.update(|mut tx| {
594  ///     let mut b = tx.create_bucket_if_not_exists("test")?;
595  ///     b.set_fill_percent(0.90);
596  ///     Ok(())
597  ///   })?;
598  ///
599  ///   Ok(())
600  /// }
601  /// ```
602  fn set_fill_percent(&mut self, fill_percent: f64);
603
604  fn iter_mut_buckets<'a>(&'a mut self) -> BucketIterMut<'tx, 'a>;
605
606  fn rev_iter_mut_buckets<'a>(&'a mut self) -> BucketIterMut<'tx, 'a>;
607}
608
609/// Read-only Bucket
610pub struct BucketImpl<'tx: 'p, 'p> {
611  pub(crate) b: BucketCell<'tx>,
612  p: PhantomData<&'p u8>,
613}
614
615impl<'tx, 'p> From<BucketCell<'tx>> for BucketImpl<'tx, 'p> {
616  fn from(value: BucketCell<'tx>) -> Self {
617    BucketImpl {
618      b: value,
619      p: PhantomData,
620    }
621  }
622}
623
624impl<'tx, 'p> BucketApi<'tx> for BucketImpl<'tx, 'p> {
625  fn root(&self) -> PgId {
626    self.b.root()
627  }
628
629  fn writable(&self) -> bool {
630    self.b.is_writeable()
631  }
632
633  fn cursor<'a>(&'a self) -> CursorImpl<'tx, 'a> {
634    InnerCursor::new(self.b, self.b.tx().bump()).into()
635  }
636
637  fn bucket<'a, T: AsRef<[u8]>>(&'a self, name: T) -> Option<BucketImpl<'tx, 'a>> {
638    self.b.api_bucket(name.as_ref()).map(BucketImpl::from)
639  }
640
641  fn get<T: AsRef<[u8]>>(&self, key: T) -> Option<&[u8]> {
642    self.b.api_get(key.as_ref())
643  }
644
645  fn sequence(&self) -> u64 {
646    self.b.api_sequence()
647  }
648
649  fn for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
650    &self, f: F,
651  ) -> crate::Result<()> {
652    self.b.api_for_each(f)
653  }
654
655  fn for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(&self, f: F) -> crate::Result<()> {
656    self.b.api_for_each_bucket(f)
657  }
658
659  fn stats(&self) -> BucketStats {
660    self.b.api_stats()
661  }
662
663  fn iter_entries<'a>(&'a self) -> EntryIter<'tx, 'a> {
664    EntryIter::new(self.b.i_cursor())
665  }
666
667  fn iter_buckets<'a>(&'a self) -> BucketIter<'tx, 'a> {
668    BucketIter::new(self.b.i_cursor())
669  }
670}
671
672/// Read/Write Bucket
673pub struct BucketRwImpl<'tx: 'p, 'p> {
674  b: BucketCell<'tx>,
675  p: PhantomData<&'p u8>,
676}
677
678impl<'tx, 'p> From<BucketCell<'tx>> for BucketRwImpl<'tx, 'p> {
679  fn from(value: BucketCell<'tx>) -> Self {
680    BucketRwImpl {
681      b: value,
682      p: PhantomData,
683    }
684  }
685}
686
687impl<'tx, 'p> BucketApi<'tx> for BucketRwImpl<'tx, 'p> {
688  fn root(&self) -> PgId {
689    self.b.root()
690  }
691
692  fn writable(&self) -> bool {
693    self.b.is_writeable()
694  }
695
696  fn cursor<'a>(&'a self) -> CursorImpl<'tx, 'a> {
697    InnerCursor::new(self.b, self.b.tx().bump()).into()
698  }
699
700  fn bucket<'a, T: AsRef<[u8]>>(&'a self, name: T) -> Option<BucketImpl<'tx, 'a>> {
701    self.b.api_bucket(name.as_ref()).map(BucketImpl::from)
702  }
703
704  fn get<T: AsRef<[u8]>>(&self, key: T) -> Option<&[u8]> {
705    self.b.api_get(key.as_ref())
706  }
707
708  fn sequence(&self) -> u64 {
709    self.b.api_sequence()
710  }
711
712  fn for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
713    &self, f: F,
714  ) -> crate::Result<()> {
715    self.b.api_for_each(f)
716  }
717
718  fn for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(&self, f: F) -> crate::Result<()> {
719    self.b.api_for_each_bucket(f)
720  }
721
722  fn stats(&self) -> BucketStats {
723    self.b.api_stats()
724  }
725
726  fn iter_entries<'a>(&'a self) -> EntryIter<'tx, 'a> {
727    EntryIter::new(self.b.i_cursor())
728  }
729
730  fn iter_buckets<'a>(&'a self) -> BucketIter<'tx, 'a> {
731    BucketIter::new(self.b.i_cursor())
732  }
733}
734
735impl<'tx, 'p> BucketRwApi<'tx> for BucketRwImpl<'tx, 'p> {
736  fn bucket_mut<'a, T: AsRef<[u8]>>(&'a mut self, name: T) -> Option<BucketRwImpl<'tx, 'a>> {
737    self.b.api_bucket(name.as_ref()).map(BucketRwImpl::from)
738  }
739
740  fn create_bucket<'a, T: AsRef<[u8]>>(
741    &'a mut self, key: T,
742  ) -> crate::Result<BucketRwImpl<'tx, 'a>> {
743    self
744      .b
745      .api_create_bucket(key.as_ref())
746      .map(BucketRwImpl::from)
747  }
748
749  fn create_bucket_if_not_exists<'a, T: AsRef<[u8]>>(
750    &'a mut self, key: T,
751  ) -> crate::Result<BucketRwImpl<'tx, 'a>> {
752    self
753      .b
754      .api_create_bucket_if_not_exists(key.as_ref())
755      .map(BucketRwImpl::from)
756  }
757
758  fn cursor_mut<'a>(&'a self) -> CursorRwImpl<'tx, 'a> {
759    CursorRwImpl::new(InnerCursor::new(self.b, self.b.tx().bump()))
760  }
761
762  fn delete_bucket<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()> {
763    self.b.api_delete_bucket(key.as_ref())
764  }
765
766  fn put<T: AsRef<[u8]>, U: AsRef<[u8]>>(&mut self, key: T, data: U) -> crate::Result<()> {
767    self.b.api_put(key.as_ref(), data.as_ref())
768  }
769
770  fn delete<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()> {
771    self.b.api_delete(key.as_ref())
772  }
773
774  fn set_sequence(&mut self, v: u64) -> crate::Result<()> {
775    self.b.api_set_sequence(v)
776  }
777
778  fn next_sequence(&mut self) -> crate::Result<u64> {
779    self.b.api_next_sequence()
780  }
781
782  fn set_fill_percent(&mut self, fill_percent: f64) {
783    // TODO: Move to cell api call
784    self.b.cell.borrow_mut().w.as_mut().unwrap().fill_percent = fill_percent;
785  }
786
787  fn iter_mut_buckets<'a>(&'a mut self) -> BucketIterMut<'tx, 'a> {
788    BucketIterMut::new(self.b.i_cursor())
789  }
790
791  fn rev_iter_mut_buckets<'a>(&'a mut self) -> BucketIterMut<'tx, 'a> {
792    BucketIterMut::new(self.b.i_cursor())
793  }
794}
795
796/// BucketStats records statistics about resources used by a bucket.
797#[derive(Copy, Clone, Eq, PartialEq, Default, Debug, CopyGetters)]
798#[getset(get_copy = "pub")]
799pub struct BucketStats {
800  // Page count statistics.
801  /// number of logical branch pages
802  branch_page_n: i64,
803  /// number of physical branch overflow pages
804  branch_overflow_n: i64,
805  /// number of logical leaf pages
806  leaf_page_n: i64,
807  /// number of physical leaf overflow pages
808  leaf_overflow_n: i64,
809
810  // Tree statistics.
811  /// number of keys/value pairs
812  pub(crate) key_n: i64,
813  /// number of levels in B+tree
814  depth: i64,
815
816  // Page size utilization.
817  /// bytes allocated for physical branch pages
818  branch_alloc: i64,
819  /// bytes actually used for branch data
820  branch_in_use: i64,
821  /// bytes allocated for physical leaf pages
822  leaf_alloc: i64,
823  /// bytes actually used for leaf data
824  leaf_in_use: i64,
825
826  // Bucket statistics
827  /// total number of buckets including the top bucket
828  bucket_n: i64,
829  /// total number on inlined buckets
830  inline_bucket_n: i64,
831  /// bytes used for inlined buckets (also accounted for in LeafInuse)
832  inline_bucket_in_use: i64,
833}
834
835impl AddAssign<BucketStats> for BucketStats {
836  fn add_assign(&mut self, rhs: BucketStats) {
837    self.branch_page_n += rhs.branch_page_n;
838    self.branch_overflow_n += rhs.branch_overflow_n;
839    self.leaf_page_n += rhs.leaf_page_n;
840    self.leaf_overflow_n += rhs.leaf_overflow_n;
841
842    self.key_n += rhs.key_n;
843    if self.depth < rhs.depth {
844      self.depth = rhs.depth;
845    }
846
847    self.branch_alloc += rhs.branch_alloc;
848    self.branch_in_use += rhs.branch_in_use;
849    self.leaf_alloc += rhs.leaf_alloc;
850    self.leaf_in_use += rhs.leaf_in_use;
851
852    self.bucket_n += rhs.bucket_n;
853    self.inline_bucket_n += rhs.inline_bucket_n;
854    self.inline_bucket_in_use += rhs.inline_bucket_in_use;
855  }
856}
857
858/// DefaultFillPercent is the percentage that split pages are filled.
859/// This value can be changed by setting Bucket.FillPercent.
860const DEFAULT_FILL_PERCENT: f64 = 0.5;
861
862/// MAX_KEY_SIZE is the maximum length of a key, in bytes.
863const MAX_KEY_SIZE: u32 = 32768;
864
865/// MaxValueSize is the maximum length of a value, in bytes.
866const MAX_VALUE_SIZE: u32 = (1 << 31) - 2;
867const INLINE_BUCKET_ALIGNMENT: usize = mem::align_of::<InlineBucket>();
868const INLINE_BUCKET_SIZE: usize = mem::size_of::<InlineBucket>();
869
870pub(crate) const MIN_FILL_PERCENT: f64 = 0.1;
871pub(crate) const MAX_FILL_PERCENT: f64 = 1.0;
872
873/// A convenience struct representing an inline page header
874#[repr(C)]
875#[derive(Copy, Clone, Pod, Zeroable)]
876struct InlineBucket {
877  header: BucketHeader,
878  page: PageHeader,
879}
880
881impl Default for InlineBucket {
882  fn default() -> Self {
883    InlineBucket {
884      header: BucketHeader::new(ZERO_PGID, 0),
885      page: PageHeader {
886        id: Default::default(),
887        flags: LEAF_PAGE_FLAG,
888        count: 0,
889        overflow: 0,
890      },
891    }
892  }
893}
894
895/// The internal Bucket API
896pub(crate) trait BucketIApi<'tx> {
897  fn new_r_in(
898    bump: &'tx Bump, bucket_header: BucketHeader, tx: TxCell<'tx>,
899    inline_page: Option<RefPage<'tx>>,
900  ) -> BucketCell<'tx>;
901
902  fn new_rw_in(
903    bump: &'tx Bump, bucket_header: BucketHeader, tx: TxCell<'tx>,
904    inline_page: Option<RefPage<'tx>>,
905  ) -> BucketCell<'tx>;
906
907  /// Returns whether the bucket is writable.
908  fn is_writeable(&self) -> bool;
909
910  /// Returns the rc ptr Tx of the bucket
911  fn tx(self) -> TxCell<'tx>;
912
913  /// Returns the root page id of the bucket
914  fn root(self) -> PgId;
915
916  /// Create a new cursor for this Bucket
917  fn i_cursor(self) -> InnerCursor<'tx>;
918
919  /// See [BucketApi::bucket]
920  fn api_bucket(self, name: &[u8]) -> Option<BucketCell<'tx>>;
921
922  /// Helper method that re-interprets a sub-bucket value
923  /// from a parent into a Bucket
924  fn open_bucket(self, value: &[u8]) -> BucketCell<'tx>;
925
926  /// See [BucketApi::get]
927  fn api_get(self, key: &[u8]) -> Option<&'tx [u8]>;
928
929  /// See [BucketApi::for_each]
930  fn api_for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
931    self, f: F,
932  ) -> crate::Result<()>;
933
934  /// See [BucketApi::for_each_bucket]
935  fn api_for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(self, f: F)
936    -> crate::Result<()>;
937
938  /// forEachPage iterates over every page in a bucket, including inline pages.
939  fn for_each_page<F: FnMut(&RefPage<'tx>, usize, &mut BVec<PgId>)>(self, f: &mut F);
940
941  /// forEachPageNode iterates over every page (or node) in a bucket.
942  /// This also includes inline pages.
943  fn for_each_page_node<F: FnMut(&PageNode<'tx>, usize) + Copy>(self, f: F);
944
945  fn _for_each_page_node<F: FnMut(&PageNode<'tx>, usize) + Copy>(
946    self, root: PgId, depth: usize, f: F,
947  );
948
949  fn page_node(self, id: PgId) -> PageNode<'tx>;
950
951  /// See [BucketApi::sequence]
952  fn api_sequence(self) -> u64;
953
954  /// Returns the maximum total size of a bucket to make it a candidate for inlining.
955  fn max_inline_bucket_size(self) -> usize;
956
957  /// See [BucketApi::stats]
958  fn api_stats(self) -> BucketStats;
959
960  fn into_impl<'a>(self) -> BucketImpl<'tx, 'a>;
961}
962
963pub(crate) trait BucketRwIApi<'tx>: BucketIApi<'tx> {
964  /// Explicitly materialize the root node
965  fn materialize_root(self) -> NodeRwCell<'tx>;
966
967  /// See [BucketRwApi::create_bucket]
968  fn api_create_bucket(self, key: &[u8]) -> crate::Result<Self>
969  where
970    Self: Sized;
971
972  /// See [BucketRwApi::create_bucket_if_not_exists]
973  fn api_create_bucket_if_not_exists(self, key: &[u8]) -> crate::Result<Self>
974  where
975    Self: Sized;
976
977  /// See [BucketRwApi::delete_bucket]
978  fn api_delete_bucket(self, key: &[u8]) -> crate::Result<()>;
979
980  /// See [BucketRwApi::put]
981  fn api_put(self, key: &[u8], value: &[u8]) -> crate::Result<()>;
982
983  /// See [BucketRwApi::delete]
984  fn api_delete(self, key: &[u8]) -> crate::Result<()>;
985
986  /// See [BucketRwApi::set_sequence]
987  fn api_set_sequence(self, v: u64) -> crate::Result<()>;
988
989  /// See [BucketRwApi::next_sequence]
990  fn api_next_sequence(self) -> crate::Result<u64>;
991
992  /// free recursively frees all pages in the bucket.
993  fn free(self);
994
995  /// spill writes all the nodes for this bucket to dirty pages.
996  fn spill(self, bump: &'tx Bump) -> crate::Result<()>;
997
998  fn write(self, bump: &'tx Bump) -> &'tx [u8];
999
1000  /// inlineable returns true if a bucket is small enough to be written inline
1001  /// and if it contains no subbuckets. Otherwise returns false.
1002  fn inlineable(self) -> bool;
1003
1004  /// own_in removes all references to the old mmap.
1005  fn own_in(self);
1006
1007  /// node creates a node from a page and associates it with a given parent.
1008  fn node(self, pgid: PgId, parent: Option<NodeRwCell<'tx>>) -> NodeRwCell<'tx>;
1009
1010  /// rebalance attempts to balance all nodes.
1011  fn rebalance(self);
1012}
1013
1014pub struct BucketR<'tx> {
1015  pub(crate) bucket_header: BucketHeader,
1016  /// inline page reference
1017  pub(crate) inline_page: Option<RefPage<'tx>>,
1018  p: PhantomData<&'tx u8>,
1019}
1020
1021impl<'tx> BucketR<'tx> {
1022  pub fn new(in_bucket: BucketHeader) -> BucketR<'tx> {
1023    BucketR {
1024      bucket_header: in_bucket,
1025      inline_page: None,
1026      p: Default::default(),
1027    }
1028  }
1029}
1030
1031pub struct BucketW<'tx> {
1032  /// materialized node for the root page.
1033  pub(crate) root_node: Option<NodeRwCell<'tx>>,
1034  /// subbucket cache
1035  buckets: HashMap<'tx, &'tx [u8], BucketCell<'tx>>,
1036  /// node cache
1037  pub(crate) nodes: HashMap<'tx, PgId, NodeRwCell<'tx>>,
1038
1039  /// Sets the threshold for filling nodes when they split. By default,
1040  /// the bucket will fill to 50% but it can be useful to increase this
1041  /// amount if you know that your write workloads are mostly append-only.
1042  ///
1043  /// This is non-persisted across transactions so it must be set in every Tx.
1044  pub(crate) fill_percent: f64,
1045}
1046
1047impl<'tx> BucketW<'tx> {
1048  pub fn new_in(bump: &'tx Bump) -> BucketW<'tx> {
1049    BucketW {
1050      root_node: None,
1051      buckets: HashMap::with_capacity_in(0, bump),
1052      nodes: HashMap::with_capacity_in(0, bump),
1053      fill_percent: DEFAULT_FILL_PERCENT,
1054    }
1055  }
1056}
1057
1058pub struct BucketRW<'tx> {
1059  pub(crate) r: BucketR<'tx>,
1060  pub(crate) w: Option<BucketW<'tx>>,
1061}
1062
1063#[derive(Copy, Clone)]
1064pub(crate) struct BucketCell<'tx> {
1065  pub(crate) cell: BCell<'tx, BucketRW<'tx>, TxCell<'tx>>,
1066}
1067
1068impl<'tx> PartialEq for BucketCell<'tx> {
1069  fn eq(&self, other: &Self) -> bool {
1070    let self_txid = self.tx().api_id();
1071    let other_txid = other.tx().api_id();
1072    let self_header = self.split_r().bucket_header;
1073    let other_header = other.split_r().bucket_header;
1074    self_txid == other_txid && self_header == other_header
1075  }
1076}
1077
1078impl<'tx> Eq for BucketCell<'tx> {}
1079
1080impl<'tx> SplitRef<BucketR<'tx>, TxCell<'tx>, BucketW<'tx>> for BucketCell<'tx> {
1081  fn split_r(&self) -> Ref<BucketR<'tx>> {
1082    Ref::map(self.cell.borrow(), |b| &b.r)
1083  }
1084
1085  fn split_ref(&self) -> (Ref<BucketR<'tx>>, Ref<Option<BucketW<'tx>>>) {
1086    let (r, w) = Ref::map_split(self.cell.borrow(), |b| (&b.r, &b.w));
1087    (r, w)
1088  }
1089
1090  fn split_ow(&self) -> Ref<Option<BucketW<'tx>>> {
1091    Ref::map(self.cell.borrow(), |b| &b.w)
1092  }
1093
1094  fn split_bound(&self) -> TxCell<'tx> {
1095    self.cell.bound()
1096  }
1097
1098  fn split_r_mut(&self) -> RefMut<BucketR<'tx>> {
1099    RefMut::map(self.cell.borrow_mut(), |b| &mut b.r)
1100  }
1101
1102  fn split_ow_mut(&self) -> RefMut<Option<BucketW<'tx>>> {
1103    RefMut::map(self.cell.borrow_mut(), |b| &mut b.w)
1104  }
1105}
1106
1107impl<'tx> BucketIApi<'tx> for BucketCell<'tx> {
1108  fn new_r_in(
1109    bump: &'tx Bump, bucket_header: BucketHeader, tx: TxCell<'tx>,
1110    inline_page: Option<RefPage<'tx>>,
1111  ) -> BucketCell<'tx> {
1112    let r = BucketR {
1113      bucket_header,
1114      inline_page,
1115      p: Default::default(),
1116    };
1117
1118    BucketCell {
1119      cell: BCell::new_in(BucketRW { r, w: None }, tx, bump),
1120    }
1121  }
1122
1123  fn new_rw_in(
1124    bump: &'tx Bump, bucket_header: BucketHeader, tx: TxCell<'tx>,
1125    inline_page: Option<RefPage<'tx>>,
1126  ) -> BucketCell<'tx> {
1127    let r = BucketR {
1128      bucket_header,
1129      inline_page,
1130      p: Default::default(),
1131    };
1132
1133    let w = BucketW::new_in(bump);
1134
1135    BucketCell {
1136      cell: BCell::new_in(BucketRW { r, w: Some(w) }, tx, bump),
1137    }
1138  }
1139
1140  #[inline(always)]
1141  fn is_writeable(&self) -> bool {
1142    self.cell.borrow().w.is_some()
1143  }
1144
1145  /// Returns the rc ptr Tx of the bucket
1146  fn tx(self) -> TxCell<'tx> {
1147    self.split_bound()
1148  }
1149
1150  /// Returns the root page id of the bucket
1151  fn root(self) -> PgId {
1152    self.split_r().bucket_header.root()
1153  }
1154
1155  fn i_cursor(self) -> InnerCursor<'tx> {
1156    let tx = self.tx();
1157    tx.split_r().stats.as_ref().unwrap().inc_cursor_count(1);
1158    InnerCursor::new(self, tx.bump())
1159  }
1160
1161  /// See [BucketApi::bucket]
1162  fn api_bucket(self, name: &[u8]) -> Option<BucketCell<'tx>> {
1163    if let Some(w) = self.split_ow().as_ref() {
1164      if let Some(child) = w.buckets.get(name) {
1165        return Some(*child);
1166      }
1167    }
1168    let mut c = self.i_cursor();
1169    // Move cursor to key.
1170    let (k, v, flags) = c.i_seek(name)?;
1171    // Return None if the key doesn't exist or it is not a bucket.
1172    if name != k || (flags & BUCKET_LEAF_FLAG) == 0 {
1173      return None;
1174    }
1175
1176    // Otherwise create a bucket and cache it.
1177    let child = self.open_bucket(v);
1178    if let Some(w) = self.split_ow_mut().as_mut() {
1179      let tx = self.split_bound();
1180      let bump = tx.bump();
1181      let name = bump.alloc_slice_copy(name);
1182      w.buckets.insert(name, child);
1183    }
1184
1185    Some(child)
1186  }
1187
1188  /// Helper method that re-interprets a sub-bucket value
1189  /// from a parent into a Bucket
1190  fn open_bucket(self, mut value: &[u8]) -> BucketCell<'tx> {
1191    let tx = self.tx();
1192    let bump = tx.bump();
1193    // Unaligned access requires a copy to be made.
1194    //TODO: use std is_aligned_to when it comes out
1195    if !IsAligned::is_aligned_to::<InlineBucket>(value.as_ptr()) {
1196      // TODO: Shove this into a centralized function somewhere
1197      let layout = Layout::from_size_align(value.len(), INLINE_BUCKET_ALIGNMENT).unwrap();
1198      let new_value = unsafe {
1199        let data = bump.alloc_layout(layout).as_ptr();
1200        ptr::write_bytes(data, 0, value.len());
1201        &mut *slice_from_raw_parts_mut(data, value.len())
1202      };
1203      new_value.copy_from_slice(value);
1204      value = new_value;
1205    }
1206    let bucket_header = *bytemuck::from_bytes::<BucketHeader>(value.split_at(BUCKET_HEADER_SIZE).0);
1207    // Save a reference to the inline page if the bucket is inline.
1208    let ref_page = if bucket_header.root() == ZERO_PGID {
1209      assert!(
1210        value.len() >= INLINE_BUCKET_SIZE,
1211        "subbucket value not large enough. Expected at least {} bytes. Was {}",
1212        INLINE_BUCKET_SIZE,
1213        value.len()
1214      );
1215      unsafe {
1216        let ref_page_ptr = value.as_ptr().add(BUCKET_HEADER_SIZE);
1217        Some(RefPage::new(ref_page_ptr))
1218      }
1219    } else {
1220      None
1221    };
1222    if tx.split_ow().is_some() {
1223      Self::new_rw_in(bump, bucket_header, tx, ref_page)
1224    } else {
1225      Self::new_r_in(bump, bucket_header, tx, ref_page)
1226    }
1227  }
1228
1229  /// See [BucketApi::get]
1230  fn api_get(self, key: &[u8]) -> Option<&'tx [u8]> {
1231    if let Some((k, v, flags)) = self.i_cursor().i_seek(key) {
1232      // Return None if this is a bucket.
1233      if (flags & BUCKET_LEAF_FLAG) != 0 {
1234        return None;
1235      }
1236      // If our target node isn't the same key as what's passed in then return None.
1237      if key != k {
1238        return None;
1239      }
1240      Some(v)
1241    } else {
1242      None
1243    }
1244  }
1245
1246  /// See [BucketApi::for_each]
1247  fn api_for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
1248    self, mut f: F,
1249  ) -> crate::Result<()> {
1250    let mut c = self.i_cursor();
1251    let mut inode = c.api_first();
1252    while let Some((k, v)) = inode {
1253      f(k, v)?;
1254      inode = c.api_next();
1255    }
1256    Ok(())
1257  }
1258
1259  /// See [BucketApi::for_each_bucket]
1260  fn api_for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(
1261    self, mut f: F,
1262  ) -> crate::Result<()> {
1263    let mut c = self.i_cursor();
1264    let mut inode = c.i_first();
1265    while let Some((k, _, flags)) = inode {
1266      if flags & BUCKET_LEAF_FLAG != 0 {
1267        f(k)?;
1268      }
1269      inode = c.i_next();
1270    }
1271    Ok(())
1272  }
1273
1274  /// forEachPage iterates over every page in a bucket, including inline pages.
1275  fn for_each_page<F: FnMut(&RefPage<'tx>, usize, &mut BVec<PgId>)>(self, f: &mut F) {
1276    let tx = self.tx();
1277    let root = {
1278      let r = self.split_r();
1279      let root = r.bucket_header.root();
1280      // If we have an inline page then just use that.
1281      if let Some(page) = &r.inline_page {
1282        let mut v = BVec::with_capacity_in(1, tx.bump());
1283        v.push(root);
1284        f(page, 0, &mut v);
1285        return;
1286      }
1287      root
1288    };
1289    // Otherwise traverse the page hierarchy.
1290    tx.for_each_page(root, f)
1291  }
1292
1293  /// forEachPageNode iterates over every page (or node) in a bucket.
1294  /// This also includes inline pages.
1295  fn for_each_page_node<F: FnMut(&PageNode<'tx>, usize) + Copy>(self, mut f: F) {
1296    let root = {
1297      let r = self.split_r();
1298      // If we have an inline page or root node then just use that.
1299      if let Some(page) = &r.inline_page {
1300        f(&PageNode::Page(*page), 0);
1301        return;
1302      }
1303      r.bucket_header.root()
1304    };
1305    self._for_each_page_node(root, 0, f);
1306  }
1307
1308  fn _for_each_page_node<F: FnMut(&PageNode<'tx>, usize) + Copy>(
1309    self, root: PgId, depth: usize, mut f: F,
1310  ) {
1311    let pn = self.page_node(root);
1312
1313    // Execute function.
1314    f(&pn, depth);
1315
1316    // Recursively loop over children.
1317    match &pn {
1318      PageNode::Page(page) => {
1319        if let Some(branch_page) = MappedBranchPage::coerce_ref(page) {
1320          branch_page.elements().iter().for_each(|elem| {
1321            self._for_each_page_node(elem.pgid(), depth + 1, f);
1322          });
1323        }
1324      }
1325      PageNode::Node(node) => {
1326        let bump = self.tx().bump();
1327        // To keep with our rules we much copy the inode pgids to temporary storage first
1328        // This should be unnecessary, but working first *then* optimize
1329        let v = {
1330          let node_borrow = node.cell.borrow();
1331          if node_borrow.is_leaf {
1332            return;
1333          }
1334          let mut v = BVec::with_capacity_in(node_borrow.inodes.len(), bump);
1335          let ids = node_borrow.inodes.iter().map(|inode| inode.pgid());
1336          v.extend(ids);
1337          v
1338        };
1339        for pgid in v.into_iter() {
1340          self._for_each_page_node(pgid, depth + 1, f);
1341        }
1342      }
1343    }
1344  }
1345
1346  fn page_node(self, id: PgId) -> PageNode<'tx> {
1347    let (r, w) = self.split_ref();
1348    // Inline buckets have a fake page embedded in their value so treat them
1349    // differently. We'll return the rootNode (if available) or the fake page.
1350    if r.bucket_header.root() == ZERO_PGID {
1351      if id != ZERO_PGID {
1352        panic!("inline bucket non-zero page access(2): {} != 0", id)
1353      }
1354      return if let Some(root_node) = w.as_ref().and_then(|wb| wb.root_node) {
1355        PageNode::Node(root_node)
1356      } else {
1357        PageNode::Page(r.inline_page.unwrap())
1358      };
1359    }
1360
1361    // Check the node cache for non-inline buckets.
1362    if let Some(wb) = w.as_ref() {
1363      if let Some(node) = wb.nodes.get(&id) {
1364        return PageNode::Node(*node);
1365      }
1366    }
1367
1368    PageNode::Page(self.tx().mem_page(id))
1369  }
1370
1371  /// See [BucketApi::sequence]
1372  fn api_sequence(self) -> u64 {
1373    self.split_r().bucket_header.sequence()
1374  }
1375
1376  /// Returns the maximum total size of a bucket to make it a candidate for inlining.
1377  fn max_inline_bucket_size(self) -> usize {
1378    self.tx().page_size() / 4
1379  }
1380
1381  /// See [BucketApi::stats]
1382  fn api_stats(self) -> BucketStats {
1383    let mut s = BucketStats::default();
1384    let mut sub_stats = BucketStats::default();
1385    let page_size = self.tx().page_size();
1386    s.bucket_n += 1;
1387    if self.root() == ZERO_PGID {
1388      s.inline_bucket_n += 1;
1389    }
1390    self.for_each_page(&mut |p, depth, _| {
1391      if let Some(leaf_page) = MappedLeafPage::coerce_ref(p) {
1392        s.key_n += p.count as i64;
1393
1394        // used totals the used bytes for the page
1395        let mut used = PAGE_HEADER_SIZE;
1396        if let Some(last_element) = leaf_page.elements().last() {
1397          // If page has any elements, add all element headers.
1398          used += LEAF_PAGE_ELEMENT_SIZE * (p.count - 1) as usize;
1399
1400          // Add all element key, value sizes.
1401          // The computation takes advantage of the fact that the position
1402          // of the last element's key/value equals to the total of the sizes
1403          // of all previous elements' keys and values.
1404          // It also includes the last element's header.
1405          used += last_element.pos() as usize
1406            + last_element.key_size() as usize
1407            + last_element.value_size() as usize;
1408        }
1409
1410        // For inlined bucket just update the inline stats
1411        if self.root() == ZERO_PGID {
1412          s.inline_bucket_in_use += used as i64;
1413        } else {
1414          // For non-inlined bucket update all the leaf stats
1415          s.leaf_page_n += 1;
1416          s.leaf_in_use += used as i64;
1417          s.leaf_overflow_n += leaf_page.overflow as i64;
1418
1419          // Collect stats from sub-buckets.
1420          // Do that by iterating over all element headers
1421          // looking for the ones with the bucketLeafFlag.
1422          for leaf_elem in leaf_page.iter() {
1423            if leaf_elem.is_bucket_entry() {
1424              // For any bucket element, open the element value
1425              // and recursively call Stats on the contained bucket.
1426              sub_stats += self.open_bucket(leaf_elem.value()).api_stats();
1427            }
1428          }
1429        }
1430      } else if let Some(branch_page) = MappedBranchPage::coerce_ref(p) {
1431        s.branch_page_n += 1;
1432        if let Some(last_element) = branch_page.elements().last() {
1433          // used totals the used bytes for the page
1434          // Add header and all element headers.
1435          let mut used =
1436            PAGE_HEADER_SIZE + (BRANCH_PAGE_ELEMENT_SIZE * (branch_page.count - 1) as usize);
1437          // Add size of all keys and values.
1438          // Again, use the fact that last element's position equals to
1439          // the total of key, value sizes of all previous elements.
1440          used += last_element.pos() as usize + last_element.key_size() as usize;
1441          s.branch_in_use += used as i64;
1442          s.branch_overflow_n += branch_page.overflow as i64;
1443        }
1444      }
1445
1446      if (depth + 1) as i64 > s.depth {
1447        s.depth = (depth + 1) as i64;
1448      }
1449    });
1450    // Alloc stats can be computed from page counts and pageSize.
1451    s.branch_alloc = (s.branch_page_n + s.branch_overflow_n) * page_size as i64;
1452    s.leaf_alloc = (s.leaf_page_n + s.leaf_overflow_n) * page_size as i64;
1453
1454    // Add the max depth of sub-buckets to get total nested depth.
1455    s.depth += sub_stats.depth;
1456    // Add the stats for all sub-buckets
1457    s += sub_stats;
1458    s
1459  }
1460
1461  fn into_impl<'a>(self) -> BucketImpl<'tx, 'a> {
1462    self.into()
1463  }
1464}
1465
1466impl<'tx> BucketRwIApi<'tx> for BucketCell<'tx> {
1467  fn materialize_root(self) -> NodeRwCell<'tx> {
1468    let root_id = {
1469      let bucket = self.cell.borrow();
1470      match bucket.w.as_ref().unwrap().root_node {
1471        None => bucket.r.bucket_header.root(),
1472        Some(root_node) => return root_node,
1473      }
1474    };
1475    self.node(root_id, None)
1476  }
1477
1478  fn api_create_bucket(self, key: &[u8]) -> crate::Result<Self> {
1479    if key.is_empty() {
1480      return Err(BucketNameRequired);
1481    }
1482    let mut c = self.i_cursor();
1483
1484    if let Some((k, _, flags)) = c.i_seek(key) {
1485      if k == key {
1486        if flags & BUCKET_LEAF_FLAG != 0 {
1487          return Err(BucketExists);
1488        }
1489        return Err(IncompatibleValue);
1490      }
1491    }
1492
1493    let inline_page = InlineBucket::default();
1494    let layout = Layout::from_size_align(INLINE_BUCKET_SIZE, INLINE_BUCKET_ALIGNMENT).unwrap();
1495    let bump = self.tx().bump();
1496    let data = bump.alloc_layout(layout).as_ptr();
1497
1498    let value = unsafe {
1499      ptr::write_bytes(data, 0, INLINE_BUCKET_SIZE);
1500      from_raw_parts_mut(data, INLINE_BUCKET_SIZE)
1501    };
1502    value.copy_from_slice(bytemuck::bytes_of(&inline_page));
1503    let key = bump.alloc_slice_clone(key) as &[u8];
1504
1505    c.node().put(key, key, value, ZERO_PGID, BUCKET_LEAF_FLAG);
1506
1507    self.split_r_mut().inline_page = None;
1508
1509    Ok(self.api_bucket(key).unwrap())
1510  }
1511
1512  fn api_create_bucket_if_not_exists(self, key: &[u8]) -> crate::Result<Self> {
1513    match self.api_create_bucket(key) {
1514      Ok(child) => Ok(child),
1515      Err(error) => {
1516        if error == BucketExists {
1517          Ok(self.api_bucket(key).unwrap())
1518        } else {
1519          Err(error)
1520        }
1521      }
1522    }
1523  }
1524
1525  fn api_delete_bucket(self, key: &[u8]) -> crate::Result<()> {
1526    let mut c = self.i_cursor();
1527
1528    let (k, _, flags) = c.i_seek(key).unwrap_or((&[], &[], 0));
1529    if key != k {
1530      return Err(BucketNotFound);
1531    } else if flags & BUCKET_LEAF_FLAG == 0 {
1532      return Err(IncompatibleValue);
1533    }
1534
1535    let child = self.api_bucket(key).unwrap();
1536    child.api_for_each_bucket(|k| {
1537      match child.api_delete_bucket(k) {
1538        Ok(_) => Ok(()),
1539        // TODO: Ideally we want to properly chain errors here
1540        Err(e) => Err(Error::Other(e.into())),
1541      }
1542    })?;
1543
1544    {
1545      let mut self_mut = self.cell.borrow_mut();
1546      let self_w = self_mut.w.as_mut().unwrap();
1547      self_w.buckets.remove(key);
1548      let mut child_mut = child.cell.borrow_mut();
1549      let child_w = child_mut.w.as_mut().unwrap();
1550      child_w.nodes.clear();
1551      child_w.root_node = None;
1552    }
1553
1554    child.free();
1555
1556    c.node().del(key);
1557    Ok(())
1558  }
1559
1560  fn api_put(self, key: &[u8], value: &[u8]) -> crate::Result<()> {
1561    if key.is_empty() {
1562      return Err(KeyRequired);
1563    } else if key.len() > MAX_KEY_SIZE as usize {
1564      return Err(KeyTooLarge);
1565    } else if value.len() > MAX_VALUE_SIZE as usize {
1566      return Err(ValueTooLarge);
1567    }
1568    let mut c = self.i_cursor();
1569    if let Some((k, _, flags)) = c.i_seek(key) {
1570      if key == k && (flags & BUCKET_LEAF_FLAG) != 0 {
1571        return Err(IncompatibleValue);
1572      }
1573    }
1574
1575    let bump = self.tx().bump();
1576    let key = &*bump.alloc_slice_clone(key);
1577    let value = &*bump.alloc_slice_clone(value);
1578    c.node().put(key, key, value, ZERO_PGID, 0);
1579    Ok(())
1580  }
1581
1582  fn api_delete(self, key: &[u8]) -> crate::Result<()> {
1583    let mut c = self.i_cursor();
1584    if let Some((k, _, flags)) = c.i_seek(key) {
1585      if key != k {
1586        return Ok(());
1587      }
1588      if flags & BUCKET_LEAF_FLAG != 0 {
1589        return Err(IncompatibleValue);
1590      }
1591
1592      c.node().del(key);
1593    }
1594    Ok(())
1595  }
1596
1597  fn api_set_sequence(self, v: u64) -> crate::Result<()> {
1598    self.materialize_root();
1599    self.split_r_mut().bucket_header.set_sequence(v);
1600    Ok(())
1601  }
1602
1603  fn api_next_sequence(self) -> crate::Result<u64> {
1604    self.materialize_root();
1605    let mut r = self.split_r_mut();
1606    r.bucket_header.inc_sequence();
1607    Ok(r.bucket_header.sequence())
1608  }
1609
1610  fn free(self) {
1611    if self.split_r().bucket_header.root() == ZERO_PGID {
1612      return;
1613    }
1614
1615    let tx = self.tx();
1616    let txid = tx.meta().txid();
1617
1618    self.for_each_page_node(|pn, _| match pn {
1619      PageNode::Page(page) => tx.freelist_free_page(txid, page),
1620      PageNode::Node(node) => node.free(),
1621    });
1622    self.split_r_mut().bucket_header.set_root(ZERO_PGID);
1623  }
1624
1625  /// spill writes all the nodes for this bucket to dirty pages.
1626  fn spill(self, bump: &'tx Bump) -> crate::Result<()> {
1627    // To keep with our rules we much copy the bucket entries to temporary storage first
1628    // This should be unnecessary, but working first *then* optimize
1629    let v = {
1630      let bucket = self.cell.borrow();
1631      let mut v = BVec::with_capacity_in(bucket.w.as_ref().unwrap().buckets.len(), bump);
1632      // v.extend() would be more idiomatic, but I'm too tired atm to figure out why
1633      // it's not working
1634      for (name, child) in &bucket.w.as_ref().unwrap().buckets {
1635        v.push((*name, *child));
1636      }
1637      v
1638    };
1639
1640    for (name, child) in v.into_iter() {
1641      let value = if child.inlineable() {
1642        child.free();
1643        child.write(bump)
1644      } else {
1645        child.spill(bump)?;
1646        let layout = Layout::from_size_align(BUCKET_HEADER_SIZE, INLINE_BUCKET_ALIGNMENT).unwrap();
1647        let inline_bucket_ptr = bump.alloc_layout(layout).as_ptr();
1648        unsafe {
1649          let inline_bucket = &mut (*(inline_bucket_ptr as *mut BucketHeader));
1650          *inline_bucket = child.split_r().bucket_header;
1651          from_raw_parts(inline_bucket_ptr, BUCKET_HEADER_SIZE)
1652        }
1653      };
1654      if child.cell.borrow().w.as_ref().unwrap().root_node.is_none() {
1655        continue;
1656      }
1657      let mut c = self.i_cursor();
1658      let (k, _, flags) = c.i_seek(name).unwrap();
1659      assert_eq!(name, k, "misplaced bucket header");
1660      assert_ne!(
1661        flags & BUCKET_LEAF_FLAG,
1662        0,
1663        "unexpected bucket header flag: {:x}",
1664        flags
1665      );
1666
1667      c.node().put(name, name, value, ZERO_PGID, BUCKET_LEAF_FLAG);
1668    }
1669
1670    let root_node = match self.cell.borrow().w.as_ref().unwrap().root_node {
1671      None => return Ok(()),
1672      Some(root_node) => root_node,
1673    };
1674
1675    root_node.spill()?;
1676    {
1677      let mut self_borrow = self.cell.borrow_mut();
1678      let new_root = root_node.root();
1679      self_borrow.w.as_mut().unwrap().root_node = Some(new_root);
1680      let borrow_root = new_root.cell.borrow_mut();
1681      let new_pgid = borrow_root.pgid;
1682      let tx_pgid = self.cell.bound().meta().pgid();
1683      if new_pgid >= tx_pgid {
1684        panic!("pgid ({}) above high water mark ({})", new_pgid, tx_pgid);
1685      }
1686      self_borrow.r.bucket_header.set_root(new_pgid);
1687    }
1688    Ok(())
1689  }
1690
1691  fn write(self, bump: &'tx Bump) -> &'tx [u8] {
1692    let root_node = self.materialize_root();
1693    let page_size = BUCKET_HEADER_SIZE + root_node.size();
1694    let layout = Layout::from_size_align(page_size, INLINE_BUCKET_ALIGNMENT).unwrap();
1695    let inline_bucket_ptr = bump.alloc_layout(layout).as_ptr();
1696
1697    unsafe {
1698      let inline_bucket = &mut (*(inline_bucket_ptr as *mut BucketHeader));
1699      *inline_bucket = self.cell.borrow().r.bucket_header;
1700      let mut mut_page = MutPage::new(inline_bucket_ptr.add(BUCKET_HEADER_SIZE));
1701      mut_page.id = PgId(0);
1702      mut_page.count = 0;
1703      mut_page.overflow = 0;
1704      root_node.write(&mut mut_page);
1705      from_raw_parts(inline_bucket_ptr, page_size)
1706    }
1707  }
1708
1709  fn inlineable(self) -> bool {
1710    let bucket = self.cell.borrow_mut();
1711
1712    // Bucket must only contain a single leaf node.
1713    let n = match bucket.w.as_ref().unwrap().root_node {
1714      None => return false,
1715      Some(n) => n,
1716    };
1717
1718    let node_ref = n.cell.borrow();
1719    if !node_ref.is_leaf {
1720      return false;
1721    }
1722
1723    // Bucket is not inlineable if it contains subbuckets or if it goes beyond
1724    // our threshold for inline bucket size.
1725    let mut size = PAGE_HEADER_SIZE;
1726    for inode in node_ref.inodes.deref() {
1727      size += LEAF_PAGE_ELEMENT_SIZE + inode.key().len() + inode.value().len();
1728
1729      if inode.flags() & BUCKET_LEAF_FLAG != 0 || size > self.max_inline_bucket_size() {
1730        return false;
1731      }
1732    }
1733
1734    true
1735  }
1736
1737  fn own_in(self) {
1738    let (bump, root, children) = {
1739      let tx = self.split_bound();
1740      let bucket = self.cell.borrow();
1741      let bump = tx.bump();
1742      let mut children: BVec<BucketCell<'tx>> =
1743        BVec::with_capacity_in(bucket.w.as_ref().unwrap().buckets.len(), bump);
1744      children.extend(bucket.w.as_ref().unwrap().buckets.values());
1745      (bump, bucket.w.as_ref().unwrap().root_node, children)
1746    };
1747
1748    if let Some(node) = root {
1749      node.root().own_in(bump);
1750    }
1751
1752    for child in children.into_iter() {
1753      child.own_in();
1754    }
1755  }
1756
1757  fn node(self, pgid: PgId, parent: Option<NodeRwCell<'tx>>) -> NodeRwCell<'tx> {
1758    let inline_page = {
1759      let self_borrow = self.cell.borrow_mut();
1760
1761      // Retrieve node if it's already been created.
1762      if let Some(n) = self_borrow.w.as_ref().unwrap().nodes.get(&pgid) {
1763        return *n;
1764      }
1765      self_borrow.r.inline_page
1766    };
1767
1768    // Otherwise create a node and cache it.
1769    // Use the inline page if this is an inline bucket.
1770    let page = match inline_page {
1771      None => self.tx().mem_page(pgid),
1772      Some(page) => page,
1773    };
1774
1775    // Read the page into the node and cache it.
1776    let n = NodeRwCell::read_in(self, parent, &page);
1777    let mut bucket = self.cell.borrow_mut();
1778    let wb = &mut bucket.w;
1779    match parent {
1780      None => wb.as_mut().unwrap().root_node = Some(n),
1781      Some(parent_node) => parent_node.cell.borrow_mut().children.push(n),
1782    }
1783
1784    wb.as_mut().unwrap().nodes.insert(pgid, n);
1785
1786    // Update statistics.
1787    self
1788      .split_bound()
1789      .split_r()
1790      .stats
1791      .as_ref()
1792      .unwrap()
1793      .inc_node_count(1);
1794
1795    n
1796  }
1797
1798  fn rebalance(self) {
1799    let bump = self.tx().bump();
1800    let (nodes, buckets) = {
1801      let borrow = self.cell.borrow();
1802      let nodes = BVec::from_iter_in(borrow.w.as_ref().unwrap().nodes.values().cloned(), bump);
1803      let buckets = BVec::from_iter_in(borrow.w.as_ref().unwrap().buckets.values().cloned(), bump);
1804      (nodes, buckets)
1805    };
1806    let _nodes = nodes.as_slice();
1807    for node in nodes.into_iter() {
1808      node.rebalance();
1809    }
1810    for bucket in buckets.into_iter() {
1811      bucket.rebalance();
1812    }
1813  }
1814}
1815
1816#[cfg(test)]
1817mod tests {
1818  use crate::bucket::MAX_VALUE_SIZE;
1819  use crate::test_support::{quick_check, DummyVec, TestDb};
1820  use crate::{
1821    Bolt, BoltOptionsBuilder, BucketApi, BucketRwApi, CursorApi, DbApi, DbRwAPI, Error, TxApi,
1822    TxRwRefApi,
1823  };
1824  use anyhow::anyhow;
1825  use fake::{Fake, Faker};
1826  use std::collections::HashMap;
1827  use std::fs;
1828  use std::fs::{File, OpenOptions};
1829  use std::io::{Read, Write};
1830  use std::path::Path;
1831  use std::sync::atomic::{AtomicU32, Ordering};
1832
1833  #[test]
1834  fn test_bucket_get_non_existent() -> crate::Result<()> {
1835    let mut db = TestDb::new()?;
1836    db.update(|mut tx| {
1837      let b = tx.create_bucket(b"widgets")?;
1838      assert_eq!(None, b.get(b"foo"));
1839      Ok(())
1840    })?;
1841    Ok(())
1842  }
1843
1844  #[test]
1845  fn test_bucket_get_from_node() -> crate::Result<()> {
1846    let mut db = TestDb::new()?;
1847    db.update(|mut tx| {
1848      let mut b = tx.create_bucket(b"widgets")?;
1849      b.put(b"foo", b"bar")?;
1850      assert_eq!(Some(b"bar".as_slice()), b.get(b"foo"));
1851      Ok(())
1852    })?;
1853    Ok(())
1854  }
1855
1856  #[test]
1857  fn test_bucket_get_incompatible_value() -> crate::Result<()> {
1858    let mut db = TestDb::new()?;
1859    db.update(|mut tx| {
1860      let _ = tx.create_bucket(b"widgets")?;
1861      tx.bucket_mut(b"widgets").unwrap().create_bucket(b"foo")?;
1862      assert_eq!(None, tx.bucket(b"widgets").unwrap().get(b"foo"));
1863      Ok(())
1864    })?;
1865    Ok(())
1866  }
1867
1868  // Ensure that a slice returned from a bucket has a capacity equal to its length.
1869  // This also allows slices to be appended to since it will require a realloc by Go.
1870  //
1871  // https://github.com/boltdb/bolt/issues/544
1872  #[test]
1873  #[ignore]
1874  fn test_bucket_get_capacity() -> crate::Result<()> {
1875    let mut db = TestDb::new()?;
1876    db.update(|mut tx| {
1877      let mut b = tx.create_bucket(b"widgets")?;
1878      b.put(b"key", b"val")?;
1879      Ok(())
1880    })?;
1881    db.update(|tx| {
1882      let b = tx.bucket(b"widgets").unwrap();
1883      let mut c = b.cursor();
1884      if let Some((_k, Some(_v))) = c.first() {
1885        todo!("We don't allow modifying values in place for this first version");
1886      }
1887      Ok(())
1888    })?;
1889    Ok(())
1890  }
1891
1892  #[test]
1893  fn test_bucket_put() -> crate::Result<()> {
1894    let mut db = TestDb::new()?;
1895    db.update(|mut tx| {
1896      {
1897        let mut b = tx.create_bucket(b"widgets")?;
1898        b.put(b"foo", b"bar")?;
1899      }
1900
1901      assert_eq!(
1902        Some(b"bar".as_slice()),
1903        tx.bucket(b"widgets").unwrap().get(b"foo")
1904      );
1905      Ok(())
1906    })
1907  }
1908
1909  #[test]
1910  fn test_bucket_put_repeat() -> crate::Result<()> {
1911    let mut db = TestDb::new()?;
1912    db.update(|mut tx| {
1913      {
1914        let mut b = tx.create_bucket(b"widgets")?;
1915        b.put(b"foo", b"bar")?;
1916        b.put(b"foo", b"baz")?;
1917      }
1918
1919      assert_eq!(
1920        Some(b"baz".as_slice()),
1921        tx.bucket(b"widgets").unwrap().get(b"foo")
1922      );
1923      Ok(())
1924    })
1925  }
1926
1927  #[test]
1928  #[cfg(not(miri))]
1929  fn test_bucket_put_large() -> crate::Result<()> {
1930    let mut db = TestDb::new()?;
1931    let count = 100;
1932    let factor = 200;
1933    db.update(|mut tx| {
1934      let mut b = tx.create_bucket(b"widgets")?;
1935      for i in 1..count {
1936        b.put(
1937          "0".repeat(i * factor).as_bytes(),
1938          "X".repeat((count - i) * factor).as_bytes(),
1939        )?;
1940      }
1941      Ok(())
1942    })?;
1943    db.view(|tx| {
1944      let b = tx.bucket(b"widgets").unwrap();
1945      for i in 1..count {
1946        let v = b.get("0".repeat(i * factor).as_bytes()).unwrap();
1947        assert_eq!((count - i) * factor, v.len());
1948        v.iter().all(|c| c == &b'X');
1949      }
1950      Ok(())
1951    })
1952  }
1953
1954  #[test]
1955  #[cfg(all(not(miri), feature = "long-tests"))]
1956
1957  fn test_db_put_very_large() -> crate::Result<()> {
1958    let mut db = TestDb::new()?;
1959    let n = 400000u64;
1960    let batch_n = 200000u64;
1961
1962    let v = [0u8; 500];
1963    for i in (0..n).step_by(batch_n as usize) {
1964      db.update(|mut tx| {
1965        let mut b = tx.create_bucket_if_not_exists(b"widgets")?;
1966        for j in 0..batch_n {
1967          b.put((i + j).to_be_bytes().as_slice(), v)?;
1968        }
1969        Ok(())
1970      })?;
1971    }
1972    Ok(())
1973  }
1974
1975  #[test]
1976  fn test_bucket_put_incompatible_value() -> crate::Result<()> {
1977    let mut db = TestDb::new()?;
1978    db.update(|mut tx| {
1979      let _ = tx.create_bucket(b"widgets")?;
1980      tx.bucket_mut(b"widgets").unwrap().create_bucket(b"foo")?;
1981
1982      assert_eq!(
1983        Err(Error::IncompatibleValue),
1984        tx.bucket_mut(b"widgets").unwrap().put(b"foo", b"bar")
1985      );
1986      Ok(())
1987    })
1988  }
1989
1990  #[test]
1991  fn test_bucket_delete() -> crate::Result<()> {
1992    let mut db = TestDb::new()?;
1993    db.update(|mut tx| {
1994      let mut b = tx.create_bucket(b"widgets")?;
1995      b.put(b"foo", b"bar")?;
1996      b.delete(b"foo")?;
1997      assert_eq!(None, b.get(b"foo"));
1998      Ok(())
1999    })
2000  }
2001
2002  #[test]
2003  #[cfg(not(miri))]
2004  fn test_bucket_delete_large() -> crate::Result<()> {
2005    let mut db = TestDb::new()?;
2006    let var = [b'*'; 1024];
2007    db.update(|mut tx| {
2008      let mut b = tx.create_bucket(b"widgets")?;
2009      for i in 0..100 {
2010        b.put(format!("{}", i).as_bytes(), var)?;
2011      }
2012      Ok(())
2013    })?;
2014    db.update(|mut tx| {
2015      let mut b = tx.bucket_mut(b"widgets").unwrap();
2016      for i in 0..100 {
2017        b.delete(format!("{}", i).as_bytes())?;
2018      }
2019      Ok(())
2020    })?;
2021    db.view(|tx| {
2022      let b = tx.bucket(b"widgets").unwrap();
2023      for i in 0..100 {
2024        assert_eq!(None, b.get(format!("{}", i).as_bytes()));
2025      }
2026      Ok(())
2027    })?;
2028    Ok(())
2029  }
2030
2031  #[test]
2032  #[cfg(all(not(miri), feature = "long-tests"))]
2033  fn test_bucket_delete_freelist_overflow() -> crate::Result<()> {
2034    let mut db = TestDb::new()?;
2035
2036    //TODO: make this based off of page size
2037    for i in 0u64..8192 {
2038      db.update(|mut tx| {
2039        let mut b = tx.create_bucket_if_not_exists(b"0")?;
2040        for j in 0u64..1000 {
2041          let mut k = [0u8; 16];
2042          let (k0, k1) = k.split_at_mut(8);
2043          k0.copy_from_slice(i.to_be_bytes().as_slice());
2044          k1.copy_from_slice(j.to_be_bytes().as_slice());
2045          b.put(k, [])?;
2046        }
2047        Ok(())
2048      })?;
2049    }
2050    db.update(|mut tx| {
2051      let b = tx.bucket_mut(b"0").unwrap();
2052      let mut c = b.cursor_mut();
2053      let mut node = c.first();
2054      while node.is_some() {
2055        c.delete()?;
2056        node = c.next();
2057      }
2058      Ok(())
2059    })?;
2060    let stats = db.stats();
2061    let free_page_n = stats.free_page_n();
2062    let pending_page_n = stats.pending_page_n();
2063    let free_pages = free_page_n + pending_page_n;
2064    assert!(
2065      free_pages > 0xFFFF,
2066      "expected more than 0xFFFF free pages. Got {}",
2067      free_pages
2068    );
2069    db.must_close();
2070    db.must_reopen();
2071    let stats = db.stats();
2072    let reopen_free_pages = stats.free_page_n();
2073    assert_eq!(
2074      free_pages, reopen_free_pages,
2075      "Expected {} free pages, got {:?}",
2076      free_pages, reopen_free_pages
2077    );
2078    Ok(())
2079  }
2080
2081  #[test]
2082  fn test_bucket_delete_non_existing() -> crate::Result<()> {
2083    let mut db = TestDb::new()?;
2084    db.update(|mut tx| {
2085      let mut b = tx.create_bucket(b"widgets")?;
2086      let _ = b.create_bucket(b"nested")?;
2087      Ok(())
2088    })?;
2089    db.update(|mut tx| {
2090      let mut b = tx.bucket_mut(b"widgets").unwrap();
2091      b.delete(b"foo")?;
2092      assert!(
2093        b.bucket(b"nested").is_some(),
2094        "nested bucket has been deleted"
2095      );
2096      Ok(())
2097    })?;
2098    Ok(())
2099  }
2100
2101  #[test]
2102  #[cfg(not(miri))]
2103  fn test_bucket_nested() -> crate::Result<()> {
2104    let mut db = TestDb::new()?;
2105    db.update(|mut tx| {
2106      // Create a widgets bucket.
2107      let mut b = tx.create_bucket(b"widgets")?;
2108
2109      // Create a widgets/foo bucket.
2110      let _ = b.create_bucket(b"foo")?;
2111
2112      // Create a widgets/bar key.
2113      b.put(b"bar", b"0000")?;
2114      Ok(())
2115    })?;
2116    db.must_check();
2117    db.update(|mut tx| {
2118      let mut b = tx.bucket_mut(b"widgets").unwrap();
2119      b.put(b"bar", b"xxxx")?;
2120      Ok(())
2121    })?;
2122    db.must_check();
2123    db.update(|mut tx| {
2124      let mut b = tx.bucket_mut(b"widgets").unwrap();
2125      for i in 0..10000 {
2126        let s = format!("{}", i);
2127        b.put(s.as_bytes(), s.as_bytes())?;
2128      }
2129      Ok(())
2130    })?;
2131    db.must_check();
2132    db.update(|mut tx| {
2133      let mut b = tx.bucket_mut(b"widgets").unwrap();
2134      {
2135        let mut foo = b.bucket_mut(b"foo").unwrap();
2136        foo.put(b"baz", b"yyyy")?;
2137      }
2138      b.put(b"bar", b"xxxx")?;
2139      Ok(())
2140    })?;
2141    db.must_check();
2142    db.view(|tx| {
2143      let b = tx.bucket(b"widgets").unwrap();
2144      let foo = b.bucket(b"foo").unwrap();
2145      assert_eq!(Some(b"yyyy".as_slice()), foo.get(b"baz"));
2146      assert_eq!(Some(b"xxxx".as_slice()), b.get(b"bar"));
2147
2148      for i in 0..10000 {
2149        let s = format!("{}", i);
2150        assert_eq!(Some(s.as_bytes()), b.get(s.as_bytes()));
2151      }
2152      Ok(())
2153    })?;
2154    Ok(())
2155  }
2156
2157  #[test]
2158  fn test_bucket_delete_bucket() -> crate::Result<()> {
2159    let mut db = TestDb::new()?;
2160    db.update(|mut tx| {
2161      let mut b = tx.create_bucket(b"widgets")?;
2162      let _ = b.create_bucket(b"foo")?;
2163      assert_eq!(Err(Error::IncompatibleValue), b.delete(b"foo"));
2164      Ok(())
2165    })?;
2166    Ok(())
2167  }
2168
2169  #[test]
2170  // Ensure that deleting a bucket causes nested buckets to be deleted.
2171  fn test_bucket_delete_bucket_nested() -> crate::Result<()> {
2172    let mut db = TestDb::new()?;
2173    db.update(|mut tx| {
2174      {
2175        let mut widgets = tx.create_bucket(b"widgets")?;
2176        let mut foo = widgets.create_bucket(b"foo")?;
2177        let mut bar = foo.create_bucket(b"bar")?;
2178        bar.put(b"baz", b"bat")?;
2179      }
2180      tx.bucket_mut(b"widgets").unwrap().delete_bucket(b"foo")?;
2181      Ok(())
2182    })?;
2183    Ok(())
2184  }
2185
2186  #[test]
2187  // Ensure that deleting a bucket causes nested buckets to be deleted after they have been committed.
2188  fn test_bucket_delete_bucket_nested2() -> crate::Result<()> {
2189    let mut db = TestDb::new()?;
2190    db.update(|mut tx| {
2191      let mut widgets = tx.create_bucket(b"widgets")?;
2192      let mut foo = widgets.create_bucket(b"foo")?;
2193      let mut bar = foo.create_bucket(b"bar")?;
2194      bar.put(b"baz", b"bat")?;
2195      Ok(())
2196    })?;
2197    db.update(|mut tx| {
2198      {
2199        let widgets = tx.bucket(b"widgets").unwrap();
2200        let foo = widgets.bucket(b"foo").unwrap();
2201        let bar = foo.bucket(b"bar").unwrap();
2202        assert_eq!(Some(b"bat".as_slice()), bar.get(b"baz"));
2203      }
2204      tx.delete_bucket(b"widgets")?;
2205      Ok(())
2206    })?;
2207    db.view(|tx| {
2208      assert!(tx.bucket(b"widgets").is_none());
2209      Ok(())
2210    })?;
2211    Ok(())
2212  }
2213
2214  #[test]
2215  #[cfg(not(miri))]
2216  // Ensure that deleting a child bucket with multiple pages causes all pages to get collected.
2217  // NOTE: Consistency check in bolt_test.DB.Close() will panic if pages not freed properly.
2218  fn test_bucket_delete_bucket_large() -> crate::Result<()> {
2219    let mut db = TestDb::new()?;
2220    db.update(|mut tx| {
2221      let mut widgets = tx.create_bucket(b"widgets")?;
2222      let mut foo = widgets.create_bucket(b"foo")?;
2223      for i in 0..1000 {
2224        let k = format!("{}", i);
2225        let v = format!("{:0100}", i);
2226        foo.put(k.as_bytes(), v.as_bytes())?;
2227      }
2228      Ok(())
2229    })?;
2230    db.update(|mut tx| {
2231      tx.delete_bucket(b"widgets")?;
2232      Ok(())
2233    })?;
2234    Ok(())
2235  }
2236
2237  #[test]
2238  fn test_bucket_bucket_incompatible_value() -> crate::Result<()> {
2239    let mut db = TestDb::new()?;
2240    db.update(|mut tx| {
2241      let mut widgets = tx.create_bucket(b"widgets")?;
2242      widgets.put(b"foo", b"bar")?;
2243      assert!(widgets.bucket(b"foo").is_none());
2244      Ok(())
2245    })?;
2246    Ok(())
2247  }
2248
2249  #[test]
2250  fn test_bucket_create_bucket_incompatible_value() -> crate::Result<()> {
2251    let mut db = TestDb::new()?;
2252    db.update(|mut tx| {
2253      let mut widgets = tx.create_bucket(b"widgets")?;
2254      widgets.put(b"foo", b"bar")?;
2255      assert_eq!(
2256        Some(Error::IncompatibleValue),
2257        widgets.create_bucket(b"foo").err()
2258      );
2259      Ok(())
2260    })?;
2261    Ok(())
2262  }
2263
2264  #[test]
2265  fn test_bucket_delete_bucket_incompatible_value() -> crate::Result<()> {
2266    let mut db = TestDb::new()?;
2267    db.update(|mut tx| {
2268      let mut widgets = tx.create_bucket(b"widgets")?;
2269      widgets.put(b"foo", b"bar")?;
2270      assert_eq!(
2271        Some(Error::IncompatibleValue),
2272        widgets.delete_bucket(b"foo").err()
2273      );
2274      Ok(())
2275    })?;
2276    Ok(())
2277  }
2278
2279  #[test]
2280  fn test_bucket_sequence() -> crate::Result<()> {
2281    let mut db = TestDb::new()?;
2282    db.update(|mut tx| {
2283      let mut bkt = tx.create_bucket(b"0")?;
2284      assert_eq!(0, bkt.sequence());
2285      bkt.set_sequence(1000)?;
2286      assert_eq!(1000, bkt.sequence());
2287      Ok(())
2288    })?;
2289    db.view(|tx| {
2290      let bkt = tx.bucket(b"0").unwrap();
2291      assert_eq!(1000, bkt.sequence());
2292      Ok(())
2293    })?;
2294    Ok(())
2295  }
2296
2297  #[test]
2298  fn test_bucket_next_sequence() -> crate::Result<()> {
2299    let mut db = TestDb::new()?;
2300    db.update(|mut tx| {
2301      let _ = tx.create_bucket(b"widgets")?;
2302      let _ = tx.create_bucket(b"woojits")?;
2303      {
2304        let mut widgets = tx.bucket_mut("widgets").unwrap();
2305        assert_eq!(1, widgets.next_sequence()?);
2306        assert_eq!(2, widgets.next_sequence()?);
2307      }
2308      let mut woojits = tx.bucket_mut("woojits").unwrap();
2309      assert_eq!(1, woojits.next_sequence()?);
2310
2311      Ok(())
2312    })?;
2313    Ok(())
2314  }
2315
2316  #[test]
2317  // Ensure that a bucket will persist an autoincrementing sequence even if its
2318  // the only thing updated on the bucket.
2319  // https://github.com/boltdb/bolt/issues/296
2320  fn test_bucket_next_sequence_persist() -> crate::Result<()> {
2321    let mut db = TestDb::new()?;
2322    db.update(|mut tx| {
2323      tx.create_bucket(b"widgets")?;
2324      Ok(())
2325    })?;
2326    db.update(|mut tx| {
2327      let mut widgets = tx.bucket_mut(b"widgets").unwrap();
2328      assert_eq!(1, widgets.next_sequence()?);
2329      Ok(())
2330    })?;
2331    db.update(|mut tx| {
2332      let mut widgets = tx.bucket_mut(b"widgets").unwrap();
2333      assert_eq!(2, widgets.next_sequence()?);
2334      Ok(())
2335    })?;
2336    Ok(())
2337  }
2338
2339  fn for_each_collect_kv<'tx, B: BucketApi<'tx>>(
2340    b: B,
2341  ) -> crate::Result<Vec<(&'tx [u8], Option<&'tx [u8]>)>> {
2342    let items = std::cell::RefCell::new(Vec::new());
2343    b.for_each(|k, v| {
2344      items.borrow_mut().push((k, v));
2345      Ok(())
2346    })?;
2347    Ok(items.into_inner())
2348  }
2349
2350  fn for_each_bucket_collect_k<'tx, B: BucketApi<'tx>>(b: B) -> crate::Result<Vec<&'tx [u8]>> {
2351    let items = std::cell::RefCell::new(Vec::new());
2352    b.for_each_bucket(|k| {
2353      items.borrow_mut().push(k);
2354      Ok(())
2355    })?;
2356    Ok(items.into_inner())
2357  }
2358
2359  #[test]
2360  fn test_bucket_for_each() -> crate::Result<()> {
2361    let expected_items = [
2362      (b"bar".as_slice(), Some(b"0002".as_slice())),
2363      (b"baz".as_slice(), Some(b"0001".as_slice())),
2364      (b"csubbucket".as_slice(), None),
2365      (b"foo".as_slice(), Some(b"0000".as_slice())),
2366    ];
2367    let mut db = TestDb::new()?;
2368    db.update(|mut tx| {
2369      let mut b = tx.create_bucket(b"widgets")?;
2370      b.put(b"foo", b"0000")?;
2371      b.put(b"baz", b"0001")?;
2372      b.put(b"bar", b"0002")?;
2373      b.create_bucket(b"csubbucket")?;
2374
2375      let items = for_each_collect_kv(b)?;
2376      assert_eq!(
2377        expected_items.as_slice(),
2378        &items,
2379        "what we iterated (ForEach) is not what we put"
2380      );
2381      Ok(())
2382    })?;
2383    db.view(|tx| {
2384      let b = tx.bucket(b"widgets").unwrap();
2385      let items = for_each_collect_kv(b)?;
2386      assert_eq!(
2387        expected_items.as_slice(),
2388        &items,
2389        "what we iterated (ForEach) is not what we put"
2390      );
2391      Ok(())
2392    })?;
2393    Ok(())
2394  }
2395
2396  #[test]
2397  fn test_bucket_for_each_bucket() -> crate::Result<()> {
2398    let expected_items = [b"csubbucket".as_slice(), b"zsubbucket".as_slice()];
2399    let mut db = TestDb::new()?;
2400    db.update(|mut tx| {
2401      let mut b = tx.create_bucket(b"widgets")?;
2402      b.put(b"foo", b"0000")?;
2403      let _ = b.create_bucket(b"zsubbucket")?;
2404      b.put(b"baz", b"0001")?;
2405      b.put(b"bar", b"0002")?;
2406      let _ = b.create_bucket(b"csubbucket")?;
2407
2408      let items = for_each_bucket_collect_k(b)?;
2409      assert_eq!(
2410        expected_items.as_slice(),
2411        &items,
2412        "what we iterated (ForEach) is not what we put"
2413      );
2414      Ok(())
2415    })?;
2416    db.view(|tx| {
2417      let b = tx.bucket(b"widgets").unwrap();
2418      let items = for_each_bucket_collect_k(b)?;
2419      assert_eq!(
2420        expected_items.as_slice(),
2421        &items,
2422        "what we iterated (ForEach) is not what we put"
2423      );
2424      Ok(())
2425    })?;
2426    Ok(())
2427  }
2428
2429  #[test]
2430  fn test_bucket_for_each_bucket_no_buckets() -> crate::Result<()> {
2431    let mut db = TestDb::new()?;
2432    db.update(|mut tx| {
2433      let mut b = tx.create_bucket(b"widgets")?;
2434      b.put(b"foo", b"0000")?;
2435      b.put(b"baz", b"0001")?;
2436
2437      let items = for_each_bucket_collect_k(b)?;
2438      assert!(
2439        items.is_empty(),
2440        "what we iterated (ForEach) is not what we put"
2441      );
2442      Ok(())
2443    })?;
2444    db.view(|tx| {
2445      let b = tx.bucket(b"widgets").unwrap();
2446      let items = for_each_bucket_collect_k(b)?;
2447      assert!(
2448        items.is_empty(),
2449        "what we iterated (ForEach) is not what we put"
2450      );
2451      Ok(())
2452    })?;
2453    Ok(())
2454  }
2455
2456  #[test]
2457  fn test_bucket_for_each_short_circuit() -> crate::Result<()> {
2458    let mut db = TestDb::new()?;
2459    let result = db.update(|mut tx| {
2460      {
2461        let mut b = tx.create_bucket(b"widgets")?;
2462        b.put(b"bar", b"0000")?;
2463        b.put(b"baz", b"0000")?;
2464        b.put(b"foo", b"0000")?;
2465      }
2466      let index = AtomicU32::new(0);
2467      tx.bucket(b"widgets").unwrap().for_each(|k, _| {
2468        index.fetch_add(1, Ordering::Relaxed);
2469        if k == b"baz" {
2470          return Err(Error::Other(anyhow!("marker")));
2471        }
2472        Ok(())
2473      })?;
2474
2475      Ok(())
2476    });
2477    let e = result.map_err(|e| e.to_string()).err().unwrap();
2478    assert_eq!("marker", e);
2479    Ok(())
2480  }
2481
2482  #[test]
2483  fn test_bucket_put_empty_key() -> crate::Result<()> {
2484    let mut db = TestDb::new()?;
2485    db.update(|mut tx| {
2486      let mut widgets = tx.create_bucket(b"widgets")?;
2487      assert_eq!(Some(Error::KeyRequired), widgets.put([], []).err());
2488      Ok(())
2489    })?;
2490    Ok(())
2491  }
2492
2493  #[test]
2494  fn test_bucket_put_key_too_large() -> crate::Result<()> {
2495    let mut db = TestDb::new()?;
2496    let key = [0u8; 32769];
2497    db.update(|mut tx| {
2498      let mut widgets = tx.create_bucket(b"widgets")?;
2499      assert_eq!(
2500        Some(Error::KeyTooLarge),
2501        widgets.put(key.as_slice(), b"bar").err()
2502      );
2503      Ok(())
2504    })?;
2505    Ok(())
2506  }
2507
2508  #[test]
2509  fn test_bucket_put_value_too_large() -> crate::Result<()> {
2510    let mut db = TestDb::new()?;
2511    let value = vec![0u8; MAX_VALUE_SIZE as usize + 1];
2512    db.update(|mut tx| {
2513      let mut widgets = tx.create_bucket(b"widgets")?;
2514      assert_eq!(
2515        Some(Error::ValueTooLarge),
2516        widgets.put(b"foo", value.as_slice()).err()
2517      );
2518      Ok(())
2519    })?;
2520    Ok(())
2521  }
2522
2523  #[test]
2524  #[cfg(feature = "long-tests")]
2525  fn test_bucket_stats() -> crate::Result<()> {
2526    let mut db = TestDb::new()?;
2527    let big_key = "really-big-value";
2528    for i in 0..500 {
2529      db.update(|mut tx| {
2530        let mut b = tx.create_bucket_if_not_exists("woojits")?;
2531        b.put(format!("{:03}", i), format!("{}", i))?;
2532        Ok(())
2533      })?;
2534    }
2535    // TODO: Update to support different page sizes
2536    let long_key_length = 10 * 4096 + 17;
2537    db.update(|mut tx| {
2538      tx.bucket_mut("woojits")
2539        .unwrap()
2540        .put(big_key, "*".repeat(long_key_length))?;
2541      Ok(())
2542    })?;
2543    db.must_check();
2544
2545    // TODO: Support pagesize that's not 4096
2546    let stat_4096 = BucketStats {
2547      branch_page_n: 1,
2548      branch_overflow_n: 0,
2549      leaf_page_n: 7,
2550      leaf_overflow_n: 10,
2551      key_n: 501,
2552      depth: 2,
2553      branch_alloc: 4096,
2554      branch_in_use: 149,
2555      leaf_alloc: 69_632,
2556      leaf_in_use: 0 +
2557      7 * 16 + // leaf page header (x LeafPageN)
2558      501 * 16 + // leaf elements
2559      500 * 3 + big_key.len() as i64 + // leaf keys
2560      1 * 10 + 2 * 90 + 3 * 400 + long_key_length as i64, // leaf values: 10 * 1digit, 90*2digits, ...
2561      bucket_n: 1,
2562      inline_bucket_n: 0,
2563      inline_bucket_in_use: 0,
2564    };
2565    db.view(|tx| {
2566      let b = tx.bucket("woojits").unwrap();
2567      let stats = b.stats();
2568      assert_eq!(stat_4096, stats, "stats differs from expectations");
2569      Ok(())
2570    })?;
2571    Ok(())
2572  }
2573
2574  #[test]
2575  #[cfg(feature = "long-tests")]
2576  fn test_bucket_stats_random_fill() -> crate::Result<()> {
2577    let mut db = TestDb::new()?;
2578    let mut count = 0;
2579    let mut rand = StdRng::seed_from_u64(42);
2580    let mut outer_range = (0..1000).collect_vec();
2581    outer_range.shuffle(&mut rand);
2582    for i in outer_range {
2583      db.update(|mut tx| {
2584        let mut b = tx.create_bucket_if_not_exists("woojits")?;
2585        b.set_fill_percent(0.90);
2586        let mut inner_range = (0..100).collect_vec();
2587        inner_range.shuffle(&mut rand);
2588        for j in inner_range {
2589          let index = (j * 1000) + i;
2590          b.put(format!("{:015}", index), "0000000000")?;
2591          count += 1;
2592        }
2593        Ok(())
2594      })?;
2595    }
2596    db.must_check();
2597    db.view(|tx| {
2598      let b = tx.bucket("woojits").unwrap();
2599      let stats = b.stats();
2600      assert_eq!(68, stats.branch_page_n, "unexpected BranchPageN");
2601      assert_eq!(0, stats.branch_overflow_n, "unexpected BranchOverflowN");
2602      assert_eq!(2946, stats.leaf_page_n, "unexpected LeafPageN");
2603      assert_eq!(0, stats.leaf_overflow_n, "unexpected LeafOverflowN");
2604      assert_eq!(10_0000, stats.key_n, "unexpected KeyN");
2605      assert_eq!(94_491, stats.branch_in_use, "unexpected BranchInuse");
2606      assert_eq!(4_147_136, stats.leaf_in_use, "unexpected LeafInuse");
2607      assert_eq!(278_528, stats.branch_alloc, "unexpected BranchAlloc");
2608      assert_eq!(12_066_816, stats.leaf_alloc, "unexpected LeafAlloc");
2609      Ok(())
2610    })?;
2611    Ok(())
2612  }
2613
2614  #[test]
2615  fn test_bucket_stats_small() -> crate::Result<()> {
2616    let mut db = TestDb::new()?;
2617    db.update(|mut tx| {
2618      let mut b = tx.create_bucket("whozawhats")?;
2619      b.put("foo", "bar")?;
2620      Ok(())
2621    })?;
2622    db.must_check();
2623    db.view(|tx| {
2624      let b = tx.bucket("whozawhats").unwrap();
2625      let stats = b.stats();
2626      assert_eq!(0, stats.branch_page_n, "unexpected BranchPageN");
2627      assert_eq!(0, stats.branch_overflow_n, "unexpected BranchOverflowN");
2628      assert_eq!(0, stats.leaf_page_n, "unexpected LeafPageN");
2629      assert_eq!(0, stats.leaf_overflow_n, "unexpected LeafOverflowN");
2630      assert_eq!(1, stats.key_n, "unexpected KeyN");
2631      assert_eq!(1, stats.depth, "unexpected Depth");
2632      assert_eq!(0, stats.branch_in_use, "unexpected BranchInuse");
2633      assert_eq!(0, stats.leaf_in_use, "unexpected LeafInuse");
2634
2635      //TODO: Fails if page_size != 4096? Db.Info?
2636      assert_eq!(0, stats.branch_alloc, "unexpected BranchAlloc");
2637      assert_eq!(0, stats.leaf_alloc, "unexpected LeafAlloc");
2638
2639      assert_eq!(1, stats.bucket_n, "unexpected BucketN");
2640      assert_eq!(1, stats.inline_bucket_n, "unexpected InlineBucketN");
2641      assert_eq!(
2642        16 + 16 + 6,
2643        stats.inline_bucket_in_use,
2644        "unexpected InlineBucketInuse"
2645      );
2646
2647      Ok(())
2648    })?;
2649    Ok(())
2650  }
2651
2652  #[test]
2653  fn test_bucket_stats_empty_bucket() -> crate::Result<()> {
2654    let mut db = TestDb::new()?;
2655    db.update(|mut tx| {
2656      tx.create_bucket("whozawhats")?;
2657      Ok(())
2658    })?;
2659    db.must_check();
2660    db.view(|tx| {
2661      let b = tx.bucket("whozawhats").unwrap();
2662      let stats = b.stats();
2663      assert_eq!(0, stats.branch_page_n, "unexpected BranchPageN");
2664      assert_eq!(0, stats.branch_overflow_n, "unexpected BranchOverflowN");
2665      assert_eq!(0, stats.leaf_page_n, "unexpected LeafPageN");
2666      assert_eq!(0, stats.leaf_overflow_n, "unexpected LeafOverflowN");
2667      assert_eq!(0, stats.key_n, "unexpected KeyN");
2668      assert_eq!(1, stats.depth, "unexpected Depth");
2669      assert_eq!(0, stats.branch_in_use, "unexpected BranchInuse");
2670      assert_eq!(0, stats.leaf_in_use, "unexpected LeafInuse");
2671
2672      //TODO: Fails if page_size != 4096? Db.Info?
2673      assert_eq!(0, stats.branch_alloc, "unexpected BranchAlloc");
2674      assert_eq!(0, stats.leaf_alloc, "unexpected LeafAlloc");
2675
2676      assert_eq!(1, stats.bucket_n, "unexpected BucketN");
2677      assert_eq!(1, stats.inline_bucket_n, "unexpected InlineBucketN");
2678      assert_eq!(
2679        16, stats.inline_bucket_in_use,
2680        "unexpected InlineBucketInuse"
2681      );
2682
2683      Ok(())
2684    })?;
2685    Ok(())
2686  }
2687
2688  #[test]
2689  fn test_bucket_stats_nested() -> crate::Result<()> {
2690    let mut db = TestDb::new()?;
2691    db.update(|mut tx| {
2692      let mut b = tx.create_bucket("foo")?;
2693      for i in 0..100 {
2694        let i_str = format!("{:02}", i);
2695        b.put(&i_str, &i_str)?;
2696      }
2697      let mut bar = b.create_bucket("bar")?;
2698      for i in 0..10 {
2699        let i_str = format!("{}", i);
2700        bar.put(&i_str, &i_str)?;
2701      }
2702      let mut baz = bar.create_bucket("baz")?;
2703      for i in 0..10 {
2704        let i_str = format!("{}", i);
2705        baz.put(&i_str, &i_str)?;
2706      }
2707      Ok(())
2708    })?;
2709    db.must_check();
2710
2711    db.view(|tx| {
2712      let b = tx.bucket("foo").unwrap();
2713      let stats = b.stats();
2714      assert_eq!(0, stats.branch_page_n, "unexpected BranchPageN");
2715      assert_eq!(0, stats.branch_overflow_n, "unexpected BranchOverflowN");
2716      assert_eq!(2, stats.leaf_page_n, "unexpected LeafPageN");
2717      assert_eq!(0, stats.leaf_overflow_n, "unexpected LeafOverflowN");
2718      assert_eq!(122, stats.key_n, "unexpected KeyN");
2719      assert_eq!(3, stats.depth, "unexpected Depth");
2720      assert_eq!(0, stats.branch_in_use, "unexpected BranchInuse");
2721
2722      let mut foo = 16; // foo (pghdr)
2723      foo += 101 * 16; // foo leaf elements
2724      foo += 100 * 2 + 100 * 2; // foo leaf key/values
2725      foo += 3 + 16; // foo -> bar key/value
2726
2727      let mut bar = 16; // bar (pghdr)
2728      bar += 11 * 16; // bar leaf elements
2729      bar += 10 + 10; // bar leaf key/values
2730      bar += 3 + 16; //bar -> baz key/value
2731
2732      let mut baz = 16; // baz (inline) (pghdr)
2733      baz += 10 * 16; // baz leaf elements
2734      baz += 10 + 10; // baz leaf key/values
2735
2736      assert_eq!(foo + bar + baz, stats.leaf_in_use, "unexpected LeafInuse");
2737
2738      //TODO: Fails if page_size != 4096? Db.Info?
2739      assert_eq!(0, stats.branch_alloc, "unexpected BranchAlloc");
2740      assert_eq!((page_size::get() * 2) as i64, stats.leaf_alloc, "unexpected LeafAlloc");
2741
2742      assert_eq!(3, stats.bucket_n, "unexpected BucketN");
2743      assert_eq!(1, stats.inline_bucket_n, "unexpected InlineBucketN");
2744      assert_eq!(
2745        baz, stats.inline_bucket_in_use,
2746        "unexpected InlineBucketInuse"
2747      );
2748      Ok(())
2749    })?;
2750    Ok(())
2751  }
2752
2753  #[test]
2754  #[cfg(feature = "long-tests")]
2755  fn test_bucket_stats_large() -> crate::Result<()> {
2756    let mut db = TestDb::new()?;
2757    let mut index = 0;
2758    for _ in 0..100 {
2759      db.update(|mut tx| {
2760        let mut b = tx.create_bucket_if_not_exists("widgets")?;
2761        for _ in 0..1000 {
2762          let i_str = format!("{}", index);
2763          b.put(&i_str, &i_str)?;
2764          index += 1;
2765        }
2766        Ok(())
2767      })?;
2768    }
2769
2770    db.must_check();
2771
2772    // TODO: Support pagesize that's not 4096
2773    let stat_4096 = BucketStats {
2774      branch_page_n: 13,
2775      branch_overflow_n: 0,
2776      leaf_page_n: 1196,
2777      leaf_overflow_n: 0,
2778      key_n: 100_000,
2779      depth: 3,
2780      branch_alloc: 53_248,
2781      branch_in_use: 25_257,
2782      leaf_alloc: 4_898_816,
2783      leaf_in_use: 2_596_916,
2784      bucket_n: 1,
2785      inline_bucket_n: 0,
2786      inline_bucket_in_use: 0,
2787    };
2788
2789    db.view(|tx| {
2790      let b = tx.bucket("widgets").unwrap();
2791      let stats = b.stats();
2792      assert_eq!(stat_4096, stats, "stats differs from expectations");
2793      Ok(())
2794    })?;
2795    Ok(())
2796  }
2797
2798  #[test]
2799  fn test_bucket_put_single() -> crate::Result<()> {
2800    let mut index = 0;
2801    quick_check(5, |d: &mut DummyVec| {
2802      let mut db = TestDb::new().unwrap();
2803
2804      let mut m = HashMap::new();
2805
2806      db.update(|mut tx| {
2807        tx.create_bucket("widgets")?;
2808        Ok(())
2809      })
2810      .unwrap();
2811
2812      for entry in &d.values {
2813        db.update(|mut tx| {
2814          let mut b = tx.bucket_mut("widgets").unwrap();
2815          b.put(&entry.key, &entry.value).unwrap();
2816          m.insert(entry.key.clone(), entry.value.clone());
2817          Ok(())
2818        })
2819        .unwrap();
2820        db.must_check();
2821      }
2822
2823      db.view(|tx| {
2824        let b = tx.bucket("widgets").unwrap();
2825        for (i, entry) in d.values.iter().enumerate() {
2826          let value = b.get(&entry.key).unwrap();
2827          assert_eq!(
2828            &entry.value,
2829            value,
2830            "values mismatch [run {}] ({} of {})",
2831            index,
2832            i,
2833            d.values.len()
2834          );
2835          //todo- copy temp if fails
2836        }
2837        Ok(())
2838      })
2839      .unwrap();
2840      index += 1;
2841      true
2842    });
2843    Ok(())
2844  }
2845
2846  #[test]
2847  fn test_bucket_put_multiple() -> crate::Result<()> {
2848    let mut index = 0;
2849    quick_check(5, |d: &mut DummyVec| {
2850      let mut db = TestDb::new().unwrap();
2851
2852      let mut m = HashMap::new();
2853
2854      db.update(|mut tx| {
2855        tx.create_bucket("widgets")?;
2856        Ok(())
2857      })
2858      .unwrap();
2859
2860      db.update(|mut tx| {
2861        let mut b = tx.bucket_mut("widgets").unwrap();
2862        for entry in &d.values {
2863          b.put(&entry.key, &entry.value).unwrap();
2864          m.insert(entry.key.clone(), entry.value.clone());
2865        }
2866        Ok(())
2867      })
2868      .unwrap();
2869
2870      db.must_check();
2871
2872      db.view(|tx| {
2873        let b = tx.bucket("widgets").unwrap();
2874        for (i, entry) in d.values.iter().enumerate() {
2875          let value = b.get(&entry.key).unwrap();
2876          assert_eq!(
2877            &entry.value,
2878            value,
2879            "values mismatch [run {}] ({} of {})",
2880            index,
2881            i,
2882            d.values.len()
2883          );
2884          //todo- copy temp if fails
2885        }
2886        Ok(())
2887      })
2888      .unwrap();
2889      index += 1;
2890      true
2891    });
2892    Ok(())
2893  }
2894
2895  #[test]
2896  fn test_bucket_delete_quick() -> crate::Result<()> {
2897    let mut index = 0;
2898    quick_check(5, |d: &mut DummyVec| {
2899      let mut db = TestDb::new().unwrap();
2900
2901      db.update(|mut tx| {
2902        tx.create_bucket("widgets")?;
2903        Ok(())
2904      })
2905      .unwrap();
2906
2907      db.update(|mut tx| {
2908        let mut b = tx.bucket_mut("widgets").unwrap();
2909        for entry in &d.values {
2910          b.put(&entry.key, &entry.value).unwrap();
2911        }
2912        Ok(())
2913      })
2914      .unwrap();
2915
2916      db.must_check();
2917
2918      for (i, entry) in d.values.iter().enumerate() {
2919        db.update(|mut tx| {
2920          let mut b = tx.bucket_mut("widgets").unwrap();
2921          b.delete(&entry.key).unwrap();
2922          Ok(())
2923        })
2924        .unwrap();
2925        db.must_check();
2926      }
2927
2928      db.view(|tx| {
2929        let b = tx.bucket("widgets").unwrap();
2930        for entry in &d.values {
2931          let value = b.get(&entry.key);
2932          assert!(
2933            value.is_none(),
2934            "bucket should be empty; found {:?}",
2935            &entry.key[0..3]
2936          );
2937          //todo- copy temp if fails
2938        }
2939        Ok(())
2940      })
2941      .unwrap();
2942      index += 1;
2943      true
2944    });
2945    Ok(())
2946  }
2947}