[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