Index: trac/db/api.py
===================================================================
--- trac/db/api.py	(revision 3868)
+++ trac/db/api.py	(working copy)
@@ -17,7 +17,7 @@
 import os
 import urllib
 
-from trac.config import Option
+from trac.config import Option, FloatOption
 from trac.core import *
 from trac.db.pool import ConnectionPool
 
@@ -57,6 +57,10 @@
         [wiki:TracEnvironment#DatabaseConnectionStrings string] for this
         project""")
 
+    timeout = FloatOption('trac', 'timeout', '20.0',
+        """Timeout value for database connection, in seconds.
+        Use '0' to specify ''no timeout''. ''(Since 0.11)''""")
+
     def __init__(self):
         self._cnx_pool = None
 
@@ -68,7 +72,7 @@
         if not self._cnx_pool:
             connector, args = self._get_connector()
             self._cnx_pool = ConnectionPool(5, connector, **args)
-        return self._cnx_pool.get_cnx()
+        return self._cnx_pool.get_cnx(self.timeout or None)
 
     def shutdown(self, tid=None):
         if self._cnx_pool:
Index: trac/db/pool.py
===================================================================
--- trac/db/pool.py	(revision 3868)
+++ trac/db/pool.py	(working copy)
@@ -79,18 +79,19 @@
                         break
                     except Exception:
                         cnx.close()
+                        self._cursize -= 1
                 elif self._maxsize and self._cursize < self._maxsize:
                     cnx = self._connector.get_connection(**self._kwargs)
                     self._cursize += 1
                     break
                 else:
                     if timeout:
+                        if (time.time() - start) >= timeout:
+                            raise TimeoutError('Unable to get database '
+                                               'connection within %d seconds'
+                                                % timeout)
                         self._available.wait(timeout)
-                        if (time.time() - start) >= timeout:
-                            raise TimeoutError, 'Unable to get database ' \
-                                                'connection within %d seconds' \
-                                                % timeout
-                    else:
+                    else: # Warning: without timeout, Trac *might* hang
                         self._available.wait()
             self._active[tid] = [1, cnx]
             return PooledConnection(self, cnx, tid)
@@ -116,17 +117,18 @@
         # Note: self._available *must* be acquired
         if tid in self._active:
             cnx = self._active.pop(tid)[1]
-            if cnx not in self._dormant: # hm, how could that happen?
-                if cnx.poolable: # i.e. we can manipulate it from other threads
-                    cnx.rollback()
-                    self._dormant.append(cnx)
-                elif tid == threading._get_ident():
-                    cnx.rollback() # non-poolable but same thread: close
-                    cnx.close()
-                    self._cursize -= 1
-                else: # non-poolable, different thread: push it back
-                    self._active[tid] = [0, cnx]
-                self._available.notify()
+            assert cnx not in self._dormant
+            if cnx.poolable: # i.e. we can manipulate it from other threads
+                cnx.rollback()
+                self._dormant.append(cnx)
+            elif tid == threading._get_ident():
+                cnx.rollback() # non-poolable but same thread: close
+                cnx.close()
+                self._cursize -= 1
+            else: # non-poolable, different thread: push it back
+                self._active[tid] = [0, cnx]
+                return # no need to notify other threads
+            self._available.notify()
 
     def shutdown(self, tid=None):
         self._available.acquire()
Index: trac/config.py
===================================================================
--- trac/config.py	(revision 3868)
+++ trac/config.py	(working copy)
@@ -25,7 +25,8 @@
 from trac.core import ExtensionPoint, TracError
 from trac.util import sorted, to_unicode
 
-__all__ = ['Configuration', 'Option', 'BoolOption', 'IntOption', 'ListOption',
+__all__ = ['Configuration', 'Option',
+           'BoolOption', 'IntOption', 'FloatOption', 'ListOption',
            'ExtensionOption', 'OrderedExtensionsOption', 'ConfigurationError',
            'default_dir']
 
@@ -89,6 +90,16 @@
         """
         return self[section].getint(name, default)
 
+    def getfloat(self, section, name, default=None):
+        """Return the value of the specified option as a floating number.
+        
+        If the specified option can not be converted to an integer, a
+        `ConfigurationError` exception is raised.
+        
+        (since Trac 0.11)
+        """
+        return self[section].getfloat(name, default)
+
     def getlist(self, section, name, default=None, sep=',', keep_empty=False):
         """Return a list of values that have been specified as a single
         comma-separated option.
@@ -261,6 +272,20 @@
         except ValueError:
             raise ConfigurationError('expected integer, got %s' % repr(value))
 
+    def getfloat(self, name, default=None):
+        """Return the value of the specified option as a floating number.
+        
+        If the specified option can not be converted to a float, a
+        `ConfigurationError` exception is raised.
+        """
+        value = self.get(name, default)
+        if value == '':
+            return default
+        try:
+            return float(value)
+        except ValueError:
+            raise ConfigurationError('expected float, got %s' % repr(value))
+
     def getlist(self, name, default=None, sep=',', keep_empty=True):
         """Return a list of values that have been specified as a single
         comma-separated option.
@@ -346,6 +371,9 @@
     """Descriptor for integer configuration options."""
     accessor = Section.getint
 
+class FloatOption(Option):
+    """Descriptor for floating-point numbers configuration options."""
+    accessor = Section.getfloat
 
 class ListOption(Option):
     """Descriptor for configuration options that contain multiple values

