From e8f238359f6a35a34094dfd5f02a653048c22c6e Mon Sep 17 00:00:00 2001 From: Lain Soykaf Date: Tue, 27 Oct 2026 20:49:52 +0400 Subject: [PATCH] perf(stats): read peers from instances, update every 5 minutes The peers query read the nickname of every remote user every minute (2.7 s and 1.2M buffer hits on a large instance). The instances table now has a row for every host we know users from, so read it instead, and recompute the stats every 5 minutes. Based on Akkoma 138b1aea2 and 7b76fdeed. Co-authored-by: Oneric Co-authored-by: FloatingGhost --- changelog.d/stats-peers-from-instances.change | 1 + lib/pleroma/stats.ex | 14 +++++--------- .../controllers/instance_controller_test.exs | 9 +++++---- 3 files changed, 11 insertions(+), 13 deletions(-) create mode 100644 changelog.d/stats-peers-from-instances.change diff --git a/changelog.d/stats-peers-from-instances.change b/changelog.d/stats-peers-from-instances.change new file mode 100644 index 000000000..c493b4550 --- /dev/null +++ b/changelog.d/stats-peers-from-instances.change @@ -0,0 +1 @@ +Read the peer list from the instances table and update instance stats every 5 minutes instead of every minute; the old peers query was one of the most expensive regular queries diff --git a/lib/pleroma/stats.ex b/lib/pleroma/stats.ex index 47b30b951..328aa110a 100644 --- a/lib/pleroma/stats.ex +++ b/lib/pleroma/stats.ex @@ -8,10 +8,11 @@ defmodule Pleroma.Stats do import Ecto.Query alias Pleroma.CounterCache + alias Pleroma.Instances.Instance alias Pleroma.Repo alias Pleroma.User - @interval :timer.seconds(60) + @interval :timer.seconds(300) def start_link(_) do GenServer.start_link( @@ -64,14 +65,9 @@ defmodule Pleroma.Stats do } } def calculate_stat_data do - peers = - from( - u in User, - select: fragment("distinct split_part(?, '@', 2)", u.nickname), - where: u.local != ^true - ) - |> Repo.all() - |> Enum.filter(& &1) + # Hosts are unique in instances, and remote users add theirs. Scanning + # all remote users for their domains was one of the costliest queries. + peers = Repo.all(from(i in Instance, select: i.host)) domain_count = Enum.count(peers) diff --git a/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs index 461b46066..404d276db 100644 --- a/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/instance_controller_test.exs @@ -63,8 +63,8 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do user2 = insert(:user, %{local: true}) {:ok, _user2} = User.set_activation(user2, false) - insert(:user, %{local: false, nickname: "u@peer1.com"}) - insert(:user, %{local: false, nickname: "u@peer2.com"}) + insert(:instance, host: "peer1.com") + insert(:instance, host: "peer2.com") {:ok, _} = Pleroma.Web.CommonAPI.post(user, %{status: "cofe"}) @@ -83,8 +83,9 @@ defmodule Pleroma.Web.MastodonAPI.InstanceControllerTest do end test "get peers", %{conn: conn} do - insert(:user, %{local: false, nickname: "u@peer1.com"}) - insert(:user, %{local: false, nickname: "u@peer2.com"}) + # Peers come from the instances table, which remote users add to. + insert(:instance, host: "peer1.com") + insert(:instance, host: "peer2.com") Pleroma.Stats.force_update()