[CalendarServer-changes] [11040] CalendarServer/trunk/txdav/base/datastore
source_changes at macosforge.org
source_changes at macosforge.org
Mon Apr 15 13:55:19 PDT 2013
Revision: 11040
http://trac.calendarserver.org//changeset/11040
Author: sagen at apple.com
Date: 2013-04-15 13:55:19 -0700 (Mon, 15 Apr 2013)
Log Message:
-----------
First try connecting to postgres before using pg_ctl to save a few seconds
Modified Paths:
--------------
CalendarServer/trunk/txdav/base/datastore/subpostgres.py
CalendarServer/trunk/txdav/base/datastore/test/test_subpostgres.py
Modified: CalendarServer/trunk/txdav/base/datastore/subpostgres.py
===================================================================
--- CalendarServer/trunk/txdav/base/datastore/subpostgres.py 2013-04-15 17:52:50 UTC (rev 11039)
+++ CalendarServer/trunk/txdav/base/datastore/subpostgres.py 2013-04-15 20:55:19 UTC (rev 11040)
@@ -27,14 +27,12 @@
from twisted.python.procutils import which
from twisted.internet.protocol import ProcessProtocol
-from twisted.python.reflect import namedAny
from twext.python.log import Logger
from twext.python.filepath import CachingFilePath
-pgdb = namedAny("pgdb")
+import pgdb
from twisted.protocols.basic import LineReceiver
-from twisted.internet import reactor
from twisted.internet.defer import Deferred
from txdav.base.datastore.dbapiclient import DBAPIConnector
from txdav.base.datastore.dbapiclient import postgresPreflight
@@ -168,7 +166,8 @@
spawnedDBUser="caldav",
importFileName=None,
pgCtl="pg_ctl",
- initDB="initdb"):
+ initDB="initdb",
+ reactor=None):
"""
Initialize a L{PostgresService} pointed at a data store directory.
@@ -239,8 +238,16 @@
self.openConnections = []
self._pgCtl = pgCtl
self._initdb = initDB
+ self._reactor = reactor
+ @property
+ def reactor(self):
+ if self._reactor is None:
+ from twisted.internet import reactor
+ self._reactor = reactor
+ return self._reactor
+
def pgCtl(self):
"""
Locate the path to pg_ctl.
@@ -300,17 +307,12 @@
return self._connectorFor(databaseName).connect(label)
- def ready(self):
+ def ready(self, createDatabaseConn, createDatabaseCursor):
"""
Subprocess is ready. Time to initialize the subservice.
If the database has not been created and there is a dump file,
then the dump file is imported.
"""
- createDatabaseConn = self.produceConnection(
- 'schema creation', 'postgres'
- )
- createDatabaseCursor = createDatabaseConn.cursor()
- createDatabaseCursor.execute("commit")
if self.resetSchema:
try:
@@ -347,9 +349,6 @@
connection.commit()
connection.close()
- # TODO: anyone know why these two lines are here?
- connection = self.produceConnection()
- cursor = connection.cursor()
if self.shutdownDeferred is None:
# Only continue startup if we've not begun shutdown
@@ -383,6 +382,30 @@
"""
Start the database and initialize the subservice.
"""
+
+ def createConnection():
+ createDatabaseConn = self.produceConnection(
+ 'schema creation', 'postgres'
+ )
+ createDatabaseCursor = createDatabaseConn.cursor()
+ createDatabaseCursor.execute("commit")
+ return createDatabaseConn, createDatabaseCursor
+
+ try:
+ createDatabaseConn, createDatabaseCursor = createConnection()
+ except pgdb.DatabaseError:
+ # We could not connect the database, so attempt to start it
+ pass
+ except Exception, e:
+ # Some other unexpected error is preventing us from connecting
+ # to the database
+ log.warn("Failed to connect to Postgres: %s" % (str(e)))
+ else:
+ # Database is running, so just use our connection
+ self.ready(createDatabaseConn, createDatabaseCursor)
+ self.deactivateDelayedShutdown()
+ return
+
monitor = _PostgresMonitor(self)
pgCtl = self.pgCtl()
# check consistency of initdb and postgres?
@@ -400,7 +423,7 @@
options.append("-c standard_conforming_strings=on")
options.extend(self.options)
- reactor.spawnProcess(
+ self.reactor.spawnProcess(
monitor, pgCtl,
[
pgCtl,
@@ -418,7 +441,7 @@
self.monitor = monitor
def gotReady(result):
self.shouldStopDatabase = result
- self.ready()
+ self.ready(*createConnection())
self.deactivateDelayedShutdown()
def reportit(f):
log.err(f)
@@ -454,7 +477,7 @@
os.chown(self.dataStoreDirectory.path, self.uid, self.gid)
os.chown(workingDir.path, self.uid, self.gid)
dbInited = Deferred()
- reactor.spawnProcess(
+ self.reactor.spawnProcess(
CapturingProcessProtocol(dbInited, None),
initdb, [initdb, "-E", "UTF8", "-U", self.spawnedDBUser], env, workingDir.path,
uid=self.uid, gid=self.gid,
@@ -486,7 +509,7 @@
if self.shouldStopDatabase:
monitor = _PostgresMonitor()
pgCtl = self.pgCtl()
- reactor.spawnProcess(monitor, pgCtl,
+ self.reactor.spawnProcess(monitor, pgCtl,
[pgCtl, '-l', 'logfile', 'stop'],
self.env,
uid=self.uid, gid=self.gid,
Modified: CalendarServer/trunk/txdav/base/datastore/test/test_subpostgres.py
===================================================================
--- CalendarServer/trunk/txdav/base/datastore/test/test_subpostgres.py 2013-04-15 17:52:50 UTC (rev 11039)
+++ CalendarServer/trunk/txdav/base/datastore/test/test_subpostgres.py 2013-04-15 20:55:19 UTC (rev 11040)
@@ -20,12 +20,19 @@
from twisted.trial.unittest import TestCase
+# NOTE: This import will fail eventuall when this functionality is added to
+# MemoryReactor:
+from twisted.runner.test.test_procmon import DummyProcessReactor
+
+from twisted.python.filepath import FilePath
from twext.python.filepath import CachingFilePath
from txdav.base.datastore.subpostgres import PostgresService
from twisted.internet.defer import inlineCallbacks, Deferred
from twisted.application.service import Service
+import pgdb
+
class SubprocessStartup(TestCase):
"""
Tests for starting and stopping the subprocess.
@@ -185,3 +192,73 @@
values = cursor.fetchall()
self.assertEquals(values, [["value1"],["value2"]])
+ def test_startDatabaseRunning(self):
+ """ Ensure that if we can connect to postgres we don't spawn pg_ctl """
+
+ self.cursorHistory = []
+
+ class DummyCursor(object):
+ def __init__(self, historyHolder):
+ self.historyHolder = historyHolder
+
+ def execute(self, *args):
+ self.historyHolder.cursorHistory.append(args)
+
+ def close(self):
+ pass
+
+ class DummyConnection(object):
+ def __init__(self, historyHolder):
+ self.historyHolder = historyHolder
+
+ def cursor(self):
+ return DummyCursor(self.historyHolder)
+
+ def commit(self):
+ pass
+
+ def close(self):
+ pass
+
+ def produceConnection(*args):
+ return DummyConnection(self)
+
+ dummyReactor = DummyProcessReactor()
+ svc = PostgresService(
+ FilePath("postgres_4.pgdb"),
+ lambda x : Service(),
+ "",
+ reactor=dummyReactor,
+ )
+ svc.produceConnection = produceConnection
+ svc.env = {}
+ svc.startDatabase()
+ self.assertEquals(
+ self.cursorHistory,
+ [
+ ('commit',),
+ ("create database subpostgres with encoding 'UTF8'",),
+ ('',)
+ ]
+ )
+ self.assertEquals(dummyReactor.spawnedProcesses, [])
+
+
+ def test_startDatabaseNotRunning(self):
+ """ Ensure that if we can't connect to postgres we spawn pg_ctl """
+
+ def produceConnection(*args):
+ raise pgdb.DatabaseError
+
+ dummyReactor = DummyProcessReactor()
+ svc = PostgresService(
+ FilePath("postgres_4.pgdb"),
+ lambda x : Service(),
+ "",
+ reactor=dummyReactor,
+ )
+ svc.produceConnection = produceConnection
+ svc.env = {}
+ svc.startDatabase()
+ self.assertEquals(len(dummyReactor.spawnedProcesses), 1)
+ self.assertTrue(dummyReactor.spawnedProcesses[0]._executable.endswith("pg_ctl"))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130415/fc79020a/attachment.html>
More information about the calendarserver-changes
mailing list