improve performance of community followers inbox query (#3482)

* improve performance of community followers inbox query

* nightly format

* force woodpecker to retry

---------

Co-authored-by: Dessalines <dessalines@users.noreply.github.com>
pull/3490/head^2
phiresky 2023-07-05 17:50:26 +02:00 committed by GitHub
parent ebaf69bd70
commit 45b1a0d4fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 21 deletions

View File

@ -14,7 +14,6 @@ use activitypub_federation::{
traits::{Actor, Object}, traits::{Actor, Object},
}; };
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use itertools::Itertools;
use lemmy_api_common::{ use lemmy_api_common::{
context::LemmyContext, context::LemmyContext,
utils::{generate_featured_url, generate_moderators_url, generate_outbox_url}, utils::{generate_featured_url, generate_moderators_url, generate_outbox_url},
@ -188,17 +187,11 @@ impl ApubCommunity {
let id = self.id; let id = self.id;
let local_site_data = local_site_data_cached(context.pool()).await?; let local_site_data = local_site_data_cached(context.pool()).await?;
let follows = CommunityFollowerView::for_community(context.pool(), id).await?; let follows = CommunityFollowerView::get_community_follower_inboxes(context.pool(), id).await?;
let inboxes: Vec<Url> = follows let inboxes: Vec<Url> = follows
.into_iter() .into_iter()
.filter(|f| !f.follower.local) .map(Into::into)
.map(|f| {
f.follower
.shared_inbox_url
.unwrap_or(f.follower.inbox_url)
.into()
})
.unique()
.filter(|inbox: &Url| inbox.host_str() != Some(&context.settings().hostname)) .filter(|inbox: &Url| inbox.host_str() != Some(&context.settings().hostname))
// Don't send to blocked instances // Don't send to blocked instances
.filter(|inbox| check_apub_id_valid(inbox, &local_site_data).is_ok()) .filter(|inbox| check_apub_id_valid(inbox, &local_site_data).is_ok())

View File

@ -22,12 +22,12 @@ impl GroupFollowers {
) -> Result<GroupFollowers, LemmyError> { ) -> Result<GroupFollowers, LemmyError> {
let community_id = community.id; let community_id = community.id;
let community_followers = let community_followers =
CommunityFollowerView::for_community(context.pool(), community_id).await?; CommunityFollowerView::count_community_followers(context.pool(), community_id).await?;
Ok(GroupFollowers { Ok(GroupFollowers {
id: generate_followers_url(&community.actor_id)?.into(), id: generate_followers_url(&community.actor_id)?.into(),
r#type: CollectionType::Collection, r#type: CollectionType::Collection,
total_items: community_followers.len() as i32, total_items: community_followers as i32,
items: vec![], items: vec![],
}) })
} }

View File

@ -1,8 +1,14 @@
use crate::structs::CommunityFollowerView; use crate::structs::CommunityFollowerView;
use diesel::{result::Error, ExpressionMethods, QueryDsl}; use diesel::{
dsl::{count_star, not},
result::Error,
sql_function,
ExpressionMethods,
QueryDsl,
};
use diesel_async::RunQueryDsl; use diesel_async::RunQueryDsl;
use lemmy_db_schema::{ use lemmy_db_schema::{
newtypes::{CommunityId, PersonId}, newtypes::{CommunityId, DbUrl, PersonId},
schema::{community, community_follower, person}, schema::{community, community_follower, person},
source::{community::Community, person::Person}, source::{community::Community, person::Person},
traits::JoinView, traits::JoinView,
@ -11,19 +17,37 @@ use lemmy_db_schema::{
type CommunityFollowerViewTuple = (Community, Person); type CommunityFollowerViewTuple = (Community, Person);
sql_function!(fn coalesce(x: diesel::sql_types::Nullable<diesel::sql_types::Text>, y: diesel::sql_types::Text) -> diesel::sql_types::Text);
impl CommunityFollowerView { impl CommunityFollowerView {
pub async fn for_community(pool: &DbPool, community_id: CommunityId) -> Result<Vec<Self>, Error> { pub async fn get_community_follower_inboxes(
pool: &DbPool,
community_id: CommunityId,
) -> Result<Vec<DbUrl>, Error> {
let conn = &mut get_conn(pool).await?; let conn = &mut get_conn(pool).await?;
let res = community_follower::table let res = community_follower::table
.inner_join(community::table)
.inner_join(person::table)
.select((community::all_columns, person::all_columns))
.filter(community_follower::community_id.eq(community_id)) .filter(community_follower::community_id.eq(community_id))
.order_by(community::title) .filter(not(person::local))
.load::<CommunityFollowerViewTuple>(conn) .inner_join(person::table)
.select(coalesce(person::shared_inbox_url, person::inbox_url))
.distinct()
.load::<DbUrl>(conn)
.await?; .await?;
Ok(res.into_iter().map(Self::from_tuple).collect()) Ok(res)
}
pub async fn count_community_followers(
pool: &DbPool,
community_id: CommunityId,
) -> Result<i64, Error> {
let conn = &mut get_conn(pool).await?;
let res = community_follower::table
.filter(community_follower::community_id.eq(community_id))
.select(count_star())
.first::<i64>(conn)
.await?;
Ok(res)
} }
pub async fn for_person(pool: &DbPool, person_id: PersonId) -> Result<Vec<Self>, Error> { pub async fn for_person(pool: &DbPool, person_id: PersonId) -> Result<Vec<Self>, Error> {