Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Warn if postgres database has non-C locale. #6734

Merged
merged 11 commits into from
Jan 28, 2020
1 change: 1 addition & 0 deletions .buildkite/docker-compose.py35.pg95.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
image: postgres:9.5
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: "--lc-collate C --lc-ctype C"
command: -c fsync=off

testenv:
Expand Down
1 change: 1 addition & 0 deletions .buildkite/docker-compose.py37.pg11.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
image: postgres:11
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: "--lc-collate C --lc-ctype C"
command: -c fsync=off

testenv:
Expand Down
1 change: 1 addition & 0 deletions .buildkite/docker-compose.py37.pg95.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ services:
image: postgres:9.5
environment:
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: "--lc-collate C --lc-ctype C"
command: -c fsync=off

testenv:
Expand Down
9 changes: 9 additions & 0 deletions UPGRADE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,15 @@ for example:
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb


Upgrading to **<NEXT_VERSION>**
===============================

Synapse will now log a warning on start up if used with a PostgreSQL database
that has a non-recommended locale set.

See [docs/postgres.md](docs/postgres.md) for details.


Upgrading to v1.8.0
===================

Expand Down
1 change: 1 addition & 0 deletions changelog.d/6734.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Warn if postgres database has a non-C locale, as that can cause issues when upgrading locales (e.g. due to upgrading OS).
16 changes: 15 additions & 1 deletion docs/postgres.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Assuming your PostgreSQL database user is called `postgres`, first authenticate
su - postgres
# Or, if your system uses sudo to get administrative rights
sudo -u postgres bash

Then, create a user ``synapse_user`` with:

createuser --pwprompt synapse_user
Expand Down Expand Up @@ -63,6 +63,20 @@ You may need to enable password authentication so `synapse_user` can
connect to the database. See
<https://www.postgresql.org/docs/11/auth-pg-hba-conf.html>.

### Fixing incorrect `COLLATE` or `CTYPE`

Synapse will refuse to set up a new database if it has the wrong values of
`COLLATE` and `CTYPE` set, and will log warnings on existing databases. Using
different locales can cause issues if the locale library is updated from
underneath the database, or if a different version of the locale is used on any
replicas.

The safest way to fix the issue is to take a dump and recreate the database with
the correct `COLLATE` and `CTYPE` parameters (as per
[docs/postgres.md](docs/postgres.md)). It is also possible to change the
parameters on a live database and run a `REINDEX` on the entire database,
however extreme care must be taken to avoid database corruption.
richvdh marked this conversation as resolved.
Show resolved Hide resolved

## Tuning Postgres

The default settings should be fine for most deployments. For larger
Expand Down
41 changes: 41 additions & 0 deletions synapse/storage/engines/postgres.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from ._base import IncorrectDatabaseSetup

logger = logging.getLogger(__name__)


class PostgresEngine(object):
single_threaded = False
Expand Down Expand Up @@ -52,6 +56,43 @@ def check_database(self, db_conn, allow_outdated_version: bool = False):
"See docs/postgres.rst for more information." % (rows[0][0],)
)

txn.execute(
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
)
collation, ctype = txn.fetchone()
if collation != "C":
logger.warning(
"Database has incorrect collation of %r. Should be 'C'", collation
)

if ctype != "C":
logger.warning(
"Database has incorrect ctype of %r. Should be 'C'", ctype
)

def check_new_database(self, txn):
"""Gets called when setting up a brand new database. This allows us to
apply stricter checks on new databases versus existing database.
"""

txn.execute(
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
)
collation, ctype = txn.fetchone()

errors = []

if collation != "C":
errors.append(" - 'COLLATE' is set to %r. Should be 'C'" % (collation,))

if ctype != "C":
errors.append(" - 'CTYPE' is set to %r. Should be 'C'" % (collation,))

if errors:
raise IncorrectDatabaseSetup(
"Database is incorrectly configured:\n%s" % ("\n".join(errors))
)

def convert_param_style(self, sql):
return sql.replace("?", "%s")

Expand Down
5 changes: 5 additions & 0 deletions synapse/storage/engines/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ def check_database(self, db_conn, allow_outdated_version: bool = False):
if version < (3, 11, 0):
raise RuntimeError("Synapse requires sqlite 3.11 or above.")

def check_new_database(self, txn):
"""Gets called when setting up a brand new database. This allows us to
apply stricter checks on new databases versus existing database.
"""

def convert_param_style(self, sql):
return sql

Expand Down
5 changes: 5 additions & 0 deletions synapse/storage/prepare_database.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,11 @@ def _setup_new_database(cur, database_engine, data_stores):
data_stores (list[str]): The names of the data stores to instantiate
on the given database.
"""

# We're about to set up a brand new database so we check that its
# configured to our liking.
database_engine.check_new_database(cur)

current_dir = os.path.join(dir_path, "schema", "full_schemas")
directory_entries = os.listdir(current_dir)

Expand Down