Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove aggregate tables (fixes #4869) #5407

Draft
wants to merge 45 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5ca40a7
migration
Nutomic Feb 7, 2025
a3b835f
update code
Nutomic Feb 7, 2025
549e51f
tests
Nutomic Feb 7, 2025
43ef0b5
triggers
Nutomic Feb 7, 2025
2ea59bf
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 7, 2025
31cbe18
fix
Nutomic Feb 7, 2025
cd29e85
fmt
Nutomic Feb 7, 2025
61c5038
clippy
Nutomic Feb 7, 2025
b27aea0
post aggregate migration
Nutomic Feb 7, 2025
bb4bfe3
changes for post aggregate code
Nutomic Feb 10, 2025
17d8d98
wip: update tests for post aggregate
Nutomic Feb 10, 2025
4124f03
format
Nutomic Feb 10, 2025
c9aaaf0
fix partialeq
Nutomic Feb 10, 2025
068aded
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 10, 2025
a88845e
trigger fix
Nutomic Feb 10, 2025
1a1c366
fix post insert trigger
Nutomic Feb 10, 2025
af3035b
wip
Nutomic Feb 10, 2025
41112a9
reorder
Nutomic Feb 11, 2025
bb30add
fixes
Nutomic Feb 11, 2025
8cd04b4
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 11, 2025
f2d2852
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 11, 2025
794240c
community aggregate migration
Nutomic Feb 12, 2025
082cdfd
update code
Nutomic Feb 12, 2025
261c0a1
triggers
Nutomic Feb 12, 2025
f145565
person aggregate migration
Nutomic Feb 12, 2025
1ee4e63
person aggregate code
Nutomic Feb 12, 2025
f29c21d
person triggers
Nutomic Feb 12, 2025
8c92d25
test fixes
Nutomic Feb 12, 2025
707c418
fix scheduled task
Nutomic Feb 12, 2025
85fc71d
update api tests
Nutomic Feb 12, 2025
42015ab
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 12, 2025
cf86bc7
site_aggregates to local_site migration
Nutomic Feb 12, 2025
c9da44d
site_aggregates code changes
Nutomic Feb 12, 2025
7badf7c
triggers, tests
Nutomic Feb 12, 2025
ac7b305
more fixes
Nutomic Feb 12, 2025
47414e3
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 13, 2025
f732f63
Rename PersonPostAggregates to PostActions
Nutomic Feb 13, 2025
25aa10a
Merge local_user_vote_display_mode into local_user
Nutomic Feb 13, 2025
416ad1b
fix schema
Nutomic Feb 13, 2025
b0bc927
remove duplicate fields
Nutomic Feb 17, 2025
4a6a5e6
remove "aggregates" from index names
Nutomic Feb 17, 2025
4b7422a
uncomment indices
Nutomic Feb 17, 2025
f758ed8
if count = 0
Nutomic Feb 17, 2025
1cf4a9c
Merge branch 'main' into remove-aggregate-tables
Nutomic Feb 20, 2025
44c5990
remove commentaggregates
Nutomic Feb 25, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion crates/api_crud/src/comment/create.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ pub async fn create_comment(
update_read_comments(
local_user_view.person.id,
post_id,
post_view.counts.comments + 1,
post.comments + 1,
&mut context.pool(),
)
.await?;
Expand Down
2 changes: 1 addition & 1 deletion crates/api_crud/src/post/read.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ pub async fn get_post(
update_read_comments(
person_id,
post_id,
post_view.counts.comments,
post_view.post.comments,
&mut context.pool(),
)
.await?;
Expand Down
3 changes: 1 addition & 2 deletions crates/apub/src/activities/create_or_update/comment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ use lemmy_api_common::{
utils::{check_post_deleted_or_removed, is_mod_or_admin},
};
use lemmy_db_schema::{
aggregates::structs::CommentAggregates,
newtypes::{PersonId, PostOrCommentId},
source::{
activity::ActivitySendTargets,
Expand Down Expand Up @@ -160,7 +159,7 @@ impl ActivityHandler for CreateOrUpdateNote {
CommentLike::like(&mut context.pool(), &like_form).await?;

// Calculate initial hot_rank
CommentAggregates::update_hot_rank(&mut context.pool(), comment.id).await?;
Comment::update_hot_rank(&mut context.pool(), comment.id).await?;

let do_send_email = self.kind == CreateOrUpdateType::Create;
let actor = self.actor.dereference(context).await?;
Expand Down
3 changes: 1 addition & 2 deletions crates/apub/src/activities/create_or_update/post.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ use activitypub_federation::{
};
use lemmy_api_common::{build_response::send_local_notifs, context::LemmyContext};
use lemmy_db_schema::{
aggregates::structs::PostAggregates,
newtypes::{PersonId, PostOrCommentId},
source::{
activity::ActivitySendTargets,
Expand Down Expand Up @@ -121,7 +120,7 @@ impl ActivityHandler for CreateOrUpdatePage {
PostLike::like(&mut context.pool(), &like_form).await?;

// Calculate initial hot_rank for post
PostAggregates::update_ranks(&mut context.pool(), post.id).await?;
Post::update_ranks(&mut context.pool(), post.id).await?;

let do_send_email = self.kind == CreateOrUpdateType::Create;
let actor = self.actor.dereference(context).await?;
Expand Down
1 change: 1 addition & 0 deletions crates/db_schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ diesel = { workspace = true, features = [
"postgres",
"serde_json",
"uuid",
"64-column-tables",
], optional = true }
diesel-derive-newtype = { workspace = true, optional = true }
diesel-derive-enum = { workspace = true, optional = true }
Expand Down
111 changes: 41 additions & 70 deletions crates/db_schema/replaceable_schema/triggers.sql
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
-- before the automatic deletion of the row that references it. This is not a problem for insert or delete.
--
-- Triggers that update multiple tables should use this order: person_aggregates, comment_aggregates,
-- post_aggregates, community_aggregates, site_aggregates
-- post, community_aggregates, site_aggregates
-- * The order matters because the updated rows are locked until the end of the transaction, and statements
-- in a trigger don't use separate transactions. This means that updates closer to the beginning cause
-- longer locks because the duration of each update extends the durations of the locks caused by previous
Expand All @@ -19,19 +19,6 @@
--
--
-- Create triggers for both post and comments
CREATE FUNCTION r.creator_id_from_post_aggregates (agg post_aggregates)
RETURNS int IMMUTABLE PARALLEL SAFE RETURN agg.creator_id;

CREATE FUNCTION r.creator_id_from_comment_aggregates (agg comment_aggregates)
RETURNS int IMMUTABLE PARALLEL SAFE RETURN (
SELECT
creator_id
FROM
comment
WHERE
comment.id = agg.comment_id LIMIT 1
);

CREATE PROCEDURE r.post_or_comment (table_name text)
LANGUAGE plpgsql
AS $a$
Expand All @@ -41,18 +28,18 @@ BEGIN
CALL r.create_triggers ('thing_actions', $$
BEGIN
WITH thing_diff AS ( UPDATE
thing_aggregates AS a
thing AS a
SET
score = a.score + diff.upvotes - diff.downvotes, upvotes = a.upvotes + diff.upvotes, downvotes = a.downvotes + diff.downvotes, controversy_rank = r.controversy_rank ((a.upvotes + diff.upvotes)::numeric, (a.downvotes + diff.downvotes)::numeric)
FROM (
SELECT
(thing_actions).thing_id, coalesce(sum(count_diff) FILTER (WHERE (thing_actions).like_score = 1), 0) AS upvotes, coalesce(sum(count_diff) FILTER (WHERE (thing_actions).like_score != 1), 0) AS downvotes FROM select_old_and_new_rows AS old_and_new_rows
WHERE (thing_actions).like_score IS NOT NULL GROUP BY (thing_actions).thing_id) AS diff
WHERE
a.thing_id = diff.thing_id
a.id = diff.thing_id
AND (diff.upvotes, diff.downvotes) != (0, 0)
RETURNING
r.creator_id_from_thing_aggregates (a.*) AS creator_id, diff.upvotes - diff.downvotes AS score)
a.creator_id AS creator_id, diff.upvotes - diff.downvotes AS score)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was quite confused by this trigger because it actually replaces thing in the sql code with post/comment, and so kept referring to post_aggregates when that was already removed. I fixed it and ran into another problem: the trigger for comment updates the comment table, so it fires another trigger, and ultimately throws "stack depth limit exceeded". I fixed this by adding WHEN (pg_trigger_depth( ) = 0 ) to create_triggers()

UPDATE
person_aggregates AS a
SET
Expand Down Expand Up @@ -109,7 +96,7 @@ WHERE
AND diff.comment_count != 0;

UPDATE
comment_aggregates AS a
comment AS a
SET
child_count = a.child_count + diff.child_count
FROM (
Expand Down Expand Up @@ -143,12 +130,12 @@ FROM (
GROUP BY
parent_id) AS diff
WHERE
a.comment_id = diff.parent_id
a.id = diff.parent_id
AND diff.child_count != 0;

WITH post_diff AS (
UPDATE
post_aggregates AS a
post AS a
SET
comments = a.comments + diff.comments,
newest_comment_time = GREATEST (a.newest_comment_time, diff.newest_comment_time),
Expand All @@ -173,7 +160,7 @@ WITH post_diff AS (
GROUP BY
post.id) AS diff
WHERE
a.post_id = diff.post_id
a.id = diff.post_id
AND (diff.comments,
GREATEST (a.newest_comment_time, diff.newest_comment_time),
GREATEST (a.newest_comment_time_necro, diff.newest_comment_time_necro)) != (0,
Expand Down Expand Up @@ -338,12 +325,12 @@ BEGIN
1
ELSE
-1
END) * post_aggregates.comments) AS comments
END) * post.comments) AS comments
FROM
new_post
INNER JOIN old_post ON new_post.id = old_post.id
AND (r.is_counted (new_post.*) != r.is_counted (old_post.*))
INNER JOIN post_aggregates ON post_aggregates.post_id = new_post.id
INNER JOIN post ON post.id = new_post.id
GROUP BY
old_post.community_id) AS diff
WHERE
Expand Down Expand Up @@ -387,15 +374,15 @@ $$);
CALL r.create_triggers ('post_report', $$
BEGIN
UPDATE
post_aggregates AS a
post AS a
SET
report_count = a.report_count + diff.report_count, unresolved_report_count = a.unresolved_report_count + diff.unresolved_report_count
FROM (
SELECT
(post_report).post_id, coalesce(sum(count_diff), 0) AS report_count, coalesce(sum(count_diff) FILTER (WHERE NOT (post_report).resolved), 0) AS unresolved_report_count
FROM select_old_and_new_rows AS old_and_new_rows GROUP BY (post_report).post_id) AS diff
WHERE (diff.report_count, diff.unresolved_report_count) != (0, 0)
AND a.post_id = diff.post_id;
AND a.id = diff.post_id;

RETURN NULL;

Expand All @@ -406,15 +393,15 @@ $$);
CALL r.create_triggers ('comment_report', $$
BEGIN
UPDATE
comment_aggregates AS a
comment AS a
SET
report_count = a.report_count + diff.report_count, unresolved_report_count = a.unresolved_report_count + diff.unresolved_report_count
FROM (
SELECT
(comment_report).comment_id, coalesce(sum(count_diff), 0) AS report_count, coalesce(sum(count_diff) FILTER (WHERE NOT (comment_report).resolved), 0) AS unresolved_report_count
FROM select_old_and_new_rows AS old_and_new_rows GROUP BY (comment_report).comment_id) AS diff
WHERE (diff.report_count, diff.unresolved_report_count) != (0, 0)
AND a.comment_id = diff.comment_id;
AND a.id = diff.comment_id;

RETURN NULL;

Expand Down Expand Up @@ -443,26 +430,6 @@ $$);

-- These triggers create and update rows in each aggregates table to match its associated table's rows.
-- Deleting rows and updating IDs are already handled by `CASCADE` in foreign key constraints.
CREATE FUNCTION r.comment_aggregates_from_comment ()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO comment_aggregates (comment_id, published)
SELECT
id,
published
FROM
new_comment;
RETURN NULL;
END;
$$;

CREATE TRIGGER aggregates
AFTER INSERT ON comment REFERENCING NEW TABLE AS new_comment
FOR EACH STATEMENT
EXECUTE FUNCTION r.comment_aggregates_from_comment ();

CREATE FUNCTION r.community_aggregates_from_community ()
RETURNS TRIGGER
LANGUAGE plpgsql
Expand Down Expand Up @@ -502,41 +469,44 @@ CREATE TRIGGER aggregates
FOR EACH STATEMENT
EXECUTE FUNCTION r.person_aggregates_from_person ();

CREATE FUNCTION r.post_aggregates_from_post ()
CREATE FUNCTION r.post_from_post ()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO post_aggregates (post_id, published, newest_comment_time, newest_comment_time_necro, community_id, creator_id, instance_id, featured_community, featured_local)
SELECT
new_post.id,
new_post.published,
new_post.published,
new_post.published,
new_post.community_id,
new_post.creator_id,
community.instance_id,
new_post.featured_community,
new_post.featured_local
UPDATE
post
SET
published = new_post.published,
newest_comment_time = new_post.published,
newest_comment_time_necro = new_post.published,
community_id = new_post.community_id,
creator_id = new_post.creator_id,
instance_id = community.instance_id,
featured_community = new_post.featured_community,
featured_local = new_post.featured_local
FROM
new_post
INNER JOIN community ON community.id = new_post.community_id;
INNER JOIN community ON community.id = new_post.community_id
WHERE
post.id = new_post.id;
RETURN NULL;
END;
$$;

CREATE TRIGGER aggregates
AFTER INSERT ON post REFERENCING NEW TABLE AS new_post
FOR EACH STATEMENT
EXECUTE FUNCTION r.post_aggregates_from_post ();
WHEN (pg_trigger_depth() = 0)
EXECUTE FUNCTION r.post_from_post ();

CREATE FUNCTION r.post_aggregates_from_post_update ()
CREATE FUNCTION r.post_from_post_update ()
RETURNS TRIGGER
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE
post_aggregates
post
SET
featured_community = new_post.featured_community,
featured_local = new_post.featured_local
Expand All @@ -547,15 +517,16 @@ BEGIN
old_post.featured_local) != (new_post.featured_community,
new_post.featured_local)
WHERE
post_aggregates.post_id = new_post.id;
post.id = new_post.id;
RETURN NULL;
END;
$$;

CREATE TRIGGER aggregates_update
AFTER UPDATE ON post REFERENCING OLD TABLE AS old_post NEW TABLE AS new_post
FOR EACH STATEMENT
EXECUTE FUNCTION r.post_aggregates_from_post_update ();
WHEN (pg_trigger_depth() = 0)
EXECUTE FUNCTION r.post_from_post_update ();

CREATE FUNCTION r.site_aggregates_from_site ()
RETURNS TRIGGER
Expand Down Expand Up @@ -961,7 +932,7 @@ CALL r.create_search_combined_trigger ('community');
CALL r.create_search_combined_trigger ('person');

-- You also need to triggers to update the `score` column.
-- post | post_aggregates::score
-- post | post::score
-- comment | comment_aggregates::score
-- community | community_aggregates::users_active_monthly
-- person | person_aggregates::post_score
Expand All @@ -977,13 +948,13 @@ BEGIN
SET
score = NEW.score
WHERE
post_id = NEW.post_id;
post_id = NEW.id;
RETURN NULL;
END
$$;

CREATE TRIGGER search_combined_post_score
AFTER UPDATE OF score ON post_aggregates
AFTER UPDATE OF score ON post
FOR EACH ROW
EXECUTE FUNCTION r.search_combined_post_score_update ();

Expand All @@ -998,13 +969,13 @@ BEGIN
SET
score = NEW.score
WHERE
comment_id = NEW.comment_id;
comment_id = NEW.id;
RETURN NULL;
END
$$;

CREATE TRIGGER search_combined_comment_score
AFTER UPDATE OF score ON comment_aggregates
AFTER UPDATE OF score ON comment
FOR EACH ROW
EXECUTE FUNCTION r.search_combined_comment_score_update ();

Expand Down
5 changes: 4 additions & 1 deletion crates/db_schema/replaceable_schema/utils.sql
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ DECLARE
CREATE TRIGGER delete_statement
AFTER DELETE ON thing REFERENCING OLD TABLE AS select_old_rows
FOR EACH STATEMENT
WHEN (pg_trigger_depth( ) = 0 )
EXECUTE FUNCTION r.thing_delete_statement ( );
-- Insert
CREATE FUNCTION r.thing_insert_statement ( )
Expand All @@ -101,6 +102,7 @@ DECLARE
CREATE TRIGGER insert_statement
AFTER INSERT ON thing REFERENCING NEW TABLE AS select_new_rows
FOR EACH STATEMENT
WHEN (pg_trigger_depth( ) = 0 )
EXECUTE FUNCTION r.thing_insert_statement ( );
-- Update
CREATE FUNCTION r.thing_update_statement ( )
Expand All @@ -110,6 +112,7 @@ DECLARE
CREATE TRIGGER update_statement
AFTER UPDATE ON thing REFERENCING OLD TABLE AS select_old_rows NEW TABLE AS select_new_rows
FOR EACH STATEMENT
WHEN (pg_trigger_depth( ) = 0 )
EXECUTE FUNCTION r.thing_update_statement ( );
$$;
select_old_and_new_rows text := $$ (
Expand Down Expand Up @@ -225,7 +228,7 @@ BEGIN
COALESCE(sum(comments + upvotes + downvotes)::bigint, 0) AS count_,
community_id AS community_id_
FROM
post_aggregates
post
WHERE
published >= (CURRENT_TIMESTAMP - i::interval)
GROUP BY
Expand Down
Loading