healing tracker

Signed-off-by: junxiang Mu <1948535941@qq.com>
This commit is contained in:
junxiang Mu
2024-10-15 18:28:55 +08:00
parent e4f5ca7ea8
commit 3f2772c74c
16 changed files with 636 additions and 44 deletions
+55 -26
View File
@@ -1,14 +1,18 @@
use std::{
fmt::Debug,
ptr,
sync::{atomic::{AtomicPtr, AtomicU64, Ordering}, Arc, Mutex},
sync::{
atomic::{AtomicPtr, AtomicU64, Ordering},
Arc,
},
time::{Duration, SystemTime, UNIX_EPOCH},
};
use tokio::spawn;
use tokio::{spawn, sync::Mutex};
use crate::error::{Error, Result};
use crate::error::Result;
type UpdateFn<T> = Box<dyn Fn() -> Result<T>>;
type UpdateFn<T> = Arc<dyn Fn() -> Result<T> + Send + Sync>;
#[derive(Clone, Debug, Default)]
pub struct Opts {
@@ -16,7 +20,7 @@ pub struct Opts {
no_wait: bool,
}
pub struct Cache<T: Copy> {
pub struct Cache<T: Clone + Debug + Send> {
update_fn: UpdateFn<T>,
ttl: Duration,
opts: Opts,
@@ -25,7 +29,7 @@ pub struct Cache<T: Copy> {
updating: Arc<Mutex<bool>>,
}
impl<T: Copy> Cache<T> {
impl<T: Clone + Debug + Send + 'static> Cache<T> {
pub fn new(update_fn: UpdateFn<T>, ttl: Duration, opts: Opts) -> Self {
let val = AtomicPtr::new(ptr::null_mut());
Self {
@@ -38,9 +42,13 @@ impl<T: Copy> Cache<T> {
}
}
pub fn get(&self) -> Result<T> {
pub async fn get(self: Arc<Self>) -> Result<T> {
let v_ptr = self.val.load(Ordering::SeqCst);
let v = if v_ptr.is_null() { None } else { Some(unsafe { *v_ptr }) };
let v = if v_ptr.is_null() {
None
} else {
Some(unsafe { (*v_ptr).clone() })
};
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
@@ -52,37 +60,58 @@ impl<T: Copy> Cache<T> {
if self.opts.no_wait && v.is_some() && now - self.last_update_ms.load(Ordering::SeqCst) < self.ttl.as_secs() * 2 {
if self.updating.try_lock().is_ok() {
let this = self.clone();
spawn(async {
let this = Arc::clone(&self);
spawn(async move {
let _ = this.update().await;
});
self.update();
}
return Ok(v.unwrap());
}
match self.updating.lock() {
Ok(_) => {
if let Ok(duration) = SystemTime::now().duration_since(UNIX_EPOCH + Duration::from_secs(self.last_update_ms.load(Ordering::SeqCst))) {
if duration < self.ttl {
return Ok(v.unwrap());
}
}
let _ = self.updating.lock().await;
match self.update() {
}
},
Err(err) => {
return Err(Error::from_string(err.to_string()));
if let Ok(duration) =
SystemTime::now().duration_since(UNIX_EPOCH + Duration::from_secs(self.last_update_ms.load(Ordering::SeqCst)))
{
if duration < self.ttl {
return Ok(v.unwrap());
}
}
todo!()
match self.update().await {
Ok(_) => {
let v_ptr = self.val.load(Ordering::SeqCst);
let v = if v_ptr.is_null() {
None
} else {
Some(unsafe { (*v_ptr).clone() })
};
Ok(v.unwrap())
}
Err(err) => Err(err),
}
}
async fn update(&self) -> Result<()> {
todo!()
match (self.update_fn)() {
Ok(val) => {
self.val.store(Box::into_raw(Box::new(val)), Ordering::SeqCst);
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("Time went backwards")
.as_secs();
self.last_update_ms.store(now, Ordering::SeqCst);
Ok(())
}
Err(err) => {
let v_ptr = self.val.load(Ordering::SeqCst);
if self.opts.return_last_good && !v_ptr.is_null() {
return Ok(());
}
return Err(err);
}
}
}
}