1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
use crate::base_node::NodeType;
pub(crate) fn convert_type_to_version(n_type: NodeType) -> usize {
(n_type as usize) << 62
}
use core::cell::Cell;
use core::fmt;
const SPIN_LIMIT: u32 = 6;
const YIELD_LIMIT: u32 = 10;
pub(crate) struct Backoff {
step: Cell<u32>,
}
impl Backoff {
#[inline]
pub(crate) fn new() -> Self {
Backoff { step: Cell::new(0) }
}
#[inline]
#[allow(dead_code)]
pub(crate) fn reset(&self) {
self.step.set(0);
}
#[inline]
pub(crate) fn spin(&self) {
for _ in 0..1 << self.step.get().min(SPIN_LIMIT) {
std::hint::spin_loop();
}
if self.step.get() <= SPIN_LIMIT {
self.step.set(self.step.get() + 1);
}
#[cfg(shuttle)]
shuttle::thread::yield_now();
}
#[allow(dead_code)]
#[inline]
pub(crate) fn snooze(&self) {
if self.step.get() <= SPIN_LIMIT {
for _ in 0..1 << self.step.get() {
std::hint::spin_loop();
}
} else {
#[cfg(shuttle)]
shuttle::thread::yield_now();
#[cfg(not(shuttle))]
::std::thread::yield_now();
}
if self.step.get() <= YIELD_LIMIT {
self.step.set(self.step.get() + 1);
}
}
#[inline]
pub(crate) fn is_completed(&self) -> bool {
self.step.get() > YIELD_LIMIT
}
}
impl fmt::Debug for Backoff {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Backoff")
.field("step", &self.step)
.field("is_completed", &self.is_completed())
.finish()
}
}
impl Default for Backoff {
fn default() -> Backoff {
Backoff::new()
}
}