Package Products :: Package ZenEvents :: Module DbConnectionPool |
[hide private]
[frames] | no frames]

# Source Code for Module Products.ZenEvents.DbConnectionPool

      1  ###########################################################################
      2  #
      3  # This program is part of Zenoss Core, an open source monitoring platform.
      4  # Copyright (C) 2007, Zenoss Inc.
      5  #
      6  # This program is free software; you can redistribute it and/or modify it
      7  # under the terms of the GNU General Public License version 2 as published by
      8  # the Free Software Foundation.
      9  #
     10  # For complete information please visit: http://www.zenoss.com/oss/
     11  #
     12  ###########################################################################
     13  from Exceptions import MySQLConnectionError
     14
     15  import time
     16  import DateTime
     17
     18  from Products.ZenUtils import Time as timeutils
     19  from Queue import Queue, Empty, Full
     20
     21  import logging
     22  log = logging.getLogger("zen.DbConnectionPool")
     23
     24  POOL_SIZE = 5
     25  KEEP_ALIVE = 28800
     26
     27
     28 -def timestamp_conv(s):
     29      #timestamps from mysql are passed in as iso dates in the server's timezone
     30      #but do not contain timezone information.  Convert iso time to a timestamp
     31      #using the system timezone. We need to do this because the Zope DateTime
     32      #will use GMT+0 when converting iso times that do not contain tz info.
     33      timestamp = timeutils.isoToTimestamp(s)
     34      return DateTime.DateTime(timestamp)
     35
     36 -class DbConnectionPool:
     37
     38 -    def __new__(self):                  # self is a type
     39          if not '_the_instance' in self.__dict__:
     40              self._the_instance = object.__new__(self)
     41          return self._the_instance
     42
     43      '''
     44      instance = None
     45      def __new__(cls, *args, **kargs):
     46          if cls.instance is None:
     47              cls.instance = object.__new__(cls, *args, **kargs)
     48          log.debug('Returning single instance of DbConnectionPool')
     49          return cls.instance
     50      '''
     51
     52 -    def __init__(self):
     53          self.q = Queue(POOL_SIZE)
     54
     55 -    def qsize(self):
     56          return self.q.qsize()
     57
     58 -    def get(self, host=None, port=None, username=None,
     59              password=None, database=None, block=0):
     60          try:
     61              putstamp,obj = self.q.get(block)
     62
     63              if time.time() - putstamp >= KEEP_ALIVE:
     64                  log.debug('Retrieved a stale connection; Pool size: %s' % self.qsize())
     65                  obj.close()
     66                  return self._createConnection(host=host, port=port,
     67                                              username=username,
     68                                              password=password,
     69                                              database=database)
     70              else:
     71                  log.debug('Retrieved a connection; Pool size: %s' % self.qsize())
     72                  if hasattr(obj, 'ping'):
     73                      # maybe the connection timed out: reconnect if necessary
     74                      obj.ping()
     75                  return obj
     76
     77          except Empty:
     78              return self._createConnection(host=host, port=port,
     79                                          username=username,
     80                                          password=password,
     81                                          database=database)
     82
     83 -    def put(self, obj, block=0):
     84          try:
     85              self.q.put((time.time(),obj), block)
     86              log.debug('Returned a connection; Pool size: %s' % self.qsize())
     87          except Full:
     88              pass
     89
     90 -    def _createConnection(self, host=None, port=None,
     91                          username=None, password=None, database=None):
     92          # These MySQLdb imports were moved from the top of the file to
     93          # here to avoid importing MySQLdb libs at startup.  This is
     94          # desirable for DistributedCollector where we are usually
     95          # executing on a remote box that may not have mysql libs around.
     96          import MySQLdb
     97          import MySQLdb.converters
     98          from MySQLdb.constants import FIELD_TYPE
     99          log.debug('Creating a new connection; Pool size: %s' % self.qsize())
    100          conn = None
    101          mysqlconv = MySQLdb.converters.conversions.copy()
    102          mysqlconv[FIELD_TYPE.DATETIME] = DateTime.DateTime
    103          mysqlconv[FIELD_TYPE.TIMESTAMP] = timestamp_conv
    104          # FIXME for some reason it thinks my int is a long -EAD
    105          mysqlconv[FIELD_TYPE.LONG] = int
    106          if not host:
    107              host, database = database, 'events'
    108          if port:
    109              port = int(port)
    110          try:
    111              conn = MySQLdb.connect(host=host, user=username,
    112                                     port=port, passwd=password,
    113                                     db=database, conv=mysqlconv, reconnect=1)
    114              conn.autocommit(1)
    115              return conn
    116          except Exception, e:
    117              raise MySQLConnectionError(str(e))
    118