Skip to content

Commit 80fa6c4

Browse files
committed
transport/timestamp_generator: Added MonotonicTimestampGenerator
Added TimestampGenerator trait and MonotonicTimestampGenerator based on c++ driver's implementation
1 parent be14812 commit 80fa6c4

File tree

2 files changed

+77
-0
lines changed

2 files changed

+77
-0
lines changed

scylla/src/transport/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub mod retry_policy;
1818
pub mod session;
1919
pub mod session_builder;
2020
pub mod speculative_execution;
21+
pub mod timestamp_generator;
2122
pub mod topology;
2223

2324
pub use crate::frame::{Authenticator, Compression};
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use std::{
2+
sync::atomic::AtomicI64,
3+
time::{SystemTime, UNIX_EPOCH},
4+
};
5+
6+
use std::sync::atomic::Ordering;
7+
use tracing::warn;
8+
9+
pub(crate) trait TimestampGenerator {
10+
fn next(&self) -> i64;
11+
}
12+
13+
pub struct MonotonicTimestampGenerator {
14+
last: AtomicI64,
15+
warning_threshold_us: i64,
16+
}
17+
18+
impl MonotonicTimestampGenerator {
19+
pub fn new_with_settings(warning_threshold_us: i64) -> Self {
20+
MonotonicTimestampGenerator {
21+
last: AtomicI64::new(0),
22+
warning_threshold_us,
23+
}
24+
}
25+
pub fn new() -> Self {
26+
MonotonicTimestampGenerator::new_with_settings(1000000)
27+
}
28+
29+
// This is guaranteed to return a monotonic timestamp. If clock skew is detected
30+
// then this method will increment the last timestamp.
31+
fn compute_next(&self, last: i64) -> i64 {
32+
let current = SystemTime::now().duration_since(UNIX_EPOCH);
33+
if let Ok(cur_time) = current {
34+
let u_cur = cur_time.as_micros() as i64;
35+
if u_cur > last {
36+
return u_cur;
37+
} else if last - u_cur > self.warning_threshold_us {
38+
warn!(
39+
"Clock skew detected. The current time ({}) was {} \
40+
microseconds behind the last generated timestamp ({}). \
41+
The next generated timestamp will be artificially incremented \
42+
to guarantee monotonicity.",
43+
u_cur,
44+
last - u_cur,
45+
last
46+
)
47+
}
48+
} else {
49+
warn!("Clock skew detected. The current time was behind UNIX epoch.");
50+
}
51+
52+
last + 1
53+
}
54+
}
55+
56+
impl Default for MonotonicTimestampGenerator {
57+
fn default() -> Self {
58+
Self::new()
59+
}
60+
}
61+
62+
impl TimestampGenerator for MonotonicTimestampGenerator {
63+
fn next(&self) -> i64 {
64+
loop {
65+
let last = self.last.load(Ordering::SeqCst);
66+
let cur = self.compute_next(last);
67+
if self
68+
.last
69+
.compare_exchange(last, cur, Ordering::SeqCst, Ordering::SeqCst)
70+
.is_ok()
71+
{
72+
return cur;
73+
}
74+
}
75+
}
76+
}

0 commit comments

Comments
 (0)