Issue2326
Created on 2015-04-14.02:10:04 by jmadden, last changed 2015-04-14.14:41:36 by zyasoft.
Messages | |||
---|---|---|---|
msg9824 (view) | Author: Jason Madden (jmadden) | Date: 2015-04-14.02:10:03 | |
Currently, WeakValueDictionary.valuerefs looks like this: return [ref(value) for value in self.itervalues()] But, as the CPython documentation says: Caution: Because a WeakKeyDictionary is built on top of a Python dictionary, it must not change size when iterating over it. This can be difficult to ensure for a WeakKeyDictionary because actions performed by the program during iteration may cause items in the dictionary to vanish “by magic” (as a side effect of garbage collection). This is enforced by the Jython dictionary implementation, and together with of having Java's truly non-deterministic GC means that using itervalues is extremely dangerous. Practically speaking, this makes `valuerefs` impossible to use. This came up in porting the widely used `transaction` package to work on Jython[1]. When the system is put under any strain, a RuntimeError results from this method. Here's an example from running the ZODB test suite; changing `itervalues` to `values` solves the problem: File "<doctest ZODB.tests.testblob.loadblob_tmpstore[12]>", line 1, in <module> database.close() File "//ZODB/src/ZODB/DB.py", line 629, in close @self._connectionMap File "//ZODB/src/ZODB/DB.py", line 505, in _connectionMap self.pool.map(f) File "//ZODB/src/ZODB/DB.py", line 205, in map self.all.map(f) File "//transaction-1.4.4.dev0-py2.7.egg/transaction/weakset.py", line 63, in map f(elt) File "//ZODB/src/ZODB/DB.py", line 631, in _ c.transaction_manager.abort() File "//transaction-1.4.4.dev0-py2.7.egg/transaction/_manager.py", line 116, in abort return self.get().abort() File "//transaction-1.4.4.dev0-py2.7.egg/transaction/_transaction.py", line 443, in abort self._synchronizers.map(lambda s: s.beforeCompletion(self)) File "//transaction-1.4.4.dev0-py2.7.egg/transaction/weakset.py", line 60, in map for wr in self.as_weakref_list(): File "//transaction-1.4.4.dev0-py2.7.egg/transaction/weakset.py", line 87, in as_weakref_list refs = self.data.valuerefs() File "//jython2.7rc2/Lib/weakref.py", line 69, in valuerefs return [ref(value) for value in self.itervalues()] RuntimeError: dictionary changed size during iteration The same reasoning for `WeakKeyDictionary.keyrefs` [1] https://github.com/zopefoundation/transaction/pull/8 |
|||
msg9826 (view) | Author: Jim Baker (zyasoft) | Date: 2015-04-14.02:54:01 | |
Ack, we should relax this check in PyDictionary, this is unnecessary in general given concurrent modification support in ConcurrentHashMap. Something similar was already changed in PySet. |
|||
msg9827 (view) | Author: Jim Baker (zyasoft) | Date: 2015-04-14.02:55:46 | |
The other unfortunate thing here is that this test if (getMap().size() != size) { throw Py.RuntimeError("dictionary changed size during iteration"); } is not even correct on weak maps in Guava, given eventual consistency. |
|||
msg9828 (view) | Author: Jim Baker (zyasoft) | Date: 2015-04-14.03:18:17 | |
Should be fixed as of https://hg.python.org/jython/rev/5064a5c5b1a3, so please verify with your testing |
|||
msg9833 (view) | Author: Jason Madden (jmadden) | Date: 2015-04-14.11:44:45 | |
With that commit, the ZODB tests run clean. Seems fixed to me. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2015-04-14 14:41:36 | zyasoft | set | status: pending -> closed |
2015-04-14 11:44:45 | jmadden | set | messages: + msg9833 |
2015-04-14 03:18:17 | zyasoft | set | status: open -> pending resolution: fixed messages: + msg9828 |
2015-04-14 02:55:47 | zyasoft | set | messages: + msg9827 |
2015-04-14 02:54:01 | zyasoft | set | nosy:
+ zyasoft messages: + msg9826 |
2015-04-14 02:10:04 | jmadden | create |
Supported by Python Software Foundation,
Powered by Roundup