Commit 219006cd authored by Jim Fulton's avatar Jim Fulton

Bugs Fixed

----------

- "activity monitor not updated for subconnections when connection
  returned to pool"

https://bugs.launchpad.net/zodb/+bug/737198
parent acab791f
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
$Id$""" $Id$"""
import threading
import time import time
...@@ -24,14 +25,13 @@ class ActivityMonitor: ...@@ -24,14 +25,13 @@ class ActivityMonitor:
This simple implementation just keeps a small log in memory This simple implementation just keeps a small log in memory
and iterates over the log when getActivityAnalysis() is called. and iterates over the log when getActivityAnalysis() is called.
It assumes that log entries are added in chronological sequence, It assumes that log entries are added in chronological sequence.
which is only guaranteed because DB.py holds a lock when calling
the closedConnection() method.
""" """
def __init__(self, history_length=3600): def __init__(self, history_length=3600):
self.history_length = history_length # Number of seconds self.history_length = history_length # Number of seconds
self.log = [] # [(time, loads, stores)] self.log = [] # [(time, loads, stores)]
self.trim_lock = threading.Lock()
def closedConnection(self, conn): def closedConnection(self, conn):
log = self.log log = self.log
...@@ -41,6 +41,8 @@ class ActivityMonitor: ...@@ -41,6 +41,8 @@ class ActivityMonitor:
self.trim(now) self.trim(now)
def trim(self, now): def trim(self, now):
self.trim_lock.acquire()
log = self.log log = self.log
cutoff = now - self.history_length cutoff = now - self.history_length
n = 0 n = 0
...@@ -50,6 +52,8 @@ class ActivityMonitor: ...@@ -50,6 +52,8 @@ class ActivityMonitor:
if n: if n:
del log[:n] del log[:n]
self.trim_lock.release()
def setHistoryLength(self, history_length): def setHistoryLength(self, history_length):
self.history_length = history_length self.history_length = history_length
self.trim(time.time()) self.trim(time.time())
......
...@@ -322,6 +322,10 @@ class Connection(ExportImport, object): ...@@ -322,6 +322,10 @@ class Connection(ExportImport, object):
else: else:
self.opened = None self.opened = None
am = self._db._activity_monitor
if am is not None:
am.closedConnection(self)
def db(self): def db(self):
"""Returns a handle to the database this connection belongs to.""" """Returns a handle to the database this connection belongs to."""
return self._db return self._db
......
...@@ -491,10 +491,6 @@ class DB(object): ...@@ -491,10 +491,6 @@ class DB(object):
assert connection._db is self assert connection._db is self
connection.opened = None connection.opened = None
am = self._activity_monitor
if am is not None:
am.closedConnection(connection)
if connection.before: if connection.before:
self.historical_pool.repush(connection, connection.before) self.historical_pool.repush(connection, connection.before)
else: else:
......
...@@ -325,6 +325,39 @@ class UserMethodTests(unittest.TestCase): ...@@ -325,6 +325,39 @@ class UserMethodTests(unittest.TestCase):
>>> cn._Connection__onCloseCallbacks >>> cn._Connection__onCloseCallbacks
""" """
def test_close_dispatches_to_activity_monitors(self):
r"""doctest that connection close updates activity monitors
Set up a multi-database:
>>> db1 = ZODB.DB(None)
>>> db2 = ZODB.DB(None, databases=db1.databases, database_name='2',
... cache_size=10)
>>> conn1 = db1.open()
>>> conn2 = conn1.get_connection('2')
Add activity monitors to both dbs:
>>> from ZODB.ActivityMonitor import ActivityMonitor
>>> db1.setActivityMonitor(ActivityMonitor())
>>> db2.setActivityMonitor(ActivityMonitor())
Commit a transaction that affects both connections:
>>> conn1.root()[0] = conn1.root().__class__()
>>> conn2.root()[0] = conn2.root().__class__()
>>> transaction.commit()
After closing the primary connection, both monitors should be up to
date:
>>> conn1.close()
>>> len(db1.getActivityMonitor().log)
1
>>> len(db2.getActivityMonitor().log)
1
"""
def test_db(self): def test_db(self):
r"""doctest of db() method r"""doctest of db() method
......
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