feat: post comments cache & use cache everywhere

This commit is contained in:
2022-03-24 23:33:32 +08:00
parent cc32c318a7
commit c8b8ad0787
8 changed files with 228 additions and 131 deletions

View File

@@ -1,6 +1,6 @@
#![allow(clippy::all)]
use crate::cache::{PostCache, UserCache};
use crate::cache::{PostCache, PostCommentCache, UserCache};
use crate::db_conn::Db;
use crate::libs::diesel_logger::LoggingConnection;
use crate::rds_conn::RdsConn;
@@ -17,9 +17,9 @@ use std::convert::identity;
no_arg_sql_function!(RANDOM, (), "Represents the sql RANDOM() function");
macro_rules! get {
macro_rules! _get {
($table:ident) => {
pub async fn get(db: &Db, id: i32) -> QueryResult<Self> {
async fn _get(db: &Db, id: i32) -> QueryResult<Self> {
let pid = id;
db.run(move |c| $table::table.find(pid).first(with_log!((c))))
.await
@@ -27,9 +27,9 @@ macro_rules! get {
};
}
macro_rules! get_multi {
macro_rules! _get_multi {
($table:ident) => {
pub async fn get_multi(db: &Db, ids: Vec<i32>) -> QueryResult<Vec<Self>> {
async fn _get_multi(db: &Db, ids: Vec<i32>) -> QueryResult<Vec<Self>> {
if ids.is_empty() {
return Ok(vec![]);
}
@@ -47,14 +47,16 @@ macro_rules! get_multi {
macro_rules! set_deleted {
($table:ident) => {
pub async fn set_deleted(&self, db: &Db) -> QueryResult<usize> {
let pid = self.id;
db.run(move |c| {
diesel::update($table::table.find(pid))
.set($table::is_deleted.eq(true))
.execute(with_log!(c))
})
.await
pub async fn set_deleted(&mut self, db: &Db) -> QueryResult<()> {
let id = self.id;
*self = db
.run(move |c| {
diesel::update($table::table.find(id))
.set($table::is_deleted.eq(true))
.get_result(with_log!(c))
})
.await?;
Ok(())
}
};
}
@@ -73,7 +75,7 @@ macro_rules! with_log {
};
}
#[derive(Queryable, Insertable, Serialize, Deserialize)]
#[derive(Queryable, Insertable, Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct Comment {
pub id: i32,
@@ -106,7 +108,7 @@ pub struct Post {
pub allow_search: bool,
}
#[derive(Queryable, Insertable, Serialize, Deserialize)]
#[derive(Queryable, Insertable, Serialize, Deserialize, Debug)]
#[serde(crate = "rocket::serde")]
pub struct User {
pub id: i32,
@@ -129,17 +131,13 @@ pub struct NewPost {
}
impl Post {
get!(posts);
_get!(posts);
get_multi!(posts);
_get_multi!(posts);
set_deleted!(posts);
pub async fn get_multi_with_cache(
db: &Db,
rconn: &RdsConn,
ids: &Vec<i32>,
) -> QueryResult<Vec<Self>> {
pub async fn get_multi(db: &Db, rconn: &RdsConn, ids: &Vec<i32>) -> QueryResult<Vec<Self>> {
let mut cacher = PostCache::init(&rconn);
let mut cached_posts = cacher.gets(ids).await;
let mut id2po = HashMap::<i32, &mut Option<Post>>::new();
@@ -153,17 +151,19 @@ impl Post {
None => {
id2po.insert(pid.clone(), p);
Some(pid)
},
}
_ => None,
})
.copied()
.collect();
dbg!(&missing_ids);
let missing_ps = Self::get_multi(db, missing_ids).await?;
// dbg!(&missing_ids);
let missing_ps = Self::_get_multi(db, missing_ids).await?;
// dbg!(&missing_ps);
cacher.sets(&missing_ps.iter().map(identity).collect()).await;
cacher
.sets(&missing_ps.iter().map(identity).collect())
.await;
for p in missing_ps.into_iter() {
if let Some(op) = id2po.get_mut(&p.id) {
@@ -171,16 +171,43 @@ impl Post {
}
}
// dbg!(&cached_posts);
Ok(
cached_posts.into_iter().filter_map(identity).collect()
)
Ok(cached_posts
.into_iter()
.filter_map(|p| p.filter(|p| !p.is_deleted))
.collect())
}
pub async fn get_with_cache(db: &Db, rconn: &RdsConn, id: i32) -> QueryResult<Self> {
Self::get_multi_with_cache(db, rconn, &vec![id])
.await?
.pop()
.ok_or(diesel::result::Error::NotFound)
pub async fn get(db: &Db, rconn: &RdsConn, id: i32) -> QueryResult<Self> {
let mut cacher = PostCache::init(&rconn);
if let Some(p) = cacher.get(&id).await {
if p.is_deleted {
return Err(diesel::result::Error::NotFound);
}
Ok(p)
} else {
let p = Self::_get(db, id).await?;
cacher.sets(&vec![&p]).await;
Ok(p)
}
}
pub async fn get_comments(
&self,
db: &Db,
rconn: &RdsConn,
) -> QueryResult<Vec<Comment>> {
let mut cacher = PostCommentCache::init(self.id, rconn);
if let Some(cs) = cacher.get().await {
Ok(cs)
} else {
let cs = Comment::gets_by_post_id(db, self.id).await?;
cacher.set(&cs).await;
Ok(cs)
}
}
pub async fn clear_comments_cache(&self, rconn: &RdsConn) {
PostCommentCache::init(self.id, rconn).clear().await;
}
pub async fn gets_by_page(
@@ -264,44 +291,52 @@ impl Post {
.await
}
pub async fn update_cw(&self, db: &Db, new_cw: String) -> QueryResult<usize> {
pub async fn update_cw(&mut self, db: &Db, new_cw: String) -> QueryResult<()> {
let pid = self.id;
db.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::cw.eq(new_cw))
.execute(with_log!(c))
})
.await
*self = db
.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::cw.eq(new_cw))
.get_result(with_log!(c))
})
.await?;
Ok(())
}
pub async fn change_n_comments(&self, db: &Db, delta: i32) -> QueryResult<Self> {
pub async fn change_n_comments(&mut self, db: &Db, delta: i32) -> QueryResult<()> {
let pid = self.id;
db.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::n_comments.eq(posts::n_comments + delta))
.get_result(with_log!(c))
})
.await
*self = db
.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::n_comments.eq(posts::n_comments + delta))
.get_result(with_log!(c))
})
.await?;
Ok(())
}
pub async fn change_n_attentions(&self, db: &Db, delta: i32) -> QueryResult<Self> {
pub async fn change_n_attentions(&mut self, db: &Db, delta: i32) -> QueryResult<()> {
let pid = self.id;
db.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::n_attentions.eq(posts::n_attentions + delta))
.get_result(with_log!(c))
})
.await
*self = db
.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::n_attentions.eq(posts::n_attentions + delta))
.get_result(with_log!(c))
})
.await?;
Ok(())
}
pub async fn change_hot_score(&self, db: &Db, delta: i32) -> QueryResult<Self> {
pub async fn change_hot_score(&mut self, db: &Db, delta: i32) -> QueryResult<()> {
let pid = self.id;
db.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::hot_score.eq(posts::hot_score + delta))
.get_result(with_log!(c))
})
.await
*self = db
.run(move |c| {
diesel::update(posts::table.find(pid))
.set(posts::hot_score.eq(posts::hot_score + delta))
.get_result(with_log!(c))
})
.await?;
Ok(())
}
pub async fn set_instance_cache(&self, rconn: &RdsConn) {
@@ -313,7 +348,7 @@ impl Post {
}
impl User {
pub async fn get_by_token(db: &Db, token: &str) -> Option<Self> {
async fn _get_by_token(db: &Db, token: &str) -> Option<Self> {
let token = token.to_string();
db.run(move |c| {
users::table
@@ -324,12 +359,12 @@ impl User {
.ok()
}
pub async fn get_by_token_with_cache(db: &Db, rconn: &RdsConn, token: &str) -> Option<Self> {
pub async fn get_by_token(db: &Db, rconn: &RdsConn, token: &str) -> Option<Self> {
let mut cacher = UserCache::init(token, &rconn);
if let Some(u) = cacher.get().await {
Some(u)
} else {
let u = Self::get_by_token(db, token).await?;
let u = Self::_get_by_token(db, token).await?;
cacher.set(&u).await;
Some(u)
}
@@ -347,10 +382,15 @@ pub struct NewComment {
}
impl Comment {
get!(comments);
_get!(comments);
set_deleted!(comments);
pub async fn get(db: &Db, id: i32) -> QueryResult<Self> {
// no cache for single comment
Self::_get(db, id).await
}
pub async fn create(db: &Db, new_comment: NewComment) -> QueryResult<Self> {
db.run(move |c| {
insert_into(comments::table)