update counter_cache logic

This commit is contained in:
Roman Chvanikov 2020-05-09 01:20:50 +03:00
parent 0c2b09a9ba
commit 39d2f2118a
3 changed files with 82 additions and 34 deletions

View file

@ -17,30 +17,46 @@ defmodule Mix.Tasks.Pleroma.RefreshCounterCache do
def run([]) do def run([]) do
Mix.Pleroma.start_pleroma() Mix.Pleroma.start_pleroma()
["public", "unlisted", "private", "direct"] Activity
|> Enum.each(fn visibility -> |> distinct([a], true)
count = status_visibility_count_query(visibility) |> select([a], fragment("split_part(?, '/', 3)", a.actor))
name = "status_visibility_#{visibility}" |> Repo.all()
CounterCache.set(name, count) |> Enum.each(fn instance ->
Mix.Pleroma.shell_info("Set #{name} to #{count}") counters = instance_counters(instance)
CounterCache.set(instance, counters)
Mix.Pleroma.shell_info("Setting #{instance} counters: #{inspect(counters)}")
end) end)
Mix.Pleroma.shell_info("Done") Mix.Pleroma.shell_info("Done")
end end
defp status_visibility_count_query(visibility) do defp instance_counters(instance) do
counters = %{"public" => 0, "unlisted" => 0, "private" => 0, "direct" => 0}
Activity Activity
|> where( |> where([a], fragment("(? ->> 'type'::text) = 'Create'", a.data))
|> where([a], like(a.actor, ^"%#{instance}%"))
|> select(
[a], [a],
fragment( {fragment(
"activity_visibility(?, ?, ?) = ?", "activity_visibility(?, ?, ?)",
a.actor, a.actor,
a.recipients, a.recipients,
a.data, a.data
^visibility ), count(a.id)}
)
|> group_by(
[a],
fragment(
"activity_visibility(?, ?, ?)",
a.actor,
a.recipients,
a.data
) )
) )
|> where([a], fragment("(? ->> 'type'::text) = 'Create'", a.data)) |> Repo.all(timeout: :timer.minutes(30))
|> Repo.aggregate(:count, :id, timeout: :timer.minutes(30)) |> Enum.reduce(counters, fn {visibility, count}, acc ->
Map.put(acc, visibility, count)
end)
end end
end end

View file

@ -10,32 +10,70 @@ defmodule Pleroma.CounterCache do
import Ecto.Query import Ecto.Query
schema "counter_cache" do schema "counter_cache" do
field(:name, :string) field(:instance, :string)
field(:count, :integer) field(:public, :integer)
field(:unlisted, :integer)
field(:private, :integer)
field(:direct, :integer)
end end
def changeset(struct, params) do def changeset(struct, params) do
struct struct
|> cast(params, [:name, :count]) |> cast(params, [:instance, :public, :unlisted, :private, :direct])
|> validate_required([:name]) |> validate_required([:instance])
|> unique_constraint(:name) |> unique_constraint(:instance)
end end
def get_as_map(names) when is_list(names) do def get_by_instance(instance) do
CounterCache CounterCache
|> where([cc], cc.name in ^names) |> select([c], %{
|> Repo.all() "public" => c.public,
|> Enum.group_by(& &1.name, & &1.count) "unlisted" => c.unlisted,
|> Map.new(fn {k, v} -> {k, hd(v)} end) "private" => c.private,
"direct" => c.direct
})
|> where([c], c.instance == ^instance)
|> Repo.one()
|> case do
nil -> %{"public" => 0, "unlisted" => 0, "private" => 0, "direct" => 0}
val -> val
end
end end
def set(name, count) do def get_as_map() do
CounterCache
|> select([c], %{
"public" => sum(c.public),
"unlisted" => sum(c.unlisted),
"private" => sum(c.private),
"direct" => sum(c.direct)
})
|> Repo.one()
end
def set(instance, values) do
params =
Enum.reduce(
["public", "private", "unlisted", "direct"],
%{"instance" => instance},
fn param, acc ->
Map.put_new(acc, param, Map.get(values, param, 0))
end
)
%CounterCache{} %CounterCache{}
|> changeset(%{"name" => name, "count" => count}) |> changeset(params)
|> Repo.insert( |> Repo.insert(
on_conflict: [set: [count: count]], on_conflict: [
set: [
public: params["public"],
private: params["private"],
unlisted: params["unlisted"],
direct: params["direct"]
]
],
returning: true, returning: true,
conflict_target: :name conflict_target: :instance
) )
end end
end end

View file

@ -98,13 +98,7 @@ def calculate_stat_data do
end end
def get_status_visibility_count do def get_status_visibility_count do
counter_cache = counter_cache = CounterCache.get_as_map()
CounterCache.get_as_map([
"status_visibility_public",
"status_visibility_private",
"status_visibility_unlisted",
"status_visibility_direct"
])
%{ %{
public: counter_cache["status_visibility_public"] || 0, public: counter_cache["status_visibility_public"] || 0,