Message9824

Author jmadden
Recipients jmadden
Date 2015-04-14.02:10:03
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1428977404.9.0.392233485787.issue2326@psf.upfronthosting.co.za>
In-reply-to
Content
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
History
Date User Action Args
2015-04-14 02:10:05jmaddensetrecipients: + jmadden
2015-04-14 02:10:04jmaddensetmessageid: <1428977404.9.0.392233485787.issue2326@psf.upfronthosting.co.za>
2015-04-14 02:10:04jmaddenlinkissue2326 messages
2015-04-14 02:10:03jmaddencreate