Skip to main content

left_right/
write.rs

1use crate::read::ReadHandle;
2use crate::sync::{fence, Arc, AtomicUsize, MutexGuard, Ordering};
3use crate::Absorb;
4use crossbeam_utils::CachePadded;
5use std::collections::VecDeque;
6use std::marker::PhantomData;
7use std::ops::DerefMut;
8use std::ptr::NonNull;
9use std::{fmt, thread};
10
11#[cfg(test)]
12use std::sync::atomic::AtomicBool;
13
14/// A writer handle to a left-right guarded data structure.
15///
16/// All operations on the underlying data should be enqueued as operations of type `O` using
17/// [`append`](Self::append). The effect of this operations are only exposed to readers once
18/// [`publish`](Self::publish) is called.
19///
20/// # Reading through a `WriteHandle`
21///
22/// `WriteHandle` allows access to a [`ReadHandle`] through `Deref<Target = ReadHandle>`. Note that
23/// since the reads go through a [`ReadHandle`], those reads are subject to the same visibility
24/// restrictions as reads that do not go through the `WriteHandle`: they only see the effects of
25/// operations prior to the last call to [`publish`](Self::publish).
26pub struct WriteHandle<T, O>
27where
28    T: Absorb<O>,
29{
30    epochs: crate::Epochs,
31    w_handle: NonNull<T>,
32    oplog: VecDeque<O>,
33    swap_index: usize,
34    r_handle: ReadHandle<T>,
35    last_epochs: Vec<usize>,
36    #[cfg(test)]
37    refreshes: usize,
38    #[cfg(test)]
39    is_waiting: Arc<AtomicBool>,
40    /// Write directly to the write handle map, since no publish has happened.
41    first: bool,
42    /// A publish has happened, but the two copies have not been synchronized yet.
43    second: bool,
44    /// If we call `Self::take` the drop needs to be different.
45    taken: bool,
46}
47
48// safety: if a `WriteHandle` is sent across a thread boundary, we need to be able to take
49// ownership of both Ts and Os across that thread boundary. since `WriteHandle` holds a
50// `ReadHandle`, we also need to respect its Send requirements.
51unsafe impl<T, O> Send for WriteHandle<T, O>
52where
53    T: Absorb<O>,
54    T: Send,
55    O: Send,
56    ReadHandle<T>: Send,
57{
58}
59
60impl<T, O> fmt::Debug for WriteHandle<T, O>
61where
62    T: Absorb<O> + fmt::Debug,
63    O: fmt::Debug,
64{
65    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
66        f.debug_struct("WriteHandle")
67            .field("epochs", &self.epochs)
68            .field("w_handle", &self.w_handle)
69            .field("oplog", &self.oplog)
70            .field("swap_index", &self.swap_index)
71            .field("r_handle", &self.r_handle)
72            .field("first", &self.first)
73            .field("second", &self.second)
74            .finish()
75    }
76}
77
78/// A **smart pointer** to an owned backing data structure. This makes sure that the
79/// data is dropped correctly (using [`Absorb::drop_second`]).
80///
81/// Additionally it allows for unsafely getting the inner data out using [`into_box()`](Taken::into_box).
82pub struct Taken<T: Absorb<O>, O> {
83    inner: Option<Box<T>>,
84    _marker: PhantomData<O>,
85}
86
87impl<T: Absorb<O> + std::fmt::Debug, O> std::fmt::Debug for Taken<T, O> {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.debug_struct("Taken")
90            .field(
91                "inner",
92                self.inner
93                    .as_ref()
94                    .expect("inner is only taken in `into_box` which drops self"),
95            )
96            .finish()
97    }
98}
99
100impl<T: Absorb<O>, O> Deref for Taken<T, O> {
101    type Target = T;
102
103    fn deref(&self) -> &Self::Target {
104        self.inner
105            .as_ref()
106            .expect("inner is only taken in `into_box` which drops self")
107    }
108}
109
110impl<T: Absorb<O>, O> DerefMut for Taken<T, O> {
111    fn deref_mut(&mut self) -> &mut Self::Target {
112        self.inner
113            .as_mut()
114            .expect("inner is only taken in `into_box` which drops self")
115    }
116}
117
118impl<T: Absorb<O>, O> Taken<T, O> {
119    /// # Safety
120    ///
121    /// You must call [`Absorb::drop_second`] in case just dropping `T` is not safe and sufficient.
122    ///
123    /// If you used the default implementation of [`Absorb::drop_second`] (which just calls
124    /// [`drop`](Drop::drop)) you don't need to call [`Absorb::drop_second`].
125    pub unsafe fn into_box(mut self) -> Box<T> {
126        self.inner
127            .take()
128            .expect("inner is only taken here then self is dropped")
129    }
130}
131
132impl<T: Absorb<O>, O> Drop for Taken<T, O> {
133    fn drop(&mut self) {
134        if let Some(inner) = self.inner.take() {
135            T::drop_second(inner);
136        }
137    }
138}
139
140impl<T, O> WriteHandle<T, O>
141where
142    T: Absorb<O>,
143{
144    /// Takes out the inner backing data structure if it hasn't been taken yet. Otherwise returns `None`.
145    ///
146    /// Makes sure that all the pending operations are applied and waits till all the read handles
147    /// have departed. Then it uses [`Absorb::drop_first`] to drop one of the copies of the data and
148    /// returns the other copy as a [`Taken`] smart pointer.
149    fn take_inner(&mut self) -> Option<Taken<T, O>> {
150        use std::ptr;
151        // Can only take inner once.
152        if self.taken {
153            return None;
154        }
155
156        // Disallow taking again.
157        self.taken = true;
158
159        // first, ensure both copies are up to date
160        // (otherwise safely dropping the possibly duplicated w_handle data is a pain)
161        if self.first || !self.oplog.is_empty() {
162            self.publish();
163            // all writes are applied to at least one T
164        }
165        if !self.oplog.is_empty() {
166            self.publish();
167            // all writes are in both Ts (i.e., there are no pending writes)
168        }
169        assert!(self.oplog.is_empty());
170
171        // next, grab the read handle and set it to NULL
172        let r_handle = self.r_handle.inner.swap(ptr::null_mut(), Ordering::Release);
173
174        // now, wait for all readers to depart
175        let epochs = Arc::clone(&self.epochs);
176        let mut epochs = epochs.lock().unwrap();
177
178        // ensure that the subsequent epoch reads aren't re-ordered to before the swap
179        fence(Ordering::SeqCst);
180
181        // refresh `last_epochs` with a snapshot taken *after* the NULL swap above, otherwise we
182        // would only be waiting for the readers to have observed _some_ swap since the last
183        // publish, but not necessarily _our_ NULL swap. in particular, they may simply have
184        // observed the swap at the last publish.
185        self.last_epochs.resize(epochs.capacity(), 0);
186        for (ri, epoch) in epochs.iter() {
187            self.last_epochs[ri] = epoch.load(Ordering::Acquire);
188        }
189
190        // and now do the actual blocking loop until every reader has moved on
191        self.wait(&mut epochs);
192
193        // all readers have now observed the NULL, so we own both handles.
194        // all operations have been applied to both w_handle and r_handle.
195        // give the underlying data structure an opportunity to handle the one copy differently:
196        //
197        // safety: w_handle was initially crated from a `Box`, and is no longer aliased.
198        Absorb::drop_first(unsafe { Box::from_raw(self.w_handle.as_ptr()) });
199
200        // next we take the r_handle and return it as a boxed value.
201        //
202        // this is safe, since we know that no readers are using this pointer
203        // anymore (due to the .wait() following swapping the pointer with NULL).
204        //
205        // safety: r_handle was initially crated from a `Box`, and is no longer aliased.
206        let boxed_r_handle = unsafe { Box::from_raw(r_handle) };
207
208        Some(Taken {
209            inner: Some(boxed_r_handle),
210            _marker: PhantomData,
211        })
212    }
213}
214
215impl<T, O> Drop for WriteHandle<T, O>
216where
217    T: Absorb<O>,
218{
219    fn drop(&mut self) {
220        if let Some(inner) = self.take_inner() {
221            drop(inner);
222        }
223    }
224}
225
226impl<T, O> WriteHandle<T, O>
227where
228    T: Absorb<O>,
229{
230    pub(crate) fn new(w_handle: T, epochs: crate::Epochs, r_handle: ReadHandle<T>) -> Self {
231        Self {
232            epochs,
233            // safety: Box<T> is not null and covariant.
234            w_handle: unsafe { NonNull::new_unchecked(Box::into_raw(Box::new(w_handle))) },
235            oplog: VecDeque::new(),
236            swap_index: 0,
237            r_handle,
238            last_epochs: Vec::new(),
239            #[cfg(test)]
240            is_waiting: Arc::new(AtomicBool::new(false)),
241            #[cfg(test)]
242            refreshes: 0,
243            first: true,
244            second: true,
245            taken: false,
246        }
247    }
248
249    fn wait(&mut self, epochs: &mut MutexGuard<'_, slab::Slab<Arc<CachePadded<AtomicUsize>>>>) {
250        let mut iter = 0;
251        let mut starti = 0;
252
253        #[cfg(test)]
254        {
255            self.is_waiting.store(true, Ordering::Relaxed);
256        }
257        // we're over-estimating here, but slab doesn't expose its max index
258        // note that the defaulted value here is even, so new readers since the last publish won't
259        // be waited for. however, since they were created after the swap anyway, they must have
260        // observed that swap, and so we don't need to wait for them.
261        self.last_epochs.resize(epochs.capacity(), 0);
262        'retry: loop {
263            // read all and see if all have changed (which is likely)
264            for (ii, (ri, epoch)) in epochs.iter().enumerate().skip(starti) {
265                // if the reader's epoch was even last we read it (which was _after_ the swap),
266                // then they either do not have the pointer, or must have read the pointer strictly
267                // after the swap. in either case, they cannot be using the old pointer value (what
268                // is now w_handle).
269                //
270                // note that this holds even with wrap-around since std::u{N}::MAX == 2 ^ N - 1,
271                // which is odd, and std::u{N}::MAX + 1 == 0 is even.
272                //
273                // note also that `ri` _may_ have been re-used since we last read into last_epochs.
274                // this is okay though, as a change still implies that the new reader must have
275                // arrived _after_ we did the atomic swap, and thus must also have seen the new
276                // pointer.
277                if self.last_epochs[ri] % 2 == 0 {
278                    continue;
279                }
280
281                let now = epoch.load(Ordering::Acquire);
282                if now != self.last_epochs[ri] {
283                    // reader must have seen the last swap, since they have done at least one
284                    // operation since we last looked at their epoch, which _must_ mean that they
285                    // are no longer using the old pointer value.
286                } else {
287                    // reader may not have seen swap
288                    // continue from this reader's epoch
289                    starti = ii;
290
291                    if !cfg!(loom) {
292                        // how eagerly should we retry?
293                        if iter != 20 {
294                            iter += 1;
295                        } else {
296                            thread::yield_now();
297                        }
298                    }
299
300                    #[cfg(loom)]
301                    loom::thread::yield_now();
302
303                    continue 'retry;
304                }
305            }
306            break;
307        }
308        #[cfg(test)]
309        {
310            self.is_waiting.store(false, Ordering::Relaxed);
311        }
312    }
313
314    /// Try to publish once without waiting.
315    ///
316    /// This performs a single, non-blocking check of reader epochs. If all current readers have
317    /// advanced since the last swap, it performs a publish and returns `true`. If any reader may
318    /// still be accessing the old copy, it does nothing and returns `false`.
319    ///
320    /// Unlike [`publish`](Self::publish), this never spins or waits. Use it on latency-sensitive
321    /// paths where skipping a publish is preferable to blocking; call again later or fall back to
322    /// [`publish`](Self::publish) if you must ensure visibility.
323    ///
324    /// Returns `true` if a publish occurred, `false` otherwise.
325    pub fn try_publish(&mut self) -> bool {
326        let epochs = Arc::clone(&self.epochs);
327        let mut epochs = epochs.lock().unwrap();
328
329        // This wait loop is exactly like the one in wait, except that if we find a reader that
330        // has not observed the latest swap, we return rather than spin-and-retry.
331        self.last_epochs.resize(epochs.capacity(), 0);
332        for (ri, epoch) in epochs.iter() {
333            if self.last_epochs[ri] % 2 == 0 {
334                continue;
335            }
336
337            let now = epoch.load(Ordering::Acquire);
338            if now != self.last_epochs[ri] {
339                continue;
340            } else {
341                return false;
342            }
343        }
344        #[cfg(test)]
345        {
346            self.is_waiting.store(false, Ordering::Relaxed);
347        }
348        self.update_and_swap(&mut epochs);
349
350        true
351    }
352
353    /// Publish all operations append to the log to reads.
354    ///
355    /// This method needs to wait for all readers to move to the "other" copy of the data so that
356    /// it can replay the operational log onto the stale copy the readers used to use. This can
357    /// take some time, especially if readers are executing slow operations, or if there are many
358    /// of them.
359    pub fn publish(&mut self) -> &mut Self {
360        // we need to wait until all epochs have changed since the swaps *or* until a "finished"
361        // flag has been observed to be on for two subsequent iterations (there still may be some
362        // readers present since we did the previous refresh)
363        //
364        // NOTE: it is safe for us to hold the lock for the entire duration of the swap. we will
365        // only block on pre-existing readers, and they are never waiting to push onto epochs
366        // unless they have finished reading.
367        let epochs = Arc::clone(&self.epochs);
368        let mut epochs = epochs.lock().unwrap();
369        // on first publish, no readers are in the write_handle, so no need to wait.
370        if !self.first {
371            self.wait(&mut epochs);
372        }
373
374        self.update_and_swap(&mut epochs)
375    }
376
377    /// Brings `w_handle` up to date with the oplog, then swaps `r_handle` and `w_handle`.
378    ///
379    /// This method must only be called when all readers have exited `w_handle` (e.g., after
380    /// `wait`).
381    fn update_and_swap(
382        &mut self,
383        epochs: &mut MutexGuard<'_, slab::Slab<Arc<CachePadded<AtomicUsize>>>>,
384    ) -> &mut Self {
385        if !self.first {
386            // all the readers have left!
387            // safety: we haven't freed the Box, and no readers are accessing the w_handle
388            let w_handle = unsafe { self.w_handle.as_mut() };
389
390            // safety: we will not swap while we hold this reference
391            let r_handle = unsafe {
392                self.r_handle
393                    .inner
394                    .load(Ordering::Acquire)
395                    .as_ref()
396                    .unwrap()
397            };
398
399            if self.second {
400                Absorb::sync_with(w_handle, r_handle);
401                self.second = false
402            }
403
404            // the w_handle copy has not seen any of the writes in the oplog
405            // the r_handle copy has not seen any of the writes following swap_index
406            if self.swap_index != 0 {
407                // we can drain out the operations that only the w_handle copy needs
408                //
409                // NOTE: the if above is because drain(0..0) would remove 0
410                for op in self.oplog.drain(0..self.swap_index) {
411                    T::absorb_second(w_handle, op, r_handle);
412                }
413            }
414            // we cannot give owned operations to absorb_first
415            // since they'll also be needed by the r_handle copy
416            for op in self.oplog.iter_mut() {
417                T::absorb_first(w_handle, op, r_handle);
418            }
419            // the w_handle copy is about to become the r_handle, and can ignore the oplog
420            self.swap_index = self.oplog.len();
421
422        // w_handle (the old r_handle) is now fully up to date!
423        } else {
424            self.first = false
425        }
426
427        // at this point, we have exclusive access to w_handle, and it is up-to-date with all
428        // writes. the stale r_handle is accessed by readers through an Arc clone of atomic pointer
429        // inside the ReadHandle. oplog contains all the changes that are in w_handle, but not in
430        // r_handle.
431        //
432        // it's now time for us to swap the copies so that readers see up-to-date results from
433        // w_handle.
434
435        // swap in our w_handle, and get r_handle in return
436        let r_handle = self
437            .r_handle
438            .inner
439            .swap(self.w_handle.as_ptr(), Ordering::Release);
440
441        // NOTE: at this point, there are likely still readers using r_handle.
442        // safety: r_handle was also created from a Box, so it is not null and is covariant.
443        self.w_handle = unsafe { NonNull::new_unchecked(r_handle) };
444
445        // ensure that the subsequent epoch reads aren't re-ordered to before the swap
446        fence(Ordering::SeqCst);
447
448        self.last_epochs.resize(epochs.capacity(), 0);
449        for (ri, epoch) in epochs.iter() {
450            self.last_epochs[ri] = epoch.load(Ordering::Acquire);
451        }
452
453        #[cfg(test)]
454        {
455            self.refreshes += 1;
456        }
457
458        self
459    }
460
461    /// Publish as necessary to ensure that all operations are visible to readers.
462    ///
463    /// `WriteHandle::publish` will *always* wait for old readers to depart and swap the maps.
464    /// This method will only do so if there are pending operations.
465    pub fn flush(&mut self) {
466        if self.has_pending_operations() {
467            self.publish();
468        }
469    }
470
471    /// Returns true if there are operations in the operational log that have not yet been exposed
472    /// to readers.
473    pub fn has_pending_operations(&self) -> bool {
474        // NOTE: we don't use self.oplog.is_empty() here because it's not really that important if
475        // there are operations that have not yet been applied to the _write_ handle.
476        self.swap_index < self.oplog.len()
477    }
478
479    /// Append the given operation to the operational log.
480    ///
481    /// Its effects will not be exposed to readers until you call [`publish`](Self::publish).
482    pub fn append(&mut self, op: O) -> &mut Self {
483        self.extend(std::iter::once(op));
484        self
485    }
486
487    /// Returns a raw pointer to the write copy of the data (the one readers are _not_ accessing).
488    ///
489    /// Note that it is only safe to mutate through this pointer if you _know_ that there are no
490    /// readers still present in this copy. This is not normally something you know; even after
491    /// calling `publish`, readers may still be in the write copy for some time. In general, the
492    /// only time you know this is okay is before the first call to `publish` (since no readers
493    /// ever entered the write copy).
494    // TODO: Make this return `Option<&mut T>`,
495    // and only `Some` if there are indeed to readers in the write copy.
496    pub fn raw_write_handle(&mut self) -> NonNull<T> {
497        self.w_handle
498    }
499
500    /// Returns the backing data structure.
501    ///
502    /// Makes sure that all the pending operations are applied and waits till all the read handles
503    /// have departed. Then it uses [`Absorb::drop_first`] to drop one of the copies of the data and
504    /// returns the other copy as a [`Taken`] smart pointer.
505    pub fn take(mut self) -> Taken<T, O> {
506        // It is always safe to `expect` here because `take_inner` is private
507        // and it is only called here and in the drop impl. Since we have an owned
508        // `self` we know the drop has not yet been called. And every first call of
509        // `take_inner` returns `Some`
510        self.take_inner()
511            .expect("inner is only taken here then self is dropped")
512    }
513}
514
515// allow using write handle for reads
516use std::ops::Deref;
517impl<T, O> Deref for WriteHandle<T, O>
518where
519    T: Absorb<O>,
520{
521    type Target = ReadHandle<T>;
522    fn deref(&self) -> &Self::Target {
523        &self.r_handle
524    }
525}
526
527impl<T, O> Extend<O> for WriteHandle<T, O>
528where
529    T: Absorb<O>,
530{
531    /// Add multiple operations to the operational log.
532    ///
533    /// Their effects will not be exposed to readers until you call [`publish`](Self::publish)
534    fn extend<I>(&mut self, ops: I)
535    where
536        I: IntoIterator<Item = O>,
537    {
538        if self.first {
539            // Safety: we know there are no outstanding w_handle readers, since we haven't
540            // refreshed ever before, so we can modify it directly!
541            let mut w_inner = self.raw_write_handle();
542            let w_inner = unsafe { w_inner.as_mut() };
543            let r_handle = self.enter().expect("map has not yet been destroyed");
544            // Because we are operating directly on the map, and nothing is aliased, we do want
545            // to perform drops, so we invoke absorb_second.
546            for op in ops {
547                Absorb::absorb_second(w_inner, op, &*r_handle);
548            }
549        } else {
550            self.oplog.extend(ops);
551        }
552    }
553}
554
555/// `WriteHandle` can be sent across thread boundaries:
556///
557/// ```
558/// use left_right::WriteHandle;
559///
560/// struct Data;
561/// impl left_right::Absorb<()> for Data {
562///     fn absorb_first(&mut self, _: &mut (), _: &Self) {}
563///     fn sync_with(&mut self, _: &Self) {}
564/// }
565///
566/// fn is_send<T: Send>() {
567///   // dummy function just used for its parameterized type bound
568/// }
569///
570/// is_send::<WriteHandle<Data, ()>>()
571/// ```
572///
573/// As long as the inner types allow that of course.
574/// Namely, the data type has to be `Send`:
575///
576/// ```compile_fail
577/// use left_right::WriteHandle;
578/// use std::rc::Rc;
579///
580/// struct Data(Rc<()>);
581/// impl left_right::Absorb<()> for Data {
582///     fn absorb_first(&mut self, _: &mut (), _: &Self) {}
583/// }
584///
585/// fn is_send<T: Send>() {
586///   // dummy function just used for its parameterized type bound
587/// }
588///
589/// is_send::<WriteHandle<Data, ()>>()
590/// ```
591///
592/// .. the operation type has to be `Send`:
593///
594/// ```compile_fail
595/// use left_right::WriteHandle;
596/// use std::rc::Rc;
597///
598/// struct Data;
599/// impl left_right::Absorb<Rc<()>> for Data {
600///     fn absorb_first(&mut self, _: &mut Rc<()>, _: &Self) {}
601/// }
602///
603/// fn is_send<T: Send>() {
604///   // dummy function just used for its parameterized type bound
605/// }
606///
607/// is_send::<WriteHandle<Data, Rc<()>>>()
608/// ```
609///
610/// .. and the data type has to be `Sync` so it's still okay to read through `ReadHandle`s:
611///
612/// ```compile_fail
613/// use left_right::WriteHandle;
614/// use std::cell::Cell;
615///
616/// struct Data(Cell<()>);
617/// impl left_right::Absorb<()> for Data {
618///     fn absorb_first(&mut self, _: &mut (), _: &Self) {}
619/// }
620///
621/// fn is_send<T: Send>() {
622///   // dummy function just used for its parameterized type bound
623/// }
624///
625/// is_send::<WriteHandle<Data, ()>>()
626/// ```
627#[allow(dead_code)]
628struct CheckWriteHandleSend;
629
630#[cfg(test)]
631mod tests {
632    use crate::sync::{Arc, AtomicUsize, Mutex, Ordering};
633    use crate::Absorb;
634    use crossbeam_utils::CachePadded;
635    use slab::Slab;
636    include!("./utilities.rs");
637
638    #[test]
639    fn append_test() {
640        let (mut w, _r) = crate::new::<i32, _>();
641        assert_eq!(w.first, true);
642        w.append(CounterAddOp(1));
643        assert_eq!(w.oplog.len(), 0);
644        assert_eq!(w.first, true);
645        w.publish();
646        assert_eq!(w.first, false);
647        w.append(CounterAddOp(2));
648        w.append(CounterAddOp(3));
649        assert_eq!(w.oplog.len(), 2);
650    }
651
652    #[test]
653    fn take_test() {
654        // publish twice then take with no pending operations
655        let (mut w, _r) = crate::new_from_empty::<i32, _>(2);
656        w.append(CounterAddOp(1));
657        w.publish();
658        w.append(CounterAddOp(1));
659        w.publish();
660        assert_eq!(*w.take(), 4);
661
662        // publish twice then pending operation published by take
663        let (mut w, _r) = crate::new_from_empty::<i32, _>(2);
664        w.append(CounterAddOp(1));
665        w.publish();
666        w.append(CounterAddOp(1));
667        w.publish();
668        w.append(CounterAddOp(2));
669        assert_eq!(*w.take(), 6);
670
671        // normal publish then pending operations published by take
672        let (mut w, _r) = crate::new_from_empty::<i32, _>(2);
673        w.append(CounterAddOp(1));
674        w.publish();
675        w.append(CounterAddOp(1));
676        assert_eq!(*w.take(), 4);
677
678        // pending operations published by take
679        let (mut w, _r) = crate::new_from_empty::<i32, _>(2);
680        w.append(CounterAddOp(1));
681        assert_eq!(*w.take(), 3);
682
683        // emptry op queue
684        let (mut w, _r) = crate::new_from_empty::<i32, _>(2);
685        w.append(CounterAddOp(1));
686        w.publish();
687        assert_eq!(*w.take(), 3);
688
689        // no operations
690        let (w, _r) = crate::new_from_empty::<i32, _>(2);
691        assert_eq!(*w.take(), 2);
692    }
693
694    #[test]
695    fn wait_test() {
696        use std::sync::{Arc, Barrier};
697        use std::thread;
698        let (mut w, _r) = crate::new::<i32, _>();
699
700        // Case 1: If epoch is set to default.
701        let test_epochs: crate::Epochs = Default::default();
702        let mut test_epochs = test_epochs.lock().unwrap();
703        // since there is no epoch to waiting for, wait function will return immediately.
704        w.wait(&mut test_epochs);
705
706        // Case 2: If one of the reader is still reading(epoch is odd and count is same as in last_epoch)
707        // and wait has been called.
708        let held_epoch = Arc::new(CachePadded::new(AtomicUsize::new(1)));
709
710        w.last_epochs = vec![2, 2, 1];
711        let mut epochs_slab = Slab::new();
712        epochs_slab.insert(Arc::new(CachePadded::new(AtomicUsize::new(2))));
713        epochs_slab.insert(Arc::new(CachePadded::new(AtomicUsize::new(2))));
714        epochs_slab.insert(Arc::clone(&held_epoch));
715
716        let barrier = Arc::new(Barrier::new(2));
717
718        let is_waiting = Arc::clone(&w.is_waiting);
719
720        // check writers waiting state before calling wait.
721        let is_waiting_v = is_waiting.load(Ordering::Relaxed);
722        assert_eq!(false, is_waiting_v);
723
724        let barrier2 = Arc::clone(&barrier);
725        let test_epochs = Arc::new(Mutex::new(epochs_slab));
726        let wait_handle = thread::spawn(move || {
727            barrier2.wait();
728            let mut test_epochs = test_epochs.lock().unwrap();
729            w.wait(&mut test_epochs);
730        });
731
732        barrier.wait();
733
734        // make sure that writer wait() will call first, only then allow to updates the held epoch.
735        while !is_waiting.load(Ordering::Relaxed) {
736            thread::yield_now();
737        }
738
739        held_epoch.fetch_add(1, Ordering::SeqCst);
740
741        // join to make sure that wait must return after the progress/increment
742        // of held_epoch.
743        let _ = wait_handle.join();
744    }
745
746    #[test]
747    fn flush_noblock() {
748        let (mut w, r) = crate::new::<i32, _>();
749        w.append(CounterAddOp(42));
750        w.publish();
751        assert_eq!(*r.enter().unwrap(), 42);
752
753        // pin the epoch
754        let _count = r.enter();
755        // refresh would hang here
756        assert_eq!(w.oplog.iter().skip(w.swap_index).count(), 0);
757        assert!(!w.has_pending_operations());
758    }
759
760    #[test]
761    fn flush_no_refresh() {
762        let (mut w, _) = crate::new::<i32, _>();
763
764        // Until we refresh, writes are written directly instead of going to the
765        // oplog (because there can't be any readers on the w_handle table).
766        assert!(!w.has_pending_operations());
767        w.publish();
768        assert!(!w.has_pending_operations());
769        assert_eq!(w.refreshes, 1);
770
771        w.append(CounterAddOp(42));
772        assert!(w.has_pending_operations());
773        w.publish();
774        assert!(!w.has_pending_operations());
775        assert_eq!(w.refreshes, 2);
776
777        w.append(CounterAddOp(42));
778        assert!(w.has_pending_operations());
779        w.publish();
780        assert!(!w.has_pending_operations());
781        assert_eq!(w.refreshes, 3);
782
783        // Sanity check that a refresh would have been visible
784        assert!(!w.has_pending_operations());
785        w.publish();
786        assert_eq!(w.refreshes, 4);
787    }
788
789    #[test]
790    fn try_publish() {
791        let (mut w, _r) = crate::new::<i32, _>();
792
793        // Case 1: A reader has not advanced (odd and unchanged) -> returns false
794        let mut epochs_slab = Slab::new();
795        let idx = epochs_slab.insert(Arc::new(CachePadded::new(AtomicUsize::new(1)))); // odd epoch, "in read"
796                                                                                       // Ensure last_epochs sees this reader as odd and unchanged
797        w.last_epochs = vec![0; epochs_slab.capacity()];
798        w.last_epochs[idx] = 1;
799        w.epochs = Arc::new(Mutex::new(epochs_slab));
800        assert_eq!(w.try_publish(), false);
801
802        // Case 2: All readers have advanced since last swap -> returns true and publishes
803        let mut epochs_slab_ok = Slab::new();
804        let idx_ok = epochs_slab_ok.insert(Arc::new(CachePadded::new(AtomicUsize::new(2)))); // advanced
805        w.last_epochs = vec![0; epochs_slab_ok.capacity()];
806        w.last_epochs[idx_ok] = 1; // previously odd
807        w.epochs = Arc::new(Mutex::new(epochs_slab_ok));
808        let before = w.refreshes;
809        assert_eq!(w.try_publish(), true);
810        assert_eq!(w.refreshes, before + 1);
811    }
812}