Merge pull request 'Raise minimum PostgreSQL version to 12' (#786) from Oneric/akkoma:psql-min-ver into develop

Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/786
This commit is contained in:
floatingghost 2024-06-07 16:53:22 +00:00
commit d1c4b97613
7 changed files with 26 additions and 108 deletions

View file

@ -4,6 +4,18 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## UNRELEASED
## BREAKING
- Minimum PostgreSQL version is raised to 12
## Added
- Implement [FEP-67ff](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) (federation documentation)
- Meilisearch: it is now possible to use separate keys for search and admin actions
## Fixed
- Meilisearch: order of results returned from our REST API now actually matches how Meilisearch ranks results
## 2024.04.1 (Security) ## 2024.04.1 (Security)
## Fixed ## Fixed
@ -11,15 +23,6 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Issue allowing use of non-media objects as attachments and crashing timeline rendering - Issue allowing use of non-media objects as attachments and crashing timeline rendering
- Issue allowing webfinger spoofing in certain situations - Issue allowing webfinger spoofing in certain situations
## Added
- Implement [FEP-67ff](https://codeberg.org/fediverse/fep/src/branch/main/fep/67ff/fep-67ff.md) (federation documentation)
## Added
- Meilisearch: it is now possible to use separate keys for search and admin actions
## Fixed
- Meilisearch: order of results returned from our REST API now actually matches how Meilisearch ranks results
## 2024.04 ## 2024.04
## Added ## Added

View file

@ -813,8 +813,10 @@ config :pleroma, :modules, runtime_dir: "instance/modules"
config :pleroma, configurable_from_database: false config :pleroma, configurable_from_database: false
config :pleroma, Pleroma.Repo, config :pleroma, Pleroma.Repo,
parameters: [gin_fuzzy_search_limit: "500"], parameters: [
prepare: :unnamed gin_fuzzy_search_limit: "500",
plan_cache_mode: "force_custom_plan"
]
config :pleroma, :majic_pool, size: 2 config :pleroma, :majic_pool, size: 2

View file

@ -11,21 +11,3 @@ It is also recommended to not use "Network Storage" option.
If your server runs other services, you may want to take that into account. E.g. if you have 4G ram, but 1G of it is already used for other services, it may be better to tell PGTune you only have 3G. If your server runs other services, you may want to take that into account. E.g. if you have 4G ram, but 1G of it is already used for other services, it may be better to tell PGTune you only have 3G.
In the end, PGTune only provides recomended settings, you can always try to finetune further. In the end, PGTune only provides recomended settings, you can always try to finetune further.
## Disable generic query plans
When PostgreSQL receives a query, it decides on a strategy for searching the requested data, this is called a query plan. The query planner has two modes: generic and custom. Generic makes a plan for all queries of the same shape, ignoring the parameters, which is then cached and reused. Custom, on the contrary, generates a unique query plan based on query parameters.
By default PostgreSQL has an algorithm to decide which mode is more efficient for particular query, however this algorithm has been observed to be wrong on some of the queries Akkoma sends, leading to serious performance loss. Therefore, it is recommended to disable generic mode.
Akkoma already avoids generic query plans by default, however the method it uses is not the most efficient because it needs to be compatible with all supported PostgreSQL versions. For PostgreSQL 12 and higher additional performance can be gained by adding the following to Akkoma configuration:
```elixir
config :pleroma, Pleroma.Repo,
prepare: :named,
parameters: [
plan_cache_mode: "force_custom_plan"
]
```
A more detailed explaination of the issue can be found at <https://blog.soykaf.com/post/postgresql-elixir-troubles/>.

View file

@ -1,6 +1,6 @@
## Required dependencies ## Required dependencies
* PostgreSQL 9.6+ * PostgreSQL 12+
* Elixir 1.14+ (currently tested up to 1.16) * Elixir 1.14+ (currently tested up to 1.16)
* Erlang OTP 25+ (currently tested up to OTP26) * Erlang OTP 25+ (currently tested up to OTP26)
* git * git

View file

@ -95,34 +95,17 @@ defmodule Pleroma.Application do
opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts] opts = [strategy: :one_for_one, name: Pleroma.Supervisor, max_restarts: max_restarts]
with {:ok, data} <- Supervisor.start_link(children, opts) do case Supervisor.start_link(children, opts) do
set_postgres_server_version() {:ok, data} ->
{:ok, data} {:ok, data}
else
e -> e ->
Logger.error("Failed to start!") Logger.critical("Failed to start!")
Logger.error("#{inspect(e)}") Logger.critical("#{inspect(e)}")
e e
end end
end end
defp set_postgres_server_version do
version =
with %{rows: [[version]]} <- Ecto.Adapters.SQL.query!(Pleroma.Repo, "show server_version"),
{num, _} <- Float.parse(version) do
num
else
e ->
Logger.warning(
"Could not get the postgres version: #{inspect(e)}.\nSetting the default value of 9.6"
)
9.6
end
:persistent_term.put({Pleroma.Repo, :postgres_version}, version)
end
def load_custom_modules do def load_custom_modules do
dir = Config.get([:modules, :runtime_dir]) dir = Config.get([:modules, :runtime_dir])

View file

@ -21,19 +21,12 @@ defmodule Pleroma.Search.DatabaseSearch do
offset = Keyword.get(options, :offset, 0) offset = Keyword.get(options, :offset, 0)
author = Keyword.get(options, :author) author = Keyword.get(options, :author)
search_function =
if :persistent_term.get({Pleroma.Repo, :postgres_version}) >= 11 do
:websearch
else
:plain
end
try do try do
Activity Activity
|> Activity.with_preloaded_object() |> Activity.with_preloaded_object()
|> Activity.restrict_deactivated_users() |> Activity.restrict_deactivated_users()
|> restrict_public() |> restrict_public()
|> query_with(index_type, search_query, search_function) |> query_with(index_type, search_query)
|> maybe_restrict_local(user) |> maybe_restrict_local(user)
|> maybe_restrict_author(author) |> maybe_restrict_author(author)
|> maybe_restrict_blocked(user) |> maybe_restrict_blocked(user)
@ -72,25 +65,7 @@ defmodule Pleroma.Search.DatabaseSearch do
) )
end end
defp query_with(q, :gin, search_query, :plain) do defp query_with(q, :gin, search_query) do
%{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!(
Pleroma.Repo,
"select current_setting('default_text_search_config')::regconfig::oid;"
)
from([a, o] in q,
where:
fragment(
"to_tsvector(?::oid::regconfig, ?->>'content') @@ plainto_tsquery(?)",
^tsc,
o.data,
^search_query
)
)
end
defp query_with(q, :gin, search_query, :websearch) do
%{rows: [[tsc]]} = %{rows: [[tsc]]} =
Ecto.Adapters.SQL.query!( Ecto.Adapters.SQL.query!(
Pleroma.Repo, Pleroma.Repo,
@ -108,19 +83,7 @@ defmodule Pleroma.Search.DatabaseSearch do
) )
end end
defp query_with(q, :rum, search_query, :plain) do defp query_with(q, :rum, search_query) do
from([a, o] in q,
where:
fragment(
"? @@ plainto_tsquery(?)",
o.fts_content,
^search_query
),
order_by: [fragment("? <=> now()::date", o.inserted_at)]
)
end
defp query_with(q, :rum, search_query, :websearch) do
from([a, o] in q, from([a, o] in q,
where: where:
fragment( fragment(

View file

@ -18,21 +18,6 @@ defmodule Pleroma.Search.DatabaseSearchTest do
assert result.id == post.id assert result.id == post.id
end end
test "using plainto_tsquery on postgres < 11" do
old_version = :persistent_term.get({Pleroma.Repo, :postgres_version})
:persistent_term.put({Pleroma.Repo, :postgres_version}, 10.0)
on_exit(fn -> :persistent_term.put({Pleroma.Repo, :postgres_version}, old_version) end)
user = insert(:user)
{:ok, post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"})
{:ok, _post2} = CommonAPI.post(user, %{status: "it's wednesday my bros"})
# plainto doesn't understand complex queries
assert [result] = DatabaseSearch.search(nil, "wednesday -dudes")
assert result.id == post.id
end
test "using websearch_to_tsquery" do test "using websearch_to_tsquery" do
user = insert(:user) user = insert(:user)
{:ok, _post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"}) {:ok, _post} = CommonAPI.post(user, %{status: "it's wednesday my dudes"})