Commit 47126e35 authored by Tim Peters's avatar Tim Peters

Cleanups; better comments.

Changed the behavior of _ConnectionPool.pop(), to return
None when no connections are available.
parent 8a6bd4cf
...@@ -37,7 +37,7 @@ _deprecated = object() ...@@ -37,7 +37,7 @@ _deprecated = object()
class _ConnectionPool(object): class _ConnectionPool(object):
"""Manage a pool of connections. """Manage a pool of connections.
CAUTION: All methods should be called under the protection of a lock. CAUTION: Methods should be called under the protection of a lock.
This class does no locking of its own. This class does no locking of its own.
There's no limit on the number of connections this can keep track of, There's no limit on the number of connections this can keep track of,
...@@ -56,7 +56,8 @@ class _ConnectionPool(object): ...@@ -56,7 +56,8 @@ class _ConnectionPool(object):
reference to it thereafter. It's not necessary to inform the pool reference to it thereafter. It's not necessary to inform the pool
if the connection goes away. A connection handed out by pop() counts if the connection goes away. A connection handed out by pop() counts
against pool_size only so long as it exists, and provided it isn't against pool_size only so long as it exists, and provided it isn't
repush()'ed. repush()'ed. A weak reference is retained so that DB methods like
connectionDebugInfo() can still gather statistics.
""" """
def __init__(self, pool_size): def __init__(self, pool_size):
...@@ -64,16 +65,21 @@ class _ConnectionPool(object): ...@@ -64,16 +65,21 @@ class _ConnectionPool(object):
self.pool_size = pool_size self.pool_size = pool_size
# A weak set of all connections we've seen. A connection vanishes # A weak set of all connections we've seen. A connection vanishes
# from this set if get() hands it out, it's not reregistered via # from this set if pop() hands it out, it's not reregistered via
# repush(), and it becomes unreachable. # repush(), and it becomes unreachable.
self.all = WeakSet() self.all = WeakSet()
# A stack of connections available to hand out. This is a subset # A stack of connections available to hand out. This is a subset
# of self.all. push() and repush() add to this, and may remove # of self.all. push() and repush() add to this, and may remove
# the oldest available connections if the pool is too large. # the oldest available connections if the pool is too large.
# get() pops this stack. # pop() pops this stack.
# In Python 2.4, a collections.deque would make more sense than
# a list (we push only "on the right", but may pop from both ends).
self.available = [] self.available = []
# Change our belief about the expected maximum # of live connections.
# If the pool_size is smaller than the current value, this may discard
# the oldest available connections.
def set_pool_size(self, pool_size): def set_pool_size(self, pool_size):
self.pool_size = pool_size + 1 # _reduce_size shoots for < pool_size self.pool_size = pool_size + 1 # _reduce_size shoots for < pool_size
self._reduce_size() self._reduce_size()
...@@ -102,25 +108,24 @@ class _ConnectionPool(object): ...@@ -102,25 +108,24 @@ class _ConnectionPool(object):
self.available.append(c) self.available.append(c)
# Throw away the oldest available connections until we're under our # Throw away the oldest available connections until we're under our
# target size. It may not be possible be achieve this. # target size. It may not be possible to achieve this.
def _reduce_size(self): def _reduce_size(self):
while self.available and len(self.all) >= self.pool_size: while self.available and len(self.all) >= self.pool_size:
c = self.available.pop(0) c = self.available.pop(0)
self.all.remove(c) self.all.remove(c)
# The number of available connections. # Pop an available connection and return it, or return None if none are
def num_available(self): # available. In the latter case, the caller should create a new
return len(self.available) # connection, register it via push(), and call pop() again. The
# caller is responsible for serializing this sequence.
# Pop an available connection and return it. A caller must ensurue
# that num_available() > 0 before calling pop(), and if it's not,
# create a connection and register it via push() first.
def pop(self): def pop(self):
# Leave it in self.all, so we can still get at it for statistics result = None
# while it's alive. if self.available:
c = self.available.pop() result = self.available.pop()
assert c in self.all # Leave it in self.all, so we can still get at it for statistics
return c # while it's alive.
assert result in self.all
return result
# Return a list of all connections we currently know about. # Return a list of all connections we currently know about.
def all_as_list(self): def all_as_list(self):
...@@ -249,6 +254,7 @@ class DB(object): ...@@ -249,6 +254,7 @@ class DB(object):
if hasattr(storage, 'undoInfo'): if hasattr(storage, 'undoInfo'):
self.undoInfo = storage.undoInfo self.undoInfo = storage.undoInfo
# This is called by Connection.close().
def _closeConnection(self, connection): def _closeConnection(self, connection):
"""Return a connection to the pool. """Return a connection to the pool.
...@@ -280,11 +286,11 @@ class DB(object): ...@@ -280,11 +286,11 @@ class DB(object):
finally: finally:
self._r() self._r()
# Call f(c) for all connections in all pools in all versions. # Call f(c) for all connections c in all pools in all versions.
def _connectionMap(self, f): def _connectionMap(self, f):
self._a() self._a()
try: try:
for pool in self._pools.itervalues(): for pool in self._pools.values():
for c in pool.all_as_list(): for c in pool.all_as_list():
f(c) f(c)
finally: finally:
...@@ -362,7 +368,7 @@ class DB(object): ...@@ -362,7 +368,7 @@ class DB(object):
self._connectionMap(lambda c: c._cache.full_sweep()) self._connectionMap(lambda c: c._cache.full_sweep())
def cacheLastGCTime(self): def cacheLastGCTime(self):
m=[0] m = [0]
def f(con, m=m): def f(con, m=m):
t = con._cache.cache_last_gc_time t = con._cache.cache_last_gc_time
if t > m[0]: if t > m[0]:
...@@ -375,7 +381,7 @@ class DB(object): ...@@ -375,7 +381,7 @@ class DB(object):
self._connectionMap(lambda c: c._cache.minimize()) self._connectionMap(lambda c: c._cache.minimize())
def cacheSize(self): def cacheSize(self):
m=[0] m = [0]
def f(con, m=m): def f(con, m=m):
m[0] += con._cache.cache_non_ghost_count m[0] += con._cache.cache_non_ghost_count
...@@ -522,7 +528,8 @@ class DB(object): ...@@ -522,7 +528,8 @@ class DB(object):
self._pools[version] = pool = _ConnectionPool(size) self._pools[version] = pool = _ConnectionPool(size)
# result <- a connection # result <- a connection
if pool.num_available() == 0: result = pool.pop()
if result is None:
if version: if version:
cache = self._version_cache_size cache = self._version_cache_size
else: else:
...@@ -530,7 +537,8 @@ class DB(object): ...@@ -530,7 +537,8 @@ class DB(object):
c = self.klass(version=version, cache_size=cache, c = self.klass(version=version, cache_size=cache,
mvcc=mvcc, txn_mgr=txn_mgr) mvcc=mvcc, txn_mgr=txn_mgr)
pool.push(c) pool.push(c)
result = pool.pop() result = pool.pop()
assert result is not None
# Tell the connection it belongs to self. # Tell the connection it belongs to self.
result._setDB(self, mvcc=mvcc, txn_mgr=txn_mgr, synch=synch) result._setDB(self, mvcc=mvcc, txn_mgr=txn_mgr, synch=synch)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment