2025-07-29 22:42:10 +00:00
|
|
|
use std::{ops::Range, sync::Arc};
|
2022-10-05 15:33:57 +02:00
|
|
|
|
2025-07-25 10:06:40 +00:00
|
|
|
use tokio::sync::{watch, watch::Sender};
|
2025-07-24 00:15:33 +00:00
|
|
|
use tuwunel_core::{
|
2025-07-25 10:06:40 +00:00
|
|
|
Result, err, utils,
|
2025-07-24 00:15:33 +00:00
|
|
|
utils::two_phase_counter::{Counter as TwoPhaseCounter, Permit as TwoPhasePermit},
|
|
|
|
|
};
|
2025-04-22 01:41:02 +00:00
|
|
|
use tuwunel_database::{Database, Deserialized, Map};
|
2024-05-26 21:29:19 +00:00
|
|
|
|
2024-05-27 03:17:20 +00:00
|
|
|
pub struct Data {
|
2024-06-28 22:51:39 +00:00
|
|
|
global: Arc<Map>,
|
2025-07-25 10:06:40 +00:00
|
|
|
retires: Sender<u64>,
|
2025-07-24 00:15:33 +00:00
|
|
|
counter: Arc<Counter>,
|
2024-07-18 06:37:47 +00:00
|
|
|
pub(super) db: Arc<Database>,
|
2022-09-07 13:25:51 +02:00
|
|
|
}
|
2024-05-26 21:29:19 +00:00
|
|
|
|
2025-07-24 00:15:33 +00:00
|
|
|
pub(super) type Permit = TwoPhasePermit<Callback>;
|
|
|
|
|
type Counter = TwoPhaseCounter<Callback>;
|
|
|
|
|
type Callback = Box<dyn Fn(u64) -> Result + Send + Sync>;
|
|
|
|
|
|
2024-07-13 08:07:49 +00:00
|
|
|
const COUNTER: &[u8] = b"c";
|
|
|
|
|
|
2024-05-27 03:17:20 +00:00
|
|
|
impl Data {
|
2024-07-18 06:37:47 +00:00
|
|
|
pub(super) fn new(args: &crate::Args<'_>) -> Self {
|
2025-07-24 00:15:33 +00:00
|
|
|
let db = args.db.clone();
|
2025-07-25 10:06:40 +00:00
|
|
|
let count = Self::stored_count(&args.db["global"]).expect("initialize global counter");
|
|
|
|
|
let retires = watch::channel(count).0;
|
2024-05-27 03:17:20 +00:00
|
|
|
Self {
|
2024-07-18 06:37:47 +00:00
|
|
|
db: args.db.clone(),
|
2025-07-24 00:15:33 +00:00
|
|
|
global: args.db["global"].clone(),
|
2025-07-25 10:06:40 +00:00
|
|
|
retires: retires.clone(),
|
2025-07-24 00:15:33 +00:00
|
|
|
counter: Counter::new(
|
2025-07-25 10:06:40 +00:00
|
|
|
count,
|
2025-07-24 00:15:33 +00:00
|
|
|
Box::new(move |count| Self::store_count(&db, &db["global"], count)),
|
2025-07-25 10:06:40 +00:00
|
|
|
Box::new(move |count| Self::handle_retire(&retires, count)),
|
2025-07-24 00:15:33 +00:00
|
|
|
),
|
2024-05-27 03:17:20 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-25 10:06:40 +00:00
|
|
|
pub async fn wait_pending(&self) -> Result<u64> {
|
|
|
|
|
let count = self.counter.dispatched();
|
|
|
|
|
self.wait_count(&count).await.inspect(|retired| {
|
|
|
|
|
debug_assert!(
|
|
|
|
|
*retired >= count,
|
|
|
|
|
"Expecting retired sequence number >= snapshotted dispatch number"
|
|
|
|
|
);
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub async fn wait_count(&self, count: &u64) -> Result<u64> {
|
|
|
|
|
self.retires
|
|
|
|
|
.subscribe()
|
|
|
|
|
.wait_for(|retired| retired.ge(count))
|
|
|
|
|
.await
|
|
|
|
|
.map(|retired| *retired)
|
2025-07-29 22:42:10 +00:00
|
|
|
.map_err(|e| err!(debug_error!("counter channel error {e:?}")))
|
2025-07-25 10:06:40 +00:00
|
|
|
}
|
|
|
|
|
|
2025-07-24 00:15:33 +00:00
|
|
|
#[inline]
|
|
|
|
|
pub fn next_count(&self) -> Permit {
|
|
|
|
|
self.counter
|
|
|
|
|
.next()
|
|
|
|
|
.expect("failed to obtain next sequence number")
|
2024-07-02 07:56:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2025-07-24 00:15:33 +00:00
|
|
|
pub fn current_count(&self) -> u64 { self.counter.current() }
|
|
|
|
|
|
2025-07-29 22:42:10 +00:00
|
|
|
#[inline]
|
|
|
|
|
pub fn pending_count(&self) -> Range<u64> { self.counter.range() }
|
|
|
|
|
|
2025-07-25 10:06:40 +00:00
|
|
|
fn handle_retire(sender: &Sender<u64>, count: u64) -> Result {
|
|
|
|
|
let _prev = sender.send_replace(count);
|
|
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
|
2025-07-24 00:15:33 +00:00
|
|
|
fn store_count(db: &Arc<Database>, global: &Arc<Map>, count: u64) -> Result {
|
|
|
|
|
let _cork = db.cork();
|
|
|
|
|
global.insert(COUNTER, count.to_be_bytes());
|
2024-07-02 07:56:45 +00:00
|
|
|
|
2025-07-24 00:15:33 +00:00
|
|
|
Ok(())
|
2024-05-26 21:29:19 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-02 07:56:45 +00:00
|
|
|
fn stored_count(global: &Arc<Map>) -> Result<u64> {
|
|
|
|
|
global
|
2024-09-29 07:37:43 +00:00
|
|
|
.get_blocking(COUNTER)
|
2024-07-02 07:56:45 +00:00
|
|
|
.as_deref()
|
|
|
|
|
.map_or(Ok(0_u64), utils::u64_from_bytes)
|
2024-05-26 21:29:19 +00:00
|
|
|
}
|
2025-07-24 00:15:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Data {
|
|
|
|
|
pub fn bump_database_version(&self, new_version: u64) {
|
|
|
|
|
self.global.raw_put(b"version", new_version);
|
|
|
|
|
}
|
2024-05-26 21:29:19 +00:00
|
|
|
|
2024-09-29 13:13:09 +00:00
|
|
|
pub async fn database_version(&self) -> u64 {
|
|
|
|
|
self.global
|
|
|
|
|
.get(b"version")
|
|
|
|
|
.await
|
|
|
|
|
.deserialized()
|
|
|
|
|
.unwrap_or(0)
|
|
|
|
|
}
|
2024-05-26 21:29:19 +00:00
|
|
|
}
|