From 1eed61a7374adc998f1bb6311abe644fc4dc1e9a Mon Sep 17 00:00:00 2001
From: Axel Gembe <ago@bastart.eu.org>
Date: Thu, 26 Jun 2008 09:42:05 +0200
Subject: [PATCH 1/3] db: add the ability to have a seperate write database
Basically this patch adds a second connection pool for the write server. The new
configuration option is "database_write", with the same syntax as the normal
"database" option. If database_write is omitted then the normal pool will be
used.
It works by returning a DatabasePair instead of the actual database connection.
Much existing code will have to be changed to support this change, which will be
done in the following patch. The goal of this is to implement easy
synchronization between two Trac instances by having one master database which
pushes changes to the slave databases.
Signed-off-by: Axel Gembe <ago@bastart.eu.org>
---
trac/db/api.py | 42 ++++++++++++++++++++++++++++++++++++------
trac/env.py | 2 +-
2 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/trac/db/api.py b/trac/db/api.py
index e194293..acbb9e7 100644
|
a
|
b
|
|
| 49 | 49 | """Return the DDL statements necessary to create the specified table, |
| 50 | 50 | including indices.""" |
| 51 | 51 | |
| | 52 | class DatabasePair(object): |
| | 53 | """ |
| | 54 | Holds two database connections, one for reading and one for writing. |
| | 55 | """ |
| | 56 | def __init__(self, db, dbwr): |
| | 57 | self.read = db |
| | 58 | self.write = dbwr |
| 52 | 59 | |
| 53 | 60 | class DatabaseManager(Component): |
| 54 | 61 | |
| … |
… |
|
| 59 | 66 | [wiki:TracEnvironment#DatabaseConnectionStrings string] for this |
| 60 | 67 | project""") |
| 61 | 68 | |
| | 69 | write_connection_uri = Option('trac', 'database_write', '', |
| | 70 | """Database write connection |
| | 71 | [wiki:TracEnvironment#DatabaseConnectionStrings string] for this |
| | 72 | project""") |
| | 73 | |
| 62 | 74 | timeout = IntOption('trac', 'timeout', '20', |
| 63 | 75 | """Timeout value for database connection, in seconds. |
| 64 | 76 | Use '0' to specify ''no timeout''. ''(Since 0.11)''""") |
| 65 | 77 | |
| 66 | 78 | def __init__(self): |
| 67 | 79 | self._cnx_pool = None |
| | 80 | self._cnx_pool_write = None |
| 68 | 81 | |
| 69 | 82 | def init_db(self): |
| 70 | | connector, args = self._get_connector() |
| | 83 | connector, args = self._get_connector(self.connection_uri) |
| | 84 | if self.write_connection_uri and self.write_connection_uri != '': |
| | 85 | connector, args = self._get_connector(self.write_connection_uri) |
| 71 | 86 | connector.init_db(**args) |
| 72 | 87 | |
| 73 | | def get_connection(self): |
| | 88 | def _create_pool(self): |
| 74 | 89 | if not self._cnx_pool: |
| 75 | | connector, args = self._get_connector() |
| | 90 | connector, args = self._get_connector(self.connection_uri) |
| 76 | 91 | self._cnx_pool = ConnectionPool(5, connector, **args) |
| 77 | | return self._cnx_pool.get_cnx(self.timeout or None) |
| | 92 | if self.write_connection_uri and self.write_connection_uri != '' and not self._cnx_pool_write: |
| | 93 | connector, args = self._get_connector(self.write_connection_uri) |
| | 94 | ### FIXME: Connection pool does not handle the max number although it might be needed |
| | 95 | self._cnx_pool_write = ConnectionPool(1, connector, **args) |
| | 96 | |
| | 97 | def get_connection(self): |
| | 98 | self._create_pool() |
| | 99 | conn = self._cnx_pool.get_cnx(self.timeout or None) |
| | 100 | if not self.write_connection_uri or self.write_connection_uri == '': |
| | 101 | return DatabasePair(conn, conn); |
| | 102 | else: |
| | 103 | return DatabasePair(conn, self._cnx_pool_write.get_cnx(self.timeout or None)) |
| 78 | 104 | |
| 79 | 105 | def shutdown(self, tid=None): |
| 80 | 106 | if self._cnx_pool: |
| 81 | 107 | self._cnx_pool.shutdown(tid) |
| 82 | 108 | if not tid: |
| 83 | 109 | self._cnx_pool = None |
| | 110 | if self._cnx_pool_write: |
| | 111 | self._cnx_pool_write.shutdown(tid) |
| | 112 | if not tid: |
| | 113 | self._cnx_pool_write = None |
| 84 | 114 | |
| 85 | | def _get_connector(self): ### FIXME: Make it public? |
| 86 | | scheme, args = _parse_db_str(self.connection_uri) |
| | 115 | def _get_connector(self, db_str): ### FIXME: Make it public? |
| | 116 | scheme, args = _parse_db_str(db_str) |
| 87 | 117 | candidates = {} |
| 88 | 118 | for connector in self.connectors: |
| 89 | 119 | for scheme_, priority in connector.get_supported_schemes(): |
diff --git a/trac/env.py b/trac/env.py
index d082269..11a4314 100644
|
a
|
b
|
|
| 253 | 253 | fd.close() |
| 254 | 254 | |
| 255 | 255 | def get_db_cnx(self): |
| 256 | | """Return a database connection from the connection pool.""" |
| | 256 | """Return a database connection pair from the connection pool.""" |
| 257 | 257 | return DatabaseManager(self).get_connection() |
| 258 | 258 | |
| 259 | 259 | def shutdown(self, tid=None): |