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

Commit

Permalink
Add database config class (#6513)
Browse files Browse the repository at this point in the history
* commit '2284eb3a5':
  Add database config class (#6513)
  too many parens
  • Loading branch information
anoadragon453 committed Mar 20, 2020
2 parents 84cb2f7 + 2284eb3 commit 032fed6
Show file tree
Hide file tree
Showing 21 changed files with 321 additions and 245 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ This release includes several security fixes as well as a fix to a bug exposed b
Security updates
----------------

- Fix a bug which could cause room events to be incorrectly authorized using events from a different room. ([\#6501](https://github.com/matrix-org/synapse/issues/6501)), ([\#6503](https://github.com/matrix-org/synapse/issues/6503)), ([\#6521](https://github.com/matrix-org/synapse/issues/6521)), ([\#6524](https://github.com/matrix-org/synapse/issues/6524), [\#6530](https://github.com/matrix-org/synapse/issues/6530), [\#6531](https://github.com/matrix-org/synapse/issues/6531))
- Fix a bug which could cause room events to be incorrectly authorized using events from a different room. ([\#6501](https://github.com/matrix-org/synapse/issues/6501), [\#6503](https://github.com/matrix-org/synapse/issues/6503), [\#6521](https://github.com/matrix-org/synapse/issues/6521), [\#6524](https://github.com/matrix-org/synapse/issues/6524), [\#6530](https://github.com/matrix-org/synapse/issues/6530), [\#6531](https://github.com/matrix-org/synapse/issues/6531))
- Fix a bug causing responses to the `/context` client endpoint to not use the pruned version of the event. ([\#6553](https://github.com/matrix-org/synapse/issues/6553))
- Fix a cause of state resets in room versions 2 onwards. ([\#6556](https://github.com/matrix-org/synapse/issues/6556), [\#6560](https://github.com/matrix-org/synapse/issues/6560))

Expand Down
1 change: 1 addition & 0 deletions changelog.d/6513.misc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Remove all assumptions of there being a single phyiscal DB apart from the `synapse.config`.
9 changes: 2 additions & 7 deletions scripts-dev/update_database
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ from synapse.config.homeserver import HomeServerConfig
from synapse.metrics.background_process_metrics import run_as_background_process
from synapse.server import HomeServer
from synapse.storage import DataStore
from synapse.storage.prepare_database import prepare_database

logger = logging.getLogger("update_database")

Expand Down Expand Up @@ -77,12 +76,8 @@ if __name__ == "__main__":
# Instantiate and initialise the homeserver object.
hs = MockHomeserver(config)

db_conn = hs.get_db_conn()
# Update the database to the latest schema.
prepare_database(db_conn, hs.database_engine, config=config)
db_conn.commit()

# setup instantiates the store within the homeserver object.
# Setup instantiates the store within the homeserver object and updates the
# DB.
hs.setup()
store = hs.get_datastore()

Expand Down
58 changes: 24 additions & 34 deletions scripts/synapse_port_db
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import yaml
from twisted.enterprise import adbapi
from twisted.internet import defer, reactor

from synapse.config.database import DatabaseConnectionConfig
from synapse.config.homeserver import HomeServerConfig
from synapse.logging.context import PreserveLoggingContext
from synapse.storage._base import LoggingTransaction
Expand All @@ -55,7 +56,7 @@ from synapse.storage.data_stores.main.stats import StatsStore
from synapse.storage.data_stores.main.user_directory import (
UserDirectoryBackgroundUpdateStore,
)
from synapse.storage.database import Database
from synapse.storage.database import Database, make_conn
from synapse.storage.engines import create_engine
from synapse.storage.prepare_database import prepare_database
from synapse.util import Clock
Expand Down Expand Up @@ -165,23 +166,17 @@ class Store(


class MockHomeserver:
def __init__(self, config, database_engine, db_conn, db_pool):
self.database_engine = database_engine
self.db_conn = db_conn
self.db_pool = db_pool
def __init__(self, config):
self.clock = Clock(reactor)
self.config = config
self.hostname = config.server_name

def get_db_conn(self):
return self.db_conn

def get_db_pool(self):
return self.db_pool

def get_clock(self):
return self.clock

def get_reactor(self):
return reactor


class Porter(object):
def __init__(self, **kwargs):
Expand Down Expand Up @@ -445,45 +440,36 @@ class Porter(object):
else:
return

def setup_db(self, db_config, database_engine):
db_conn = database_engine.module.connect(
**{
k: v
for k, v in db_config.get("args", {}).items()
if not k.startswith("cp_")
}
)

prepare_database(db_conn, database_engine, config=None)
def setup_db(self, db_config: DatabaseConnectionConfig, engine):
db_conn = make_conn(db_config, engine)
prepare_database(db_conn, engine, config=None)

db_conn.commit()

return db_conn

@defer.inlineCallbacks
def build_db_store(self, config):
def build_db_store(self, db_config: DatabaseConnectionConfig):
"""Builds and returns a database store using the provided configuration.
Args:
config: The database configuration, i.e. a dict following the structure of
the "database" section of Synapse's configuration file.
config: The database configuration
Returns:
The built Store object.
"""
engine = create_engine(config)

self.progress.set_state("Preparing %s" % config["name"])
conn = self.setup_db(config, engine)
self.progress.set_state("Preparing %s" % db_config.config["name"])

db_pool = adbapi.ConnectionPool(config["name"], **config["args"])
engine = create_engine(db_config.config)
conn = self.setup_db(db_config, engine)

hs = MockHomeserver(self.hs_config, engine, conn, db_pool)
hs = MockHomeserver(self.hs_config)

store = Store(Database(hs), conn, hs)
store = Store(Database(hs, db_config, engine), conn, hs)

yield store.db.runInteraction(
"%s_engine.check_database" % config["name"], engine.check_database,
"%s_engine.check_database" % db_config.config["name"],
engine.check_database,
)

return store
Expand All @@ -509,7 +495,11 @@ class Porter(object):
@defer.inlineCallbacks
def run(self):
try:
self.sqlite_store = yield self.build_db_store(self.sqlite_config)
self.sqlite_store = yield self.build_db_store(
DatabaseConnectionConfig(
"master", self.sqlite_config, data_stores=["main"]
)
)

# Check if all background updates are done, abort if not.
updates_complete = (
Expand All @@ -524,7 +514,7 @@ class Porter(object):
defer.returnValue(None)

self.postgres_store = yield self.build_db_store(
self.hs_config.database_config
self.hs_config.get_single_database()
)

yield self.run_background_updates_on_postgres()
Expand Down
78 changes: 62 additions & 16 deletions synapse/config/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,43 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
from textwrap import indent
from typing import List

import yaml

from ._base import Config
from synapse.config._base import Config, ConfigError

logger = logging.getLogger(__name__)


class DatabaseConnectionConfig:
"""Contains the connection config for a particular database.
Args:
name: A label for the database, used for logging.
db_config: The config for a particular database, as per `database`
section of main config. Has two fields: `name` for database
module name, and `args` for the args to give to the database
connector.
data_stores: The list of data stores that should be provisioned on the
database.
"""

def __init__(self, name: str, db_config: dict, data_stores: List[str]):
if db_config["name"] not in ("sqlite3", "psycopg2"):
raise ConfigError("Unsupported database type %r" % (db_config["name"],))

if db_config["name"] == "sqlite3":
db_config.setdefault("args", {}).update(
{"cp_min": 1, "cp_max": 1, "check_same_thread": False}
)

self.name = name
self.config = db_config
self.data_stores = data_stores


class DatabaseConfig(Config):
Expand All @@ -26,20 +57,14 @@ class DatabaseConfig(Config):
def read_config(self, config, **kwargs):
self.event_cache_size = self.parse_size(config.get("event_cache_size", "10K"))

self.database_config = config.get("database")
database_config = config.get("database")

if self.database_config is None:
self.database_config = {"name": "sqlite3", "args": {}}
if database_config is None:
database_config = {"name": "sqlite3", "args": {}}

name = self.database_config.get("name", None)
if name == "psycopg2":
pass
elif name == "sqlite3":
self.database_config.setdefault("args", {}).update(
{"cp_min": 1, "cp_max": 1, "check_same_thread": False}
)
else:
raise RuntimeError("Unsupported database type '%s'" % (name,))
self.databases = [
DatabaseConnectionConfig("master", database_config, data_stores=["main"])
]

self.set_databasepath(config.get("database_path"))

Expand Down Expand Up @@ -76,11 +101,24 @@ def read_arguments(self, args):
self.set_databasepath(args.database_path)

def set_databasepath(self, database_path):
if database_path is None:
return

if database_path != ":memory:":
database_path = self.abspath(database_path)
if self.database_config.get("name", None) == "sqlite3":
if database_path is not None:
self.database_config["args"]["database"] = database_path

# We only support setting a database path if we have a single sqlite3
# database.
if len(self.databases) != 1:
raise ConfigError("Cannot specify 'database_path' with multiple databases")

database = self.get_single_database()
if database.config["name"] != "sqlite3":
# We don't raise here as we haven't done so before for this case.
logger.warn("Ignoring 'database_path' for non-sqlite3 database")
return

database.config["args"]["database"] = database_path

@staticmethod
def add_arguments(parser):
Expand All @@ -91,3 +129,11 @@ def add_arguments(parser):
metavar="SQLITE_DATABASE_PATH",
help="The path to a sqlite database to use.",
)

def get_single_database(self) -> DatabaseConnectionConfig:
"""Returns the database if there is only one, useful for e.g. tests
"""
if len(self.databases) != 1:
raise Exception("More than one database exists")

return self.databases[0]
Loading

0 comments on commit 032fed6

Please sign in to comment.