summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorlain <lain@soykaf.club>2020-02-18 13:17:00 +0100
committerlain <lain@soykaf.club>2020-02-18 13:17:00 +0100
commit12738732c90592032cd5c7455363a3a0a4a26e7a (patch)
tree2867babdf87bf30dabd61e6cc742487ebd724049
parent5178c8dbc34db3b78eaa21a2f46300ac1a639c8c (diff)
Hashtags, Blocks: Reword for performance.
-rw-r--r--benchmarks/mix/tasks/pleroma/benchmarks/tags.ex30
-rw-r--r--lib/pleroma/activity.ex1
-rw-r--r--lib/pleroma/web/activity_pub/activity_pub.ex56
-rw-r--r--lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex1
-rw-r--r--mix.exs1
-rw-r--r--priv/repo/migrations/20200214102520_add_tags_field_to_activities.exs35
-rw-r--r--priv/repo/migrations/20200217134311_add_block_cache_to_activities.exs46
7 files changed, 98 insertions, 72 deletions
diff --git a/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex
index fd1506907..73796b5f9 100644
--- a/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex
+++ b/benchmarks/mix/tasks/pleroma/benchmarks/tags.ex
@@ -33,36 +33,6 @@ defmodule Mix.Tasks.Pleroma.Benchmarks.Tags do
Benchee.run(
%{
- "Hashtag fetching, any" => fn tags ->
- Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
- %{
- "any" => tags
- },
- user,
- false
- )
- end,
- # Will always return zero results because no overlapping hashtags are generated.
- "Hashtag fetching, all" => fn tags ->
- Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
- %{
- "all" => tags
- },
- user,
- false
- )
- end
- },
- inputs:
- tags
- |> Enum.map(fn {_, v} -> v end)
- |> Enum.chunk_every(2)
- |> Enum.map(fn tags -> {"For #{inspect(tags)}", tags} end),
- time: 5
- )
-
- Benchee.run(
- %{
"Hashtag fetching" => fn tag ->
Pleroma.Web.MastodonAPI.TimelineController.hashtag_fetching(
%{
diff --git a/lib/pleroma/activity.ex b/lib/pleroma/activity.ex
index 72e2256ea..ffdcf7562 100644
--- a/lib/pleroma/activity.ex
+++ b/lib/pleroma/activity.ex
@@ -43,6 +43,7 @@ defmodule Pleroma.Activity do
field(:local, :boolean, default: true)
field(:actor, :string)
field(:recipients, {:array, :string}, default: [])
+ field(:block_cache, {:array, :string}, default: [], read_after_writes: true)
field(:thread_muted?, :boolean, virtual: true)
# This is a fake relation,
diff --git a/lib/pleroma/web/activity_pub/activity_pub.ex b/lib/pleroma/web/activity_pub/activity_pub.ex
index 5c436941a..ea648bd9f 100644
--- a/lib/pleroma/web/activity_pub/activity_pub.ex
+++ b/lib/pleroma/web/activity_pub/activity_pub.ex
@@ -800,50 +800,35 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
defp restrict_since(query, _), do: query
- defp restrict_tag_reject(_query, %{"tag_reject" => _tag_reject, "skip_preload" => true}) do
- raise "Can't use the child object without preloading!"
- end
-
defp restrict_tag_reject(query, %{"tag_reject" => tag_reject})
when is_list(tag_reject) and tag_reject != [] do
from(
- [_activity, object] in query,
- where: fragment("not (?)->'tag' \\?| (?)", object.data, ^tag_reject)
+ activity in query,
+ where: fragment("not ? && ?", activity.tags, ^tag_reject)
)
end
defp restrict_tag_reject(query, _), do: query
- defp restrict_tag_all(_query, %{"tag_all" => _tag_all, "skip_preload" => true}) do
- raise "Can't use the child object without preloading!"
- end
-
defp restrict_tag_all(query, %{"tag_all" => tag_all})
when is_list(tag_all) and tag_all != [] do
from(
- [_activity, object] in query,
- where: fragment("(?)->'tag' \\?& (?)", object.data, ^tag_all)
+ activity in query,
+ where: fragment("? @> ?", activity.tags, ^tag_all)
)
end
defp restrict_tag_all(query, _), do: query
- defp restrict_tag(_query, %{"tag" => _tag, "skip_preload" => true}) do
- raise "Can't use the child object without preloading!"
- end
-
defp restrict_tag(query, %{"tag" => tag}) when is_list(tag) do
from(
- [_activity, object] in query,
- where: fragment("(?)->'tag' \\?| (?)", object.data, ^tag)
+ activity in query,
+ where: fragment("? && ?", activity.tags, ^tag)
)
end
defp restrict_tag(query, %{"tag" => tag}) when is_binary(tag) do
- from(
- [_activity, object] in query,
- where: fragment("(?)->'tag' \\? (?)", object.data, ^tag)
- )
+ restrict_tag(query, %{"tag" => [tag]})
end
defp restrict_tag(query, _), do: query
@@ -934,8 +919,7 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
query =
from([activity] in query,
- where: fragment("not (? = ANY(?))", activity.actor, ^mutes),
- where: fragment("not (?->'to' \\?| ?)", activity.data, ^mutes)
+ where: fragment("not (? && ?)", activity.block_cache, ^mutes)
)
unless opts["skip_preload"] do
@@ -953,34 +937,22 @@ defmodule Pleroma.Web.ActivityPub.ActivityPub do
following_ap_ids = User.get_friends_ap_ids(user)
- query =
- if has_named_binding?(query, :object), do: query, else: Activity.with_joined_object(query)
-
from(
- [activity, object: o] in query,
- where: fragment("not (? = ANY(?))", activity.actor, ^blocked_ap_ids),
- where: fragment("not (? && ?)", activity.recipients, ^blocked_ap_ids),
- where:
- fragment(
- "not (?->>'type' = 'Announce' and ?->'to' \\?| ?)",
- activity.data,
- activity.data,
- ^blocked_ap_ids
- ),
+ [activity] in query,
where:
fragment(
- "(not (split_part(?, '/', 3) = ANY(?))) or ? = ANY(?)",
- activity.actor,
- ^domain_blocks,
+ "((not (? && ?)) or (? = ANY(?)))",
+ activity.block_cache,
+ ^(blocked_ap_ids ++ domain_blocks),
activity.actor,
^following_ap_ids
),
where:
fragment(
"(not (split_part(?->>'actor', '/', 3) = ANY(?))) or (?->>'actor') = ANY(?)",
- o.data,
+ activity.data,
^domain_blocks,
- o.data,
+ activity.data,
^following_ap_ids
)
)
diff --git a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
index 29964a1d4..4cac95014 100644
--- a/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
+++ b/lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex
@@ -105,6 +105,7 @@ defmodule Pleroma.Web.MastodonAPI.TimelineController do
|> Map.put("tag", tags)
|> Map.put("tag_all", tag_all)
|> Map.put("tag_reject", tag_reject)
+ |> Map.put("skip_preload", true)
|> ActivityPub.fetch_public_activities()
end
diff --git a/mix.exs b/mix.exs
index b28c65694..39cf55c5e 100644
--- a/mix.exs
+++ b/mix.exs
@@ -76,6 +76,7 @@ defmodule Pleroma.Mixfile do
defp warnings_as_errors(:prod), do: false
# Uncomment this if you need testing configurable_from_database logic
# defp warnings_as_errors(:dev), do: false
+ defp warnings_as_errors(:benchmark), do: false
defp warnings_as_errors(_), do: true
# Specifies OAuth dependencies.
diff --git a/priv/repo/migrations/20200214102520_add_tags_field_to_activities.exs b/priv/repo/migrations/20200214102520_add_tags_field_to_activities.exs
new file mode 100644
index 000000000..ffb216ddd
--- /dev/null
+++ b/priv/repo/migrations/20200214102520_add_tags_field_to_activities.exs
@@ -0,0 +1,35 @@
+defmodule Pleroma.Repo.Migrations.AddTagsFieldToActivities do
+ use Ecto.Migration
+
+ def up do
+ alter table(:activities) do
+ add(:tags, {:array, :string})
+ end
+
+ execute("CREATE FUNCTION activities_tags_update() RETURNS trigger AS $$
+ begin
+ IF new.data->>'type' = 'Create' THEN
+ select array_agg(tags->>0) into new.tags from (select jsonb_array_elements(data->'tag') tags from objects where jsonb_typeof(data->'tag') = 'array' and objects.data->>'id' = new.data->>'object') as tags where jsonb_typeof(tags) = 'string';
+ END IF;
+ return new;
+ end
+ $$ LANGUAGE plpgsql")
+
+ execute(
+ "create trigger update_activity_tags before insert or update on activities for each row execute procedure activities_tags_update()"
+ )
+
+ create_if_not_exists(index(:activities, [:tags], using: :gin))
+ end
+
+ def down do
+ drop("trigger if exists update_activity_tags")
+ drop("function if exists activities_tags_update")
+
+ alter table(:activities) do
+ remove(:tags, {:array, :string})
+ end
+
+ drop_if_exists(index(:activities, [:tags], using: :gin))
+ end
+end
diff --git a/priv/repo/migrations/20200217134311_add_block_cache_to_activities.exs b/priv/repo/migrations/20200217134311_add_block_cache_to_activities.exs
new file mode 100644
index 000000000..c74f37515
--- /dev/null
+++ b/priv/repo/migrations/20200217134311_add_block_cache_to_activities.exs
@@ -0,0 +1,46 @@
+defmodule Pleroma.Repo.Migrations.AddBlockCacheToActivities do
+ use Ecto.Migration
+
+ def up do
+ alter table(:activities) do
+ add(:block_cache, {:array, :string})
+ end
+
+ create_if_not_exists(index(:activities, [:block_cache], using: :gin))
+
+ statement = """
+ create function activities_block_cache_update() returns trigger as $$
+ DECLARE to_ary varchar[];
+ begin
+ if new.data->>'type' = 'Announce' then
+ SELECT array_cat(array_agg(ary)::varchar[], array_agg(split_part(ary, '/', 3))::varchar[])
+ INTO to_ary
+ FROM jsonb_array_elements_text(new.data->'to') AS ary;
+
+ new.block_cache := array_cat(ARRAY[new.actor, split_part(new.actor, '/', 3)], to_ary);
+ else
+ new.block_cache := array_cat(ARRAY[new.actor, split_part(new.actor, '/', 3)], new.recipients);
+ end if;
+ return new;
+ end
+ $$ language plpgsql
+ """
+
+ execute(statement)
+
+ execute(
+ "create trigger activities_block_cache_update before insert or update on activities for each row execute procedure activities_block_cache_update()"
+ )
+ end
+
+ def down do
+ execute("drop trigger if exists activities_block_cache_update on activities")
+ execute("drop function if exists activities_block_cache_update()")
+
+ drop_if_exists(index(:activities, [:block_cache], using: :gin))
+
+ alter table(:activities) do
+ remove(:block_cache, {:array, :string})
+ end
+ end
+end