Skip to main content

indexset/concurrent/
set.rs

1use ::core::borrow::Borrow;
2use ::core::fmt::Debug;
3use ::core::iter::FusedIterator;
4use ::core::marker::PhantomData;
5use ::core::ops::{Bound, RangeBounds};
6use ::core::sync::atomic::{AtomicPtr, AtomicU64, Ordering};
7use alloc::boxed::Box;
8use alloc::collections::BTreeMap;
9use alloc::sync::Arc;
10use alloc::vec;
11use alloc::vec::Vec;
12use parking_lot::{
13    ArcRwLockReadGuard, ArcRwLockWriteGuard, Mutex, MutexGuard, RawRwLock, RwLock, RwLockReadGuard, RwLockWriteGuard,
14};
15
16use crate::cdc::change::ChangeEvent;
17use crate::concurrent::operation::*;
18use crate::core::constants::DEFAULT_INNER_SIZE;
19use crate::core::node::*;
20
21use super::r#ref::Ref;
22
23/// Give the scheduler the core, when there is a scheduler to give it to.
24///
25/// `yield_now` is a `std` call, and a `no_std` build has no thread to yield.
26/// Spinning is the honest fallback there: it is what the caller was already
27/// doing on the fast path, without the syscall that would make it wait longer.
28#[inline]
29fn yield_now() {
30    #[cfg(feature = "std")]
31    std::thread::yield_now();
32    #[cfg(not(feature = "std"))]
33    ::core::hint::spin_loop();
34}
35
36const ROOT_PUBLICATION_SPIN_LIMIT: usize = 16;
37const STABLE_READ_BLOCKING_FALLBACK_AFTER: usize = 2;
38const PUBLICATION_BACKLOG_DRAIN_THRESHOLD: usize = 64;
39
40type NodeIndex<T, Node> = BTreeMap<T, Arc<RwLock<Node>>>;
41
42// Point-read routes are kept in immutable, cache-friendly chunks. Publishing
43// clones only the short vector of chunk Arcs and the one chunk containing the
44// changed boundary; it never copies the full node index. At WorkTable's
45// default 1,024 rows per node, one 128-route chunk covers roughly 131k rows.
46const PUBLISHED_ROUTES_PER_CHUNK: usize = 128;
47// Leave rebuilt chunks room for subsequent inserts, and merge only below the
48// split threshold so alternating insert/remove cannot thrash one boundary.
49const PUBLISHED_REBUILD_ROUTES_PER_CHUNK: usize = PUBLISHED_ROUTES_PER_CHUNK * 2 / 3;
50const PUBLISHED_ROUTE_MERGE_THRESHOLD: usize = PUBLISHED_ROUTES_PER_CHUNK * 3 / 4;
51
52struct PublishedChunk<T, Node> {
53    entries: Vec<(T, Arc<RwLock<Node>>)>,
54}
55
56impl<T: Clone, Node> Clone for PublishedChunk<T, Node> {
57    fn clone(&self) -> Self {
58        Self {
59            entries: self.entries.clone(),
60        }
61    }
62}
63
64struct PublishedNodeIndex<T, Node> {
65    chunks: Vec<Arc<PublishedChunk<T, Node>>>,
66    len: usize,
67}
68
69impl<T, Node> Clone for PublishedNodeIndex<T, Node> {
70    fn clone(&self) -> Self {
71        Self {
72            chunks: self.chunks.clone(),
73            len: self.len,
74        }
75    }
76}
77
78impl<T, Node> PublishedNodeIndex<T, Node>
79where
80    T: Ord + Clone,
81{
82    fn from_canonical(index: &NodeIndex<T, Node>) -> Self {
83        let mut chunks = Vec::with_capacity(index.len().div_ceil(PUBLISHED_REBUILD_ROUTES_PER_CHUNK));
84        let mut entries = Vec::with_capacity(PUBLISHED_REBUILD_ROUTES_PER_CHUNK);
85
86        for (key, node) in index {
87            entries.push((key.clone(), node.clone()));
88            if entries.len() == PUBLISHED_REBUILD_ROUTES_PER_CHUNK {
89                chunks.push(Arc::new(PublishedChunk { entries }));
90                entries = Vec::with_capacity(PUBLISHED_REBUILD_ROUTES_PER_CHUNK);
91            }
92        }
93        if !entries.is_empty() {
94            chunks.push(Arc::new(PublishedChunk { entries }));
95        }
96
97        Self {
98            chunks,
99            len: index.len(),
100        }
101    }
102
103    fn iter(&self) -> impl Iterator<Item = (&T, &Arc<RwLock<Node>>)> {
104        self.chunks
105            .iter()
106            .flat_map(|chunk| chunk.entries.iter().map(|(key, node)| (key, node)))
107    }
108
109    fn first_key_value(&self) -> Option<(&T, &Arc<RwLock<Node>>)> {
110        self.chunks.first()?.entries.first().map(|(key, node)| (key, node))
111    }
112
113    fn last_key_value(&self) -> Option<(&T, &Arc<RwLock<Node>>)> {
114        self.chunks.last()?.entries.last().map(|(key, node)| (key, node))
115    }
116
117    fn chunk_for<Q>(&self, key: &Q) -> usize
118    where
119        T: Borrow<Q>,
120        Q: Ord + ?Sized,
121    {
122        self.chunks.partition_point(|chunk| {
123            let max = &chunk.entries.last().expect("published chunks are non-empty").0;
124            <T as Borrow<Q>>::borrow(max) < key
125        })
126    }
127
128    fn first_for_bound<Q>(&self, bound: Bound<&Q>) -> Option<(&T, &Arc<RwLock<Node>>)>
129    where
130        T: Borrow<Q>,
131        Q: Ord + ?Sized,
132    {
133        let key = match bound {
134            Bound::Included(key) | Bound::Excluded(key) => key,
135            Bound::Unbounded => return self.first_key_value(),
136        };
137        let mut chunk_index = self.chunk_for(key);
138        while let Some(chunk) = self.chunks.get(chunk_index) {
139            let entry_index = chunk.entries.partition_point(|(candidate, _)| match bound {
140                Bound::Included(_) => <T as Borrow<Q>>::borrow(candidate) < key,
141                Bound::Excluded(_) => <T as Borrow<Q>>::borrow(candidate) <= key,
142                Bound::Unbounded => false,
143            });
144            if let Some((found, node)) = chunk.entries.get(entry_index) {
145                return Some((found, node));
146            }
147            chunk_index += 1;
148        }
149        None
150    }
151
152    fn insert(&mut self, key: T, node: Arc<RwLock<Node>>) -> Option<Arc<RwLock<Node>>> {
153        if self.chunks.is_empty() {
154            self.chunks.push(Arc::new(PublishedChunk {
155                entries: vec![(key, node)],
156            }));
157            self.len = 1;
158            return None;
159        }
160
161        let mut chunk_index = self.chunk_for(&key);
162        if chunk_index == self.chunks.len() {
163            chunk_index -= 1;
164        }
165        let chunk = Arc::make_mut(&mut self.chunks[chunk_index]);
166        match chunk.entries.binary_search_by(|(candidate, _)| candidate.cmp(&key)) {
167            Ok(index) => Some(::core::mem::replace(&mut chunk.entries[index].1, node)),
168            Err(index) => {
169                chunk.entries.insert(index, (key, node));
170                self.len += 1;
171                if chunk.entries.len() > PUBLISHED_ROUTES_PER_CHUNK {
172                    let right = chunk.entries.split_off(chunk.entries.len() / 2);
173                    self.chunks
174                        .insert(chunk_index + 1, Arc::new(PublishedChunk { entries: right }));
175                }
176                None
177            }
178        }
179    }
180
181    fn remove<Q>(&mut self, key: &Q) -> Option<Arc<RwLock<Node>>>
182    where
183        T: Borrow<Q>,
184        Q: Ord + ?Sized,
185    {
186        let chunk_index = self.chunk_for(key);
187        let entry_index = self
188            .chunks
189            .get(chunk_index)?
190            .entries
191            .binary_search_by(|(candidate, _)| <T as Borrow<Q>>::borrow(candidate).cmp(key))
192            .ok()?;
193        let chunk = Arc::make_mut(&mut self.chunks[chunk_index]);
194        let (_, removed) = chunk.entries.remove(entry_index);
195        self.len -= 1;
196
197        if chunk.entries.is_empty() {
198            self.chunks.remove(chunk_index);
199        } else if chunk_index > 0
200            && self.chunks[chunk_index - 1].entries.len() + self.chunks[chunk_index].entries.len()
201                <= PUBLISHED_ROUTE_MERGE_THRESHOLD
202        {
203            let right = self.chunks.remove(chunk_index);
204            Arc::make_mut(&mut self.chunks[chunk_index - 1])
205                .entries
206                .extend(right.entries.iter().cloned());
207        } else if chunk_index + 1 < self.chunks.len()
208            && self.chunks[chunk_index].entries.len() + self.chunks[chunk_index + 1].entries.len()
209                <= PUBLISHED_ROUTE_MERGE_THRESHOLD
210        {
211            let right = self.chunks.remove(chunk_index + 1);
212            Arc::make_mut(&mut self.chunks[chunk_index])
213                .entries
214                .extend(right.entries.iter().cloned());
215        }
216
217        Some(removed)
218    }
219}
220
221#[inline]
222fn node_identity<Node>(node: &Arc<RwLock<Node>>) -> usize {
223    // Identity token only: it is never converted back into or dereferenced as
224    // a pointer. The Arc stays live while the token is present, preventing
225    // allocator reuse from aliasing two published nodes.
226    Arc::as_ptr(node) as usize
227}
228
229struct RetiredIndex<T, Node>(*mut PublishedNodeIndex<T, Node>);
230
231// SAFETY: the pointer is uniquely owned after it has been swapped out of the
232// publication slot, and this wrapper exposes no access to the map. Its only
233// operation is destruction after the grace period. Dropping a shared route
234// chunk only decrements its Arc; dropping the final route path can move/drop T
235// and Node on the reclaiming thread, hence Send. The wrapper never dereferences
236// the index, and its private field prevents callers from adding such access
237// without revisiting this proof.
238unsafe impl<T: Send, Node: Send> Send for RetiredIndex<T, Node> {}
239
240impl<T, Node> Drop for RetiredIndex<T, Node> {
241    fn drop(&mut self) {
242        // SAFETY: this wrapper is created exactly once for a pointer returned
243        // by `Box::into_raw`, after that pointer has been atomically unlinked.
244        unsafe { drop(Box::from_raw(self.0)) }
245    }
246}
247
248struct PublishedIndex<T, Node> {
249    current: AtomicPtr<PublishedNodeIndex<T, Node>>,
250    domain: ps_reclaim::Domain,
251}
252
253impl<T, Node> PublishedIndex<T, Node> {
254    fn new() -> Self {
255        Self {
256            current: AtomicPtr::new(Box::into_raw(Box::new(PublishedNodeIndex {
257                chunks: Vec::new(),
258                len: 0,
259            }))),
260            domain: ps_reclaim::Domain::new(),
261        }
262    }
263}
264
265impl<T, Node> PublishedIndex<T, Node>
266where
267    T: Ord + Clone + Send + 'static,
268    Node: Send + 'static,
269{
270    fn snapshot(&self) -> PublishedNodeIndex<T, Node> {
271        let current = self.current.load(Ordering::Acquire);
272        // SAFETY: callers hold the only structural writer lock. `current`
273        // cannot be unlinked until that writer publishes its replacement.
274        unsafe { (&*current).clone() }
275    }
276
277    fn replace(&self, replacement: PublishedNodeIndex<T, Node>) -> RetiredIndex<T, Node> {
278        // The route index is structurally shared: publishing moves one root,
279        // and the writer copied only its chunk-Arc vector plus touched chunks.
280        let replacement = Box::into_raw(Box::new(replacement));
281        let retired = self.current.swap(replacement, Ordering::AcqRel);
282        RetiredIndex(retired)
283    }
284
285    fn retire(&self, retired: RetiredIndex<T, Node>) {
286        // Keep the pointer's provenance intact while transferring its unique
287        // ownership to the retirement callback.
288        self.domain.retire(move || drop(retired));
289    }
290
291    fn advance(&self) {
292        // A reader delayed on a node writer never holds a pin (see the point
293        // read paths below). Do not sweep ps-reclaim's 256-slot registry on
294        // every split: that turns the registry into the same reader/writer
295        // cache-line fight this publication path removes. A small bounded
296        // backlog amortizes the sweep while `advance` drains every route root
297        // whose grace period has elapsed.
298        if self.domain.pending() >= PUBLICATION_BACKLOG_DRAIN_THRESHOLD {
299            self.domain.advance();
300        }
301    }
302}
303
304impl<T, Node> Drop for PublishedIndex<T, Node> {
305    fn drop(&mut self) {
306        let current = *self.current.get_mut();
307        // SAFETY: exclusive access proves no reader can load `current`, and it
308        // is the one still-linked allocation created by `Box::into_raw`.
309        unsafe { drop(Box::from_raw(current)) }
310    }
311}
312
313// Publication invariant: every canonical node appears once and in the same
314// order in the published route index. At most one route key may differ from
315// its canonical key, and only for the canonical last node. That exception is
316// safe because point lookup falls back to the published last node above all
317// routes, while a stale route below the current maximum still selects that
318// same final node. A last-node shrink cannot reorder it before the preceding
319// node because node ranges are non-overlapping. Attachment repairs the route
320// before it can cease to be the last node.
321pub(crate) struct Topology<T, Node> {
322    index: RwLock<NodeIndex<T, Node>>,
323    // Writer-only reverse lookup from node identity to its current published
324    // route key. This differs from the canonical key only for the last node,
325    // whose stale route remains a valid final point-read fallback.
326    published_keys: Mutex<BTreeMap<usize, T>>,
327    published: PublishedIndex<T, Node>,
328    // Even values are stable publications; odd values mean a writer may have
329    // changed node contents or routing but has not published the new route.
330    generation: AtomicU64,
331}
332
333impl<T, Node> Debug for Topology<T, Node> {
334    fn fmt(&self, formatter: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
335        formatter
336            .debug_struct("Topology")
337            .field("nodes", &self.index.read().len())
338            .field("generation", &self.generation.load(Ordering::Relaxed))
339            .finish()
340    }
341}
342
343impl<T, Node> Topology<T, Node> {
344    fn new() -> Self {
345        Self {
346            index: RwLock::new(BTreeMap::new()),
347            published_keys: Mutex::new(BTreeMap::new()),
348            published: PublishedIndex::new(),
349            generation: AtomicU64::new(0),
350        }
351    }
352
353    #[inline]
354    pub(crate) fn read(&self) -> RwLockReadGuard<'_, NodeIndex<T, Node>> {
355        self.index.read()
356    }
357}
358
359impl<T, Node> Topology<T, Node>
360where
361    T: Ord + Clone + Send + 'static,
362    Node: Send + 'static,
363{
364    #[inline]
365    fn write(&self) -> TopologyWriteGuard<'_, T, Node> {
366        let index = self.index.write();
367        self.generation.fetch_add(1, Ordering::AcqRel);
368        TopologyWriteGuard {
369            topology: self,
370            index: Some(index),
371            published: None,
372            published_keys: None,
373            publish: true,
374            dirty: false,
375        }
376    }
377
378    /// Re-keys a node without replacing the point-read snapshot.
379    ///
380    /// This guard starts without a replacement snapshot. The commit may retain
381    /// that fast path only when re-keying the last node: point reads already
382    /// fall back to the last route beyond its published maximum. Re-keying any
383    /// earlier node must call `enable_publication`, because a subsequent insert
384    /// can fill a gap left by a shrinking maximum in the following node.
385    #[inline]
386    fn write_rekey(&self) -> TopologyWriteGuard<'_, T, Node> {
387        let index = self.index.write();
388        TopologyWriteGuard {
389            topology: self,
390            index: Some(index),
391            published: None,
392            published_keys: None,
393            publish: false,
394            dirty: false,
395        }
396    }
397
398    #[inline]
399    fn try_write(&self) -> Option<TopologyWriteGuard<'_, T, Node>> {
400        let index = self.index.try_write()?;
401        self.generation.fetch_add(1, Ordering::AcqRel);
402        Some(TopologyWriteGuard {
403            topology: self,
404            index: Some(index),
405            published: None,
406            published_keys: None,
407            publish: true,
408            dirty: false,
409        })
410    }
411}
412
413pub(crate) struct TopologyWriteGuard<'a, T, Node>
414where
415    T: Ord + Clone + Send + 'static,
416    Node: Send + 'static,
417{
418    topology: &'a Topology<T, Node>,
419    // Option lets Drop release the structural lock before advancing the
420    // reclamation domain. Range readers should not wait for a registry scan.
421    index: Option<RwLockWriteGuard<'a, NodeIndex<T, Node>>>,
422    published: Option<PublishedNodeIndex<T, Node>>,
423    published_keys: Option<MutexGuard<'a, BTreeMap<usize, T>>>,
424    publish: bool,
425    dirty: bool,
426}
427
428impl<T, Node> ::core::ops::Deref for TopologyWriteGuard<'_, T, Node>
429where
430    T: Ord + Clone + Send + 'static,
431    Node: Send + 'static,
432{
433    type Target = NodeIndex<T, Node>;
434
435    fn deref(&self) -> &Self::Target {
436        self.index.as_deref().expect("topology guard already released")
437    }
438}
439
440impl<'a, T, Node> TopologyWriteGuard<'a, T, Node>
441where
442    T: Ord + Clone + Send + 'static,
443    Node: Send + 'static,
444{
445    pub(crate) fn enable_publication(&mut self) {
446        if self.publish {
447            return;
448        }
449        debug_assert!(
450            !self.dirty,
451            "publication must be enabled before mutating an opt-out topology guard"
452        );
453        // `write_rekey` deliberately leaves the stable generation untouched
454        // for a route-safe last-node rekey. If commit discovers that the
455        // route really must change, enter the odd writer generation before
456        // constructing or publishing its replacement.
457        self.topology.generation.fetch_add(1, Ordering::AcqRel);
458        self.publish = true;
459    }
460
461    fn ensure_publication_snapshot(&mut self) {
462        if self.published.is_none() {
463            self.published_keys = Some(self.topology.published_keys.lock());
464            self.published = Some(self.topology.published.snapshot());
465        }
466    }
467
468    /// Restores all derived publication state from the canonical topology.
469    ///
470    /// Ordinary mutations update one route in O(log N). This bounded O(N)
471    /// recovery is reserved for an internal identity mismatch or impossible
472    /// key collision; it prevents a bookkeeping defect from panicking or
473    /// entering an unbounded repair loop while the structural lock is held.
474    fn rebuild_publication(&mut self) {
475        if self.published_keys.is_none() {
476            self.published_keys = Some(self.topology.published_keys.lock());
477        }
478        let canonical = self.index.as_deref().expect("topology guard already released");
479        let rebuilt = PublishedNodeIndex::from_canonical(canonical);
480        let rebuilt_keys = canonical
481            .iter()
482            .map(|(key, node)| (node_identity(node), key.clone()))
483            .collect();
484        **self
485            .published_keys
486            .as_mut()
487            .expect("publication identity lock was initialized") = rebuilt_keys;
488        self.published = Some(rebuilt);
489        self.dirty = true;
490    }
491
492    pub(crate) fn is_last_node(&self, node: &Arc<RwLock<Node>>) -> bool {
493        self.index
494            .as_deref()
495            .and_then(BTreeMap::last_key_value)
496            .is_some_and(|(_, candidate)| Arc::ptr_eq(candidate, node))
497    }
498
499    /// Re-keys the one route that may safely remain stale for point reads.
500    ///
501    /// This is deliberately separate from `insert`/`remove`: those general
502    /// mutation methods require publication to be enabled. The caller has
503    /// already verified that `old_key` identifies `node` and that it is the
504    /// canonical last node. Its published route remains a valid final
505    /// fallback whether the maximum grows or shrinks.
506    pub(crate) fn rekey_last_node(&mut self, old_key: &T, new_key: T, node: Arc<RwLock<Node>>) {
507        debug_assert!(!self.publish, "last-node rekey must use the opt-out guard");
508        debug_assert!(
509            !self.dirty,
510            "an opt-out guard may perform only one explicit last-node rekey"
511        );
512        debug_assert!(
513            self.is_last_node(&node),
514            "only the canonical last node may skip publication"
515        );
516
517        let index = self.index.as_deref_mut().expect("topology guard already released");
518        let removed = index.remove(old_key);
519        debug_assert!(
520            removed.as_ref().is_some_and(|removed| Arc::ptr_eq(removed, &node)),
521            "last-node rekey must remove its expected canonical route"
522        );
523        let replaced = index.insert(new_key, node);
524        debug_assert!(
525            replaced.is_none(),
526            "last-node rekey must not collide with another canonical route"
527        );
528        self.dirty = true;
529    }
530
531    /// Makes the current canonical last-node route exact before attachment
532    /// can place another node after it. This runs once per attach batch, not
533    /// once per node.
534    fn repair_last_route_before_attach(&mut self) {
535        debug_assert!(self.publish, "attachment repair requires publication");
536        let Some((canonical_key, last_node)) = self
537            .index
538            .as_deref()
539            .expect("topology guard already released")
540            .last_key_value()
541            .map(|(key, node)| (key.clone(), node.clone()))
542        else {
543            return;
544        };
545
546        self.ensure_publication_snapshot();
547        let published_key = self
548            .published_keys
549            .as_ref()
550            .expect("publication identity map initialized")
551            .get(&node_identity(&last_node))
552            .cloned();
553        let Some(published_key) = published_key else {
554            self.rebuild_publication();
555            return;
556        };
557        if published_key == canonical_key {
558            return;
559        }
560
561        let repaired_consistently = {
562            let published = self.published.as_mut().expect("publication snapshot initialized");
563            let published_keys = self
564                .published_keys
565                .as_mut()
566                .expect("publication identity map initialized");
567            let removed = published.remove(&published_key);
568            let displaced = published.insert(canonical_key.clone(), last_node.clone());
569            published_keys.insert(node_identity(&last_node), canonical_key);
570            removed.is_some_and(|old_node| Arc::ptr_eq(&old_node, &last_node)) && displaced.is_none()
571        };
572        if !repaired_consistently {
573            self.rebuild_publication();
574        } else {
575            self.dirty = true;
576        }
577    }
578
579    pub(crate) fn insert(&mut self, key: T, node: Arc<RwLock<Node>>) -> Option<Arc<RwLock<Node>>> {
580        debug_assert!(self.publish, "generic topology insertion requires publication");
581        let replaced = self
582            .index
583            .as_deref_mut()
584            .expect("topology guard already released")
585            .insert(key.clone(), node.clone());
586        self.dirty = true;
587
588        if self.publish {
589            self.ensure_publication_snapshot();
590            if let Some(replaced) = &replaced {
591                let removed_consistently = {
592                    let published = self.published.as_mut().expect("publication snapshot initialized");
593                    let published_keys = self
594                        .published_keys
595                        .as_mut()
596                        .expect("publication identity map initialized");
597                    published_keys
598                        .remove(&node_identity(replaced))
599                        .and_then(|old_key| published.remove(&old_key))
600                        .is_some_and(|old_node| Arc::ptr_eq(&old_node, replaced))
601                };
602                if !removed_consistently {
603                    self.rebuild_publication();
604                    return Some(replaced.clone());
605                }
606            }
607
608            let displaced = self
609                .published
610                .as_mut()
611                .expect("publication snapshot initialized")
612                .insert(key.clone(), node.clone());
613            self.published_keys
614                .as_mut()
615                .expect("publication identity map initialized")
616                .insert(node_identity(&node), key);
617            if displaced.is_some_and(|old_node| !Arc::ptr_eq(&old_node, &node)) {
618                // Canonical keys are unique, so a different node cannot
619                // lawfully occupy this route. Recover once from canonical
620                // state instead of scanning and chaining while the generation
621                // remains odd.
622                self.rebuild_publication();
623            }
624        }
625
626        replaced
627    }
628
629    pub(crate) fn remove<Q>(&mut self, key: &Q) -> Option<Arc<RwLock<Node>>>
630    where
631        T: Borrow<Q>,
632        Q: Ord + ?Sized,
633    {
634        debug_assert!(self.publish, "generic topology removal requires publication");
635        let removed = self
636            .index
637            .as_deref_mut()
638            .expect("topology guard already released")
639            .remove(key)?;
640        self.dirty = true;
641
642        if self.publish {
643            self.ensure_publication_snapshot();
644            let removed_consistently = {
645                let published = self.published.as_mut().expect("publication snapshot initialized");
646                let published_keys = self
647                    .published_keys
648                    .as_mut()
649                    .expect("publication identity map initialized");
650                published_keys
651                    .remove(&node_identity(&removed))
652                    .and_then(|route_key| published.remove::<T>(&route_key))
653                    .is_some_and(|route_node| Arc::ptr_eq(&route_node, &removed))
654            };
655            if !removed_consistently {
656                self.rebuild_publication();
657            }
658        }
659
660        Some(removed)
661    }
662}
663
664impl<T, Node> Drop for TopologyWriteGuard<'_, T, Node>
665where
666    T: Ord + Clone + Send + 'static,
667    Node: Send + 'static,
668{
669    fn drop(&mut self) {
670        #[cfg(debug_assertions)]
671        if self.publish && self.dirty {
672            let canonical = self.index.as_deref().expect("topology guard exists while validating");
673            let published = self.published.as_ref().expect("publishing guard carries snapshot");
674            let published_keys = self
675                .published_keys
676                .as_deref()
677                .expect("publishing guard carries identity map");
678            debug_assert_eq!(
679                canonical.len(),
680                published.len,
681                "canonical and published node counts diverged"
682            );
683            debug_assert_eq!(
684                canonical.len(),
685                published_keys.len(),
686                "canonical and published identity counts diverged"
687            );
688            for ((_, canonical_node), (route_key, route_node)) in canonical.iter().zip(published.iter()) {
689                debug_assert!(
690                    Arc::ptr_eq(route_node, canonical_node),
691                    "canonical and published node order diverged"
692                );
693                debug_assert!(
694                    published_keys.get(&node_identity(canonical_node)) == Some(route_key),
695                    "published identity key does not match the route index"
696                );
697            }
698        }
699
700        if !self.publish {
701            drop(self.published_keys.take());
702            drop(self.index.take());
703            return;
704        }
705        if !self.dirty {
706            self.topology.generation.fetch_add(1, Ordering::Release);
707            drop(self.published_keys.take());
708            drop(self.index.take());
709            return;
710        }
711        let retired = self.topology.published.replace(
712            self.published
713                .take()
714                .expect("publishing guard must carry a read snapshot"),
715        );
716        // Readers may proceed as soon as the O(1) root publication completes.
717        // Garbage bookkeeping and the registry sweep are deliberately outside
718        // that odd-generation window.
719        self.topology.generation.fetch_add(1, Ordering::Release);
720        self.topology.published.retire(retired);
721        drop(self.published_keys.take());
722        drop(self.index.take());
723        self.topology.published.advance();
724    }
725}
726
727// Default identity-adoption hook for replace-on-equality: plain sets and maps
728// have no hidden ordering state to carry over. See
729// `MultiPairLike::adopt_stored_identity`.
730pub(crate) fn no_identity_adoption<T>(_stored: &T, _incoming: &mut T) {}
731
732// `BTreeMap::range::<Q>` requires the borrowed ordering to be identical to
733// the stored-key ordering. That is true for ordinary borrowed keys such as
734// `String`/`str`, but deliberately false for multimap entries: many distinct
735// `(key, value)` entries borrow as the same `key`. Route those lookups by the
736// borrowed view explicitly so node maxima sharing one logical key remain
737// reachable.
738fn first_for_borrowed_bound<'a, T, Q, V>(
739    index: &'a BTreeMap<T, V>,
740    bound: Bound<&Q>,
741    borrow_order_matches: bool,
742) -> Option<(&'a T, &'a V)>
743where
744    T: Ord + Borrow<Q>,
745    Q: Ord + ?Sized,
746{
747    if borrow_order_matches {
748        return index.range::<Q, _>((bound, Bound::Unbounded)).next();
749    }
750
751    index.iter().find(|(key, _)| match bound {
752        Bound::Included(value) => <T as Borrow<Q>>::borrow(key) >= value,
753        Bound::Excluded(value) => <T as Borrow<Q>>::borrow(key) > value,
754        Bound::Unbounded => true,
755    })
756}
757
758fn first_published_for_borrowed_bound<'a, T, Q, V>(
759    index: &'a PublishedNodeIndex<T, V>,
760    bound: Bound<&Q>,
761    borrow_order_matches: bool,
762) -> Option<(&'a T, &'a Arc<RwLock<V>>)>
763where
764    T: Ord + Clone + Borrow<Q>,
765    Q: Ord + ?Sized,
766{
767    if borrow_order_matches {
768        return index.first_for_bound(bound);
769    }
770
771    index.iter().find(|(key, _)| match bound {
772        Bound::Included(value) => <T as Borrow<Q>>::borrow(key) >= value,
773        Bound::Excluded(value) => <T as Borrow<Q>>::borrow(key) > value,
774        Bound::Unbounded => true,
775    })
776}
777
778fn node_for_borrowed_end<'a, T, Q, V>(
779    index: &'a BTreeMap<T, V>,
780    end: &Q,
781    borrow_order_matches: bool,
782) -> Option<(&'a T, &'a V)>
783where
784    T: Ord + Borrow<Q>,
785    Q: Ord + ?Sized,
786{
787    if borrow_order_matches {
788        return index
789            .range::<Q, _>((Bound::Included(end), Bound::Unbounded))
790            .next()
791            .or_else(|| index.last_key_value());
792    }
793
794    let mut last_equal = None;
795    for entry @ (key, _) in index {
796        match <T as Borrow<Q>>::borrow(key).cmp(end) {
797            ::core::cmp::Ordering::Less => {}
798            ::core::cmp::Ordering::Equal => last_equal = Some(entry),
799            // The first node whose maximum is above the end may still start
800            // with values inside the range. `Range::new` ranks within that
801            // node to obtain the first out-of-range sentinel.
802            ::core::cmp::Ordering::Greater => return Some(entry),
803        }
804    }
805    last_equal.or_else(|| index.last_key_value())
806}
807
808/// A **persistent** concurrent ordered set based on a B-Tree.
809///
810/// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance
811/// benefits and drawbacks.
812///
813/// It is a logic error for an item to be modified in such a way that the item's ordering relative
814/// to any other item, as determined by the [`Ord`] trait, changes while it is in the set. This is
815/// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code.
816/// The behavior resulting from such a logic error is not specified, but will be encapsulated to the
817/// `BTreeSet` that observed the logic error and not result in undefined behavior. This could
818/// include panics, incorrect results, aborts, memory leaks, and non-termination.
819///
820/// Iterators returned by [`crate::BTreeSet::iter`] produce their items in order, and take worst-case
821/// logarithmic and amortized constant time per item returned.
822///
823/// [`Cell`]: cratestd::cell::Cell
824/// [`RefCell`]: cratestd::cell::RefCell
825///
826/// # Examples
827///
828/// ```
829/// use indexset::concurrent::set::BTreeSet;
830///
831/// // Type inference lets us omit an explicit type signature (which
832/// // would be `BTreeSet<&str>` in this example).
833/// let mut books = BTreeSet::<&str>::new();
834///
835/// // Add some books.
836/// books.insert("A Dance With Dragons");
837/// books.insert("To Kill a Mockingbird");
838/// books.insert("The Odyssey");
839/// books.insert("The Great Gatsby");
840///
841/// // Check for a specific one.
842/// if !books.contains("The Winds of Winter") {
843///     println!("We have {} books, but The Winds of Winter ain't one.",
844///              books.len());
845/// }
846///
847/// // Remove a book.
848/// books.remove("The Odyssey");
849///
850/// // Iterate over everything.
851/// for book in &books {
852///     println!("{book}");
853/// }
854/// ```
855///
856/// A `BTreeSet` with a known list of items can be initialized from an array:
857///
858/// ```
859/// use indexset::concurrent::set::BTreeSet;
860///
861/// let set = BTreeSet::from_iter([1, 2, 3]);
862/// ```
863#[derive(Debug)]
864pub struct BTreeSet<T, Node = Vec<T>>
865where
866    T: Ord + Clone + 'static,
867    Node: NodeLike<T>,
868{
869    // Writers maintain the canonical ordered topology under one structural
870    // lock and publish immutable snapshots for point reads. The read path is
871    // therefore free of a shared reader-count cache line. Node contents use
872    // independent read/write locks, so readers routed to one node may proceed
873    // concurrently while mutations retain exclusive node access.
874    pub(crate) index: Topology<T, Node>,
875    node_capacity: usize,
876    // Ordinary set/map keys satisfy Borrow's ordering contract and retain a
877    // logarithmic BTreeMap route. Multimap entries intentionally borrow only
878    // their leading key, so equal borrowed-key groups need an explicit scan.
879    borrow_order_matches: bool,
880    #[cfg(feature = "cdc")]
881    // The counter provides unique sequence numbers only. Node/global locks
882    // order conflicting mutations, and the persistence queue publishes event
883    // payloads, so the counter itself does not carry memory visibility.
884    event_id: AtomicU64,
885}
886impl<T: Ord + Clone + 'static, Node: NodeLike<T>> Default for BTreeSet<T, Node> {
887    fn default() -> Self {
888        Self {
889            index: Topology::new(),
890            node_capacity: DEFAULT_INNER_SIZE,
891            borrow_order_matches: true,
892            #[cfg(feature = "cdc")]
893            event_id: AtomicU64::new(0),
894        }
895    }
896}
897
898impl<T, Node> BTreeSet<T, Node>
899where
900    T: Debug + Ord + Clone + Send,
901    Node: NodeLike<T> + Send + 'static,
902{
903    pub fn new() -> Self {
904        Self::default()
905    }
906    /// Makes a new, empty `BTreeSet` with the given maximum node size. Allocates one vec with
907    /// the capacity set to be the specified node size.
908    ///
909    /// # Examples
910    ///
911    /// ```
912    /// use indexset::concurrent::set::BTreeSet;
913    ///
914    /// let set: BTreeSet<i32> = BTreeSet::with_maximum_node_size(128);
915    pub fn with_maximum_node_size(node_capacity: usize) -> Self {
916        Self {
917            index: Topology::new(),
918            node_capacity,
919            borrow_order_matches: true,
920            #[cfg(feature = "cdc")]
921            event_id: AtomicU64::new(0),
922        }
923    }
924    pub(crate) fn with_grouped_borrow_routing(mut self) -> Self {
925        self.borrow_order_matches = false;
926        self
927    }
928    pub fn attach_node(&self, node: Node) {
929        self.attach_nodes(::core::iter::once(node));
930    }
931
932    /// Attaches a persisted topology in one structural publication.
933    ///
934    /// Nodes must be non-empty and internally sorted. Their values, together
935    /// with any nodes already attached to this set, must form mutually ordered
936    /// non-overlapping ranges. The same preconditions as [`Self::attach_node`]
937    /// apply to every item.
938    pub fn attach_nodes(&self, nodes: impl IntoIterator<Item = Node>) {
939        let mut nodes = nodes.into_iter().peekable();
940        if nodes.peek().is_none() {
941            return;
942        }
943
944        let mut index = self.index.write();
945        index.repair_last_route_before_attach();
946        for node in nodes {
947            let node_id = node
948                .max()
949                .cloned()
950                .expect("node should contain at least one value to be correct node");
951            index.insert(node_id, Arc::new(RwLock::new(node)));
952        }
953    }
954
955    #[cfg(feature = "cdc")]
956    pub(crate) fn export_topology(&self) -> (usize, Vec<Vec<T>>) {
957        let index = self.index.read();
958        let nodes = index
959            .values()
960            .map(|node| node.read().iter().cloned().collect())
961            .collect();
962        (self.node_capacity, nodes)
963    }
964
965    #[allow(clippy::type_complexity)]
966    // Const specialization keeps ordinary writes free of CDC event construction
967    // even when the crate is compiled with the `cdc` feature.
968    fn put_checked_inner<const EMIT_CDC: bool>(
969        &self,
970        value: T,
971        adopt: fn(&T, &mut T),
972    ) -> Result<(Option<T>, Vec<ChangeEvent<T>>), (ArcRwLockWriteGuard<RawRwLock, Node>, usize, T)> {
973        loop {
974            let mut cdc = vec![];
975            let index = self.index.read();
976            let target_node_entry = match index.range(value.clone()..).next() {
977                Some(entry) => entry,
978                None => {
979                    if let Some(last) = index.last_key_value() {
980                        last
981                    } else {
982                        drop(index);
983                        let mut spins = 0;
984                        let mut index = loop {
985                            if let Some(guard) = self.index.try_write() {
986                                break guard;
987                            }
988                            if spins >= ROOT_PUBLICATION_SPIN_LIMIT {
989                                // A bounded block gives root publication a
990                                // deterministic progress path under reader
991                                // contention instead of livelocking.
992                                break self.index.write();
993                            }
994                            spins += 1;
995                            ::core::hint::spin_loop();
996                        };
997                        // Another first writer may have published while this
998                        // caller was acquiring the exclusive structural guard.
999                        if !index.is_empty() {
1000                            continue;
1001                        }
1002
1003                        let mut first_node = Node::with_capacity(self.node_capacity);
1004                        first_node.insert(value.clone());
1005
1006                        #[cfg(feature = "cdc")]
1007                        if EMIT_CDC {
1008                            let node_insertion = ChangeEvent::CreateNode {
1009                                // is correct as index is locked and current thread is the only that can
1010                                // fetch event_id.
1011                                event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1012                                max_value: value.clone(),
1013                            };
1014                            cdc.push(node_insertion);
1015                        }
1016
1017                        index.insert(value, Arc::new(RwLock::new(first_node)));
1018
1019                        return Ok((None, cdc));
1020                    }
1021                }
1022            };
1023
1024            let mut node_guard = target_node_entry.1.clone().write_arc();
1025
1026            #[allow(unused_assignments)]
1027            let mut operation = None;
1028            if !node_guard.need_to_split(self.node_capacity, &value) {
1029                let old_max = node_guard.max().cloned();
1030                let (inserted, idx) = NodeLike::insert(&mut *node_guard, value.clone());
1031                if inserted {
1032                    #[cfg(feature = "cdc")]
1033                    if EMIT_CDC {
1034                        let node_element_insertion = ChangeEvent::InsertAt {
1035                            // is correct as node is locked and current thread is the only that can
1036                            // fetch event_id, so events for this node will have monotonic id's.
1037                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1038                            max_value: old_max.clone().unwrap_or(value.clone()),
1039                            value: value.clone(),
1040                            index: idx,
1041                        };
1042                        cdc.push(node_element_insertion);
1043                    }
1044
1045                    if node_guard.max().cloned() == old_max {
1046                        return Ok((None, cdc));
1047                    }
1048
1049                    // The node's maximum changed, so its index entry must be
1050                    // re-keyed. Address the repair by the entry's CURRENT key,
1051                    // not the observed maximum: during a stale-key window (a
1052                    // concurrent writer changed the maximum but its own repair
1053                    // has not committed, or a remove emptied the node before
1054                    // this insert refilled it, leaving `old_max` as `None`)
1055                    // the two differ, and a repair addressed by the maximum
1056                    // misses the entry at commit time and is silently dropped,
1057                    // leaving the entry permanently stale (unreachable values,
1058                    // and a pending `MakeUnreachable` could unlink the node
1059                    // containing this acknowledged insert).
1060                    operation = Some(Operation::UpdateMax(
1061                        target_node_entry.1.clone(),
1062                        target_node_entry.0.clone(),
1063                    ));
1064                } else {
1065                    return Err((node_guard, idx, old_max.unwrap()));
1066                }
1067            } else {
1068                operation = Some(Operation::Split(
1069                    target_node_entry.1.clone(),
1070                    target_node_entry.0.clone(),
1071                    value.clone(),
1072                ));
1073            }
1074
1075            drop(node_guard);
1076            drop(index);
1077
1078            let op = operation.unwrap();
1079            let mut index = match &op {
1080                Operation::UpdateMax(_, _) => self.index.write_rekey(),
1081                Operation::Split(_, _, _) | Operation::MakeUnreachable(_, _) => self.index.write(),
1082            };
1083            match &op {
1084                Operation::Split(_, _, _) => {
1085                    if let Ok((value, value_cdc)) = op.commit::<EMIT_CDC>(&mut index, adopt) {
1086                        #[cfg(feature = "cdc")]
1087                        if EMIT_CDC {
1088                            for unassigned_event in value_cdc {
1089                                let event_id = self.event_id.fetch_add(1, Ordering::Relaxed).into();
1090                                cdc.push(unassigned_event.assign_id(event_id));
1091                            }
1092                        }
1093                        return Ok((value, cdc));
1094                    } else {
1095                        continue;
1096                    }
1097                }
1098                Operation::UpdateMax(_, _) => {
1099                    return if let Ok((value, value_cdc)) = op.commit::<EMIT_CDC>(&mut index, adopt) {
1100                        #[cfg(feature = "cdc")]
1101                        if EMIT_CDC {
1102                            for unassigned_event in value_cdc {
1103                                let event_id = self.event_id.fetch_add(1, Ordering::Relaxed).into();
1104                                cdc.push(unassigned_event.assign_id(event_id));
1105                            }
1106                        }
1107                        Ok((value, cdc))
1108                    } else {
1109                        Ok((None, cdc))
1110                    }
1111                }
1112                Operation::MakeUnreachable(_, _) => unreachable!(),
1113            }
1114        }
1115    }
1116    fn put_inner<const EMIT_CDC: bool>(&self, value: T, adopt: fn(&T, &mut T)) -> (Option<T>, Vec<ChangeEvent<T>>) {
1117        match self.put_checked_inner::<EMIT_CDC>(value.clone(), adopt) {
1118            Ok(res) => res,
1119            Err((mut node_guard, idx, max)) => {
1120                // Replace-on-logical-equality: let the incoming value adopt
1121                // the stored value's hidden ordering state before it takes
1122                // the stored position (see MultiPairLike::adopt_stored_identity).
1123                let mut value = value;
1124                if let Some(stored) = node_guard.get_ith(idx) {
1125                    adopt(stored, &mut value);
1126                }
1127                let mut cdc = vec![];
1128                #[cfg(feature = "cdc")]
1129                if EMIT_CDC {
1130                    if node_guard.len() == 1 {
1131                        let node_removal = ChangeEvent::RemoveNode {
1132                            // is correct as node is locked and current thread is the only that can
1133                            // fetch event_id, so events for this node will have monotonic id's.
1134                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1135                            max_value: max.clone(),
1136                        };
1137                        let node_insertion = ChangeEvent::CreateNode {
1138                            // same as for previous.
1139                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1140                            max_value: value.clone(),
1141                        };
1142                        cdc.push(node_removal);
1143                        cdc.push(node_insertion);
1144                    } else if idx == node_guard.len() - 1 {
1145                        let new_max = if node_guard.len() <= 1 {
1146                            None
1147                        } else {
1148                            node_guard.get_ith(node_guard.len() - 2)
1149                        };
1150                        let node_element_removal = ChangeEvent::RemoveAt {
1151                            // is correct as node is locked and current thread is the only that can
1152                            // fetch event_id, so events for this node will have monotonic id's.
1153                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1154                            max_value: max.clone(),
1155                            value: value.clone(),
1156                            index: idx,
1157                        };
1158                        let node_element_insertion = ChangeEvent::InsertAt {
1159                            // same as for previous.
1160                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1161                            max_value: new_max.expect("length was checked so should be ok").clone(),
1162                            value: value.clone(),
1163                            index: idx,
1164                        };
1165                        cdc.push(node_element_removal);
1166                        cdc.push(node_element_insertion);
1167                    } else {
1168                        let node_element_removal = ChangeEvent::RemoveAt {
1169                            // is correct as node is locked and current thread is the only that can
1170                            // fetch event_id, so events for this node will have monotonic id's.
1171                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1172                            max_value: max.clone(),
1173                            value: value.clone(),
1174                            index: idx,
1175                        };
1176                        let node_element_insertion = ChangeEvent::InsertAt {
1177                            // same as for previous.
1178                            event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1179                            max_value: max.clone(),
1180                            value: value.clone(),
1181                            index: idx,
1182                        };
1183                        cdc.push(node_element_removal);
1184                        cdc.push(node_element_insertion);
1185                    }
1186                }
1187
1188                (NodeLike::replace(&mut *node_guard, idx, value.clone()), cdc)
1189            }
1190        }
1191    }
1192
1193    pub(crate) fn put(&self, value: T) -> Option<T> {
1194        self.put_inner::<false>(value, no_identity_adoption).0
1195    }
1196
1197    #[cfg(feature = "multimap")]
1198    pub(crate) fn put_with(&self, value: T, adopt: fn(&T, &mut T)) -> Option<T> {
1199        self.put_inner::<false>(value, adopt).0
1200    }
1201
1202    #[allow(clippy::type_complexity)]
1203    pub(crate) fn put_checked(
1204        &self,
1205        value: T,
1206    ) -> Result<(Option<T>, Vec<ChangeEvent<T>>), (ArcRwLockWriteGuard<RawRwLock, Node>, usize, T)> {
1207        self.put_checked_inner::<false>(value, no_identity_adoption)
1208    }
1209
1210    pub(crate) fn put_cdc(&self, value: T) -> (Option<T>, Vec<ChangeEvent<T>>) {
1211        self.put_inner::<true>(value, no_identity_adoption)
1212    }
1213
1214    #[cfg(all(feature = "multimap", feature = "cdc"))]
1215    pub(crate) fn put_cdc_with(&self, value: T, adopt: fn(&T, &mut T)) -> (Option<T>, Vec<ChangeEvent<T>>) {
1216        self.put_inner::<true>(value, adopt)
1217    }
1218
1219    #[allow(clippy::type_complexity)]
1220    pub(crate) fn put_cdc_checked(
1221        &self,
1222        value: T,
1223    ) -> Result<(Option<T>, Vec<ChangeEvent<T>>), (ArcRwLockWriteGuard<RawRwLock, Node>, usize, T)> {
1224        self.put_checked_inner::<true>(value, no_identity_adoption)
1225    }
1226
1227    /// Adds a value to the set.
1228    ///
1229    /// Returns whether the value was newly inserted. That is:
1230    ///
1231    /// - If the set did not previously contain an equal value, `true` is
1232    ///   returned.
1233    /// - If the set already contained an equal value, `false` is returned, and
1234    ///   the entry is not updated.
1235    ///
1236    /// # Examples
1237    ///
1238    /// ```
1239    /// use indexset::concurrent::set::BTreeSet;
1240    ///
1241    /// let mut set = BTreeSet::<usize>::new();
1242    ///
1243    /// assert_eq!(set.insert(2), true);
1244    /// assert_eq!(set.insert(2), false);
1245    /// assert_eq!(set.len(), 1);
1246    /// ```
1247    pub fn insert(&self, value: T) -> bool {
1248        self.put(value).is_none()
1249    }
1250    // See `put_checked_inner`: this is const-specialized to avoid paying for
1251    // discarded events in the ordinary `remove` path.
1252    fn remove_inner<const EMIT_CDC: bool, Q>(&self, value: &Q) -> (Option<T>, Vec<ChangeEvent<T>>)
1253    where
1254        T: Borrow<Q>,
1255        Q: Ord + ?Sized,
1256    {
1257        let mut cdc = vec![];
1258        let index = self.index.read();
1259        // Fall back to the last node when the value sorts above every index
1260        // key, exactly like `put` and `lock_node_for_value`: during a stale-key
1261        // window (a node whose maximum grew before its UpdateMax repair
1262        // committed) the value lives in the last node even though no index key
1263        // covers it. Without the fallback such a value is un-removable while
1264        // `contains` still finds it.
1265        if let Some(target_node_entry) =
1266            first_for_borrowed_bound(&index, Bound::Included(value), self.borrow_order_matches)
1267                .or_else(|| index.last_key_value())
1268        {
1269            let mut node_guard = target_node_entry.1.clone().write_arc();
1270            let old_max = node_guard.max().cloned();
1271            let deleted = NodeLike::delete(&mut *node_guard, value);
1272            if deleted.is_none() {
1273                return (None, cdc);
1274            }
1275            let (deleted, idx) = deleted.expect("should be ok as checked before");
1276
1277            let operation = if node_guard.len() > 0 {
1278                #[cfg(feature = "cdc")]
1279                if EMIT_CDC {
1280                    let node_element_removal = ChangeEvent::RemoveAt {
1281                        // is correct as node is locked and current thread is the only that can
1282                        // fetch event_id, so events for this node will have monotonic id's.
1283                        event_id: self.event_id.fetch_add(1, Ordering::Relaxed).into(),
1284                        max_value: old_max.clone().expect("Max value should exist as Node is not empty"),
1285                        value: deleted.clone(),
1286                        index: idx,
1287                    };
1288                    cdc.push(node_element_removal);
1289                }
1290
1291                if old_max.as_ref() == node_guard.max() {
1292                    return (Some(deleted), cdc);
1293                }
1294
1295                // Address the repair by the entry's current key, not by the
1296                // observed old maximum: see `put_checked_inner`. In a
1297                // stale-key window they differ, and a repair addressed by the
1298                // maximum is dropped at commit time, leaving the entry stale.
1299                Some(Operation::UpdateMax(
1300                    target_node_entry.1.clone(),
1301                    target_node_entry.0.clone(),
1302                ))
1303            } else {
1304                Some(Operation::MakeUnreachable(
1305                    target_node_entry.1.clone(),
1306                    target_node_entry.0.clone(),
1307                ))
1308            };
1309
1310            drop(node_guard);
1311            drop(index);
1312
1313            let operation = operation.unwrap();
1314            let mut index = match &operation {
1315                Operation::UpdateMax(_, _) => self.index.write_rekey(),
1316                Operation::Split(_, _, _) | Operation::MakeUnreachable(_, _) => self.index.write(),
1317            };
1318
1319            return if let Ok((_, value_cdc)) = operation.commit::<EMIT_CDC>(&mut index, no_identity_adoption) {
1320                #[cfg(feature = "cdc")]
1321                if EMIT_CDC {
1322                    for unassigned_event in value_cdc {
1323                        let event_id = self.event_id.fetch_add(1, Ordering::Relaxed).into();
1324                        cdc.push(unassigned_event.assign_id(event_id));
1325                    }
1326                }
1327                (Some(deleted), cdc)
1328            } else {
1329                (Some(deleted), cdc)
1330            };
1331        }
1332
1333        (None, vec![])
1334    }
1335
1336    pub fn remove_cdc<Q>(&self, value: &Q) -> (Option<T>, Vec<ChangeEvent<T>>)
1337    where
1338        T: Borrow<Q>,
1339        Q: Ord + ?Sized,
1340    {
1341        self.remove_inner::<true, Q>(value)
1342    }
1343    /// If the set contains an element equal to the value, removes it from the
1344    /// set and drops it. Returns whether such an element was present.
1345    ///
1346    /// The value may be any borrowed form of the set's element type,
1347    /// but the ordering on the borrowed form *must* match the
1348    /// ordering on the element type.
1349    ///
1350    /// # Examples
1351    ///
1352    /// ```
1353    /// use indexset::concurrent::set::BTreeSet;
1354    ///
1355    /// let mut set = BTreeSet::<usize>::new();
1356    ///
1357    /// set.insert(2);
1358    /// assert_eq!(set.remove(&2).is_some(), true);
1359    /// assert_eq!(set.remove(&2).is_some(), false);
1360    /// ```
1361    pub fn remove<Q>(&self, value: &Q) -> Option<T>
1362    where
1363        T: Borrow<Q>,
1364        Q: Ord + ?Sized,
1365    {
1366        self.remove_inner::<false, Q>(value).0
1367    }
1368
1369    // Slow-path recovery for multimap exact removal. Holding the structural
1370    // write guard makes predicate lookup, deletion, and node reindexing one
1371    // critical section after the ordinary point-removal path has missed. Only
1372    // the multimap paths use this, and it relies on NodeLike::delete_at (also
1373    // multimap-gated), so gate the whole family to avoid an unconditional break.
1374    #[inline(always)]
1375    fn lock_node_for_value_optimistic<Q>(&self, value: &Q) -> Option<ArcRwLockReadGuard<RawRwLock, Node>>
1376    where
1377        T: Borrow<Q>,
1378        Q: Ord + ?Sized,
1379    {
1380        let node = {
1381            let index = self.index.read();
1382            match first_for_borrowed_bound(&index, Bound::Included(value), self.borrow_order_matches) {
1383                Some((_, node)) => Some(node.clone()),
1384                None => index
1385                    .last_key_value()
1386                    .map(|(_, node)| node.clone())
1387                    .or_else(|| index.first_key_value().map(|(_, node)| node.clone())),
1388            }
1389        }?;
1390        Some(node.read_arc())
1391    }
1392
1393    /// Locates and locks the node whose structural range owns `value`.
1394    ///
1395    /// Readers route through an immutable published topology and validate its
1396    /// generation after locking the node. A concurrent structural change makes
1397    /// the read retry, so hits and misses remain definitive without updating a
1398    /// shared reader-count cache line.
1399    #[inline(always)]
1400    fn lock_node_for_value<Q>(&self, value: &Q) -> Option<ArcRwLockReadGuard<RawRwLock, Node>>
1401    where
1402        T: Borrow<Q>,
1403        Q: Ord + ?Sized,
1404    {
1405        let mut retries = 0;
1406        let mut writer_spins = 0;
1407
1408        loop {
1409            let generation = self.index.generation.load(Ordering::Acquire);
1410            if !generation.is_multiple_of(2) {
1411                if writer_spins < ROOT_PUBLICATION_SPIN_LIMIT {
1412                    writer_spins += 1;
1413                    ::core::hint::spin_loop();
1414                } else {
1415                    yield_now();
1416                }
1417                continue;
1418            }
1419            writer_spins = 0;
1420
1421            if retries >= STABLE_READ_BLOCKING_FALLBACK_AFTER {
1422                // Bounded progress fallback: hold the canonical topology read
1423                // guard while acquiring the node. Structural writers follow
1424                // the same topology-before-node order.
1425                let index = self.index.read();
1426                let node = match first_for_borrowed_bound(&index, Bound::Included(value), self.borrow_order_matches) {
1427                    Some((_, node)) => Some(node.clone()),
1428                    None => index
1429                        .last_key_value()
1430                        .map(|(_, node)| node.clone())
1431                        .or_else(|| index.first_key_value().map(|(_, node)| node.clone())),
1432                }?;
1433                let node_guard = node.read_arc();
1434                drop(index);
1435                return Some(node_guard);
1436            }
1437
1438            let pin = self.index.published.domain.pin();
1439            let snapshot = self.index.published.current.load(Ordering::Acquire);
1440            // SAFETY: `snapshot` was loaded after `pin`, and the publication
1441            // domain cannot reclaim it until `pin` is dropped.
1442            let index = unsafe { &*snapshot };
1443            let node =
1444                match first_published_for_borrowed_bound(index, Bound::Included(value), self.borrow_order_matches) {
1445                    Some((_, node)) => Some(node.clone()),
1446                    None => index
1447                        .last_key_value()
1448                        .map(|(_, node)| node.clone())
1449                        .or_else(|| index.first_key_value().map(|(_, node)| node.clone())),
1450                };
1451            let Some(node) = node else {
1452                if self.index.generation.load(Ordering::Acquire) == generation {
1453                    return None;
1454                }
1455                retries += 1;
1456                continue;
1457            };
1458
1459            // The snapshot pin protects the Arc only until it is cloned. Drop
1460            // it before the potentially blocking node acquisition so a slow
1461            // node writer cannot stall topology reclamation.
1462            drop(pin);
1463            let node_guard = node.read_arc();
1464            if self.index.generation.load(Ordering::Acquire) == generation {
1465                return Some(node_guard);
1466            }
1467            retries += 1;
1468        }
1469    }
1470
1471    #[inline(always)]
1472    fn get_with_guard<Q, R>(
1473        node_guard: ArcRwLockReadGuard<RawRwLock, Node>,
1474        value: &Q,
1475        read: impl FnOnce(&T) -> R,
1476    ) -> Option<R>
1477    where
1478        T: Borrow<Q>,
1479        Q: Ord + ?Sized,
1480    {
1481        let position = node_guard.try_select(value)?;
1482        node_guard.get_ith(position).map(read)
1483    }
1484
1485    #[inline(always)]
1486    pub(crate) fn get_with<Q, R>(&self, value: &Q, read: impl FnOnce(&T) -> R) -> Option<R>
1487    where
1488        T: Borrow<Q>,
1489        Q: Ord + ?Sized,
1490    {
1491        let mut retries = 0;
1492        let mut writer_spins = 0;
1493        let mut read = Some(read);
1494
1495        loop {
1496            let generation = self.index.generation.load(Ordering::Acquire);
1497            if !generation.is_multiple_of(2) {
1498                if writer_spins < ROOT_PUBLICATION_SPIN_LIMIT {
1499                    writer_spins += 1;
1500                    ::core::hint::spin_loop();
1501                } else {
1502                    yield_now();
1503                }
1504                continue;
1505            }
1506            writer_spins = 0;
1507
1508            if retries >= STABLE_READ_BLOCKING_FALLBACK_AFTER {
1509                let index = self.index.read();
1510                let node = first_for_borrowed_bound(&index, Bound::Included(value), self.borrow_order_matches)
1511                    .or_else(|| index.last_key_value())
1512                    .or_else(|| index.first_key_value())
1513                    .map(|(_, node)| node.clone())?;
1514                let node_guard = node.read_arc();
1515                drop(index);
1516                let position = node_guard.try_select(value)?;
1517                return node_guard
1518                    .get_ith(position)
1519                    .map(read.take().expect("read closure is consumed only on return"));
1520            }
1521
1522            let pin = self.index.published.domain.pin();
1523            let snapshot = self.index.published.current.load(Ordering::Acquire);
1524            // SAFETY: `snapshot` was loaded after `pin`, and the publication
1525            // domain cannot reclaim it until `pin` is dropped.
1526            let index = unsafe { &*snapshot };
1527            let node = first_published_for_borrowed_bound(index, Bound::Included(value), self.borrow_order_matches)
1528                .or_else(|| index.last_key_value())
1529                .or_else(|| index.first_key_value())
1530                .map(|(_, node)| node);
1531            let Some(node) = node else {
1532                if self.index.generation.load(Ordering::Acquire) == generation {
1533                    return None;
1534                }
1535                retries += 1;
1536                continue;
1537            };
1538
1539            // Borrow the Arc from the protected snapshot: unlike
1540            // `lock_node_for_value`, this owned-result path does not need an
1541            // Arc clone or its shared refcount update when the node is free.
1542            // On contention, clone it and release the reclamation pin before
1543            // blocking so a node writer cannot retain old topology paths.
1544            if let Some(node_guard) = node.try_read() {
1545                if self.index.generation.load(Ordering::Acquire) != generation {
1546                    retries += 1;
1547                    continue;
1548                }
1549                let position = node_guard.try_select(value)?;
1550                return node_guard
1551                    .get_ith(position)
1552                    .map(read.take().expect("read closure is consumed only on return"));
1553            }
1554
1555            let node = node.clone();
1556            drop(pin);
1557            let node_guard = node.read_arc();
1558            if self.index.generation.load(Ordering::Acquire) != generation {
1559                retries += 1;
1560                continue;
1561            }
1562            let position = node_guard.try_select(value)?;
1563            return node_guard
1564                .get_ith(position)
1565                .map(read.take().expect("read closure is consumed only on return"));
1566        }
1567    }
1568
1569    #[inline(always)]
1570    pub(crate) fn get_with_optimistic<Q, R>(&self, value: &Q, read: impl FnOnce(&T) -> R) -> Option<R>
1571    where
1572        T: Borrow<Q>,
1573        Q: Ord + ?Sized,
1574    {
1575        Self::get_with_guard(self.lock_node_for_value_optimistic(value)?, value, read)
1576    }
1577
1578    /// Returns `true` if the set contains an element equal to the value.
1579    ///
1580    /// The value may be any borrowed form of the set's element type,
1581    /// but the ordering on the borrowed form *must* match the
1582    /// ordering on the element type.
1583    ///
1584    /// # Examples
1585    ///
1586    /// ```
1587    /// use indexset::concurrent::set::BTreeSet;
1588    ///
1589    /// let set = BTreeSet::from_iter([1, 2, 3]);
1590    /// assert_eq!(set.contains(&1), true);
1591    /// assert_eq!(set.contains(&4), false);
1592    /// ```
1593    pub fn contains<Q>(&self, value: &Q) -> bool
1594    where
1595        T: Borrow<Q>,
1596        Q: Ord + ?Sized,
1597    {
1598        self.get_with(value, |_| ()).is_some()
1599    }
1600    pub fn get<'a, Q>(&'a self, value: &'a Q) -> Option<Ref<T, Node>>
1601    where
1602        T: Borrow<Q>,
1603        Q: Ord + ?Sized,
1604    {
1605        if let Some(node_guard) = self.lock_node_for_value(value) {
1606            let potential_position = node_guard.try_select(value);
1607
1608            if let Some(position) = potential_position {
1609                return Some(Ref {
1610                    node_guard,
1611                    position,
1612                    phantom_data: PhantomData,
1613                });
1614            }
1615        }
1616
1617        None
1618    }
1619
1620    pub fn len(&self) -> usize {
1621        self.index.read().values().map(|node| node.read().len()).sum()
1622    }
1623    pub fn is_empty(&self) -> bool {
1624        self.index.read().values().all(|node| node.read().is_empty())
1625    }
1626    pub fn capacity(&self) -> usize {
1627        self.index
1628            .read()
1629            .values()
1630            .map(|node| {
1631                let guard = node.read();
1632                guard.capacity()
1633            })
1634            .sum()
1635    }
1636    pub fn node_count(&self) -> usize {
1637        self.index.read().len()
1638    }
1639}
1640
1641impl<T> FromIterator<T> for BTreeSet<T>
1642where
1643    T: Debug + Ord + Clone + Send,
1644{
1645    fn from_iter<K: IntoIterator<Item = T>>(iter: K) -> Self {
1646        let btree = BTreeSet::new();
1647        iter.into_iter().for_each(|item| {
1648            btree.insert(item);
1649        });
1650
1651        btree
1652    }
1653}
1654
1655impl<T, const N: usize> From<[T; N]> for BTreeSet<T>
1656where
1657    T: Debug + Ord + Clone + Send,
1658{
1659    fn from(value: [T; N]) -> Self {
1660        let btree: BTreeSet<T> = Default::default();
1661
1662        value.into_iter().for_each(|item| {
1663            btree.insert(item);
1664        });
1665
1666        btree
1667    }
1668}
1669
1670/// An owned-yield iterator over a concurrent `BTreeSet`.
1671///
1672/// The iterator clones one node's remaining elements into an owned batch
1673/// while holding that node's mutex, releases the mutex, and then yields the
1674/// clones. No node lock and no structural lock is ever held between calls to
1675/// `next`/`next_back`, and every yielded `T` is an independent clone: items
1676/// collected from this iterator stay valid under arbitrary concurrent
1677/// mutation of the set.
1678///
1679/// The scan is weakly consistent, exactly like iterating any concurrent
1680/// collection: elements inserted or removed while the scan is in flight may
1681/// or may not be observed, but elements present for the whole scan are
1682/// yielded exactly once, in order.
1683pub struct Iter<'a, T, Node>
1684where
1685    T: Debug + Ord + Clone + Send + 'static,
1686    Node: NodeLike<T> + Send + 'static,
1687{
1688    tree: &'a BTreeSet<T, Node>,
1689    current_front_batch: Option<alloc::vec::IntoIter<T>>,
1690    current_back_batch: Option<alloc::vec::IntoIter<T>>,
1691    // Identity of the node the last batch in each direction was cloned from,
1692    // so the next install can step past it when the cursor lookup lands on
1693    // it again (its entry key can sit past every element it still holds).
1694    exhausted_front_node: Option<Arc<RwLock<Node>>>,
1695    exhausted_back_node: Option<Arc<RwLock<Node>>>,
1696    // The node a direction is partway through, and how many of its elements it
1697    // has taken. A batch that stops short of a node's end must resume inside
1698    // that node, and must never take less than it already has: the rank-based
1699    // skip alone cannot guarantee that, because a repositioned node can leave
1700    // the cursor ranking below elements already yielded. Recording the count
1701    // makes forward progress structural rather than incidental.
1702    front_partial: Option<(Arc<RwLock<Node>>, usize)>,
1703    back_partial: Option<(Arc<RwLock<Node>>, usize)>,
1704    // How many elements the next batch may clone, doubling per install.
1705    front_batch_limit: usize,
1706    back_batch_limit: usize,
1707    current_front_value: Option<T>,
1708    current_back_value: Option<T>,
1709    met: bool,
1710}
1711
1712/// Elements the first batch of a scan clones.
1713///
1714/// A one-element range is the common case and it used to clone a whole node to
1715/// yield one value. Starting small makes that cost proportional to what is
1716/// asked for; doubling means a real scan reaches whole-node batches after a
1717/// handful of installs and pays the same total clone count it always did.
1718const INITIAL_BATCH: usize = 4;
1719
1720/// Ceiling on the growth. `available` bounds a batch to what the node holds, so
1721/// this only stops the doubling running away on a very long scan.
1722const MAX_BATCH: usize = 4096;
1723
1724impl<'a, T, Node> Iter<'a, T, Node>
1725where
1726    T: Debug + Ord + Clone + Send + 'static,
1727    Node: NodeLike<T> + Send + 'static,
1728{
1729    pub fn new(btree: &'a BTreeSet<T, Node>) -> Self {
1730        // No node is chosen here: each direction positions itself from its
1731        // cursor when it installs a batch, atomically with reading the node.
1732        // Choosing a node ahead of time and locking it later reintroduces
1733        // the split-migration window closed in `install_front_batch`.
1734        Self {
1735            tree: btree,
1736            current_front_batch: None,
1737            current_back_batch: None,
1738            exhausted_front_node: None,
1739            exhausted_back_node: None,
1740            front_partial: None,
1741            back_partial: None,
1742            front_batch_limit: INITIAL_BATCH,
1743            back_batch_limit: INITIAL_BATCH,
1744            current_front_value: None,
1745            current_back_value: None,
1746            met: false,
1747        }
1748    }
1749
1750    // Select the node covering the forward cursor and clone its remaining
1751    // elements (strictly above the cursor) into an owned batch. Returns
1752    // false when no node remains and the scan is complete.
1753    //
1754    // Selection and the content read are ONE atomic step: the node is
1755    // locked while the structural read guard is still held. Both split
1756    // commits and re-keys take the structural write lock and the node lock,
1757    // so the chosen node cannot change contents or move between being
1758    // chosen and being read. Choosing under one guard and locking later
1759    // allowed a split to migrate not-yet-yielded elements into a new node
1760    // past the resume point, silently truncating the scan (deterministically
1761    // reproduced by `backward_scan_does_not_skip_values_split_away_after_positioning`).
1762    //
1763    // Lock order is topology then node, the same order every writer
1764    // uses, so this cannot deadlock ABBA against committers; holding the
1765    // node mutex alone pins its contents, so the structural guard is
1766    // released before the clone. No lock is held once this returns.
1767    //
1768    // One batched clone per node replaces the old per-item guard-holding
1769    // scheme: the previous design kept the node mutex alive inside the
1770    // iterator and transmuted the guard's slice iterator to the iterator's
1771    // lifetime, which let callers hold `&T` into node storage after the
1772    // guard was released (a use-after-free under concurrent mutation).
1773    // Owned batches make that impossible by construction.
1774    fn install_front_batch(&mut self) -> bool {
1775        let index = self.tree.index.read();
1776        let candidate = match self.current_front_value.as_ref() {
1777            Some(last_yielded) => index.range((Bound::Excluded(last_yielded), Bound::Unbounded)).next(),
1778            None => index.first_key_value(),
1779        };
1780        // Advance by the scan cursor with one logarithmic lookup: it lands
1781        // on whichever node now covers the cursor even after re-keys or
1782        // removals, and the yield-path filters skip anything already
1783        // yielded. Step past the just-exhausted node by identity so the
1784        // scan always makes progress.
1785        let entry = match (candidate, self.exhausted_front_node.as_ref()) {
1786            (Some((key, node)), Some(exhausted)) if Arc::ptr_eq(node, exhausted) => {
1787                index.range((Bound::Excluded(key), Bound::Unbounded)).next()
1788            }
1789            (candidate, _) => candidate,
1790        };
1791        let Some((_, entry)) = entry else {
1792            return false;
1793        };
1794        let node = entry.clone();
1795        let guard = node.read_arc();
1796        drop(index);
1797
1798        let rank_skip = self
1799            .current_front_value
1800            .as_ref()
1801            .and_then(|value| guard.rank(Bound::Excluded(value), true))
1802            .map_or(0, |rank| rank + 1);
1803        // Resuming a node this scan is partway through. `front_partial` counts
1804        // *positions*, and a position is not a stable cursor: deleting an
1805        // element this scan already yielded shifts the unyielded tail left
1806        // while the count stays put. Letting it win a `max` against the value
1807        // rank steps over an element that was present for the whole scan,
1808        // which is the one thing this iterator promises not to do. See
1809        // `deleting_a_yielded_element_does_not_skip_a_live_one`.
1810        //
1811        // The value rank is authoritative wherever there is one: it counts the
1812        // elements at or below the last yielded value, so the batch resumes
1813        // strictly above the cursor. No duplicates, and progress every time.
1814        // That is also what makes dropping the `max` safe -- the
1815        // non-termination it guarded against was a batch that came back all
1816        // duplicates and advanced nothing, and a value-ranked resume cannot
1817        // produce one.
1818        //
1819        // The position still matters before anything has been yielded, where
1820        // there is no value to rank against and it is the only record that this
1821        // node was already drawn from.
1822        let partial_skip = match self.front_partial.as_ref() {
1823            Some((partial, taken)) if Arc::ptr_eq(partial, &node) => *taken,
1824            _ => 0,
1825        };
1826        let skip = if self.current_front_value.is_some() {
1827            rank_skip
1828        } else {
1829            partial_skip
1830        };
1831
1832        // Clone what was asked for rather than the rest of the node. A range
1833        // that yields one value used to clone every remaining element of the
1834        // node it landed in, which is where the 2.6x cost of this path came
1835        // from; the owned batch is what makes the iterator sound, but nothing
1836        // about that soundness required cloning eagerly.
1837        let available = guard.len().saturating_sub(skip);
1838        let take = available.min(self.front_batch_limit);
1839        let batch = guard.iter().skip(skip).take(take).cloned().collect::<Vec<_>>();
1840        drop(guard);
1841
1842        if take == available {
1843            // The node is finished, so the next install must step past it.
1844            self.exhausted_front_node = Some(node);
1845            self.front_partial = None;
1846        } else {
1847            // More of this node remains: resume inside it rather than stepping
1848            // past, and remember how far in.
1849            self.exhausted_front_node = None;
1850            self.front_partial = Some((node, skip + take));
1851        }
1852        self.front_batch_limit = self.front_batch_limit.saturating_mul(2).min(MAX_BATCH);
1853        self.current_front_batch = Some(batch.into_iter());
1854        true
1855    }
1856
1857    // Mirror of `install_front_batch` for the backward cursor: select the
1858    // node covering the cursor (the last node when every entry key sits
1859    // below it) and clone the elements strictly below the cursor.
1860    fn install_back_batch(&mut self) -> bool {
1861        let index = self.tree.index.read();
1862        let candidate = match self.current_back_value.as_ref() {
1863            Some(last_yielded) => index
1864                .range((Bound::Included(last_yielded), Bound::Unbounded))
1865                .next()
1866                .or_else(|| index.last_key_value()),
1867            None => index.last_key_value(),
1868        };
1869        let entry = match (candidate, self.exhausted_back_node.as_ref()) {
1870            (Some((key, node)), Some(exhausted)) if Arc::ptr_eq(node, exhausted) => index.range(..key).next_back(),
1871            (candidate, _) => candidate,
1872        };
1873        let Some((_, entry)) = entry else {
1874            return false;
1875        };
1876        let node = entry.clone();
1877        let guard = node.read_arc();
1878        drop(index);
1879
1880        let truncate = self
1881            .current_back_value
1882            .as_ref()
1883            .and_then(|value| guard.rank(Bound::Excluded(value), false))
1884            .map_or(0, |rank| rank + 1);
1885        // Mirror of the forward cursor's partial resume, defect included:
1886        // walking backwards the count already taken is trimmed from the end
1887        // rather than skipped at the start, and removing an already-yielded
1888        // high element shifts the unyielded head right while the count stays
1889        // put. The value rank wins here for the same reason it wins there. See
1890        // `deleting_a_yielded_element_backwards_does_not_skip_a_live_one`.
1891        let partial_truncate = match self.back_partial.as_ref() {
1892            Some((partial, taken)) if Arc::ptr_eq(partial, &node) => *taken,
1893            _ => 0,
1894        };
1895        let truncate = if self.current_back_value.is_some() {
1896            truncate
1897        } else {
1898            partial_truncate
1899        };
1900        let available = guard.len().saturating_sub(truncate);
1901        let take = available.min(self.back_batch_limit);
1902        // The backward batch is the last `take` of what remains, so the skip is
1903        // whatever sits below it.
1904        let skip = available - take;
1905        let batch = guard.iter().skip(skip).take(take).cloned().collect::<Vec<_>>();
1906        drop(guard);
1907
1908        if take == available {
1909            self.exhausted_back_node = Some(node);
1910            self.back_partial = None;
1911        } else {
1912            self.exhausted_back_node = None;
1913            self.back_partial = Some((node, truncate + take));
1914        }
1915        self.back_batch_limit = self.back_batch_limit.saturating_mul(2).min(MAX_BATCH);
1916        self.current_back_batch = Some(batch.into_iter());
1917        true
1918    }
1919}
1920
1921impl<'a, T, Node> Iterator for Iter<'a, T, Node>
1922where
1923    T: Debug + Ord + Clone + Send + 'static,
1924    Node: NodeLike<T> + Send + 'static,
1925{
1926    type Item = T;
1927
1928    fn next(&mut self) -> Option<Self::Item> {
1929        loop {
1930            if self.met {
1931                return None;
1932            }
1933
1934            if self.current_front_batch.is_none() && !self.install_front_batch() {
1935                return None;
1936            }
1937
1938            let batch = self.current_front_batch.as_mut().expect("installed above");
1939            if let Some(value) = batch.next() {
1940                // A batch installed after repositioning can re-expose
1941                // elements at or below the last yielded value (a split
1942                // re-distributes the just-finished node, a repositioned node
1943                // covers part of the scanned range). Skip them instead of
1944                // yielding duplicates.
1945                if let Some(current_front_value) = self.current_front_value.as_ref() {
1946                    if value.le(current_front_value) {
1947                        continue;
1948                    }
1949                }
1950                if let Some(current_back_value) = self.current_back_value.as_ref() {
1951                    if value.ge(current_back_value) {
1952                        self.met = true;
1953                        return None;
1954                    }
1955                }
1956                self.current_front_value = Some(value.clone());
1957                return Some(value);
1958            } else {
1959                self.current_front_batch = None;
1960            }
1961        }
1962    }
1963}
1964
1965impl<'a, T, Node> DoubleEndedIterator for Iter<'a, T, Node>
1966where
1967    T: Debug + Ord + Clone + Send + 'static,
1968    Node: NodeLike<T> + Send + 'static,
1969{
1970    fn next_back(&mut self) -> Option<Self::Item> {
1971        loop {
1972            if self.met {
1973                return None;
1974            }
1975
1976            if self.current_back_batch.is_none() && !self.install_back_batch() {
1977                return None;
1978            }
1979
1980            let batch = self.current_back_batch.as_mut().expect("installed above");
1981            if let Some(value) = batch.next_back() {
1982                // Mirror of the forward path: skip elements at or above the
1983                // last value yielded from the back, which a freshly
1984                // installed batch can re-expose after churn.
1985                if let Some(current_back_value) = self.current_back_value.as_ref() {
1986                    if value.ge(current_back_value) {
1987                        continue;
1988                    }
1989                }
1990                if let Some(current_front_value) = self.current_front_value.as_ref() {
1991                    if value.le(current_front_value) {
1992                        self.met = true;
1993                        return None;
1994                    }
1995                }
1996                self.current_back_value = Some(value.clone());
1997                return Some(value);
1998            } else {
1999                self.current_back_batch = None;
2000            }
2001        }
2002    }
2003}
2004
2005impl<'a, T: Debug + Ord + Clone + Send, Node: NodeLike<T> + Send + 'static> FusedIterator for Iter<'a, T, Node> {}
2006
2007impl<'a, T, Node> IntoIterator for &'a BTreeSet<T, Node>
2008where
2009    T: Debug + Ord + Send + Clone,
2010    Node: NodeLike<T> + Send + 'static,
2011{
2012    type Item = T;
2013
2014    type IntoIter = Iter<'a, T, Node>;
2015
2016    fn into_iter(self) -> Self::IntoIter {
2017        Iter::new(self)
2018    }
2019}
2020
2021/// An owned-yield double-ended range iterator; see [`Iter`] for the
2022/// consistency and cloning semantics.
2023pub struct Range<'a, T, Node>
2024where
2025    T: Debug + Ord + Clone + Send + 'static,
2026    Node: NodeLike<T> + Send + 'static,
2027{
2028    iter: Iter<'a, T, Node>,
2029}
2030
2031impl<'a, T, Node> Range<'a, T, Node>
2032where
2033    T: Debug + Ord + Clone + Send + 'static,
2034    Node: NodeLike<T> + Send + 'static,
2035{
2036    pub fn new<Q, R>(btree: &'a BTreeSet<T, Node>, range: R) -> Self
2037    where
2038        T: Borrow<Q>,
2039        Q: Ord + ?Sized,
2040        R: RangeBounds<Q>,
2041    {
2042        let index = btree.index.read();
2043
2044        let start_bound = range.start_bound();
2045        let end_bound = range.end_bound();
2046        let mut met = match (start_bound, end_bound) {
2047            (Bound::Included(start), Bound::Included(end)) => start > end,
2048            (Bound::Included(start), Bound::Excluded(end))
2049            | (Bound::Excluded(start), Bound::Included(end))
2050            | (Bound::Excluded(start), Bound::Excluded(end)) => start >= end,
2051            _ => false,
2052        };
2053
2054        let current_front_entry = first_for_borrowed_bound(&index, start_bound, btree.borrow_order_matches);
2055
2056        let front_value = if let Some((front_key, front_node)) = current_front_entry {
2057            let front_guard = front_node.clone().read_arc();
2058            let rank = match start_bound {
2059                Bound::Included(v) => front_guard.rank(Bound::Included(v), true),
2060                Bound::Excluded(v) => front_guard.rank(Bound::Excluded(v), true),
2061                Bound::Unbounded => None,
2062            };
2063            if let Some(rank) = rank {
2064                let value = front_guard.iter().nth(rank).cloned();
2065                drop(front_guard);
2066
2067                value
2068            } else {
2069                // Release the current node before locking its neighbor: this
2070                // branch used to hold front then prev (descending) while the
2071                // back branch below held back then next (ascending), an
2072                // ABBA deadlock between two concurrent Range constructions.
2073                // Never hold two node locks here.
2074                drop(front_guard);
2075                if let Some((_, pre_front_node)) = index.range::<T, _>(..front_key).next_back() {
2076                    let pre_front_guard = pre_front_node.clone().read_arc();
2077                    pre_front_guard.iter().last().cloned()
2078                } else {
2079                    None
2080                }
2081            }
2082        } else {
2083            None
2084        };
2085
2086        let current_back_entry = match end_bound {
2087            Bound::Included(end) | Bound::Excluded(end) => {
2088                node_for_borrowed_end(&index, end, btree.borrow_order_matches)
2089            }
2090            Bound::Unbounded => index.last_key_value(),
2091        };
2092
2093        let back_value = if let Some((back_key, back_node)) = current_back_entry {
2094            let back_guard = back_node.clone().read_arc();
2095            let rank = match end_bound {
2096                Bound::Included(v) => back_guard.rank(Bound::Included(v), false),
2097                Bound::Excluded(v) => back_guard.rank(Bound::Excluded(v), false),
2098                Bound::Unbounded => None,
2099            };
2100            if let Some(rank) = rank {
2101                let value = back_guard.iter().nth_back(rank).cloned();
2102                drop(back_guard);
2103
2104                value
2105            } else {
2106                // See the front branch: release before locking the neighbor.
2107                drop(back_guard);
2108                if let Some((_, next_back_node)) = index
2109                    .range::<T, _>((Bound::Excluded(back_key), Bound::Unbounded))
2110                    .next()
2111                {
2112                    let next_back_guard = next_back_node.clone().read_arc();
2113                    next_back_guard.iter().next().cloned()
2114                } else {
2115                    None
2116                }
2117            }
2118        } else {
2119            None
2120        };
2121
2122        if front_value.is_none() && back_value.is_none() {
2123            // in this case we iter full or no iter at all
2124            if start_bound != Bound::Unbounded || end_bound != Bound::Unbounded {
2125                if let Some(max) = index
2126                    .last_key_value()
2127                    .and_then(|(_, node)| node.clone().read_arc().max().cloned())
2128                {
2129                    if let Bound::Included(v) = start_bound {
2130                        if v > max.borrow() {
2131                            met = true;
2132                        }
2133                    } else if let Bound::Excluded(v) = start_bound {
2134                        if v >= max.borrow() {
2135                            met = true;
2136                        }
2137                    }
2138                }
2139
2140                if let Some(min) = index
2141                    .first_key_value()
2142                    .and_then(|(_, node)| node.clone().read_arc().min().cloned())
2143                {
2144                    if let Bound::Included(v) = end_bound {
2145                        if v < min.borrow() {
2146                            met = true;
2147                        }
2148                    } else if let Bound::Excluded(v) = end_bound {
2149                        if v <= min.borrow() {
2150                            met = true;
2151                        }
2152                    }
2153                }
2154            }
2155        }
2156
2157        // Only the cursor sentinels position the iterator: each direction
2158        // selects and reads its node atomically at install time. Prewiring
2159        // the entries' node Arcs here would reintroduce the choose-then-lock
2160        // split-migration window (see `Iter::install_front_batch`).
2161        Self {
2162            iter: Iter {
2163                tree: btree,
2164                current_front_batch: None,
2165                current_back_batch: None,
2166                exhausted_front_node: None,
2167                exhausted_back_node: None,
2168                front_partial: None,
2169                back_partial: None,
2170                front_batch_limit: INITIAL_BATCH,
2171                back_batch_limit: INITIAL_BATCH,
2172                current_front_value: front_value,
2173                current_back_value: back_value,
2174                met,
2175            },
2176        }
2177    }
2178}
2179
2180impl<'a, T, Node> Iterator for Range<'a, T, Node>
2181where
2182    T: Debug + Ord + Clone + Send + 'static,
2183    Node: NodeLike<T> + Send + 'static,
2184{
2185    type Item = T;
2186
2187    fn next(&mut self) -> Option<Self::Item> {
2188        self.iter.next()
2189    }
2190}
2191
2192impl<'a, T, Node> DoubleEndedIterator for Range<'a, T, Node>
2193where
2194    T: Debug + Ord + Clone + Send + 'static,
2195    Node: NodeLike<T> + Send + 'static,
2196{
2197    fn next_back(&mut self) -> Option<Self::Item> {
2198        self.iter.next_back()
2199    }
2200}
2201
2202impl<'a, T, Node> FusedIterator for Range<'a, T, Node>
2203where
2204    T: Debug + Ord + Clone + Send + 'static,
2205    Node: NodeLike<T> + Send + 'static,
2206{
2207}
2208
2209impl<'a, T, Node> BTreeSet<T, Node>
2210where
2211    T: Debug + Ord + Clone + Send + 'static,
2212    Node: NodeLike<T> + Send + 'static,
2213{
2214    /// Gets an iterator that visits the elements in the `BTreeSet` in ascending
2215    /// order.
2216    ///
2217    /// The iterator yields owned clones of the stored elements (see [`Iter`]):
2218    /// collected values remain valid under arbitrary concurrent mutation of
2219    /// the set.
2220    ///
2221    /// # Examples
2222    ///
2223    /// ```
2224    /// use indexset::concurrent::set::BTreeSet;
2225    ///
2226    /// let set = BTreeSet::from_iter([1, 2, 3]);
2227    /// let mut set_iter = set.iter();
2228    /// assert_eq!(set_iter.next(), Some(1));
2229    /// assert_eq!(set_iter.next(), Some(2));
2230    /// assert_eq!(set_iter.next(), Some(3));
2231    /// assert_eq!(set_iter.next(), None);
2232    /// ```
2233    ///
2234    /// Values returned by the iterator are returned in ascending order:
2235    ///
2236    /// ```
2237    /// use indexset::concurrent::set::BTreeSet;
2238    ///
2239    /// let set = BTreeSet::from_iter([3, 1, 2]);
2240    /// let mut set_iter = set.iter();
2241    /// assert_eq!(set_iter.next(), Some(1));
2242    /// assert_eq!(set_iter.next(), Some(2));
2243    /// assert_eq!(set_iter.next(), Some(3));
2244    /// assert_eq!(set_iter.next(), None);
2245    /// ```
2246    pub fn iter(&'a self) -> Iter<'a, T, Node> {
2247        Iter::new(self)
2248    }
2249    /// Constructs a double-ended iterator over a sub-range of elements in the set.
2250    /// The simplest way is to use the range syntax `min..max`, thus `range(min..max)` will
2251    /// yield elements from min (inclusive) to max (exclusive).
2252    /// The range may also be entered as `(Bound<T>, Bound<T>)`, so for example
2253    /// `range((Excluded(4), Included(10)))` will yield a left-exclusive, right-inclusive
2254    /// range from 4 to 10.
2255    ///
2256    /// # Panics
2257    ///
2258    /// Panics if range `start > end`.
2259    /// Panics if range `start == end` and both bounds are `Excluded`.
2260    ///
2261    /// # Examples
2262    ///
2263    /// ```
2264    /// use indexset::concurrent::set::BTreeSet;
2265    /// use std::ops::Bound::Included;
2266    ///
2267    /// let mut set = BTreeSet::<usize>::new();
2268    /// set.insert(3);
2269    /// set.insert(5);
2270    /// set.insert(8);
2271    /// for elem in set.range((Included(&4), Included(&8))) {
2272    ///     println!("{elem}");
2273    /// }
2274    /// assert_eq!(Some(5), set.range(4..).next());
2275    /// ```
2276    pub fn range<Q, R>(&'a self, range: R) -> Range<'a, T, Node>
2277    where
2278        T: Borrow<Q>,
2279        Q: Ord + ?Sized,
2280        R: RangeBounds<Q>,
2281    {
2282        Range::new(self, range)
2283    }
2284}
2285
2286impl<T> BTreeSet<T>
2287where
2288    T: Debug + Ord + Clone + Send + 'static,
2289{
2290    pub fn remove_range<R, Q>(&self, range: R)
2291    where
2292        Q: Ord + ?Sized,
2293        T: Borrow<Q>,
2294        R: RangeBounds<Q>,
2295    {
2296        // Declare detached storage before the structural guard so element
2297        // destructors run only after that guard is released.
2298        let mut detached_nodes = Vec::new();
2299        let mut index = self.index.write();
2300
2301        let start_bound = range.start_bound();
2302        let end_bound = range.end_bound();
2303
2304        // First node that can contain an element within the start bound. If
2305        // no index key reaches the start bound, nothing qualifies.
2306        let Some((front_key, front_node)) = first_for_borrowed_bound(&index, start_bound, self.borrow_order_matches)
2307        else {
2308            return;
2309        };
2310        let front_key = front_key.clone();
2311        let front_node = front_node.clone();
2312
2313        // Last node that can contain an element within the end bound. Both an
2314        // inclusive and an exclusive end resolve to the first node whose key
2315        // is >= the bound value: a node keyed exactly at an exclusive bound
2316        // still holds elements below it. Past the last key, the last node is
2317        // the only candidate.
2318        let back_entry = match end_bound {
2319            Bound::Included(end) | Bound::Excluded(end) => {
2320                node_for_borrowed_end(&index, end, self.borrow_order_matches)
2321            }
2322            Bound::Unbounded => index.last_key_value(),
2323        };
2324        let Some((back_key, back_node)) = back_entry else {
2325            return;
2326        };
2327        let back_key = back_key.clone();
2328        let back_node = back_node.clone();
2329        if back_key < front_key {
2330            // The end bound resolves before the start bound: empty range.
2331            return;
2332        }
2333
2334        // Number of leading elements of the back node that fall within the
2335        // end bound (inclusive end: elements <= bound; exclusive: < bound).
2336        let removed_prefix_len = |guard: &Vec<T>| -> usize {
2337            match end_bound {
2338                Bound::Included(end) => guard.rank(Bound::Excluded(end), true).map_or(0, |last| last + 1),
2339                Bound::Excluded(end) => guard.rank(Bound::Included(end), true).map_or(0, |last| last + 1),
2340                Bound::Unbounded => guard.len(),
2341            }
2342        };
2343
2344        if Arc::ptr_eq(&front_node, &back_node) {
2345            // The whole range lives in one node.
2346            let mut guard = front_node.clone().write_arc();
2347            let front_position = guard.rank(start_bound, true).map_or(0, |last| last + 1);
2348            let back_position = removed_prefix_len(&guard);
2349            if back_position <= front_position {
2350                return;
2351            }
2352
2353            let original_len = guard.len();
2354            guard.drain(front_position..back_position);
2355            if back_position == original_len {
2356                // The node's maximum was removed: re-key the entry, or drop
2357                // it when the node was fully drained.
2358                index.remove::<T>(&front_key);
2359                if let Some(new_max) = guard.last().cloned() {
2360                    index.insert(new_max, front_node);
2361                }
2362            }
2363            return;
2364        }
2365
2366        let mut front_guard = front_node.clone().write_arc();
2367        let mut back_guard = back_node.clone().write_arc();
2368        let front_position = front_guard.rank(start_bound, true).map_or(0, |last| last + 1);
2369        let back_position = removed_prefix_len(&back_guard);
2370
2371        // Remove every node strictly between the front and the back one.
2372        let middle_keys = index
2373            .range::<T, _>((Bound::Excluded(&front_key), Bound::Excluded(&back_key)))
2374            .map(|(key, _)| key.clone())
2375            .collect::<Vec<_>>();
2376        for key in middle_keys {
2377            let node = index
2378                .remove::<T>(&key)
2379                .expect("middle key was collected under the write lock");
2380            let mut removed_node = node.write_arc();
2381            detached_nodes.push(::core::mem::take(&mut *removed_node));
2382        }
2383
2384        // Trim the front node from the start position: its maximum goes away,
2385        // so its entry must be re-keyed (or dropped when the node empties).
2386        index.remove::<T>(&front_key);
2387        front_guard.drain(front_position..);
2388        if !front_guard.is_empty() {
2389            let new_front_max = front_guard.last().unwrap().clone();
2390            index.insert(new_front_max, front_node);
2391        }
2392
2393        // Trim the back node's prefix: its maximum survives unless the whole
2394        // node drains, so the entry only changes when the node empties.
2395        if back_position >= back_guard.len() {
2396            index.remove::<T>(&back_key);
2397            back_guard.drain(..);
2398        } else if back_position > 0 {
2399            back_guard.drain(..back_position);
2400        }
2401    }
2402}
2403
2404#[cfg(test)]
2405mod tests {
2406    use crate::concurrent::operation::Operation;
2407    use crate::concurrent::set::{BTreeSet, Iter, DEFAULT_INNER_SIZE, INITIAL_BATCH};
2408    use crate::core::node::NodeLike;
2409    use rand::Rng;
2410    use std::collections::HashSet;
2411    use std::ops::Bound::{self, Included};
2412    use std::sync::mpsc;
2413    use std::sync::{Arc, Barrier, Mutex};
2414    use std::thread;
2415    use std::time::Duration;
2416
2417    // Regression for https://github.com/lucidarium-systems/indexset/issues/57.
2418    #[test]
2419    fn test_node_size_two_preserves_all_u64_values() {
2420        let set = BTreeSet::<u64>::with_maximum_node_size(2);
2421
2422        for value in 0..10_u64 {
2423            set.insert(value);
2424        }
2425
2426        assert_eq!(set.iter().collect::<Vec<_>>(), (0..10).collect::<Vec<_>>());
2427    }
2428
2429    // Regression for https://github.com/lucidarium-systems/indexset/issues/57.
2430    #[test]
2431    fn test_node_size_three_preserves_all_u8_values() {
2432        let set = BTreeSet::<u8>::with_maximum_node_size(3);
2433
2434        for value in 0..20_u8 {
2435            set.insert(value);
2436        }
2437
2438        assert_eq!(set.iter().collect::<Vec<_>>(), (0..20).collect::<Vec<_>>());
2439    }
2440
2441    #[test]
2442    fn concurrent_first_writers_preserve_disjoint_ranges() {
2443        const WRITERS: u64 = 8;
2444        const VALUES_PER_WRITER: u64 = 1_000;
2445
2446        let set = Arc::new(BTreeSet::<u64>::new());
2447        let start = Arc::new(Barrier::new(WRITERS as usize));
2448        let handles = (0..WRITERS)
2449            .map(|writer| {
2450                let set = Arc::clone(&set);
2451                let start = Arc::clone(&start);
2452                thread::spawn(move || {
2453                    start.wait();
2454                    let first = writer * VALUES_PER_WRITER;
2455                    for value in first..first + VALUES_PER_WRITER {
2456                        assert!(set.insert(value));
2457                    }
2458                })
2459            })
2460            .collect::<Vec<_>>();
2461
2462        for handle in handles {
2463            handle.join().unwrap();
2464        }
2465
2466        let expected = (0..WRITERS * VALUES_PER_WRITER).collect::<Vec<_>>();
2467        assert_eq!(set.len(), expected.len());
2468        assert_eq!(set.iter().collect::<Vec<_>>(), expected);
2469    }
2470
2471    #[test]
2472    fn published_point_reads_remain_definitive_across_splits() {
2473        use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
2474
2475        const STABLE_KEYS: usize = 256;
2476        const FINAL_KEYS: usize = 4_096;
2477        const READERS: usize = 4;
2478
2479        let set = Arc::new(BTreeSet::<usize>::with_maximum_node_size(8));
2480        for key in 0..STABLE_KEYS {
2481            set.insert(key);
2482        }
2483
2484        let start = Arc::new(Barrier::new(READERS + 1));
2485        let done = Arc::new(AtomicBool::new(false));
2486        let published_up_to = Arc::new(AtomicUsize::new(STABLE_KEYS - 1));
2487        let readers = (0..READERS)
2488            .map(|reader| {
2489                let set = Arc::clone(&set);
2490                let start = Arc::clone(&start);
2491                let done = Arc::clone(&done);
2492                let published_up_to = Arc::clone(&published_up_to);
2493                thread::spawn(move || {
2494                    start.wait();
2495                    let mut probe = reader;
2496                    while !done.load(Ordering::Acquire) {
2497                        let key = probe % STABLE_KEYS;
2498                        assert_eq!(set.get_with(&key, |value| *value), Some(key));
2499                        let newest_acknowledged = published_up_to.load(Ordering::Acquire);
2500                        assert_eq!(
2501                            set.get_with(&newest_acknowledged, |value| *value),
2502                            Some(newest_acknowledged),
2503                            "an acknowledged insert disappeared from the published route"
2504                        );
2505                        probe += READERS;
2506                    }
2507                })
2508            })
2509            .collect::<Vec<_>>();
2510
2511        start.wait();
2512        for key in STABLE_KEYS..FINAL_KEYS {
2513            set.insert(key);
2514            published_up_to.store(key, Ordering::Release);
2515        }
2516        done.store(true, Ordering::Release);
2517
2518        for reader in readers {
2519            reader.join().unwrap();
2520        }
2521        assert_eq!(set.len(), FINAL_KEYS);
2522        for key in 0..FINAL_KEYS {
2523            assert_eq!(set.get_with(&key, |value| *value), Some(key));
2524        }
2525    }
2526
2527    #[test]
2528    fn published_pointer_survives_reclamation_interleavings() {
2529        use std::sync::atomic::{AtomicBool, Ordering};
2530
2531        let set = Arc::new(BTreeSet::<usize>::with_maximum_node_size(2));
2532        for key in 0..8 {
2533            set.insert(key);
2534        }
2535        let start = Arc::new(Barrier::new(2));
2536        let done = Arc::new(AtomicBool::new(false));
2537
2538        let reader_set = Arc::clone(&set);
2539        let reader_start = Arc::clone(&start);
2540        let reader_done = Arc::clone(&done);
2541        let reader = thread::spawn(move || {
2542            reader_start.wait();
2543            let mut probe = 0;
2544            while !reader_done.load(Ordering::Acquire) {
2545                let key = probe % 8;
2546                assert_eq!(reader_set.get_with(&key, |value| *value), Some(key));
2547                probe += 1;
2548            }
2549        });
2550
2551        start.wait();
2552        for key in 8..80 {
2553            set.insert(key);
2554        }
2555        for key in 8..80 {
2556            assert_eq!(set.remove(&key), Some(key));
2557        }
2558        done.store(true, Ordering::Release);
2559        reader.join().unwrap();
2560
2561        for key in 0..8 {
2562            assert_eq!(set.get_with(&key, |value| *value), Some(key));
2563        }
2564    }
2565
2566    #[test]
2567    fn published_route_chunks_split_and_merge_without_losing_keys() {
2568        let set = BTreeSet::<usize>::with_maximum_node_size(2);
2569        for key in 0..600 {
2570            assert!(set.insert(key));
2571        }
2572        for key in (0..600).step_by(2) {
2573            assert_eq!(set.remove(&key), Some(key));
2574        }
2575        for key in 0..600 {
2576            assert_eq!(set.contains(&key), key % 2 == 1, "probe {key}");
2577        }
2578        for key in (1..600).step_by(2) {
2579            assert_eq!(set.remove(&key), Some(key));
2580        }
2581        assert!(set.is_empty());
2582    }
2583
2584    #[test]
2585    fn mixed_structural_and_node_lock_paths_complete_without_deadlock() {
2586        const THREADS: usize = 8;
2587        const OPERATIONS: usize = 1_000;
2588
2589        let set = Arc::new(BTreeSet::<usize>::with_maximum_node_size(8));
2590        for value in 0..256 {
2591            set.insert(value);
2592        }
2593
2594        let start = Arc::new(Barrier::new(THREADS));
2595        let (done_tx, done_rx) = mpsc::channel();
2596        let handles = (0..THREADS)
2597            .map(|worker| {
2598                let set = Arc::clone(&set);
2599                let start = Arc::clone(&start);
2600                let done_tx = done_tx.clone();
2601                thread::spawn(move || {
2602                    start.wait();
2603                    for operation in 0..OPERATIONS {
2604                        let value = (operation * 17 + worker * 31) % 512;
2605                        match (operation + worker) % 5 {
2606                            0 => {
2607                                set.insert(value);
2608                            }
2609                            1 => {
2610                                set.remove(&value);
2611                            }
2612                            2 => {
2613                                let _ = set.contains(&value);
2614                            }
2615                            3 => {
2616                                let _ = set.get_with(&value, Clone::clone);
2617                            }
2618                            _ => {
2619                                set.remove_range(value..=value);
2620                                set.insert(value);
2621                            }
2622                        }
2623                    }
2624                    done_tx.send(()).unwrap();
2625                })
2626            })
2627            .collect::<Vec<_>>();
2628        drop(done_tx);
2629
2630        for _ in 0..THREADS {
2631            done_rx
2632                .recv_timeout(Duration::from_secs(10))
2633                .expect("mixed structural/node-lock workload did not complete");
2634        }
2635        for handle in handles {
2636            handle.join().unwrap();
2637        }
2638    }
2639
2640    #[test]
2641    fn test_concurrent_insert() {
2642        let set = Arc::new(BTreeSet::<i32>::new());
2643        let num_threads = 128;
2644        let operations_per_thread = 10000;
2645        let mut handles = vec![];
2646
2647        let test_data: Vec<Vec<(i32, i32)>> = (0..num_threads)
2648            .map(|_| {
2649                let mut rng = rand::rng();
2650                (0..operations_per_thread)
2651                    .map(|_| {
2652                        let value = rng.random_range(0..100000);
2653                        let operation = rng.random_range(0..2);
2654                        (operation, value)
2655                    })
2656                    .collect()
2657            })
2658            .collect();
2659
2660        let expected_values = Arc::new(Mutex::new(HashSet::new()));
2661
2662        for thread_idx in 0..num_threads {
2663            let set_clone = Arc::clone(&set);
2664            let expected_values = Arc::clone(&expected_values);
2665            let thread_data = test_data[thread_idx].clone();
2666
2667            let handle = thread::spawn(move || {
2668                for (operation, value) in thread_data {
2669                    if operation == 0 {
2670                        let _a = set_clone.insert(value);
2671                        expected_values.lock().unwrap().insert(value);
2672                    }
2673                }
2674            });
2675            handles.push(handle);
2676        }
2677
2678        for handle in handles {
2679            handle.join().unwrap();
2680        }
2681
2682        let expected_values = expected_values.lock().unwrap();
2683        assert_eq!(set.len(), expected_values.len());
2684
2685        for value in expected_values.iter() {
2686            assert!(set.contains(value));
2687        }
2688    }
2689
2690    #[test]
2691    fn test_insert_desc() {
2692        let set = Arc::new(BTreeSet::<i32>::new());
2693
2694        assert!(set.insert(2));
2695        assert!(set.insert(1));
2696    }
2697
2698    #[test]
2699    fn test_insert_st() {
2700        let set = Arc::new(BTreeSet::<i32>::new());
2701        let mut rng = rand::rng();
2702
2703        let n = 2048 * 100;
2704        let range = 0..n;
2705        let mut inserted_values = HashSet::new();
2706        for _ in range {
2707            let value = rng.random_range(0..n);
2708            if inserted_values.insert(value) {
2709                set.insert(value);
2710            }
2711        }
2712
2713        assert_eq!(
2714            set.len(),
2715            inserted_values.len(),
2716            "Length did not match, missing: {:?}",
2717            set.index
2718                .read()
2719                .values()
2720                .flat_map(|node| node.read().iter().cloned().collect::<Vec<_>>())
2721                .collect::<HashSet<_>>()
2722                .symmetric_difference(&inserted_values)
2723                .collect::<Vec<_>>()
2724        );
2725        for i in inserted_values {
2726            assert!(
2727                set.contains(&i),
2728                "Did not find: {} with index: {:?}",
2729                i,
2730                set.index.read().keys().cloned().collect::<Vec<_>>(),
2731            );
2732        }
2733    }
2734
2735    #[test]
2736    fn test_single_element() {
2737        let set = BTreeSet::<i32>::new();
2738        set.insert(1);
2739        let mut iter = set.into_iter();
2740        assert_eq!(iter.next(), Some(1));
2741        assert_eq!(iter.next(), None);
2742        assert_eq!(iter.next_back(), None);
2743    }
2744
2745    #[test]
2746    fn test_multiple_elements() {
2747        let set = BTreeSet::<i32>::new();
2748        set.insert(1);
2749        set.insert(2);
2750        set.insert(3);
2751        let mut iter = set.into_iter();
2752        assert_eq!(iter.next(), Some(1));
2753        assert_eq!(iter.next_back(), Some(3));
2754        assert_eq!(iter.next(), Some(2));
2755        assert_eq!(iter.next(), None);
2756        assert_eq!(iter.next_back(), None);
2757    }
2758
2759    #[test]
2760    fn test_bidirectional_iteration() {
2761        let set = BTreeSet::<i32>::with_maximum_node_size(3);
2762        for i in 1..=20 {
2763            set.insert(i);
2764        }
2765        let mut iter = set.into_iter();
2766        for i in 0..10 {
2767            // (1, 20), (2, 19), (3, 18), (4, 17), (5, 16), (6, 15), (7, 14), (8, 13), (9, 12), (10, 11)
2768            let tree = set.index.read().keys().cloned().collect::<Vec<_>>();
2769
2770            let expected_next = i + 1;
2771            let actual_next = iter.next();
2772            assert_eq!(actual_next, Some(expected_next), "Tree: {:?}", tree);
2773
2774            let expected_next_back = 20 - i;
2775            let actual_next_back = iter.next_back();
2776            assert_eq!(actual_next_back, Some(expected_next_back), "Tree: {:?}", tree);
2777        }
2778        assert_eq!(iter.next(), None);
2779        assert_eq!(iter.next_back(), None);
2780    }
2781
2782    #[test]
2783    fn test_fused_iterator() {
2784        let set = BTreeSet::<i32>::new();
2785        set.insert(1);
2786        let mut iter = set.into_iter();
2787        assert_eq!(iter.next(), Some(1));
2788        assert_eq!(iter.next(), None);
2789        assert_eq!(iter.next(), None);
2790    }
2791
2792    #[test]
2793    fn test_fused_iterator_back() {
2794        let set = BTreeSet::<i32>::new();
2795        set.insert(1);
2796        let mut iter = set.into_iter();
2797        assert_eq!(iter.next_back(), Some(1));
2798        assert_eq!(iter.next_back(), None);
2799        assert_eq!(iter.next_back(), None);
2800    }
2801
2802    #[test]
2803    fn test_out_of_bounds_range() {
2804        let btree: BTreeSet<usize> = BTreeSet::from_iter(0..10);
2805        assert_eq!(btree.range((Included(5), Included(10))).count(), 5);
2806        assert_eq!(btree.range((Included(5), Included(11))).count(), 5);
2807        assert_eq!(btree.range((Included(5), Included(10 + DEFAULT_INNER_SIZE))).count(), 5);
2808        assert_eq!(btree.range((Included(0), Included(11))).count(), 10);
2809    }
2810
2811    #[test]
2812    fn test_iterating_over_blocks() {
2813        let btree = BTreeSet::from_iter((0..(DEFAULT_INNER_SIZE + 10)).into_iter());
2814        assert_eq!(btree.iter().count(), (0..(DEFAULT_INNER_SIZE + 10)).count());
2815        let start = btree.range(0..DEFAULT_INNER_SIZE).into_iter().collect::<Vec<_>>();
2816
2817        assert_eq!(start, (0..DEFAULT_INNER_SIZE).collect::<Vec<_>>());
2818        assert_eq!(
2819            btree.range(0..=DEFAULT_INNER_SIZE).into_iter().collect::<Vec<_>>(),
2820            (0..=DEFAULT_INNER_SIZE).collect::<Vec<_>>()
2821        );
2822        assert_eq!(
2823            btree.range(0..=DEFAULT_INNER_SIZE + 1).count(),
2824            (0..=DEFAULT_INNER_SIZE + 1).count()
2825        );
2826        assert_eq!(btree.iter().rev().count(), (0..(DEFAULT_INNER_SIZE + 10)).count());
2827        assert_eq!(
2828            btree.range(0..DEFAULT_INNER_SIZE).rev().count(),
2829            (0..DEFAULT_INNER_SIZE).count()
2830        );
2831        assert_eq!(
2832            btree.range(0..=DEFAULT_INNER_SIZE).rev().count(),
2833            (0..=DEFAULT_INNER_SIZE).count()
2834        );
2835        assert_eq!(
2836            btree.range(0..=DEFAULT_INNER_SIZE + 1).rev().count(),
2837            (0..=DEFAULT_INNER_SIZE + 1).count()
2838        );
2839    }
2840
2841    #[test]
2842    fn test_empty_set() {
2843        let btree: BTreeSet<usize> = BTreeSet::new();
2844        assert_eq!(btree.iter().count(), 0);
2845        assert_eq!(btree.range(0..0).count(), 0);
2846        assert_eq!(btree.range(0..).count(), 0);
2847        assert_eq!(btree.range(..0).count(), 0);
2848        assert_eq!(btree.range(..).count(), 0);
2849        assert_eq!(btree.range(0..=0).count(), 0);
2850        assert_eq!(btree.range(..1).count(), 0);
2851
2852        assert_eq!(btree.iter().rev().count(), 0);
2853        assert_eq!(btree.range(0..0).rev().count(), 0);
2854        assert_eq!(btree.range(..).rev().count(), 0);
2855        assert_eq!(btree.range(..1).rev().count(), 0);
2856
2857        assert_eq!(btree.range(..DEFAULT_INNER_SIZE).count(), 0);
2858        assert_eq!(btree.range(DEFAULT_INNER_SIZE..DEFAULT_INNER_SIZE * 2).count(), 0);
2859    }
2860
2861    #[test]
2862    fn test_remove_range() {
2863        // We have DEFAULT_INNER_SIZE * 2 elements
2864        let btree = BTreeSet::from_iter(0..(DEFAULT_INNER_SIZE * 2));
2865        let expected_len = DEFAULT_INNER_SIZE * 2;
2866        let actual_len = btree.len();
2867        assert_eq!(expected_len, actual_len);
2868
2869        // We remove 10 elements from the beginning, 5 included up to 15 excluded.
2870        btree.remove_range(5..15);
2871        let expected_len = expected_len - 10;
2872        let actual_len = btree.len();
2873        assert_eq!(expected_len, actual_len);
2874
2875        // Then take more 10 from the middle
2876        btree.remove_range(DEFAULT_INNER_SIZE - 5..DEFAULT_INNER_SIZE + 5);
2877        let expected_len = expected_len - 10;
2878        let actual_len = btree.len();
2879        assert_eq!(expected_len, actual_len);
2880
2881        // And then remove 512
2882        btree.remove_range(..DEFAULT_INNER_SIZE / 2);
2883        // We add +10 here because we are removing everything up to 512, but we already removed 5..15.
2884        let expected_len = expected_len - (DEFAULT_INNER_SIZE / 2) + 10;
2885        let actual_len = btree.len();
2886        assert_eq!(expected_len, actual_len);
2887
2888        // And then everything from (512 * 3) / 2 to the end, which is
2889        // exactly the upper 512 values.
2890        let from = (DEFAULT_INNER_SIZE * 3) / 2;
2891        btree.remove_range(from..);
2892        let expected_len = expected_len - DEFAULT_INNER_SIZE / 2;
2893        let actual_len = btree.len();
2894        assert_eq!(expected_len, actual_len);
2895
2896        // We now clear the tree
2897        btree.remove_range(..);
2898        assert_eq!(btree.len(), 0);
2899
2900        // Re-insert everything
2901        for i in 0..(DEFAULT_INNER_SIZE * 2) {
2902            btree.insert(i);
2903        }
2904        let expected_len = DEFAULT_INNER_SIZE * 2;
2905        let actual_len = btree.len();
2906        assert_eq!(expected_len, actual_len);
2907
2908        btree.remove_range((std::ops::Bound::Excluded(5), std::ops::Bound::Excluded(15)));
2909        let expected_len = expected_len - 9;
2910        let actual_len = btree.len();
2911        assert_eq!(expected_len, actual_len);
2912
2913        btree.remove_range((
2914            std::ops::Bound::Included(DEFAULT_INNER_SIZE),
2915            std::ops::Bound::Excluded(DEFAULT_INNER_SIZE + 10),
2916        ));
2917        let expected_len = expected_len - 10;
2918        let actual_len = btree.len();
2919        assert_eq!(expected_len, actual_len);
2920
2921        // This range exceeds the size of the tree
2922        btree.remove_range(DEFAULT_INNER_SIZE * 3..DEFAULT_INNER_SIZE * 4);
2923        let expected_len = expected_len;
2924        let actual_len = btree.len();
2925        assert_eq!(expected_len, actual_len);
2926
2927        // This range starts at the very end of the tree, and exceeds it
2928        btree.remove_range(DEFAULT_INNER_SIZE * 2 - 5..DEFAULT_INNER_SIZE * 3);
2929        let expected_len = expected_len - 5;
2930        let actual_len = btree.len();
2931        assert_eq!(expected_len, actual_len);
2932    }
2933
2934    #[test]
2935    fn remove_range_end_bound_regressions() {
2936        // `x..` must remove only the suffix, not also drain the first node.
2937        let set = BTreeSet::<u64>::with_maximum_node_size(4);
2938        for value in 0..10 {
2939            set.insert(value);
2940        }
2941        set.remove_range(7..);
2942        assert_eq!(set.iter().collect::<Vec<_>>(), (0..7).collect::<Vec<_>>());
2943
2944        // `..` must clear every node, not only the first one.
2945        let set = BTreeSet::<u64>::with_maximum_node_size(4);
2946        for value in 0..10 {
2947            set.insert(value);
2948        }
2949        set.remove_range(..);
2950        assert_eq!(set.len(), 0);
2951        assert!(set.is_empty());
2952
2953        // An inclusive end must remove every element up to and including it.
2954        let set = BTreeSet::<u64>::with_maximum_node_size(4);
2955        for value in 0..10 {
2956            set.insert(value);
2957        }
2958        set.remove_range(3..=5);
2959        assert_eq!(set.iter().collect::<Vec<_>>(), vec![0, 1, 2, 6, 7, 8, 9]);
2960
2961        // `x..=x` must remove exactly x, not drain to the node end.
2962        let set = BTreeSet::<u64>::with_maximum_node_size(4);
2963        for value in 0..10 {
2964            set.insert(value);
2965        }
2966        set.remove_range(2..=2);
2967        assert_eq!(set.iter().collect::<Vec<_>>(), vec![0, 1, 3, 4, 5, 6, 7, 8, 9]);
2968
2969        // An exclusive end equal to a node maximum must not drain the
2970        // following node.
2971        let set = BTreeSet::<u64>::with_maximum_node_size(3);
2972        for value in 0..9 {
2973            set.insert(value);
2974        }
2975        let boundary = *set.index.read().first_key_value().expect("node must exist").0;
2976        set.remove_range(0..boundary);
2977        let expected = (0..9).filter(|value| *value >= boundary).collect::<Vec<_>>();
2978        assert_eq!(set.iter().collect::<Vec<_>>(), expected);
2979    }
2980
2981    #[test]
2982    fn remove_range_matches_btreeset_oracle() {
2983        use std::ops::Bound;
2984
2985        fn oracle_case(node_size: usize, values: &[u64], start: Bound<u64>, end: Bound<u64>) {
2986            let set = BTreeSet::<u64>::with_maximum_node_size(node_size);
2987            for &value in values {
2988                set.insert(value);
2989            }
2990            let mut oracle = values.iter().copied().collect::<std::collections::BTreeSet<_>>();
2991
2992            let range = (start, end);
2993            oracle.retain(|value| !std::ops::RangeBounds::contains(&range, value));
2994            set.remove_range(range);
2995
2996            assert_eq!(
2997                set.iter().collect::<Vec<_>>(),
2998                oracle.iter().copied().collect::<Vec<_>>(),
2999                "node_size={node_size}, start={start:?}, end={end:?}"
3000            );
3001            assert_eq!(
3002                set.len(),
3003                oracle.len(),
3004                "node_size={node_size}, start={start:?}, end={end:?}"
3005            );
3006        }
3007
3008        // Even values only, so probes hit present values, absent values, and
3009        // both sides of every node boundary.
3010        let values = (0..15u64).map(|value| value * 2).collect::<Vec<_>>();
3011        let mut bounds = vec![Bound::Unbounded];
3012        for probe in 0..=30u64 {
3013            bounds.push(Bound::Included(probe));
3014            bounds.push(Bound::Excluded(probe));
3015        }
3016
3017        // Single-node and multi-node geometries, on and off node boundaries.
3018        for node_size in [4usize, 7, 64] {
3019            for &start in &bounds {
3020                for &end in &bounds {
3021                    oracle_case(node_size, &values, start, end);
3022                }
3023            }
3024        }
3025    }
3026
3027    #[test]
3028    fn remove_range_clears_detached_nodes() {
3029        // White-box geometry fixture: a failure after split/merge tuning may
3030        // mean node boundaries changed rather than detached-node clearing
3031        // regressed. WorkTable's persisted-index fixtures have the same
3032        // geometry coupling.
3033        let set = BTreeSet::<u64>::with_maximum_node_size(4);
3034        for value in 0..32 {
3035            set.insert(value);
3036        }
3037
3038        let detached = set
3039            .index
3040            .read()
3041            .range((Included(&2), Bound::Unbounded))
3042            .nth(1)
3043            .unwrap()
3044            .1
3045            .clone();
3046        let detached_values = detached.read().iter().copied().collect::<Vec<_>>();
3047        assert!(detached_values.iter().all(|value| (2..30).contains(value)));
3048
3049        set.remove_range(2..30);
3050
3051        assert!(detached.read().is_empty());
3052        assert!(detached_values.iter().all(|value| !set.contains(value)));
3053    }
3054
3055    #[test]
3056    fn remove_reaches_value_above_every_index_key() {
3057        let set = BTreeSet::<u64>::new();
3058        for value in [1u64, 2, 3] {
3059            set.insert(value);
3060        }
3061
3062        // Simulate a stale-key window: the last node's maximum grows past its
3063        // index key before the UpdateMax repair commits. `contains` already
3064        // reaches such a value through the back-node fallback; `remove` must
3065        // reach it the same way.
3066        {
3067            let node = set.index.read().last_key_value().expect("node must exist").1.clone();
3068            let mut guard = node.write();
3069            NodeLike::insert(&mut *guard, 5u64);
3070        }
3071
3072        assert!(set.contains(&5));
3073        assert_eq!(set.remove(&5), Some(5), "value above every index key must be removable");
3074        assert!(!set.contains(&5));
3075        assert_eq!(set.iter().collect::<Vec<_>>(), vec![1, 2, 3]);
3076    }
3077
3078    // Simulates the first phase of a remove that empties a node: the elements
3079    // are deleted under the node lock, leaving the index entry with a stale
3080    // key, and the caller receives the not-yet-committed MakeUnreachable.
3081    fn drain_node_with_pending_unlink(set: &BTreeSet<u64>, values: &[u64], stale_key: u64) -> Operation<u64, Vec<u64>> {
3082        let node = set.index.read().last_key_value().expect("node must exist").1.clone();
3083        {
3084            let mut guard = node.write();
3085            for value in values {
3086                NodeLike::delete(&mut *guard, value).expect("seeded value must be present");
3087            }
3088        }
3089        Operation::MakeUnreachable(node, stale_key)
3090    }
3091
3092    #[test]
3093    fn split_commit_against_drained_node_fails_instead_of_dropping_insert() {
3094        let set = BTreeSet::<u64>::new();
3095        for seeded in [10u64, 20, 30] {
3096            set.insert(seeded);
3097        }
3098        let node = set.index.read().last_key_value().expect("node must exist").1.clone();
3099        // A split is scheduled with a pending insert riding on it...
3100        let pending_split = Operation::Split(node.clone(), 30u64, 15u64);
3101        // ...then a concurrent remove drains the node before the commit.
3102        {
3103            let mut guard = node.write();
3104            for seeded in [10u64, 20, 30] {
3105                NodeLike::delete(&mut *guard, &seeded).expect("seeded value must be present");
3106            }
3107        }
3108
3109        // The commit must fail so the insert retries; it must neither drop
3110        // the pending value silently nor unlink the still-indexed node.
3111        assert!(pending_split
3112            .commit::<false>(&mut set.index.write(), super::no_identity_adoption)
3113            .is_err());
3114        assert!(
3115            set.index.read().get(&30).is_some(),
3116            "drained node must stay linked for the retry"
3117        );
3118
3119        // The retried insert lands and repairs the index.
3120        assert!(set.insert(15));
3121        assert!(set.contains(&15));
3122        assert_eq!(set.remove(&15), Some(15));
3123        assert!(set.is_empty());
3124    }
3125
3126    #[cfg(feature = "cdc")]
3127    #[test]
3128    fn split_commit_against_drained_node_does_not_panic_in_cdc_build() {
3129        let set = BTreeSet::<u64>::new();
3130        for seeded in [10u64, 20, 30] {
3131            set.insert(seeded);
3132        }
3133        let node = set.index.read().last_key_value().expect("node must exist").1.clone();
3134        let pending_split = Operation::Split(node.clone(), 30u64, 15u64);
3135        {
3136            let mut guard = node.write();
3137            for seeded in [10u64, 20, 30] {
3138                NodeLike::delete(&mut *guard, &seeded).expect("seeded value must be present");
3139            }
3140        }
3141
3142        // The cdc-emitting commit used to panic reading the drained node's
3143        // maximum while holding the structural write lock.
3144        assert!(pending_split
3145            .commit::<true>(&mut set.index.write(), super::no_identity_adoption)
3146            .is_err());
3147        assert!(set.index.read().get(&30).is_some());
3148
3149        let (old, _events) = set.put_cdc(15);
3150        assert!(old.is_none());
3151        assert!(set.contains(&15));
3152    }
3153
3154    #[test]
3155    fn insert_into_emptied_node_survives_stale_make_unreachable() {
3156        // One value below and one above the stale index key.
3157        for value in [5u64, 40u64] {
3158            let set = BTreeSet::<u64>::new();
3159            for seeded in [10u64, 20, 30] {
3160                set.insert(seeded);
3161            }
3162            let pending_unlink = drain_node_with_pending_unlink(&set, &[10, 20, 30], 30);
3163
3164            // The insert lands in the emptied node and must repair the stale
3165            // index key immediately.
3166            assert!(set.insert(value));
3167
3168            // The stale unlink then commits: it must not remove the node that
3169            // now contains the acknowledged insert.
3170            let _ = pending_unlink.commit::<false>(&mut set.index.write(), super::no_identity_adoption);
3171
3172            assert!(set.contains(&value), "value {value} lost after stale unlink");
3173            assert_eq!(set.iter().collect::<Vec<_>>(), vec![value]);
3174            assert_eq!(set.remove(&value), Some(value));
3175            assert!(!set.contains(&value));
3176            assert_eq!(set.len(), 0);
3177        }
3178    }
3179
3180    #[test]
3181    fn stale_make_unreachable_rekeys_refilled_node_instead_of_unlinking() {
3182        for value in [5u64, 40u64] {
3183            let set = BTreeSet::<u64>::new();
3184            for seeded in [10u64, 20, 30] {
3185                set.insert(seeded);
3186            }
3187            let node = set.index.read().last_key_value().expect("node must exist").1.clone();
3188            let pending_unlink = drain_node_with_pending_unlink(&set, &[10, 20, 30], 30);
3189
3190            // First phase of a concurrent insert: the value lands in the
3191            // routed (empty) node under the node lock; the UpdateMax repair
3192            // has not committed yet.
3193            {
3194                let mut guard = node.write();
3195                NodeLike::insert(&mut *guard, value);
3196            }
3197            let pending_repair = Operation::UpdateMax(node.clone(), 30u64);
3198
3199            // The remove's stale unlink commits first: it must observe the
3200            // refilled node and re-key it rather than unlink it.
3201            assert!(pending_unlink
3202                .commit::<false>(&mut set.index.write(), super::no_identity_adoption)
3203                .is_ok());
3204            // The insert's repair then finds the entry already re-keyed.
3205            let _ = pending_repair.commit::<false>(&mut set.index.write(), super::no_identity_adoption);
3206
3207            assert!(set.contains(&value), "value {value} lost to stale unlink");
3208            assert_eq!(set.remove(&value), Some(value));
3209            assert!(set.is_empty());
3210        }
3211    }
3212
3213    #[test]
3214    fn published_route_updates_when_a_non_last_boundary_shrinks() {
3215        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3216        set.attach_nodes([vec![1, 10], vec![20, 30]]);
3217
3218        // Removing the first node's maximum changes its canonical route from
3219        // 10 to 1. If the published route remains at 10, the later insertion
3220        // of 5 correctly lands in the second node but a point read for 5 is
3221        // misrouted to the first node and reports a false miss.
3222        assert_eq!(set.remove(&10), Some(10));
3223        assert!(set.insert(5));
3224        assert!(set.contains(&5));
3225        assert_eq!(set.get(&5).map(|value| *value.get()), Some(5));
3226    }
3227
3228    #[test]
3229    fn attach_repairs_a_stale_last_node_boundary() {
3230        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3231        set.attach_node(vec![1, 10]);
3232
3233        // A last-node maximum may remain conservatively published at its old
3234        // high boundary. Incremental restoration above that node must move
3235        // the old route down before installing a new node whose values occupy
3236        // the gap.
3237        assert_eq!(set.remove(&10), Some(10));
3238        set.attach_node(vec![5, 20]);
3239
3240        assert_eq!(set.get(&5).map(|value| *value.get()), Some(5));
3241        assert!(set.contains(&5));
3242    }
3243
3244    #[test]
3245    fn attach_repairs_a_stale_low_last_node_boundary() {
3246        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3247        set.attach_node(vec![1, 10]);
3248
3249        // Growing the last node can leave its published boundary below its
3250        // canonical maximum. Once another node is attached, that old route is
3251        // no longer the final fallback and must be repaired as well.
3252        assert!(set.insert(20));
3253        set.attach_node(vec![25, 30]);
3254
3255        assert_eq!(set.get(&20).map(|value| *value.get()), Some(20));
3256        assert_eq!(set.get(&25).map(|value| *value.get()), Some(25));
3257    }
3258
3259    #[test]
3260    fn attach_recovers_from_a_missing_published_identity() {
3261        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3262        set.attach_node(vec![1, 10]);
3263        let last_identity = {
3264            let index = set.index.read();
3265            super::node_identity(index.last_key_value().unwrap().1)
3266        };
3267        assert!(set.index.published_keys.lock().remove(&last_identity).is_some());
3268
3269        set.attach_node(vec![20, 30]);
3270
3271        for value in [1, 10, 20, 30] {
3272            assert_eq!(set.get(&value).map(|found| *found.get()), Some(value));
3273        }
3274    }
3275
3276    #[test]
3277    fn insert_recovers_from_a_missing_replaced_node_identity() {
3278        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3279        set.attach_node(vec![1, 10]);
3280        let old_node = set.index.read().last_key_value().unwrap().1.clone();
3281        assert!(set
3282            .index
3283            .published_keys
3284            .lock()
3285            .remove(&super::node_identity(&old_node))
3286            .is_some());
3287
3288        {
3289            let mut index = set.index.write();
3290            let replaced = index.insert(10, Arc::new(parking_lot::RwLock::new(vec![5, 10])));
3291            assert!(replaced.is_some_and(|node| Arc::ptr_eq(&node, &old_node)));
3292        }
3293
3294        assert!(!set.contains(&1));
3295        assert!(set.contains(&5));
3296        assert!(set.contains(&10));
3297    }
3298
3299    #[test]
3300    fn remove_recovers_from_a_missing_node_identity() {
3301        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3302        set.attach_node(vec![1, 10]);
3303        let old_node = set.index.read().last_key_value().unwrap().1.clone();
3304        assert!(set
3305            .index
3306            .published_keys
3307            .lock()
3308            .remove(&super::node_identity(&old_node))
3309            .is_some());
3310
3311        {
3312            let mut index = set.index.write();
3313            let removed = index.remove(&10).expect("canonical route exists");
3314            assert!(Arc::ptr_eq(&removed, &old_node));
3315        }
3316
3317        assert!(set.is_empty());
3318        assert!(!set.contains(&1));
3319    }
3320
3321    #[test]
3322    fn missing_published_remove_does_not_clone_a_shared_chunk() {
3323        let mut published = super::PublishedNodeIndex::<u64, Vec<u64>> {
3324            chunks: Vec::new(),
3325            len: 0,
3326        };
3327        for key in 0..16 {
3328            published.insert(key, Arc::new(parking_lot::RwLock::new(vec![key])));
3329        }
3330        let snapshot = published.clone();
3331        assert!(Arc::ptr_eq(&published.chunks[0], &snapshot.chunks[0]));
3332
3333        assert!(published.remove(&100).is_none());
3334
3335        assert!(Arc::ptr_eq(&published.chunks[0], &snapshot.chunks[0]));
3336    }
3337
3338    #[test]
3339    fn published_chunks_have_split_merge_hysteresis() {
3340        let mut published = super::PublishedNodeIndex::<u64, Vec<u64>> {
3341            chunks: Vec::new(),
3342            len: 0,
3343        };
3344        for key in 0..=128 {
3345            published.insert(key, Arc::new(parking_lot::RwLock::new(vec![key])));
3346        }
3347        assert_eq!(published.chunks.len(), 2);
3348
3349        for key in 0..33 {
3350            assert!(published.remove(&key).is_some());
3351        }
3352        assert_eq!(published.chunks.len(), 1);
3353
3354        published.insert(0, Arc::new(parking_lot::RwLock::new(vec![0])));
3355        assert_eq!(
3356            published.chunks.len(),
3357            1,
3358            "one insert after a merge must not split again"
3359        );
3360        assert!(published.remove(&0).is_some());
3361        assert_eq!(
3362            published.chunks.len(),
3363            1,
3364            "one remove after a merge must not change chunking"
3365        );
3366    }
3367
3368    #[test]
3369    fn attach_boundary_repair_is_a_complete_publication_by_itself() {
3370        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3371        set.attach_node(vec![1, 10]);
3372        assert_eq!(set.remove(&10), Some(10));
3373
3374        // Model attachment stopping after its preflight repair (for example,
3375        // because user-provided Clone/Ord code panics while reading the first
3376        // incoming node). The repaired identity map and route snapshot must
3377        // still commit together when the guard drops.
3378        {
3379            let mut index = set.index.write();
3380            index.repair_last_route_before_attach();
3381        }
3382        set.attach_node(vec![5, 20]);
3383
3384        assert_eq!(set.get(&5).map(|found| *found.get()), Some(5));
3385    }
3386
3387    #[cfg(debug_assertions)]
3388    #[test]
3389    #[should_panic(expected = "generic topology removal requires publication")]
3390    fn publication_must_be_enabled_before_an_opt_out_guard_mutates() {
3391        let set = BTreeSet::<u64>::with_maximum_node_size(8);
3392        set.attach_node(vec![1, 10]);
3393        let mut index = set.index.write_rekey();
3394        index.remove(&10);
3395    }
3396
3397    #[test]
3398    fn published_point_routes_match_a_sequential_oracle_under_churn() {
3399        let set = BTreeSet::<u64>::with_maximum_node_size(4);
3400        let mut oracle = std::collections::BTreeSet::new();
3401        let mut state = 0x8f4d_2a71_c390_6be5u64;
3402
3403        for step in 0..2_000 {
3404            // Fixed xorshift stream: deterministic inserts/removes repeatedly
3405            // grow, shrink, empty, and split tiny nodes.
3406            state ^= state << 13;
3407            state ^= state >> 7;
3408            state ^= state << 17;
3409            let key = state % 64;
3410            if state & 1 == 0 {
3411                assert_eq!(set.insert(key), oracle.insert(key), "insert step {step}, key {key}");
3412            } else {
3413                assert_eq!(
3414                    set.remove(&key).is_some(),
3415                    oracle.remove(&key),
3416                    "remove step {step}, key {key}"
3417                );
3418            }
3419
3420            for probe in 0..64 {
3421                assert_eq!(
3422                    set.contains(&probe),
3423                    oracle.contains(&probe),
3424                    "point route diverged at step {step}, probe {probe}"
3425                );
3426            }
3427            assert_eq!(
3428                set.iter().collect::<Vec<_>>(),
3429                oracle.iter().copied().collect::<Vec<_>>()
3430            );
3431        }
3432    }
3433
3434    #[test]
3435    fn concurrent_remove_reinsert_over_emptying_nodes_preserves_all_keys() {
3436        const THREADS: u64 = 4;
3437        const ITERATIONS: u64 = 1_000;
3438
3439        // Tiny nodes over adjacent keys: removes empty nodes constantly, so
3440        // inserts keep racing pending MakeUnreachable repairs.
3441        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(2));
3442        for key in 0..THREADS {
3443            set.insert(key);
3444        }
3445
3446        let start = Arc::new(Barrier::new(THREADS as usize));
3447        let (done_tx, done_rx) = mpsc::channel();
3448        let handles = (0..THREADS)
3449            .map(|key| {
3450                let set = Arc::clone(&set);
3451                let start = Arc::clone(&start);
3452                let done_tx = done_tx.clone();
3453                thread::spawn(move || {
3454                    start.wait();
3455                    for _ in 0..ITERATIONS {
3456                        // A point remove may transiently miss while another
3457                        // writer's index repair is still in flight, but the
3458                        // acknowledged insert must never be LOST: under a
3459                        // stable snapshot the key must still be somewhere, and
3460                        // the self-healing repairs must make it removable
3461                        // again promptly.
3462                        let mut attempts = 0;
3463                        while set.remove(&key).is_none() {
3464                            let index = set.index.read();
3465                            let present = index.values().any(|node| node.read().contains(&key));
3466                            drop(index);
3467                            assert!(present, "acknowledged insert of {key} was lost");
3468                            attempts += 1;
3469                            assert!(attempts < 10_000, "key {key} present but never became removable");
3470                            std::hint::spin_loop();
3471                        }
3472                        assert!(set.insert(key), "{key} still present after acknowledged remove");
3473                    }
3474                    done_tx.send(()).unwrap();
3475                })
3476            })
3477            .collect::<Vec<_>>();
3478        drop(done_tx);
3479
3480        for _ in 0..THREADS {
3481            done_rx
3482                .recv_timeout(Duration::from_secs(30))
3483                .expect("remove/reinsert workload did not complete in time");
3484        }
3485        for handle in handles {
3486            handle.join().unwrap();
3487        }
3488
3489        for key in 0..THREADS {
3490            assert!(set.contains(&key), "key {key} lost after churn");
3491            assert_eq!(set.remove(&key), Some(key));
3492        }
3493        assert!(set.is_empty());
3494    }
3495
3496    #[test]
3497    fn test_remove_single_element() {
3498        let set = BTreeSet::<i32>::new();
3499        set.insert(5);
3500        assert!(set.contains(&5));
3501        assert!(set.remove(&5).is_some());
3502        assert!(!set.contains(&5));
3503        assert!(!set.remove(&5).is_some());
3504    }
3505
3506    #[test]
3507    fn test_remove_multiple_elements() {
3508        let set = BTreeSet::<i32>::new();
3509        for i in 0..2048 {
3510            set.insert(i);
3511        }
3512        for i in 0..2048 {
3513            assert!(set.remove(&i).is_some());
3514            assert!(!set.contains(&i));
3515        }
3516        assert_eq!(set.len(), 0);
3517    }
3518
3519    #[test]
3520    fn test_remove_non_existent() {
3521        let set = BTreeSet::<i32>::new();
3522        set.insert(5);
3523        assert!(!set.remove(&10).is_some());
3524        assert!(set.contains(&5));
3525    }
3526
3527    #[test]
3528    fn test_remove_stress() {
3529        let set = Arc::new(BTreeSet::<i32>::new());
3530        const NUM_ELEMENTS: i32 = 10000;
3531
3532        for i in 0..NUM_ELEMENTS {
3533            set.insert(i);
3534        }
3535        assert_eq!(set.len(), NUM_ELEMENTS as usize, "Incorrect size after insertion");
3536
3537        let num_threads = 8;
3538        let elements_per_thread = NUM_ELEMENTS / num_threads;
3539        let handles: Vec<_> = (0..num_threads)
3540            .map(|t| {
3541                let set = Arc::clone(&set);
3542                thread::spawn(move || {
3543                    for i in (t * elements_per_thread)..((t + 1) * elements_per_thread) {
3544                        if i % 2 == 1 {
3545                            assert!(set.remove(&i).is_some(), "Failed to remove {}", i);
3546                        }
3547                    }
3548                })
3549            })
3550            .collect();
3551
3552        for handle in handles {
3553            handle.join().unwrap();
3554        }
3555
3556        assert_eq!(set.len(), NUM_ELEMENTS as usize / 2, "Incorrect size after removal");
3557
3558        for i in 0..NUM_ELEMENTS {
3559            if i % 2 == 0 {
3560                assert!(set.contains(&i), "Even number {} should be in the set", i);
3561            } else {
3562                assert!(!set.contains(&i), "Odd number {} should not be in the set", i);
3563            }
3564        }
3565    }
3566
3567    #[test]
3568    fn test_remove_all_elements() {
3569        let set = BTreeSet::<i32>::new();
3570        let n = 2048;
3571
3572        for i in 0..n {
3573            set.insert(i);
3574        }
3575
3576        for i in 0..n {
3577            assert!(set.remove(&i).is_some(), "Failed to remove {}", i);
3578        }
3579
3580        assert_eq!(set.len(), 0, "Set should be empty");
3581
3582        for i in 0..n {
3583            assert!(!set.contains(&i), "Element {} should not be in the set", i);
3584        }
3585    }
3586
3587    #[test]
3588    fn test_range_edge_cases() {
3589        let set = BTreeSet::<i32>::with_maximum_node_size(10);
3590        for i in 0..20 {
3591            set.insert(i);
3592        }
3593        // Nodes are:
3594        // [0, 1, 2, 3, 4]
3595        // [5, 6, 7, 8, 9]
3596        // [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
3597
3598        // First value of the node only
3599        assert_eq!(set.range(0..=0).collect::<Vec<_>>(), vec![0]);
3600        assert_eq!(set.range(0..1).collect::<Vec<_>>(), vec![0]);
3601
3602        assert_eq!(set.range(5..=5).collect::<Vec<_>>(), vec![5]);
3603        assert_eq!(set.range(5..6).collect::<Vec<_>>(), vec![5]);
3604
3605        assert_eq!(set.range(10..=10).collect::<Vec<_>>(), vec![10]);
3606        assert_eq!(set.range(10..11).collect::<Vec<_>>(), vec![10]);
3607
3608        // From first value to middle
3609        assert_eq!(set.range(0..=3).collect::<Vec<_>>(), vec![0, 1, 2, 3]);
3610        assert_eq!(set.range(0..3).collect::<Vec<_>>(), vec![0, 1, 2]);
3611
3612        assert_eq!(set.range(5..=8).collect::<Vec<_>>(), vec![5, 6, 7, 8]);
3613        assert_eq!(set.range(5..8).collect::<Vec<_>>(), vec![5, 6, 7]);
3614
3615        assert_eq!(set.range(10..=13).collect::<Vec<_>>(), vec![10, 11, 12, 13]);
3616        assert_eq!(set.range(10..13).collect::<Vec<_>>(), vec![10, 11, 12]);
3617
3618        // Last value of the node
3619        assert_eq!(set.range(4..=4).collect::<Vec<_>>(), vec![4]);
3620        assert_eq!(set.range(4..5).collect::<Vec<_>>(), vec![4]);
3621
3622        assert_eq!(set.range(9..=9).collect::<Vec<_>>(), vec![9]);
3623        assert_eq!(set.range(9..10).collect::<Vec<_>>(), vec![9]);
3624
3625        assert_eq!(set.range(19..=19).collect::<Vec<_>>(), vec![19]);
3626        assert_eq!(set.range(19..20).collect::<Vec<_>>(), vec![19]);
3627
3628        // From middle to last value of the node
3629        assert_eq!(set.range(17..=19).collect::<Vec<_>>(), vec![17, 18, 19]);
3630        assert_eq!(set.range(17..20).collect::<Vec<_>>(), vec![17, 18, 19]);
3631
3632        assert_eq!(set.range(7..=9).collect::<Vec<_>>(), vec![7, 8, 9]);
3633        assert_eq!(set.range(7..10).collect::<Vec<_>>(), vec![7, 8, 9]);
3634
3635        assert_eq!(set.range(2..=4).collect::<Vec<_>>(), vec![2, 3, 4]);
3636        assert_eq!(set.range(2..5).collect::<Vec<_>>(), vec![2, 3, 4]);
3637
3638        // Full node
3639        assert_eq!(set.range(0..=4).collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
3640        assert_eq!(set.range(0..5).collect::<Vec<_>>(), vec![0, 1, 2, 3, 4]);
3641
3642        assert_eq!(set.range(5..=9).collect::<Vec<_>>(), vec![5, 6, 7, 8, 9]);
3643        assert_eq!(set.range(5..10).collect::<Vec<_>>(), vec![5, 6, 7, 8, 9]);
3644
3645        assert_eq!(
3646            set.range(10..=19).collect::<Vec<_>>(),
3647            vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
3648        );
3649        assert_eq!(
3650            set.range(10..20).collect::<Vec<_>>(),
3651            vec![10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
3652        );
3653
3654        // Node intersection
3655        assert_eq!(set.range(3..=6).collect::<Vec<_>>(), vec![3, 4, 5, 6]);
3656        assert_eq!(set.range(3..7).collect::<Vec<_>>(), vec![3, 4, 5, 6]);
3657
3658        assert_eq!(set.range(8..=11).collect::<Vec<_>>(), vec![8, 9, 10, 11]);
3659        assert_eq!(set.range(8..12).collect::<Vec<_>>(), vec![8, 9, 10, 11]);
3660
3661        // REVERSED
3662
3663        // First value of the node only
3664        assert_eq!(set.range(0..=0).rev().collect::<Vec<_>>(), vec![0]);
3665        assert_eq!(set.range(0..1).rev().collect::<Vec<_>>(), vec![0]);
3666
3667        assert_eq!(set.range(5..=5).rev().collect::<Vec<_>>(), vec![5]);
3668        assert_eq!(set.range(5..6).rev().collect::<Vec<_>>(), vec![5]);
3669
3670        assert_eq!(set.range(10..=10).rev().collect::<Vec<_>>(), vec![10]);
3671        assert_eq!(set.range(10..11).rev().collect::<Vec<_>>(), vec![10]);
3672
3673        // From first value to middle
3674        assert_eq!(set.range(0..=3).rev().collect::<Vec<_>>(), vec![3, 2, 1, 0]);
3675        assert_eq!(set.range(0..3).rev().collect::<Vec<_>>(), vec![2, 1, 0]);
3676
3677        assert_eq!(set.range(5..=8).rev().collect::<Vec<_>>(), vec![8, 7, 6, 5]);
3678        assert_eq!(set.range(5..8).rev().collect::<Vec<_>>(), vec![7, 6, 5]);
3679
3680        assert_eq!(set.range(10..=13).rev().collect::<Vec<_>>(), vec![13, 12, 11, 10]);
3681        assert_eq!(set.range(10..13).rev().collect::<Vec<_>>(), vec![12, 11, 10]);
3682
3683        // Last value of the node
3684        assert_eq!(set.range(4..=4).rev().collect::<Vec<_>>(), vec![4]);
3685        assert_eq!(set.range(4..5).rev().collect::<Vec<_>>(), vec![4]);
3686
3687        assert_eq!(set.range(9..=9).rev().collect::<Vec<_>>(), vec![9]);
3688        assert_eq!(set.range(9..10).rev().collect::<Vec<_>>(), vec![9]);
3689
3690        assert_eq!(set.range(19..=19).rev().collect::<Vec<_>>(), vec![19]);
3691        assert_eq!(set.range(19..20).rev().collect::<Vec<_>>(), vec![19]);
3692
3693        // From middle to last value of the node
3694        assert_eq!(set.range(17..=19).rev().collect::<Vec<_>>(), vec![19, 18, 17]);
3695        assert_eq!(set.range(17..20).rev().collect::<Vec<_>>(), vec![19, 18, 17]);
3696
3697        assert_eq!(set.range(7..=9).rev().collect::<Vec<_>>(), vec![9, 8, 7]);
3698        assert_eq!(set.range(7..10).rev().collect::<Vec<_>>(), vec![9, 8, 7]);
3699
3700        assert_eq!(set.range(2..=4).rev().collect::<Vec<_>>(), vec![4, 3, 2]);
3701        assert_eq!(set.range(2..5).rev().collect::<Vec<_>>(), vec![4, 3, 2]);
3702
3703        // Full node
3704        assert_eq!(set.range(0..=4).rev().collect::<Vec<_>>(), vec![4, 3, 2, 1, 0]);
3705        assert_eq!(set.range(0..5).rev().collect::<Vec<_>>(), vec![4, 3, 2, 1, 0]);
3706
3707        assert_eq!(set.range(5..=9).rev().collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
3708        assert_eq!(set.range(5..10).rev().collect::<Vec<_>>(), vec![9, 8, 7, 6, 5]);
3709
3710        assert_eq!(
3711            set.range(10..=19).rev().collect::<Vec<_>>(),
3712            vec![19, 18, 17, 16, 15, 14, 13, 12, 11, 10]
3713        );
3714        assert_eq!(
3715            set.range(10..20).rev().collect::<Vec<_>>(),
3716            vec![19, 18, 17, 16, 15, 14, 13, 12, 11, 10]
3717        );
3718
3719        // Node intersection
3720        assert_eq!(set.range(3..=6).rev().collect::<Vec<_>>(), vec![6, 5, 4, 3]);
3721        assert_eq!(set.range(3..7).rev().collect::<Vec<_>>(), vec![6, 5, 4, 3]);
3722
3723        assert_eq!(set.range(8..=11).rev().collect::<Vec<_>>(), vec![11, 10, 9, 8]);
3724        assert_eq!(set.range(8..12).rev().collect::<Vec<_>>(), vec![11, 10, 9, 8]);
3725
3726        // Non-existent range
3727        assert!(set.range(20..).collect::<Vec<_>>().is_empty());
3728        assert!(set.range(..0).collect::<Vec<_>>().is_empty());
3729        assert!(set.range(20..).rev().collect::<Vec<_>>().is_empty());
3730        assert!(set.range(..0).rev().collect::<Vec<_>>().is_empty());
3731    }
3732
3733    #[test]
3734    fn concurrent_range_constructions_at_node_boundaries_do_not_deadlock() {
3735        const THREAD_ITERATIONS: usize = 20_000;
3736
3737        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(4));
3738        for value in 0..64 {
3739            set.insert(value);
3740        }
3741
3742        // One thread constructs ranges whose start sits at node minima
3743        // (locking a node, then its predecessor); the other constructs
3744        // ranges whose end sits at node maxima (locking a node, then its
3745        // successor). Pre-fix these acquisitions ran in opposite orders
3746        // while both locks were held, an ABBA deadlock.
3747        let (done_tx, done_rx) = mpsc::channel();
3748        let forward = {
3749            let set = Arc::clone(&set);
3750            let done_tx = done_tx.clone();
3751            thread::spawn(move || {
3752                for iteration in 0..THREAD_ITERATIONS {
3753                    let start = (iteration % 64) as u64;
3754                    assert_eq!(set.range(start..).next(), Some(start));
3755                }
3756                done_tx.send(()).unwrap();
3757            })
3758        };
3759        let backward = {
3760            let set = Arc::clone(&set);
3761            let done_tx = done_tx.clone();
3762            thread::spawn(move || {
3763                for iteration in 0..THREAD_ITERATIONS {
3764                    let end = (iteration % 64) as u64;
3765                    assert_eq!(set.range(..=end).next_back(), Some(end));
3766                }
3767                done_tx.send(()).unwrap();
3768            })
3769        };
3770        drop(done_tx);
3771
3772        for _ in 0..2 {
3773            done_rx
3774                .recv_timeout(Duration::from_secs(30))
3775                .expect("concurrent range constructions deadlocked");
3776        }
3777        forward.join().unwrap();
3778        backward.join().unwrap();
3779    }
3780
3781    // Builds nodes [0, 10] (key 10), [20, 30] (key 30), [40, 50, 60] (key 60).
3782    fn three_node_set() -> BTreeSet<u64> {
3783        let set = BTreeSet::<u64>::with_maximum_node_size(4);
3784        for value in [0u64, 10, 20, 30, 40, 50, 60] {
3785            set.insert(value);
3786        }
3787        assert_eq!(
3788            set.index.read().keys().copied().collect::<Vec<_>>(),
3789            vec![10, 30, 60],
3790            "fixture geometry changed"
3791        );
3792        set
3793    }
3794
3795    #[test]
3796    fn forward_scan_repositions_when_current_node_vanishes() {
3797        let set = three_node_set();
3798
3799        let mut iter = set.iter();
3800        assert_eq!(iter.next(), Some(0));
3801        assert_eq!(iter.next(), Some(10));
3802        assert_eq!(iter.next(), Some(20));
3803
3804        // The node the iterator is parked in vanishes from the index, as
3805        // UpdateMax's remove-then-insert re-key does on every monotonic
3806        // insert. The scan must reposition, not end.
3807        set.index.write().remove(&30).expect("fixture entry");
3808
3809        assert_eq!(iter.next(), Some(30));
3810        assert_eq!(iter.next(), Some(40));
3811        assert_eq!(iter.next(), Some(50));
3812        assert_eq!(iter.next(), Some(60));
3813        assert_eq!(iter.next(), None);
3814    }
3815
3816    #[test]
3817    fn backward_scan_repositions_when_current_node_vanishes() {
3818        let set = three_node_set();
3819
3820        let mut iter = set.iter();
3821        assert_eq!(iter.next_back(), Some(60));
3822        assert_eq!(iter.next_back(), Some(50));
3823
3824        set.index.write().remove(&60).expect("fixture entry");
3825
3826        assert_eq!(iter.next_back(), Some(40));
3827        assert_eq!(iter.next_back(), Some(30));
3828        assert_eq!(iter.next_back(), Some(20));
3829        assert_eq!(iter.next_back(), Some(10));
3830        assert_eq!(iter.next_back(), Some(0));
3831        assert_eq!(iter.next_back(), None);
3832    }
3833
3834    #[test]
3835    fn forward_scan_does_not_re_yield_after_split_of_finished_node() {
3836        // Nodes [0, 10] (key 10) and [20, 30, 40] (key 40), as left behind by
3837        // a split of [0, 10, 20, 30].
3838        let set = BTreeSet::<u64>::with_maximum_node_size(4);
3839        for value in [0u64, 10, 20, 30, 40] {
3840            set.insert(value);
3841        }
3842
3843        // An iterator that had already yielded through 20 from the pre-split
3844        // node and just exhausted the lower half: advancing into the upper
3845        // half must not re-yield 20.
3846        let iter = Iter {
3847            tree: &set,
3848            current_front_batch: None,
3849            current_back_batch: None,
3850            exhausted_front_node: Some(set.index.read().first_key_value().expect("fixture node").1.clone()),
3851            exhausted_back_node: None,
3852            front_partial: None,
3853            back_partial: None,
3854            front_batch_limit: INITIAL_BATCH,
3855            back_batch_limit: INITIAL_BATCH,
3856            current_front_value: Some(20),
3857            current_back_value: None,
3858            met: false,
3859        };
3860
3861        assert_eq!(iter.collect::<Vec<_>>(), vec![30, 40]);
3862    }
3863
3864    #[test]
3865    fn backward_scan_does_not_re_yield_values_from_scanned_range() {
3866        // A stale-key window: the front node's maximum (35) grew past its
3867        // index key (10) while the backward scan had already advanced below
3868        // 30. Advancing into that node must not yield 35 again.
3869        let set = BTreeSet::<u64>::new();
3870        set.attach_node(vec![0u64, 10]);
3871        set.attach_node(vec![30u64, 40]);
3872        {
3873            let node = set.index.read().first_key_value().expect("fixture node").1.clone();
3874            let mut guard = node.write();
3875            NodeLike::insert(&mut *guard, 35u64);
3876        }
3877
3878        let mut iter = Iter {
3879            tree: &set,
3880            current_front_batch: None,
3881            current_back_batch: None,
3882            exhausted_front_node: None,
3883            exhausted_back_node: Some(set.index.read().last_key_value().expect("fixture node").1.clone()),
3884            front_partial: None,
3885            back_partial: None,
3886            front_batch_limit: INITIAL_BATCH,
3887            back_batch_limit: INITIAL_BATCH,
3888            current_front_value: None,
3889            current_back_value: Some(30),
3890            met: false,
3891        };
3892
3893        let mut collected = vec![];
3894        while let Some(value) = iter.next_back() {
3895            collected.push(value);
3896        }
3897        assert_eq!(collected, vec![10, 0]);
3898    }
3899
3900    #[test]
3901    fn backward_scan_does_not_skip_values_split_away_after_positioning() {
3902        // The heavy-tier churn failure in deterministic form. A backward
3903        // scan chooses its node (at construction or when advancing) and only
3904        // later locks it to read. A split committed in that window keeps the
3905        // node's LOWER half in the chosen Arc and moves the upper half to a
3906        // new node: values the scan has not yielded yet migrate above its
3907        // resume point and are silently skipped. Node selection and the
3908        // content read must be one atomic step under the structural guard.
3909        let set = BTreeSet::<u64>::with_maximum_node_size(4);
3910        for value in [0u64, 10, 20, 30] {
3911            set.insert(value);
3912        }
3913
3914        // Position the scan on the (single) node...
3915        let mut iter = set.iter();
3916        // ...then let a writer split it before the scan reads anything:
3917        // [0, 10] stays in the original Arc, [20, 30, 40] moves to a new
3918        // node above it.
3919        set.insert(40);
3920        assert!(set.node_count() > 1, "fixture must split");
3921
3922        let mut collected = vec![];
3923        while let Some(value) = iter.next_back() {
3924            collected.push(value);
3925        }
3926
3927        // 40 was inserted mid-scan, so a weakly consistent scan may or may
3928        // not observe it; every baseline value must be yielded. (Linear
3929        // scan on purpose: with NodeLike in scope, Vec::contains resolves
3930        // to NodeLike's binary search, which is wrong on this descending
3931        // vector.)
3932        for baseline in [30u64, 20, 10, 0] {
3933            assert!(
3934                collected.iter().any(|value| *value == baseline),
3935                "baseline value {baseline} skipped by backward scan (yielded: {collected:?})"
3936            );
3937        }
3938        assert!(
3939            collected.windows(2).all(|pair| pair[0] > pair[1]),
3940            "backward scan not strictly decreasing: {collected:?}"
3941        );
3942    }
3943
3944    #[test]
3945    fn bidirectional_meet_into_opposite_held_node_does_not_self_deadlock() {
3946        // Nodes [0, 10] (key 10) and [20, 30, 40] (key 40).
3947        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(4));
3948        for value in [0u64, 10, 20, 30, 40] {
3949            set.insert(value);
3950        }
3951
3952        let (done_tx, done_rx) = mpsc::channel();
3953        let handle = {
3954            let set = Arc::clone(&set);
3955            thread::spawn(move || {
3956                // The back cursor enters the final node, then the forward
3957                // end exhausts the first node and must enter the node the
3958                // back cursor is positioned in to yield the middle. Under
3959                // the guard-holding design this double-locked the
3960                // non-reentrant node mutex; owned batches must keep this
3961                // lock-free.
3962                let mut finished = set.iter();
3963                assert_eq!(finished.next_back(), Some(40));
3964                assert_eq!(finished.next(), Some(0));
3965                assert_eq!(finished.next(), Some(10));
3966                assert_eq!(finished.next(), Some(20));
3967                assert_eq!(finished.next(), Some(30));
3968                assert_eq!(finished.next(), None);
3969                assert_eq!(finished.next_back(), None);
3970
3971                // `finished` met in the middle and stays alive: a finished
3972                // iterator must hold no node locks, or the next lock of its
3973                // final node (here by a second iterator on the same thread)
3974                // self-deadlocks.
3975                let mut iter = set.iter();
3976                assert_eq!(iter.next(), Some(0));
3977                assert_eq!(iter.next_back(), Some(40));
3978                assert_eq!(iter.next_back(), Some(30));
3979                assert_eq!(iter.next_back(), Some(20));
3980                assert_eq!(iter.next_back(), Some(10));
3981                assert_eq!(iter.next_back(), None);
3982                assert_eq!(iter.next(), None);
3983                drop(finished);
3984
3985                done_tx.send(()).unwrap();
3986            })
3987        };
3988
3989        done_rx
3990            .recv_timeout(Duration::from_secs(10))
3991            .expect("bidirectional meet-in-the-middle deadlocked");
3992        handle.join().unwrap();
3993    }
3994
3995    #[test]
3996    fn structural_commits_complete_against_paused_scan() {
3997        // Several tiny nodes; the scan will pin the first one.
3998        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(2));
3999        for value in 0..8 {
4000            set.insert(value);
4001        }
4002
4003        let scan_holds_guard = Arc::new(Barrier::new(3));
4004        let (done_tx, done_rx) = mpsc::channel();
4005
4006        let scanner = {
4007            let set = Arc::clone(&set);
4008            let scan_holds_guard = Arc::clone(&scan_holds_guard);
4009            let done_tx = done_tx.clone();
4010            thread::spawn(move || {
4011                let mut iter = set.iter();
4012                // A paused scan must hold no node lock between calls;
4013                // under the guard-holding design the first node's mutex
4014                // stayed pinned here.
4015                assert_eq!(iter.next(), Some(0));
4016                scan_holds_guard.wait();
4017                // Give the writer time to take the structural write lock
4018                // and the first node's mutex while the scan is parked.
4019                thread::sleep(Duration::from_millis(100));
4020                // Resuming in the opposite direction acquires the
4021                // structural read guard; if the scan still held a node
4022                // mutex here it would deadlock ABBA against the writer
4023                // (writer: topology -> node).
4024                let mut collected = vec![];
4025                while let Some(value) = iter.next_back() {
4026                    collected.push(value);
4027                }
4028                assert_eq!(collected, vec![7, 6, 5, 4, 3, 2, 1]);
4029                done_tx.send(()).unwrap();
4030            })
4031        };
4032
4033        let writer = {
4034            let set = Arc::clone(&set);
4035            let scan_holds_guard = Arc::clone(&scan_holds_guard);
4036            let done_tx = done_tx.clone();
4037            thread::spawn(move || {
4038                scan_holds_guard.wait();
4039                // remove_range acquires the structural write lock and then
4040                // locks the node pinned by the scanner.
4041                set.remove_range(0..=0);
4042                done_tx.send(()).unwrap();
4043            })
4044        };
4045        drop(done_tx);
4046        scan_holds_guard.wait();
4047
4048        for _ in 0..2 {
4049            done_rx
4050                .recv_timeout(Duration::from_secs(10))
4051                .expect("scan or structural commit deadlocked");
4052        }
4053        scanner.join().unwrap();
4054        writer.join().unwrap();
4055        assert!(!set.contains(&0));
4056    }
4057
4058    #[test]
4059    fn full_scans_do_not_degrade_quadratically_with_node_count() {
4060        use std::time::Instant;
4061
4062        // Many tiny nodes: the node-advance cost dominates the scan.
4063        const VALUES: u64 = 30_000;
4064        let set = BTreeSet::<u64>::with_maximum_node_size(2);
4065        for value in 0..VALUES {
4066            set.insert(value);
4067        }
4068        assert!(
4069            set.node_count() >= (VALUES / 4) as usize,
4070            "fixture must be a many-node tree, got {} nodes",
4071            set.node_count()
4072        );
4073
4074        let started = Instant::now();
4075        assert_eq!(set.iter().count(), VALUES as usize);
4076        let forward = started.elapsed();
4077
4078        let started = Instant::now();
4079        assert_eq!(set.iter().rev().count(), VALUES as usize);
4080        let backward = started.elapsed();
4081
4082        // Advancing between nodes costs one logarithmic index lookup, so both
4083        // scans finish in milliseconds even in a debug build. The removed
4084        // linear identity relocation made each advance walk the index from
4085        // the front (~N^2/2 entry visits per scan, well over a minute at this
4086        // node count), so the generous budget still fails it decisively.
4087        let budget = Duration::from_secs(10);
4088        assert!(
4089            forward < budget,
4090            "forward scan took {forward:?}, node advance is not logarithmic"
4091        );
4092        assert!(
4093            backward < budget,
4094            "backward scan took {backward:?}, node advance is not logarithmic"
4095        );
4096    }
4097
4098    #[test]
4099    fn scans_stay_sorted_and_complete_under_monotonic_insert_churn() {
4100        use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
4101
4102        const BASELINE: u64 = 400;
4103        const EXTRA: u64 = 2_000;
4104        const SCAN_BOUND: usize = 10_000;
4105
4106        // Small nodes: every monotonic insert re-keys the last node and
4107        // regularly splits it, exercising the reposition paths constantly.
4108        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(8));
4109        for value in 0..BASELINE {
4110            set.insert(value);
4111        }
4112
4113        let done = Arc::new(AtomicBool::new(false));
4114        let writer = {
4115            let set = Arc::clone(&set);
4116            let done = Arc::clone(&done);
4117            thread::spawn(move || {
4118                for value in BASELINE..BASELINE + EXTRA {
4119                    assert!(set.insert(value));
4120                }
4121                done.store(true, AtomicOrdering::Release);
4122            })
4123        };
4124
4125        let mut scans = 0usize;
4126        loop {
4127            let forward = set.iter().collect::<Vec<_>>();
4128            assert!(
4129                forward.windows(2).all(|pair| pair[0] < pair[1]),
4130                "forward scan not strictly increasing (duplicate or unordered yield)"
4131            );
4132            assert_eq!(
4133                forward.iter().filter(|value| **value < BASELINE).count() as u64,
4134                BASELINE,
4135                "forward scan truncated: baseline keys missing"
4136            );
4137
4138            let backward = set.iter().rev().collect::<Vec<_>>();
4139            assert!(
4140                backward.windows(2).all(|pair| pair[0] > pair[1]),
4141                "backward scan not strictly decreasing (duplicate or unordered yield)"
4142            );
4143            assert_eq!(
4144                backward.iter().filter(|value| **value < BASELINE).count() as u64,
4145                BASELINE,
4146                "backward scan truncated: baseline keys missing"
4147            );
4148
4149            scans += 1;
4150            if done.load(AtomicOrdering::Acquire) || scans >= SCAN_BOUND {
4151                break;
4152            }
4153        }
4154
4155        writer.join().unwrap();
4156
4157        let expected = (0..BASELINE + EXTRA).collect::<Vec<_>>();
4158        assert_eq!(set.iter().collect::<Vec<_>>(), expected);
4159        assert_eq!(set.iter().rev().collect::<Vec<_>>(), {
4160            let mut reversed = expected;
4161            reversed.reverse();
4162            reversed
4163        });
4164    }
4165
4166    #[test]
4167    fn collected_owned_values_survive_arbitrary_concurrent_mutation() {
4168        use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering};
4169
4170        const BASELINE: u64 = 512;
4171        const CHURN: u64 = 4_000;
4172
4173        // Small nodes so the churn constantly splits, re-keys, and unlinks
4174        // the nodes the scans are walking.
4175        let set = Arc::new(BTreeSet::<u64>::with_maximum_node_size(8));
4176        for value in 0..BASELINE {
4177            set.insert(value);
4178        }
4179
4180        let done = Arc::new(AtomicBool::new(false));
4181        let writer = {
4182            let set = Arc::clone(&set);
4183            let done = Arc::clone(&done);
4184            thread::spawn(move || {
4185                for value in BASELINE..BASELINE + CHURN {
4186                    assert!(set.insert(value));
4187                    assert_eq!(set.remove(&value), Some(value));
4188                }
4189                done.store(true, AtomicOrdering::Release);
4190            })
4191        };
4192
4193        // The type annotation is the point: collect() yields owned values,
4194        // not references tied to node storage. Under the previous borrowed
4195        // design this collected Vec<&u64> whose referents were unlocked node
4196        // slots, a use-after-free under exactly this churn.
4197        let mut snapshots: Vec<Vec<u64>> = Vec::new();
4198        loop {
4199            let snapshot: Vec<u64> = set.iter().collect();
4200            snapshots.push(snapshot);
4201            if done.load(AtomicOrdering::Acquire) {
4202                break;
4203            }
4204        }
4205        writer.join().unwrap();
4206
4207        // Mutate the set arbitrarily after the snapshots were taken; the
4208        // snapshots must remain fully usable because they own their values.
4209        set.remove_range(..);
4210        assert!(set.is_empty());
4211
4212        for snapshot in snapshots {
4213            assert!(
4214                snapshot.windows(2).all(|pair| pair[0] < pair[1]),
4215                "snapshot not strictly increasing"
4216            );
4217            assert_eq!(
4218                snapshot.iter().filter(|value| **value < BASELINE).count() as u64,
4219                BASELINE,
4220                "snapshot lost baseline keys"
4221            );
4222        }
4223    }
4224
4225    #[test]
4226    fn parallel_iter_and_mut() {
4227        let set = Arc::new(BTreeSet::<i32>::new());
4228        for i in 0..10_000 {
4229            set.insert(i);
4230        }
4231
4232        let set_clone = Arc::clone(&set);
4233        let handle = thread::spawn(move || {
4234            for _ in 0..1000 {
4235                let mut _sum = 0;
4236                for value in set_clone.iter() {
4237                    _sum += value;
4238                }
4239            }
4240        });
4241
4242        for i in 10_000..20_000 {
4243            set.insert(i);
4244        }
4245        handle.join().unwrap();
4246    }
4247
4248    /// A scan that spans several batch installs inside one node yields every
4249    /// element, once, in order.
4250    ///
4251    /// The batch is bounded and grows, so a node larger than `INITIAL_BATCH` is
4252    /// consumed over several installs rather than one. Each install re-selects
4253    /// the node by cursor and skips what has already been taken, which is where
4254    /// a partial batch can silently drop or repeat elements. A whole-node batch
4255    /// could not get this wrong because it never resumed inside a node.
4256    #[test]
4257    fn a_scan_across_several_batch_installs_is_complete_and_ordered() {
4258        let set: BTreeSet<u64> = BTreeSet::new();
4259        // Comfortably more than INITIAL_BATCH, and more than the first few
4260        // doublings, so the scan resumes inside a node repeatedly.
4261        let count = (INITIAL_BATCH * 20) as u64;
4262        for i in 0..count {
4263            set.insert(i);
4264        }
4265
4266        let seen: Vec<u64> = set.iter().collect();
4267        let expected: Vec<u64> = (0..count).collect();
4268        assert_eq!(seen, expected, "a partial-batch scan lost or repeated elements");
4269    }
4270
4271    /// The same property backwards.
4272    #[test]
4273    fn a_backward_scan_across_several_installs_is_complete_and_ordered() {
4274        let set: BTreeSet<u64> = BTreeSet::new();
4275        let count = (INITIAL_BATCH * 20) as u64;
4276        for i in 0..count {
4277            set.insert(i);
4278        }
4279
4280        let seen: Vec<u64> = set.iter().rev().collect();
4281        let expected: Vec<u64> = (0..count).rev().collect();
4282        assert_eq!(
4283            seen, expected,
4284            "a partial-batch backward scan lost or repeated elements"
4285        );
4286    }
4287
4288    /// A scan over a node big enough to hold everything, so every install after
4289    /// the first resumes inside the same node.
4290    #[test]
4291    fn a_scan_within_a_single_node_resumes_correctly() {
4292        let set: BTreeSet<u64> = BTreeSet::with_maximum_node_size(DEFAULT_INNER_SIZE);
4293        let count = 200u64;
4294        for i in 0..count {
4295            set.insert(i);
4296        }
4297        assert_eq!(set.node_count(), 1, "fixture wants one node");
4298
4299        let seen: Vec<u64> = set.iter().collect();
4300        assert_eq!(seen, (0..count).collect::<Vec<_>>());
4301    }
4302
4303    /// A one-element range yields exactly that element.
4304    ///
4305    /// The case the bounded batch exists for: this used to clone every
4306    /// remaining element of the node it landed in to produce one value.
4307    #[test]
4308    fn a_single_element_range_yields_one_element() {
4309        let set: BTreeSet<u64> = BTreeSet::new();
4310        for i in 0..1_000u64 {
4311            set.insert(i);
4312        }
4313
4314        for probe in [0u64, 1, 499, 998, 999] {
4315            let got: Vec<u64> = set.range(probe..=probe).collect();
4316            assert_eq!(got, vec![probe], "range({probe}..={probe})");
4317        }
4318        assert!(set.range(1_000..=1_000).next().is_none(), "absent key");
4319    }
4320
4321    /// Ranges of every width across a batch boundary.
4322    ///
4323    /// Widths either side of `INITIAL_BATCH` and its first doublings are where
4324    /// an off-by-one in the resume arithmetic shows up, and nowhere else.
4325    #[test]
4326    fn ranges_spanning_batch_boundaries_are_exact() {
4327        let set: BTreeSet<u64> = BTreeSet::new();
4328        for i in 0..500u64 {
4329            set.insert(i);
4330        }
4331
4332        for width in 1..=(INITIAL_BATCH * 8) as u64 {
4333            let start = 100u64;
4334            let got: Vec<u64> = set.range(start..start + width).collect();
4335            let expected: Vec<u64> = (start..start + width).collect();
4336            assert_eq!(got, expected, "range width {width}");
4337        }
4338    }
4339
4340    /// Meeting in the middle still terminates and yields each element once.
4341    ///
4342    /// Both cursors now resume inside nodes, so the point at which they meet is
4343    /// reached through a different sequence of installs than before.
4344    #[test]
4345    fn a_double_ended_scan_meets_without_repeating() {
4346        let set: BTreeSet<u64> = BTreeSet::new();
4347        let count = (INITIAL_BATCH * 10) as u64;
4348        for i in 0..count {
4349            set.insert(i);
4350        }
4351
4352        let mut iter = set.iter();
4353        let mut front = Vec::new();
4354        let mut back = Vec::new();
4355        loop {
4356            match iter.next() {
4357                Some(v) => front.push(v),
4358                None => break,
4359            }
4360            match iter.next_back() {
4361                Some(v) => back.push(v),
4362                None => break,
4363            }
4364        }
4365        back.reverse();
4366        front.extend(back);
4367        front.sort_unstable();
4368        assert_eq!(
4369            front,
4370            (0..count).collect::<Vec<_>>(),
4371            "double-ended scan is not a partition"
4372        );
4373    }
4374
4375    /// A scan under concurrent mutation terminates and does not stream
4376    /// duplicates forever.
4377    ///
4378    /// This is the case the partial-skip guard exists for, and it cannot be
4379    /// reached from one thread. A batch that stops short of a node's end
4380    /// resumes inside that node by cursor rank; a concurrent split or re-key
4381    /// can leave that rank *below* elements already yielded, the yield path
4382    /// then drops the whole batch as duplicates, and the next install computes
4383    /// the same skip again. Without the recorded take count that is a scan
4384    /// which never advances.
4385    ///
4386    /// A stall is asserted as a bound rather than by waiting: the scan is
4387    /// capped, and a run that reaches the cap is one that was not making
4388    /// progress. Removing the guard makes this fail rather than hang, which is
4389    /// the difference between a test and a timeout.
4390    #[test]
4391    fn a_scan_under_concurrent_mutation_terminates() {
4392        use std::sync::atomic::{AtomicBool, Ordering};
4393        use std::sync::Arc;
4394
4395        const SIZE: u64 = 4_000;
4396        // Generous: any honest scan yields at most SIZE plus whatever is
4397        // inserted while it runs. Reaching this many means it is looping.
4398        const CAP: usize = (SIZE * 20) as usize;
4399
4400        for _ in 0..8 {
4401            let set: Arc<BTreeSet<u64>> = Arc::new(BTreeSet::new());
4402            for i in 0..SIZE {
4403                set.insert(i);
4404            }
4405            let stop = Arc::new(AtomicBool::new(false));
4406
4407            // Churn that forces splits and re-keys under the scan.
4408            let writers: Vec<_> = (0..3)
4409                .map(|w| {
4410                    let (set, stop) = (Arc::clone(&set), Arc::clone(&stop));
4411                    std::thread::spawn(move || {
4412                        let mut i = SIZE + w * 100_000;
4413                        while !stop.load(Ordering::Relaxed) {
4414                            set.insert(i);
4415                            set.remove(&i);
4416                            i += 1;
4417                        }
4418                    })
4419                })
4420                .collect();
4421
4422            let mut yielded = 0usize;
4423            for _ in set.iter() {
4424                yielded += 1;
4425                if yielded >= CAP {
4426                    break;
4427                }
4428            }
4429
4430            stop.store(true, Ordering::Relaxed);
4431            for w in writers {
4432                w.join().expect("writer did not panic");
4433            }
4434
4435            assert!(
4436                yielded < CAP,
4437                "scan did not make progress under concurrent mutation: {yielded} yields"
4438            );
4439        }
4440    }
4441
4442    /// `Vec::contains` is not usable in this module: `NodeLike` is in scope and
4443    /// its `contains` for `Vec<T>` is a *binary search*, which silently answers
4444    /// nonsense for any sequence that is not sorted ascending. A scan's output
4445    /// is exactly such a sequence when it runs backwards.
4446    // Clippy suggests `seen.contains(&value)` here. Taking that suggestion
4447    // reintroduces the exact bug this helper exists to avoid, which is why the
4448    // lint is silenced rather than followed.
4449    #[allow(clippy::manual_contains)]
4450    fn yielded(seen: &[u64], value: u64) -> bool {
4451        seen.iter().any(|item| *item == value)
4452    }
4453
4454    /// WTI-1: `front_partial` counts *positions*, and a position is not a
4455    /// stable cursor under deletion.
4456    ///
4457    /// Deleting an element the scan already yielded shifts the unyielded tail
4458    /// left while the recorded count stays put, so the stale position wins the
4459    /// `max` and steps over a live element. Key `0` is removed after it has
4460    /// been yielded; every key above it was present for the whole scan and must
4461    /// still appear, which is what the iterator promises.
4462    ///
4463    /// The prefix is swept because the defect only bites when the deletion
4464    /// lands while the scan is partway through a node, and where that boundary
4465    /// falls depends on the doubling batch limit.
4466    #[test]
4467    fn deleting_a_yielded_element_does_not_skip_a_live_one() {
4468        for prefix in 1..12usize {
4469            let set: BTreeSet<u64> = BTreeSet::new();
4470            for i in 0..256u64 {
4471                set.insert(i);
4472            }
4473
4474            let mut seen = Vec::new();
4475            for value in set.iter() {
4476                seen.push(value);
4477                if seen.len() == prefix {
4478                    set.remove(&0);
4479                }
4480            }
4481
4482            for expected in 1..256u64 {
4483                assert!(
4484                    yielded(&seen, expected),
4485                    "prefix {prefix}: {expected} was present for the whole scan but was never yielded"
4486                );
4487            }
4488        }
4489    }
4490
4491    /// The backward mirror. `back_partial` trims from the end rather than
4492    /// skipping from the start, so the same staleness would drop an element off
4493    /// the low end of the scan.
4494    #[test]
4495    fn deleting_a_yielded_element_backwards_does_not_skip_a_live_one() {
4496        for prefix in 1..12usize {
4497            let set: BTreeSet<u64> = BTreeSet::new();
4498            for i in 0..256u64 {
4499                set.insert(i);
4500            }
4501
4502            let mut seen = Vec::new();
4503            for value in set.iter().rev() {
4504                seen.push(value);
4505                if seen.len() == prefix {
4506                    set.remove(&255);
4507                }
4508            }
4509
4510            for expected in 0..255u64 {
4511                assert!(
4512                    yielded(&seen, expected),
4513                    "prefix {prefix}: {expected} was present for the whole scan but was never yielded"
4514                );
4515            }
4516        }
4517    }
4518}