feat: cache for posts list
This commit is contained in:
108
src/cache.rs
108
src/cache.rs
@@ -1,10 +1,15 @@
|
||||
use crate::models::{Comment, Post, User};
|
||||
use crate::rds_conn::RdsConn;
|
||||
use rand::Rng;
|
||||
use redis::AsyncCommands;
|
||||
use rocket::serde::json::serde_json;
|
||||
// can use rocket::serde::json::to_string in master version
|
||||
|
||||
const INSTANCE_EXPIRE_TIME: usize = 60 * 60;
|
||||
|
||||
const MIN_LENGTH: isize = 200;
|
||||
const MAX_LENGTH: isize = 900;
|
||||
|
||||
macro_rules! post_cache_key {
|
||||
($id: expr) => {
|
||||
format!("hole_v2:cache:post:{}", $id)
|
||||
@@ -150,6 +155,109 @@ impl PostCommentCache {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PostListCommentCache {
|
||||
key: String,
|
||||
mode: u8,
|
||||
rconn: RdsConn,
|
||||
length: isize,
|
||||
}
|
||||
|
||||
impl PostListCommentCache {
|
||||
pub async fn init(mode: u8, rconn: &RdsConn) -> Self {
|
||||
let mut cacher = PostListCommentCache {
|
||||
key: format!("hole_v2:cache:post_list:{}", &mode),
|
||||
mode: mode,
|
||||
rconn: rconn.clone(),
|
||||
length: 0,
|
||||
};
|
||||
cacher.set_and_check_length().await;
|
||||
cacher
|
||||
}
|
||||
|
||||
async fn set_and_check_length(&mut self) {
|
||||
let mut l = self.rconn.zcard(&self.key).await.unwrap();
|
||||
if l > MAX_LENGTH {
|
||||
self.rconn
|
||||
.zremrangebyrank::<&String, ()>(&self.key, MIN_LENGTH, -1)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("cut list cache failed, {}, {}", e, &self.key);
|
||||
});
|
||||
l = MIN_LENGTH;
|
||||
}
|
||||
self.length = l;
|
||||
}
|
||||
|
||||
pub fn need_fill(&self) -> bool {
|
||||
self.length < MIN_LENGTH
|
||||
}
|
||||
|
||||
pub fn i64_len(&self) -> i64 {
|
||||
self.length.try_into().unwrap()
|
||||
}
|
||||
|
||||
pub fn i64_minlen(&self) -> i64 {
|
||||
MIN_LENGTH.try_into().unwrap()
|
||||
}
|
||||
|
||||
fn p2pair(&self, p: &Post) -> (i64, i32) {
|
||||
(
|
||||
match self.mode {
|
||||
0 => (-p.id).into(),
|
||||
1 => -p.last_comment_time.timestamp(),
|
||||
2 => (-p.hot_score).into(),
|
||||
3 => rand::thread_rng().gen_range(0..i64::MAX),
|
||||
_ => panic!("wrong mode"),
|
||||
},
|
||||
p.id,
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn fill(&mut self, ps: &Vec<Post>) {
|
||||
let items: Vec<(i64, i32)> = ps.iter().map(|p| self.p2pair(p)).collect();
|
||||
self.rconn
|
||||
.zadd_multiple(&self.key, &items)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
warn!("fill list cache failed, {} {}", e, &self.key);
|
||||
});
|
||||
|
||||
self.set_and_check_length().await;
|
||||
}
|
||||
|
||||
pub async fn put(&mut self, p: &Post) {
|
||||
// 其他都是加到最前面的,但热榜不是。可能导致MIN_LENGTH到MAX_LENGTH之间的数据不可靠
|
||||
// 影响不大,先不管了
|
||||
if p.is_deleted {
|
||||
self.rconn.zrem(&self.key, p.id).await.unwrap_or_else(|e| {
|
||||
warn!(
|
||||
"remove from list cache failed, {} {} {}",
|
||||
e, &self.key, p.id
|
||||
);
|
||||
});
|
||||
} else {
|
||||
let (s, m) = self.p2pair(p);
|
||||
self.rconn.zadd(&self.key, m, s).await.unwrap_or_else(|e| {
|
||||
warn!(
|
||||
"put into list cache failed, {} {} {} {}",
|
||||
e, &self.key, m, s
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_pids(&mut self, start: i64, limit: i64) -> Vec<i32> {
|
||||
self.rconn
|
||||
.zrange(
|
||||
&self.key,
|
||||
start.try_into().unwrap(),
|
||||
(start + limit - 1).try_into().unwrap(),
|
||||
)
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UserCache {
|
||||
key: String,
|
||||
rconn: RdsConn,
|
||||
|
||||
Reference in New Issue
Block a user