diff options
author | lain <lain@soykaf.club> | 2020-02-18 13:17:00 +0100 |
---|---|---|
committer | lain <lain@soykaf.club> | 2020-02-18 13:17:00 +0100 |
commit | 12738732c90592032cd5c7455363a3a0a4a26e7a (patch) | |
tree | 2867babdf87bf30dabd61e6cc742487ebd724049 | |
parent | 5178c8dbc34db3b78eaa21a2f46300ac1a639c8c (diff) |
Hashtags, Blocks: Reword for performance.
-rw-r--r-- | benchmarks/mix/tasks/pleroma/benchmarks/tags.ex | 30 | ||||
-rw-r--r-- | lib/pleroma/activity.ex | 1 | ||||
-rw-r--r-- | lib/pleroma/web/activity_pub/activity_pub.ex | 56 | ||||
-rw-r--r-- | lib/pleroma/web/mastodon_api/controllers/timeline_controller.ex | 1 | ||||
-rw-r--r-- | mix.exs | 1 | ||||
-rw-r--r-- | priv/repo/migrations/20200214102520_add_tags_field_to_activities.exs | 35 | ||||
-rw-r--r-- | priv/repo/migrations/20200217134311_add_block_cache_to_activities.exs | 46 |
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 @@ -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 |