We do have a risk with WeakValueDict because callbacks can happen at bad times. While this is a bigger problem for your wild applications, I think it can also cause trouble in a normal application, since gc can cause callbacks from another thread. Here is a variation of the solution you suggested for just holding a plain dict of weakrefs. Please review it. =================================================================== --- connection.py (revision 28839) +++ connection.py (working copy) @@ -14,7 +14,7 @@ from itertools import islice, chain from os import getpid from time import time -from weakref import WeakValueDictionary, ref +from weakref import ref, KeyedRef ROOT_OID = p64(0) @@ -306,11 +306,48 @@ self.abort() self.storage.pack() +class ObjectDictionary (object): + def __init__(self): + self.mapping = {} + self.dead = set() + def remove(wr, selfref=ref(self)): + self = selfref() + if self is not None: + self.dead.add(wr.key) + self.remove = remove + + def get(self, key, default=None): + ref = self.mapping.get(key, None) + if ref is not None: + value = ref() + if value is not None and key not in self.dead: + return value + return default + + def __setitem__(self, key, value): + self.mapping[key] = KeyedRef(value, self.remove, key) + + def __delitem__(self, key): + self.dead.add(key) + + def __contains__(self, key): + return self.get(key, None) is not None + + def __len__(self): + return len(self.mapping) - len(self.dead) + + def __iter__(self): + while self.dead: + self.mapping.pop(self.dead.pop(), None) + for key in self.mapping: + if key not in self.dead: + yield key + + class Cache(object): def __init__(self, size): - self.objects = WeakValueDictionary() + self.objects = ObjectDictionary() self.recent_objects = set() self.set_size(size) self.finger = 0 @@ -373,7 +373,9 @@ heap = [] for oid in islice(chain(all, all), start, start + len(all)): self.finger += 1 - obj = all[oid] + obj = all.get(oid) + if obj is None: + continue # The ref is dead. if obj._p_serial == transaction_serial: continue # obj is current. Leave it alone. heappush(heap, (obj._p_serial, oid))