Commit 6b707535 authored by Jason Madden's avatar Jason Madden

patch time.time in historical_connections to avoid windows failures; fix race...

patch time.time in historical_connections to avoid windows failures; fix race condition in pool.availableGC

* patch time.time in historical_connections to avoid windows failures.

* Also use a mock version of datetime.datetime.utcnow.

We can't patch the method in-place because it's an extension type.

* synchronize sleep with time

* increment by less than the pool timeout to avoid a race condition.

* Avoid mutating the dict as we iter over it.

Seen in Python 3.4 tests:

File "/home/travis/build/zopefoundation/ZODB/src/ZODB/historical_connections.txt", line 263, in historical_connections.txt
Failed example:
    conn = db.open()
Exception raised:
    Traceback (most recent call last):
      File "/opt/python/3.4.2/lib/python3.4/doctest.py", line 1324, in __run
        compileflags, 1), test.globs)
      File "<doctest historical_connections.txt[0]>", line 1, in <module>
        conn = db.open()
      File "/home/travis/build/zopefoundation/ZODB/src/ZODB/DB.py", line 761, in open
        self.historical_pool.availableGC()
      File "/home/travis/build/zopefoundation/ZODB/src/ZODB/DB.py", line 277, in availableGC
        for key, pool in self.pools.items():
    RuntimeError: dictionary changed size during iteration
parent d7b38111
......@@ -274,7 +274,7 @@ class KeyedConnectionPool(AbstractConnectionPool):
pool.map(f)
def availableGC(self):
for key, pool in self.pools.items():
for key, pool in list(self.pools.items()):
pool.availableGC()
if not pool.all:
del self.pools[key]
......
......@@ -2,6 +2,28 @@
Historical Connections
======================
.. We need to mess with time to prevent spurious test failures on windows
>>> _now = 1231019584.0
>>> def faux_time_time():
... global _now
... _now += .001 # must be less than 0.01
... return _now
>>> import time
>>> real_time_time = time.time
>>> real_time_sleep = time.sleep
>>> def faux_time_sleep(amt):
... global _now
... _now += amt
>>> if isinstance(time,type):
... time.time = staticmethod(faux_time_time) # Jython
... time.sleep = faux_time_sleep
... else:
... time.time = faux_time_time
... time.sleep = faux_time_sleep
>>> def utcnow():
... return datetime.datetime.fromtimestamp(_now)
Usage
=====
......@@ -41,7 +63,7 @@ We wait for some time to pass, record he time, and then make some other changes.
>>> time.sleep(.01)
>>> import datetime
>>> now = datetime.datetime.utcnow()
>>> now = utcnow()
>>> time.sleep(.01)
>>> root = conn.root()
......@@ -258,7 +280,7 @@ Note that if you try to open an historical connection to a time in the future,
you will get an error.
>>> historical_conn = db.open(
... at=datetime.datetime.utcnow()+datetime.timedelta(1))
... at=utcnow()+datetime.timedelta(1))
Traceback (most recent call last):
...
ValueError: cannot open an historical connection in the future.
......@@ -293,6 +315,11 @@ memory usage would also be brief and unlikely to overlap.
>>> db.close()
>>> db2.close()
.. restore time
>>> time.time = real_time_time
>>> time.sleep = real_time_sleep
.. ......... ..
.. Footnotes ..
.. ......... ..
......
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