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

Commit 4f66a15

Browse files
committed
Warn if postgres database has non-C locale. (#6734)
* commit '02b44db92': Warn if postgres database has non-C locale. (#6734)
2 parents 1f1239d + 02b44db commit 4f66a15

File tree

6 files changed

+81
-1
lines changed

6 files changed

+81
-1
lines changed

UPGRADE.rst

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,15 @@ for example:
7676
dpkg -i matrix-synapse-py3_1.3.0+stretch1_amd64.deb
7777
7878
79+
Upgrading to **<NEXT_VERSION>**
80+
===============================
81+
82+
Synapse will now log a warning on start up if used with a PostgreSQL database
83+
that has a non-recommended locale set.
84+
85+
See [docs/postgres.md](docs/postgres.md) for details.
86+
87+
7988
Upgrading to v1.8.0
8089
===================
8190

changelog.d/6734.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Warn if postgres database has a non-C locale, as that can cause issues when upgrading locales (e.g. due to upgrading OS).

docs/postgres.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ Assuming your PostgreSQL database user is called `postgres`, first authenticate
3232
su - postgres
3333
# Or, if your system uses sudo to get administrative rights
3434
sudo -u postgres bash
35-
35+
3636
Then, create a user ``synapse_user`` with:
3737

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

66+
### Fixing incorrect `COLLATE` or `CTYPE`
67+
68+
Synapse will refuse to set up a new database if it has the wrong values of
69+
`COLLATE` and `CTYPE` set, and will log warnings on existing databases. Using
70+
different locales can cause issues if the locale library is updated from
71+
underneath the database, or if a different version of the locale is used on any
72+
replicas.
73+
74+
The safest way to fix the issue is to take a dump and recreate the database with
75+
the correct `COLLATE` and `CTYPE` parameters (as per
76+
[docs/postgres.md](docs/postgres.md)). It is also possible to change the
77+
parameters on a live database and run a `REINDEX` on the entire database,
78+
however extreme care must be taken to avoid database corruption.
79+
80+
Note that the above may fail with an error about duplicate rows if corruption
81+
has already occurred, and such duplicate rows will need to be manually removed.
82+
83+
6684
## Tuning Postgres
6785

6886
The default settings should be fine for most deployments. For larger

synapse/storage/engines/postgres.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@
1313
# See the License for the specific language governing permissions and
1414
# limitations under the License.
1515

16+
import logging
17+
1618
from ._base import IncorrectDatabaseSetup
1719

20+
logger = logging.getLogger(__name__)
21+
1822

1923
class PostgresEngine(object):
2024
single_threaded = False
@@ -52,6 +56,44 @@ def check_database(self, db_conn, allow_outdated_version: bool = False):
5256
"See docs/postgres.rst for more information." % (rows[0][0],)
5357
)
5458

59+
txn.execute(
60+
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
61+
)
62+
collation, ctype = txn.fetchone()
63+
if collation != "C":
64+
logger.warning(
65+
"Database has incorrect collation of %r. Should be 'C'", collation
66+
)
67+
68+
if ctype != "C":
69+
logger.warning(
70+
"Database has incorrect ctype of %r. Should be 'C'", ctype
71+
)
72+
73+
def check_new_database(self, txn):
74+
"""Gets called when setting up a brand new database. This allows us to
75+
apply stricter checks on new databases versus existing database.
76+
"""
77+
78+
txn.execute(
79+
"SELECT datcollate, datctype FROM pg_database WHERE datname = current_database()"
80+
)
81+
collation, ctype = txn.fetchone()
82+
83+
errors = []
84+
85+
if collation != "C":
86+
errors.append(" - 'COLLATE' is set to %r. Should be 'C'" % (collation,))
87+
88+
if ctype != "C":
89+
errors.append(" - 'CTYPE' is set to %r. Should be 'C'" % (collation,))
90+
91+
if errors:
92+
raise IncorrectDatabaseSetup(
93+
"Database is incorrectly configured:\n\n%s\n\n"
94+
"See docs/postgres.md for more information." % ("\n".join(errors))
95+
)
96+
5597
def convert_param_style(self, sql):
5698
return sql.replace("?", "%s")
5799

synapse/storage/engines/sqlite.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ def check_database(self, db_conn, allow_outdated_version: bool = False):
5959
if version < (3, 11, 0):
6060
raise RuntimeError("Synapse requires sqlite 3.11 or above.")
6161

62+
def check_new_database(self, txn):
63+
"""Gets called when setting up a brand new database. This allows us to
64+
apply stricter checks on new databases versus existing database.
65+
"""
66+
6267
def convert_param_style(self, sql):
6368
return sql
6469

synapse/storage/prepare_database.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@ def _setup_new_database(cur, database_engine, data_stores):
136136
data_stores (list[str]): The names of the data stores to instantiate
137137
on the given database.
138138
"""
139+
140+
# We're about to set up a brand new database so we check that its
141+
# configured to our liking.
142+
database_engine.check_new_database(cur)
143+
139144
current_dir = os.path.join(dir_path, "schema", "full_schemas")
140145
directory_entries = os.listdir(current_dir)
141146

0 commit comments

Comments
 (0)