1use std::fs::{File, OpenOptions};
21use std::mem::size_of;
22use std::path::Path;
23use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
24
25use memmap2::{MmapMut, MmapOptions};
26
27pub const T: usize = 8;
29pub const B: usize = 2 * T - 1; pub const NIL: u32 = u32::MAX;
33
34pub const BTREE_MAGIC: u64 = 0x4254_5245_454D_4150; #[repr(C, align(64))]
37pub struct BTreeHeader {
38 pub magic: u64,
39 pub root: AtomicU32,
40 pub node_count: AtomicU32,
41 pub capacity: u64,
42 pub len: AtomicU64,
43 pub free_head: AtomicU32,
46 _pad0: u32,
47 pub version: AtomicU64,
52 _pad: [u8; 16],
53}
54
55const _: () = {
56 assert!(size_of::<BTreeHeader>() == 64);
57};
58
59#[repr(C)]
60pub struct BTreeNode<K: Copy + Ord + Default + 'static, V: Copy + Default + 'static> {
61 pub count: u16,
62 pub is_leaf: u8,
63 _pad: [u8; 5],
64 pub keys: [K; B],
65 pub children: [u32; B + 1],
66 pub values: [V; B],
67}
68
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70pub enum BTreeError {
71 Full,
72 LayoutMismatch,
73 InvalidConfig,
74 IoError(std::io::ErrorKind),
75}
76
77impl From<std::io::Error> for BTreeError {
78 fn from(e: std::io::Error) -> Self {
79 Self::IoError(e.kind())
80 }
81}
82
83pub fn btree_file_size<K, V>(capacity: usize) -> usize
84where
85 K: Copy + Ord + Default + 'static,
86 V: Copy + Default + 'static,
87{
88 size_of::<BTreeHeader>() + capacity * size_of::<BTreeNode<K, V>>()
89}
90
91pub struct SharedBTreeMap<K: Copy + Ord + Default + 'static, V: Copy + Default + 'static> {
92 _file: File,
93 mmap: MmapMut,
94 raw_ptr: *mut u8,
95 capacity: usize,
96 _phantom: std::marker::PhantomData<(K, V)>,
97 header_sidecar: subetha_core::HandshakeHeader,
98 ring_sidecar: Box<subetha_core::ObservationRing>,
99}
100
101unsafe impl<K: Copy + Ord + Default + Send + 'static, V: Copy + Default + Send + 'static> Send
102 for SharedBTreeMap<K, V>
103{
104}
105unsafe impl<K: Copy + Ord + Default + Sync + 'static, V: Copy + Default + Sync + 'static> Sync
106 for SharedBTreeMap<K, V>
107{
108}
109
110impl<K: Copy + Ord + Default + Send + Sync + 'static, V: Copy + Default + Send + Sync + 'static>
111 subetha_sidecar::AdaptiveInstance for SharedBTreeMap<K, V>
112{
113 fn header(&self) -> &subetha_core::HandshakeHeader { &self.header_sidecar }
114 fn ring(&self) -> &subetha_core::ObservationRing { &self.ring_sidecar }
115 fn make_policy(&self) -> Box<dyn subetha_sidecar::Policy> {
116 Box::new(subetha_sidecar::NoMigrationPolicy)
117 }
118}
119
120impl<K: Copy + Ord + Default + 'static, V: Copy + Default + 'static> SharedBTreeMap<K, V> {
121 pub fn create(path: impl AsRef<Path>, capacity: usize) -> Result<Self, BTreeError> {
122 if capacity < 1 {
123 return Err(BTreeError::InvalidConfig);
124 }
125 let total = btree_file_size::<K, V>(capacity);
126 let file = OpenOptions::new()
127 .read(true).write(true).create(true).truncate(true)
128 .open(path.as_ref())?;
129 file.set_len(total as u64)?;
130 let mut mmap = unsafe { MmapOptions::new().len(total).map_mut(&file)? };
131 let hdr = mmap.as_mut_ptr() as *mut BTreeHeader;
132 unsafe {
133 std::ptr::write_bytes(hdr as *mut u8, 0, size_of::<BTreeHeader>());
134 (*hdr).magic = BTREE_MAGIC;
135 (*hdr).root = AtomicU32::new(NIL);
136 (*hdr).node_count = AtomicU32::new(0);
137 (*hdr).capacity = capacity as u64;
138 (*hdr).len = AtomicU64::new(0);
139 (*hdr).free_head = AtomicU32::new(NIL);
140 (*hdr).version = AtomicU64::new(0);
141 }
142 let raw_ptr = mmap.as_mut_ptr();
143 Ok(Self {
144 _file: file, mmap, raw_ptr, capacity,
145 _phantom: std::marker::PhantomData,
146 header_sidecar: subetha_core::HandshakeHeader::new(),
147 ring_sidecar: Box::new(subetha_core::ObservationRing::new()),
148 })
149 }
150
151 pub fn open(path: impl AsRef<Path>, expected_capacity: usize) -> Result<Self, BTreeError> {
152 let total = btree_file_size::<K, V>(expected_capacity);
153 let file = OpenOptions::new().read(true).write(true).open(path.as_ref())?;
154 if file.metadata()?.len() < total as u64 {
155 return Err(BTreeError::LayoutMismatch);
156 }
157 let mut mmap = unsafe { MmapOptions::new().len(total).map_mut(&file)? };
158 let hdr = unsafe { &*(mmap.as_ptr() as *const BTreeHeader) };
159 if hdr.magic != BTREE_MAGIC || hdr.capacity != expected_capacity as u64 {
160 return Err(BTreeError::LayoutMismatch);
161 }
162 let raw_ptr = mmap.as_mut_ptr();
163 Ok(Self {
164 _file: file, mmap, raw_ptr, capacity: expected_capacity,
165 _phantom: std::marker::PhantomData,
166 header_sidecar: subetha_core::HandshakeHeader::new(),
167 ring_sidecar: Box::new(subetha_core::ObservationRing::new()),
168 })
169 }
170
171 #[inline]
172 fn header(&self) -> &BTreeHeader {
173 unsafe { &*(self.raw_ptr as *const BTreeHeader) }
174 }
175
176 #[inline]
177 pub fn len(&self) -> usize {
178 self.header().len.load(Ordering::Acquire) as usize
179 }
180
181 #[inline]
182 pub fn is_empty(&self) -> bool {
183 self.len() == 0
184 }
185
186 #[inline]
187 pub fn capacity(&self) -> usize {
188 self.capacity
189 }
190
191 #[inline]
194 pub fn node_count(&self) -> usize {
195 self.header().node_count.load(Ordering::Acquire) as usize
196 }
197
198 #[inline]
199 fn node(&self, idx: u32) -> *mut BTreeNode<K, V> {
200 let off = size_of::<BTreeHeader>() + idx as usize * size_of::<BTreeNode<K, V>>();
201 unsafe { self.raw_ptr.add(off) as *mut BTreeNode<K, V> }
202 }
203
204 fn alloc_node(&self, is_leaf: bool) -> Result<u32, BTreeError> {
207 let h = self.header();
208 let free = h.free_head.load(Ordering::Acquire);
209 let idx = if free != NIL {
210 let next = unsafe { (*self.node(free)).children[0] };
211 h.free_head.store(next, Ordering::Release);
212 free
213 } else {
214 let idx = h.node_count.fetch_add(1, Ordering::AcqRel);
215 if idx as usize >= self.capacity {
216 h.node_count.fetch_sub(1, Ordering::AcqRel);
217 return Err(BTreeError::Full);
218 }
219 idx
220 };
221 let n = self.node(idx);
222 unsafe {
223 (*n).count = 0;
224 (*n).is_leaf = is_leaf as u8;
225 (*n).children = [NIL; B + 1];
226 }
227 Ok(idx)
228 }
229
230 fn free_node(&self, idx: u32) {
232 let h = self.header();
233 let head = h.free_head.load(Ordering::Acquire);
234 unsafe { (*self.node(idx)).children[0] = head; }
235 h.free_head.store(idx, Ordering::Release);
236 }
237
238 #[inline]
242 fn begin_write(&self) {
243 self.header().version.fetch_add(1, Ordering::AcqRel);
244 }
245 #[inline]
246 fn end_write(&self) {
247 self.header().version.fetch_add(1, Ordering::Release);
248 }
249
250 #[inline]
255 fn search(&self, idx: u32, key: &K) -> (usize, bool) {
256 let n = self.node(idx);
257 let count = (unsafe { (*n).count } as usize).min(B);
258 let (mut lo, mut hi) = (0usize, count);
259 while lo < hi {
260 let mid = (lo + hi) / 2;
261 let mk = unsafe { (*n).keys[mid] };
262 match mk.cmp(key) {
263 std::cmp::Ordering::Less => lo = mid + 1,
264 std::cmp::Ordering::Greater => hi = mid,
265 std::cmp::Ordering::Equal => return (mid, true),
266 }
267 }
268 (lo, false)
269 }
270
271 pub fn get(&self, key: &K) -> Option<V> {
273 let r = self.get_inner(key);
274 self.ring_sidecar.push_op(
275 crate::sidecar_ops::ordered::OP_GET,
276 if r.is_none() { 2 } else { 0 },
277 );
278 r
279 }
280
281 fn get_inner(&self, key: &K) -> Option<V> {
282 let h = self.header();
283 let cap = self.capacity as u32;
284 loop {
285 let v1 = h.version.load(Ordering::Acquire);
286 if v1 & 1 != 0 {
287 std::hint::spin_loop();
288 continue; }
290 let mut idx = h.root.load(Ordering::Acquire);
295 let mut result: Option<V> = None;
296 let mut torn = false;
297 while idx != NIL {
298 if idx >= cap {
299 torn = true;
300 break;
301 }
302 let (pos, found) = self.search(idx, key);
303 let n = self.node(idx);
304 if found {
305 result = Some(unsafe { (*n).values[pos] });
306 break;
307 }
308 if unsafe { (*n).is_leaf } != 0 {
309 break;
310 }
311 idx = unsafe { (*n).children[pos] };
312 }
313 let v2 = h.version.load(Ordering::Acquire);
314 if v1 == v2 && !torn {
315 return result;
316 }
317 std::hint::spin_loop();
318 }
319 }
320
321 pub fn contains_key(&self, key: &K) -> bool {
323 self.get_inner(key).is_some()
324 }
325
326 pub fn insert(&self, key: K, value: V) -> Result<Option<V>, BTreeError> {
329 self.begin_write();
330 let r = self.insert_inner(key, value);
331 self.end_write();
332 self.ring_sidecar.push_op(
333 crate::sidecar_ops::ordered::OP_INSERT,
334 if r.is_err() { 1 } else { 0 },
335 );
336 r
337 }
338
339 fn insert_inner(&self, key: K, value: V) -> Result<Option<V>, BTreeError> {
340 let root = self.header().root.load(Ordering::Acquire);
341 if root == NIL {
342 let r = self.alloc_node(true)?;
343 let n = self.node(r);
344 unsafe {
345 (*n).keys[0] = key;
346 (*n).values[0] = value;
347 (*n).count = 1;
348 }
349 self.header().root.store(r, Ordering::Release);
350 self.header().len.fetch_add(1, Ordering::AcqRel);
351 return Ok(None);
352 }
353 let root = if unsafe { (*self.node(root)).count as usize } == B {
355 let new_root = self.alloc_node(false)?;
356 unsafe {
357 (*self.node(new_root)).children[0] = root;
358 (*self.node(new_root)).count = 0;
359 }
360 self.split_child(new_root, 0)?;
361 self.header().root.store(new_root, Ordering::Release);
362 new_root
363 } else {
364 root
365 };
366 self.insert_nonfull(root, key, value)
367 }
368
369 fn insert_nonfull(&self, mut idx: u32, key: K, value: V) -> Result<Option<V>, BTreeError> {
371 loop {
372 let (pos, found) = self.search(idx, &key);
373 let n = self.node(idx);
374 if found {
375 let old = unsafe { (*n).values[pos] };
376 unsafe { (*n).values[pos] = value; }
377 return Ok(Some(old));
378 }
379 if unsafe { (*n).is_leaf } != 0 {
380 let count = unsafe { (*n).count as usize };
381 unsafe {
382 let mut j = count;
383 while j > pos {
384 (*n).keys[j] = (*n).keys[j - 1];
385 (*n).values[j] = (*n).values[j - 1];
386 j -= 1;
387 }
388 (*n).keys[pos] = key;
389 (*n).values[pos] = value;
390 (*n).count = (count + 1) as u16;
391 }
392 self.header().len.fetch_add(1, Ordering::AcqRel);
393 return Ok(None);
394 }
395 let child = unsafe { (*n).children[pos] };
396 if unsafe { (*self.node(child)).count as usize } == B {
397 self.split_child(idx, pos)?;
398 let n = self.node(idx);
400 let med = unsafe { (*n).keys[pos] };
401 match key.cmp(&med) {
402 std::cmp::Ordering::Equal => {
403 let old = unsafe { (*n).values[pos] };
404 unsafe { (*n).values[pos] = value; }
405 return Ok(Some(old));
406 }
407 std::cmp::Ordering::Greater => idx = unsafe { (*n).children[pos + 1] },
408 std::cmp::Ordering::Less => idx = unsafe { (*n).children[pos] },
409 }
410 } else {
411 idx = child;
412 }
413 }
414 }
415
416 fn split_child(&self, parent: u32, i: usize) -> Result<(), BTreeError> {
419 let full = unsafe { (*self.node(parent)).children[i] };
420 let is_leaf = unsafe { (*self.node(full)).is_leaf };
421 let right = self.alloc_node(is_leaf != 0)?;
422
423 let fp = self.node(full);
424 let rp = self.node(right);
425 unsafe {
426 for j in 0..(T - 1) {
428 (*rp).keys[j] = (*fp).keys[T + j];
429 (*rp).values[j] = (*fp).values[T + j];
430 }
431 if is_leaf == 0 {
432 for j in 0..T {
433 (*rp).children[j] = (*fp).children[T + j];
434 }
435 }
436 (*rp).count = (T - 1) as u16;
437 (*rp).is_leaf = is_leaf;
438 }
439 let median_key = unsafe { (*fp).keys[T - 1] };
440 let median_value = unsafe { (*fp).values[T - 1] };
441 unsafe { (*fp).count = (T - 1) as u16; }
444
445 let pp = self.node(parent);
446 unsafe {
447 let pc = (*pp).count as usize;
448 let mut j = pc;
449 while j > i {
450 (*pp).children[j + 1] = (*pp).children[j];
451 j -= 1;
452 }
453 (*pp).children[i + 1] = right;
454 let mut j = pc;
455 while j > i {
456 (*pp).keys[j] = (*pp).keys[j - 1];
457 (*pp).values[j] = (*pp).values[j - 1];
458 j -= 1;
459 }
460 (*pp).keys[i] = median_key;
461 (*pp).values[i] = median_value;
462 (*pp).count = (pc + 1) as u16;
463 }
464 Ok(())
465 }
466
467 pub fn remove(&self, key: &K) -> Result<Option<V>, BTreeError> {
470 self.begin_write();
471 let r = self.remove_inner(key);
472 self.end_write();
473 self.ring_sidecar.push_op(
474 crate::sidecar_ops::ordered::OP_REMOVE,
475 if r.is_none() { 2 } else { 0 },
476 );
477 Ok(r)
478 }
479
480 fn remove_inner(&self, key: &K) -> Option<V> {
481 let root = self.header().root.load(Ordering::Acquire);
482 if root == NIL {
483 return None;
484 }
485 let removed = self.delete_from(root, key);
486 let rn = self.node(root);
488 if unsafe { (*rn).count } == 0 {
489 if unsafe { (*rn).is_leaf } != 0 {
490 self.header().root.store(NIL, Ordering::Release);
491 } else {
492 let new_root = unsafe { (*rn).children[0] };
493 self.header().root.store(new_root, Ordering::Release);
494 }
495 self.free_node(root);
496 }
497 if removed.is_some() {
498 self.header().len.fetch_sub(1, Ordering::AcqRel);
499 }
500 removed
501 }
502
503 fn delete_from(&self, idx: u32, key: &K) -> Option<V> {
507 let (pos, found) = self.search(idx, key);
508 let n = self.node(idx);
509 let is_leaf = unsafe { (*n).is_leaf } != 0;
510 if found {
511 let old = unsafe { (*n).values[pos] };
512 if is_leaf {
513 let count = unsafe { (*n).count as usize };
514 unsafe {
515 for j in pos..count - 1 {
516 (*n).keys[j] = (*n).keys[j + 1];
517 (*n).values[j] = (*n).values[j + 1];
518 }
519 (*n).count = (count - 1) as u16;
520 }
521 } else {
522 let left = unsafe { (*n).children[pos] };
523 let right = unsafe { (*n).children[pos + 1] };
524 if unsafe { (*self.node(left)).count as usize } >= T {
525 let (pk, pv) = self.max_pair(left);
526 unsafe {
527 (*n).keys[pos] = pk;
528 (*n).values[pos] = pv;
529 }
530 self.delete_from(left, &pk);
531 } else if unsafe { (*self.node(right)).count as usize } >= T {
532 let (sk, sv) = self.min_pair(right);
533 unsafe {
534 (*n).keys[pos] = sk;
535 (*n).values[pos] = sv;
536 }
537 self.delete_from(right, &sk);
538 } else {
539 self.merge_at(idx, pos);
540 self.delete_from(left, key);
541 }
542 }
543 return Some(old);
544 }
545 if is_leaf {
546 return None;
547 }
548 let child = self.ensure_min_degree(idx, pos);
549 self.delete_from(child, key)
550 }
551
552 fn ensure_min_degree(&self, parent: u32, i: usize) -> u32 {
555 let p = self.node(parent);
556 let child = unsafe { (*p).children[i] };
557 if unsafe { (*self.node(child)).count as usize } >= T {
558 return child;
559 }
560 let pcount = unsafe { (*p).count as usize };
561 if i > 0 {
562 let left = unsafe { (*p).children[i - 1] };
563 if unsafe { (*self.node(left)).count as usize } >= T {
564 self.borrow_from_left(parent, i);
565 return child;
566 }
567 }
568 if i < pcount {
569 let right = unsafe { (*p).children[i + 1] };
570 if unsafe { (*self.node(right)).count as usize } >= T {
571 self.borrow_from_right(parent, i);
572 return child;
573 }
574 }
575 if i < pcount {
576 self.merge_at(parent, i);
577 unsafe { (*self.node(parent)).children[i] }
578 } else {
579 self.merge_at(parent, i - 1);
580 unsafe { (*self.node(parent)).children[i - 1] }
581 }
582 }
583
584 fn borrow_from_left(&self, parent: u32, i: usize) {
585 let p = self.node(parent);
586 let child = unsafe { (*p).children[i] };
587 let left = unsafe { (*p).children[i - 1] };
588 let c = self.node(child);
589 let l = self.node(left);
590 unsafe {
591 let cc = (*c).count as usize;
592 let internal = (*c).is_leaf == 0;
593 let mut j = cc;
594 while j > 0 {
595 (*c).keys[j] = (*c).keys[j - 1];
596 (*c).values[j] = (*c).values[j - 1];
597 j -= 1;
598 }
599 if internal {
600 let mut j = cc + 1;
601 while j > 0 {
602 (*c).children[j] = (*c).children[j - 1];
603 j -= 1;
604 }
605 }
606 (*c).keys[0] = (*p).keys[i - 1];
607 (*c).values[0] = (*p).values[i - 1];
608 let lc = (*l).count as usize;
609 if internal {
610 (*c).children[0] = (*l).children[lc];
611 }
612 (*p).keys[i - 1] = (*l).keys[lc - 1];
613 (*p).values[i - 1] = (*l).values[lc - 1];
614 (*l).count = (lc - 1) as u16;
615 (*c).count = (cc + 1) as u16;
616 }
617 }
618
619 fn borrow_from_right(&self, parent: u32, i: usize) {
620 let p = self.node(parent);
621 let child = unsafe { (*p).children[i] };
622 let right = unsafe { (*p).children[i + 1] };
623 let c = self.node(child);
624 let r = self.node(right);
625 unsafe {
626 let cc = (*c).count as usize;
627 let internal = (*c).is_leaf == 0;
628 (*c).keys[cc] = (*p).keys[i];
629 (*c).values[cc] = (*p).values[i];
630 if internal {
631 (*c).children[cc + 1] = (*r).children[0];
632 }
633 (*p).keys[i] = (*r).keys[0];
634 (*p).values[i] = (*r).values[0];
635 let rc = (*r).count as usize;
636 for j in 0..rc - 1 {
637 (*r).keys[j] = (*r).keys[j + 1];
638 (*r).values[j] = (*r).values[j + 1];
639 }
640 if internal {
641 for j in 0..rc {
642 (*r).children[j] = (*r).children[j + 1];
643 }
644 }
645 (*r).count = (rc - 1) as u16;
646 (*c).count = (cc + 1) as u16;
647 }
648 }
649
650 fn merge_at(&self, parent: u32, i: usize) {
653 let p = self.node(parent);
654 let left = unsafe { (*p).children[i] };
655 let right = unsafe { (*p).children[i + 1] };
656 let l = self.node(left);
657 let r = self.node(right);
658 unsafe {
659 let lc = (*l).count as usize;
660 let internal = (*l).is_leaf == 0;
661 (*l).keys[lc] = (*p).keys[i];
662 (*l).values[lc] = (*p).values[i];
663 let rc = (*r).count as usize;
664 for j in 0..rc {
665 (*l).keys[lc + 1 + j] = (*r).keys[j];
666 (*l).values[lc + 1 + j] = (*r).values[j];
667 }
668 if internal {
669 for j in 0..=rc {
670 (*l).children[lc + 1 + j] = (*r).children[j];
671 }
672 }
673 (*l).count = (lc + 1 + rc) as u16;
674 let pc = (*p).count as usize;
675 for j in i..pc - 1 {
676 (*p).keys[j] = (*p).keys[j + 1];
677 (*p).values[j] = (*p).values[j + 1];
678 }
679 for j in i + 1..pc {
680 (*p).children[j] = (*p).children[j + 1];
681 }
682 (*p).count = (pc - 1) as u16;
683 }
684 self.free_node(right);
685 }
686
687 fn max_pair(&self, mut idx: u32) -> (K, V) {
688 loop {
689 let n = self.node(idx);
690 let count = unsafe { (*n).count as usize };
691 if unsafe { (*n).is_leaf } != 0 {
692 return unsafe { ((*n).keys[count - 1], (*n).values[count - 1]) };
693 }
694 idx = unsafe { (*n).children[count] };
695 }
696 }
697
698 fn min_pair(&self, mut idx: u32) -> (K, V) {
699 loop {
700 let n = self.node(idx);
701 if unsafe { (*n).is_leaf } != 0 {
702 return unsafe { ((*n).keys[0], (*n).values[0]) };
703 }
704 idx = unsafe { (*n).children[0] };
705 }
706 }
707
708 pub fn first(&self) -> Option<(K, V)> {
710 let root = self.header().root.load(Ordering::Acquire);
711 let r = if root == NIL { None } else { Some(self.min_pair(root)) };
712 self.ring_sidecar.push_op(
713 crate::sidecar_ops::ordered::OP_GET,
714 if r.is_none() { 2 } else { 0 },
715 );
716 r
717 }
718
719 pub fn iter_ascending(&self) -> Vec<(K, V)> {
721 let mut out = Vec::with_capacity(self.len());
722 let root = self.header().root.load(Ordering::Acquire);
723 if root != NIL {
724 self.walk(root, &mut out);
725 }
726 out
727 }
728
729 fn walk(&self, idx: u32, out: &mut Vec<(K, V)>) {
730 let n = self.node(idx);
731 let count = unsafe { (*n).count as usize };
732 let is_leaf = unsafe { (*n).is_leaf } != 0;
733 for i in 0..count {
734 if !is_leaf {
735 let c = unsafe { (*n).children[i] };
736 self.walk(c, out);
737 }
738 out.push(unsafe { ((*n).keys[i], (*n).values[i]) });
739 }
740 if !is_leaf {
741 let c = unsafe { (*n).children[count] };
742 self.walk(c, out);
743 }
744 }
745
746 pub fn flush(&self) -> Result<(), BTreeError> {
747 self.mmap.flush()?;
748 Ok(())
749 }
750}
751
752#[cfg(test)]
753mod tests {
754 use super::*;
755
756 fn tmp(name: &str) -> std::path::PathBuf {
757 let mut p = std::env::temp_dir();
758 p.push(format!("btree_{name}_{}.bin", std::process::id()));
759 p
760 }
761
762 #[test]
763 fn insert_get_round_trip() {
764 let p = tmp("rt");
765 let m: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 64).unwrap();
766 for i in 0..100u64 {
767 assert_eq!(m.insert(i, i * 10).unwrap(), None);
768 }
769 for i in 0..100u64 {
770 assert_eq!(m.get(&i), Some(i * 10));
771 }
772 assert_eq!(m.get(&1000), None);
773 assert_eq!(m.len(), 100);
774 std::fs::remove_file(&p).ok();
775 }
776
777 #[test]
778 fn duplicate_insert_updates_and_returns_previous() {
779 let p = tmp("dup");
780 let m: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 64).unwrap();
781 assert_eq!(m.insert(5, 50).unwrap(), None);
782 assert_eq!(m.insert(5, 55).unwrap(), Some(50));
783 assert_eq!(m.get(&5), Some(55));
784 assert_eq!(m.len(), 1);
785 std::fs::remove_file(&p).ok();
786 }
787
788 #[test]
789 fn many_inserts_stay_sorted_and_findable() {
790 let p = tmp("many");
791 let n = 5000u64;
792 let m: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 4096).unwrap();
793 let mut x = 0x1234_5678u64;
795 let mut inserted = Vec::new();
796 for _ in 0..n {
797 x ^= x << 13; x ^= x >> 7; x ^= x << 17;
798 let k = x % 1_000_000;
799 if m.insert(k, k.wrapping_mul(3)).unwrap().is_none() {
800 inserted.push(k);
801 }
802 }
803 for &k in &inserted {
804 assert_eq!(m.get(&k), Some(k.wrapping_mul(3)), "missing {k}");
805 }
806 let asc = m.iter_ascending();
808 for w in asc.windows(2) {
809 assert!(w[0].0 < w[1].0, "order broken: {} >= {}", w[0].0, w[1].0);
810 }
811 assert_eq!(asc.len(), inserted.len());
812 std::fs::remove_file(&p).ok();
813 }
814
815 #[test]
816 fn cross_handle_visibility() {
817 let p = tmp("xhandle");
818 let a: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 64).unwrap();
819 for i in 0..50u64 { a.insert(i, i).unwrap(); }
820 let b: SharedBTreeMap<u64, u64> = SharedBTreeMap::open(&p, 64).unwrap();
821 for i in 0..50u64 { assert_eq!(b.get(&i), Some(i)); }
822 std::fs::remove_file(&p).ok();
823 }
824
825 #[test]
826 fn random_ops_match_std_btreemap() {
827 use std::collections::BTreeMap;
828 let p = tmp("oracle");
829 let m: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 16384).unwrap();
830 let mut oracle: BTreeMap<u64, u64> = BTreeMap::new();
831 let mut x = 0xdead_beef_1234_5678u64;
832 let mut rng = || {
833 x ^= x << 13; x ^= x >> 7; x ^= x << 17; x
834 };
835 for _ in 0..80_000 {
836 let k = rng() % 3000;
837 match rng() % 3 {
838 0 | 1 => {
839 let v = rng();
840 assert_eq!(m.insert(k, v).unwrap(), oracle.insert(k, v), "insert {k}");
841 }
842 _ => {
843 assert_eq!(m.remove(&k).unwrap(), oracle.remove(&k), "remove {k}");
844 }
845 }
846 assert_eq!(m.len(), oracle.len(), "len after op on {k}");
847 }
848 for (k, v) in &oracle {
849 assert_eq!(m.get(k), Some(*v), "final get {k}");
850 }
851 let asc = m.iter_ascending();
852 let oref: Vec<(u64, u64)> = oracle.iter().map(|(k, v)| (*k, *v)).collect();
853 assert_eq!(asc, oref, "iteration order / contents mismatch");
854 std::fs::remove_file(&p).ok();
855 }
856
857 #[test]
858 fn first_returns_smallest() {
859 let p = tmp("first");
860 let m: SharedBTreeMap<u64, u64> = SharedBTreeMap::create(&p, 1024).unwrap();
861 assert_eq!(m.first(), None);
862 for i in (0..500u64).rev() {
863 m.insert(i, i * 7).unwrap();
864 }
865 assert_eq!(m.first(), Some((0, 0)));
866 m.remove(&0).unwrap();
867 assert_eq!(m.first(), Some((1, 7)));
868 std::fs::remove_file(&p).ok();
869 }
870
871 #[test]
872 fn concurrent_readers_during_inserts() {
873 use std::sync::Arc;
874 use std::sync::atomic::AtomicBool;
875 let p = tmp("concurrent");
876 let m = Arc::new(SharedBTreeMap::<u64, u64>::create(&p, 16384).unwrap());
877 for i in 0..1000u64 {
878 m.insert(i, i.wrapping_mul(2)).unwrap();
879 }
880 let stop = Arc::new(AtomicBool::new(false));
881 let readers: Vec<_> = (0..4)
882 .map(|_| {
883 let m = m.clone();
884 let stop = stop.clone();
885 std::thread::spawn(move || {
886 while !stop.load(Ordering::Relaxed) {
887 for i in 0..1000u64 {
888 if let Some(v) = m.get(&i) {
892 assert_eq!(v, i.wrapping_mul(2), "torn read at {i}");
893 }
894 }
895 }
896 })
897 })
898 .collect();
899 for i in 1000..6000u64 {
900 m.insert(i, i.wrapping_mul(2)).unwrap();
901 }
902 stop.store(true, Ordering::Relaxed);
903 for r in readers {
904 r.join().unwrap();
905 }
906 std::fs::remove_file(&p).ok();
907 }
908}