Merge pull request 'Fix notification query plan for users with domain blocks' (#7981) from fix/domain-block-subplan-cost into develop
Reviewed-on: https://git.pleroma.social/pleroma/pleroma/pulls/7981
This commit is contained in:
commit
fa920037f1
3 changed files with 24 additions and 2 deletions
1
changelog.d/domain-block-subplan-cost.fix
Normal file
1
changelog.d/domain-block-subplan-cost.fix
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix notification and timeline queries for users with domain blocks choosing a plan that scans every active user per row; the followed-accounts exception is now an `ARRAY(SELECT ...)` InitPlan that the planner costs once.
|
||||
|
|
@ -258,10 +258,16 @@ defmodule Pleroma.FollowingRelationship do
|
|||
[_, user_actor: user_actor],
|
||||
fragment(
|
||||
# "(actor's domain NOT in domain_blocks) OR (actor IS in followed AP IDs)"
|
||||
#
|
||||
# ARRAY(SELECT ...) makes the followed-ids lookup an InitPlan that is
|
||||
# evaluated and costed once. As a plain subselect, the planner charges
|
||||
# its startup cost on every rescan of the actor lookup, which inflates
|
||||
# the cost of the index plan enough for it to lose to a plan that
|
||||
# materialises every active user for every candidate row.
|
||||
"""
|
||||
NOT (substring(? from '.*://([^/]*)') = ANY(?)) OR
|
||||
? = ANY(SELECT ap_id FROM users AS u INNER JOIN following_relationships AS fr
|
||||
ON u.id = fr.following_id WHERE fr.follower_id = ? AND fr.state = ?)
|
||||
? = ANY(ARRAY(SELECT ap_id FROM users AS u INNER JOIN following_relationships AS fr
|
||||
ON u.id = fr.following_id WHERE fr.follower_id = ? AND fr.state = ?))
|
||||
""",
|
||||
user_actor.ap_id,
|
||||
^user.domain_blocks,
|
||||
|
|
|
|||
|
|
@ -1028,6 +1028,21 @@ defmodule Pleroma.NotificationTest do
|
|||
assert Notification.for_user(user) == []
|
||||
end
|
||||
|
||||
test "it doesn't return notifications from a blocked domain unless the actor is followed",
|
||||
%{user: user} do
|
||||
blocked_domain = "blocked.example"
|
||||
stranger = insert(:user, local: false, domain: blocked_domain)
|
||||
followed = insert(:user, local: false, domain: blocked_domain)
|
||||
{:ok, user, followed} = User.follow(user, followed)
|
||||
{:ok, user} = User.block_domain(user, blocked_domain)
|
||||
|
||||
{:ok, _} = CommonAPI.post(stranger, %{status: "hey @#{user.nickname}"})
|
||||
{:ok, followed_activity} = CommonAPI.post(followed, %{status: "hey @#{user.nickname}"})
|
||||
|
||||
assert [%{activity: %{id: followed_id}}] = Notification.for_user(user)
|
||||
assert followed_id == followed_activity.id
|
||||
end
|
||||
|
||||
test "it doesn't return notifications for domain-blocked non-followed user", %{user: user} do
|
||||
blocked = insert(:user, ap_id: "http://some-domain.com")
|
||||
{:ok, user} = User.block_domain(user, "some-domain.com")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue