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}