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): ...@@ -274,7 +274,7 @@ class KeyedConnectionPool(AbstractConnectionPool):
pool.map(f) pool.map(f)
def availableGC(self): def availableGC(self):
for key, pool in self.pools.items(): for key, pool in list(self.pools.items()):
pool.availableGC() pool.availableGC()
if not pool.all: if not pool.all:
del self.pools[key] del self.pools[key]
......
...@@ -2,6 +2,28 @@ ...@@ -2,6 +2,28 @@
Historical Connections 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 Usage
===== =====
...@@ -41,7 +63,7 @@ We wait for some time to pass, record he time, and then make some other changes. ...@@ -41,7 +63,7 @@ We wait for some time to pass, record he time, and then make some other changes.
>>> time.sleep(.01) >>> time.sleep(.01)
>>> import datetime >>> import datetime
>>> now = datetime.datetime.utcnow() >>> now = utcnow()
>>> time.sleep(.01) >>> time.sleep(.01)
>>> root = conn.root() >>> root = conn.root()
...@@ -258,7 +280,7 @@ Note that if you try to open an historical connection to a time in the future, ...@@ -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. you will get an error.
>>> historical_conn = db.open( >>> historical_conn = db.open(
... at=datetime.datetime.utcnow()+datetime.timedelta(1)) ... at=utcnow()+datetime.timedelta(1))
Traceback (most recent call last): Traceback (most recent call last):
... ...
ValueError: cannot open an historical connection in the future. ValueError: cannot open an historical connection in the future.
...@@ -293,6 +315,11 @@ memory usage would also be brief and unlikely to overlap. ...@@ -293,6 +315,11 @@ memory usage would also be brief and unlikely to overlap.
>>> db.close() >>> db.close()
>>> db2.close() >>> db2.close()
.. restore time
>>> time.time = real_time_time
>>> time.sleep = real_time_sleep
.. ......... .. .. ......... ..
.. Footnotes .. .. 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