feat: cache for get multi posts

This commit is contained in:
2022-03-24 04:20:26 +08:00
parent f67912e857
commit cd940d59ba
3 changed files with 137 additions and 48 deletions

View File

@@ -5,53 +5,97 @@ use rocket::serde::json::serde_json;
// can use rocket::serde::json::to_string in master version
const INSTANCE_EXPIRE_TIME: usize = 60 * 60;
macro_rules! post_cache_key {
($id: expr) => {
format!("hole_v2:cache:post:{}", $id)
};
}
pub struct PostCache {
key: String,
rconn: RdsConn,
}
impl PostCache {
pub fn init(pid: &i32, rconn: &RdsConn) -> Self {
pub fn init(rconn: &RdsConn) -> Self {
PostCache {
key: format!("hole_v2:cache:post:{}", pid),
rconn: rconn.clone(),
}
}
pub async fn set(&mut self, p: &Post) {
self.rconn
.set_ex(
&self.key,
pub async fn sets(&mut self, ps: &Vec<&Post>) {
if ps.is_empty() {
return;
}
let kvs: Vec<(String, String)> = ps
.iter()
.map(|p| (
post_cache_key!(p.id),
serde_json::to_string(p).unwrap(),
INSTANCE_EXPIRE_TIME,
)
) ).collect();
dbg!(&kvs);
let ret = self.rconn
.set_multiple(&kvs)
.await
.unwrap_or_else(|e| {
warn!("set post cache failed: {}, {}", e, p.id);
})
warn!("set post cache failed: {}", e);
"x".to_string()
});
dbg!(ret);
}
pub async fn get(&mut self) -> Option<Post> {
let rds_result = self.rconn.get::<&String, String>(&self.key).await;
if let Ok(s) = rds_result {
debug!("hint user cache");
self.rconn
.expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME)
.await
.unwrap_or_else(|e| {
warn!(
"get post cache, set new expire failed: {}, {}, {} ",
e, &self.key, &s
);
false
});
pub async fn get(&mut self, pid: &i32) -> Option<Post> {
let key = post_cache_key!(pid);
let rds_result: Option<String> = self
.rconn
.get::<String, Option<String>>(key)
.await
.unwrap_or_else(|e| {
warn!("try to get post cache, connect rds fail, {}", e);
None
});
rds_result.and_then(|s| {
serde_json::from_str(&s).unwrap_or_else(|e| {
warn!("get post cache, decode failed {}, {}", e, s);
None
})
} else {
None
})
}
pub async fn gets(&mut self, pids: &Vec<i32>) -> Vec<Option<Post>> {
// 长度为1时会走GET而非MGET返回值格式不兼容。愚蠢的设计。
match pids.len() {
0 => vec![],
1 => vec![self.get(&pids[0]).await],
_ => {
let ks: Vec<String> = pids.iter().map(|pid| post_cache_key!(pid)).collect();
// dbg!(&ks);
// Vec is single arg, while &Vec is not. Seems a bug.
let rds_result: Vec<Option<String>> = self
.rconn
.get::<Vec<String>, Vec<Option<String>>>(ks)
.await
.unwrap_or_else(|e| {
warn!("try to get posts cache, connect rds fail, {}", e);
vec![None; pids.len()]
});
// dbg!(&rds_result);
// 定期热度衰减的时候会清空缓存,这里设不设置过期时间影响不大
rds_result
.into_iter()
.map(|x| {
// dbg!(&x);
x.and_then(|s| {
serde_json::from_str(&s).unwrap_or_else(|e| {
warn!("get post cache, decode failed {}, {}", e, s);
None
})
})
})
.collect()
}
}
}
}
@@ -85,19 +129,19 @@ impl UserCache {
pub async fn get(&mut self) -> Option<User> {
let rds_result = self.rconn.get::<&String, String>(&self.key).await;
if let Ok(s) = rds_result {
debug!("hint post cache");
debug!("hint user cache");
self.rconn
.expire::<&String, bool>(&self.key, INSTANCE_EXPIRE_TIME)
.await
.unwrap_or_else(|e| {
warn!(
"get post cache, set new expire failed: {}, {}, {} ",
"get user cache, set new expire failed: {}, {}, {} ",
e, &self.key, &s
);
false
});
serde_json::from_str(&s).unwrap_or_else(|e| {
warn!("get post cache, decode failed {}, {}", e, s);
warn!("get user cache, decode failed {}, {}", e, s);
None
})
} else {