Avoid potentially slow count queries for user note count.

For a variety of reasons, posgresql won't use the available actor,
type index to do an index only scan. We now just increase the user
note count, which will lead to slightly wrong counts in some cases,
but it's better than the potentially very slow count query.
This commit is contained in:
Roger Braun 2017-10-31 16:37:11 +01:00
parent 3037814fde
commit 4dcbb64f19
4 changed files with 26 additions and 2 deletions

View File

@ -239,6 +239,15 @@ def get_friends(%User{id: id, following: following}) do
{:ok, Repo.all(q)} {:ok, Repo.all(q)}
end end
def increase_note_count(%User{} = user) do
note_count = (user.info["note_count"] || 0) + 1
new_info = Map.put(user.info, "note_count", note_count)
cs = info_changeset(user, %{info: new_info})
Repo.update(cs)
end
def update_note_count(%User{} = user) do def update_note_count(%User{} = user) do
note_count_query = from a in Object, note_count_query = from a in Object,
where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data), where: fragment("?->>'actor' = ? and ?->>'type' = 'Note'", a.data, ^user.ap_id, a.data),

View File

@ -61,7 +61,7 @@ def post(user, %{"status" => status} = data) do
context <- make_context(inReplyTo), context <- make_context(inReplyTo),
object <- make_note_data(user.ap_id, to, context, content_html, attachments, inReplyTo, tags) do object <- make_note_data(user.ap_id, to, context, content_html, attachments, inReplyTo, tags) do
res = ActivityPub.create(to, user, context, object) res = ActivityPub.create(to, user, context, object)
User.update_note_count(user) User.increase_note_count(user)
res res
end end
end end

View File

@ -112,7 +112,7 @@ def handle_note(entry, doc \\ nil) do
note <- (if inReplyTo && !inReplyToActivity, do: note |> Map.put("inReplyTo", inReplyTo), else: note) note <- (if inReplyTo && !inReplyToActivity, do: note |> Map.put("inReplyTo", inReplyTo), else: note)
do do
res = ActivityPub.create(to, actor, context, note, %{}, date, false) res = ActivityPub.create(to, actor, context, note, %{}, date, false)
User.update_note_count(actor) User.increase_note_count(actor)
res res
else else
%Activity{} = activity -> {:ok, activity} %Activity{} = activity -> {:ok, activity}

View File

@ -246,6 +246,21 @@ test "it sets the info->note_count property" do
assert user.info["note_count"] == 1 assert user.info["note_count"] == 1
end end
test "it increases the info->note_count property" do
note = insert(:note)
user = User.get_by_ap_id(note.data["actor"])
assert user.info["note_count"] == nil
{:ok, user} = User.increase_note_count(user)
assert user.info["note_count"] == 1
{:ok, user} = User.increase_note_count(user)
assert user.info["note_count"] == 2
end
test "it sets the info->follower_count property" do test "it sets the info->follower_count property" do
user = insert(:user) user = insert(:user)
follower = insert(:user) follower = insert(:user)