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
30pub trait BucketApi<'tx>
32where
33 Self: Sized,
34{
35 fn root(&self) -> PgId;
61
62 fn writable(&self) -> bool;
86
87 fn cursor<'a>(&'a self) -> CursorImpl<'tx, 'a>;
113
114 fn bucket<'a, T: AsRef<[u8]>>(&'a self, name: T) -> Option<BucketImpl<'tx, 'a>>;
142
143 fn get<T: AsRef<[u8]>>(&self, key: T) -> Option<&[u8]>;
172
173 fn sequence(&self) -> u64;
198
199 #[deprecated(since = "1.3.9", note = "please use `iter_*` methods instead")]
200 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 fn for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(&self, f: F) -> crate::Result<()>;
270
271 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
304pub trait BucketRwApi<'tx>: BucketApi<'tx> {
306 fn bucket_mut<'a, T: AsRef<[u8]>>(&'a mut self, name: T) -> Option<BucketRwImpl<'tx, 'a>>;
333
334 fn create_bucket<'a, T: AsRef<[u8]>>(
360 &'a mut self, key: T,
361 ) -> crate::Result<BucketRwImpl<'tx, 'a>>;
362
363 fn create_bucket_if_not_exists<'a, T: AsRef<[u8]>>(
389 &'a mut self, key: T,
390 ) -> crate::Result<BucketRwImpl<'tx, 'a>>;
391
392 fn cursor_mut<'a>(&'a self) -> CursorRwImpl<'tx, 'a>;
428
429 fn delete_bucket<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()>;
461
462 fn put<T: AsRef<[u8]>, U: AsRef<[u8]>>(&mut self, key: T, data: U) -> crate::Result<()>;
501
502 fn delete<T: AsRef<[u8]>>(&mut self, key: T) -> crate::Result<()>;
539
540 fn set_sequence(&mut self, v: u64) -> crate::Result<()>;
564
565 fn next_sequence(&mut self) -> crate::Result<u64>;
584
585 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
609pub 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
672pub 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 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#[derive(Copy, Clone, Eq, PartialEq, Default, Debug, CopyGetters)]
798#[getset(get_copy = "pub")]
799pub struct BucketStats {
800 branch_page_n: i64,
803 branch_overflow_n: i64,
805 leaf_page_n: i64,
807 leaf_overflow_n: i64,
809
810 pub(crate) key_n: i64,
813 depth: i64,
815
816 branch_alloc: i64,
819 branch_in_use: i64,
821 leaf_alloc: i64,
823 leaf_in_use: i64,
825
826 bucket_n: i64,
829 inline_bucket_n: i64,
831 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
858const DEFAULT_FILL_PERCENT: f64 = 0.5;
861
862const MAX_KEY_SIZE: u32 = 32768;
864
865const 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#[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
895pub(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 fn is_writeable(&self) -> bool;
909
910 fn tx(self) -> TxCell<'tx>;
912
913 fn root(self) -> PgId;
915
916 fn i_cursor(self) -> InnerCursor<'tx>;
918
919 fn api_bucket(self, name: &[u8]) -> Option<BucketCell<'tx>>;
921
922 fn open_bucket(self, value: &[u8]) -> BucketCell<'tx>;
925
926 fn api_get(self, key: &[u8]) -> Option<&'tx [u8]>;
928
929 fn api_for_each<F: FnMut(&'tx [u8], Option<&'tx [u8]>) -> crate::Result<()>>(
931 self, f: F,
932 ) -> crate::Result<()>;
933
934 fn api_for_each_bucket<F: FnMut(&'tx [u8]) -> crate::Result<()>>(self, f: F)
936 -> crate::Result<()>;
937
938 fn for_each_page<F: FnMut(&RefPage<'tx>, usize, &mut BVec<PgId>)>(self, f: &mut F);
940
941 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 fn api_sequence(self) -> u64;
953
954 fn max_inline_bucket_size(self) -> usize;
956
957 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 fn materialize_root(self) -> NodeRwCell<'tx>;
966
967 fn api_create_bucket(self, key: &[u8]) -> crate::Result<Self>
969 where
970 Self: Sized;
971
972 fn api_create_bucket_if_not_exists(self, key: &[u8]) -> crate::Result<Self>
974 where
975 Self: Sized;
976
977 fn api_delete_bucket(self, key: &[u8]) -> crate::Result<()>;
979
980 fn api_put(self, key: &[u8], value: &[u8]) -> crate::Result<()>;
982
983 fn api_delete(self, key: &[u8]) -> crate::Result<()>;
985
986 fn api_set_sequence(self, v: u64) -> crate::Result<()>;
988
989 fn api_next_sequence(self) -> crate::Result<u64>;
991
992 fn free(self);
994
995 fn spill(self, bump: &'tx Bump) -> crate::Result<()>;
997
998 fn write(self, bump: &'tx Bump) -> &'tx [u8];
999
1000 fn inlineable(self) -> bool;
1003
1004 fn own_in(self);
1006
1007 fn node(self, pgid: PgId, parent: Option<NodeRwCell<'tx>>) -> NodeRwCell<'tx>;
1009
1010 fn rebalance(self);
1012}
1013
1014pub struct BucketR<'tx> {
1015 pub(crate) bucket_header: BucketHeader,
1016 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 pub(crate) root_node: Option<NodeRwCell<'tx>>,
1034 buckets: HashMap<'tx, &'tx [u8], BucketCell<'tx>>,
1036 pub(crate) nodes: HashMap<'tx, PgId, NodeRwCell<'tx>>,
1038
1039 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 fn tx(self) -> TxCell<'tx> {
1147 self.split_bound()
1148 }
1149
1150 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 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 let (k, v, flags) = c.i_seek(name)?;
1171 if name != k || (flags & BUCKET_LEAF_FLAG) == 0 {
1173 return None;
1174 }
1175
1176 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 fn open_bucket(self, mut value: &[u8]) -> BucketCell<'tx> {
1191 let tx = self.tx();
1192 let bump = tx.bump();
1193 if !IsAligned::is_aligned_to::<InlineBucket>(value.as_ptr()) {
1196 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 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 fn api_get(self, key: &[u8]) -> Option<&'tx [u8]> {
1231 if let Some((k, v, flags)) = self.i_cursor().i_seek(key) {
1232 if (flags & BUCKET_LEAF_FLAG) != 0 {
1234 return None;
1235 }
1236 if key != k {
1238 return None;
1239 }
1240 Some(v)
1241 } else {
1242 None
1243 }
1244 }
1245
1246 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 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 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 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 tx.for_each_page(root, f)
1291 }
1292
1293 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 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 f(&pn, depth);
1315
1316 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 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 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 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 fn api_sequence(self) -> u64 {
1373 self.split_r().bucket_header.sequence()
1374 }
1375
1376 fn max_inline_bucket_size(self) -> usize {
1378 self.tx().page_size() / 4
1379 }
1380
1381 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 let mut used = PAGE_HEADER_SIZE;
1396 if let Some(last_element) = leaf_page.elements().last() {
1397 used += LEAF_PAGE_ELEMENT_SIZE * (p.count - 1) as usize;
1399
1400 used += last_element.pos() as usize
1406 + last_element.key_size() as usize
1407 + last_element.value_size() as usize;
1408 }
1409
1410 if self.root() == ZERO_PGID {
1412 s.inline_bucket_in_use += used as i64;
1413 } else {
1414 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 for leaf_elem in leaf_page.iter() {
1423 if leaf_elem.is_bucket_entry() {
1424 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 let mut used =
1436 PAGE_HEADER_SIZE + (BRANCH_PAGE_ELEMENT_SIZE * (branch_page.count - 1) as usize);
1437 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 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 s.depth += sub_stats.depth;
1456 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 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 fn spill(self, bump: &'tx Bump) -> crate::Result<()> {
1627 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 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 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 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 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 let page = match inline_page {
1771 None => self.tx().mem_page(pgid),
1772 Some(page) => page,
1773 };
1774
1775 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 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 #[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 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 let mut b = tx.create_bucket(b"widgets")?;
2108
2109 let _ = b.create_bucket(b"foo")?;
2111
2112 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 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 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 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 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 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 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 + 501 * 16 + 500 * 3 + big_key.len() as i64 + 1 * 10 + 2 * 90 + 3 * 400 + long_key_length as i64, 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 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 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 += 101 * 16; foo += 100 * 2 + 100 * 2; foo += 3 + 16; let mut bar = 16; bar += 11 * 16; bar += 10 + 10; bar += 3 + 16; let mut baz = 16; baz += 10 * 16; baz += 10 + 10; assert_eq!(foo + bar + baz, stats.leaf_in_use, "unexpected LeafInuse");
2737
2738 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 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 }
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 }
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 }
2939 Ok(())
2940 })
2941 .unwrap();
2942 index += 1;
2943 true
2944 });
2945 Ok(())
2946 }
2947}