Commit 38d86ef7 authored by Jason Madden's avatar Jason Madden

All tests pass. Lifetime issues worked out, though probably not optimally.

Performance is way up again, beating CPython on half of the tests:

"Transaction",                mysql
"Add 3000 Objects",              8259
"Update 3000 Objects",           9454
"Read 3000 Warm Objects",        5460
"Read 3000 Cold Objects",        5454
"Read 3000 Hot Objects",        24943
"Read 3000 Steamin' Objects", 1099616

Still needs some GC work to get all the ZODB tests to pass like they do under zopefoundation/persistent#20
parent c0ef0335
......@@ -487,9 +487,12 @@ class Persistent(object):
jar = oga(self, '_Persistent__jar')
if jar is None:
return
myring = oga(self, '_Persistent__ring')
if ring is None:
return
# XXX: If we bail here, a number of persistence tests
# fail. However, the C implementation only does this if
# it's already in the ring (maybe somebody does that earlier?)
#myring = oga(self, '_Persistent__ring')
#if myring is None or not myring.r_next:
# return
oid = oga(self, '_Persistent__oid')
if oid is None:
return
......@@ -505,7 +508,7 @@ class Persistent(object):
# that at this level, all we can do is catch it.
# The AttributeError arises in ZODB test cases
try:
ring.move_to_head(jar._cache.ring_home, myring)
jar._cache.mru(oid)
except (AttributeError,KeyError):
pass
......@@ -520,10 +523,6 @@ class Persistent(object):
if cache is not None:
return cache.get(oid) is self
def __del__(self):
if self._p_is_in_cache():
ring.del_(self._Persistent__ring)
def _estimated_size_in_24_bits(value):
if value > 1073741696:
return 16777215
......
......@@ -103,6 +103,7 @@ class PickleCache(object):
self.persistent_classes = {}
self.data = weakref.WeakValueDictionary()
self.ring_home = ring.CPersistentRingHead()
self.ring_nodes = set()
self.cache_size_bytes = cache_size_bytes
# IPickleCache API
......@@ -163,9 +164,10 @@ class PickleCache(object):
self.data[oid] = value
_gc_monitor(value)
node = ring.CPersistentRing(value)
value._Persistent__ring = node
object.__setattr__(value, '_Persistent__ring', node)
if _OGA(value, '_p_state') != GHOST:
ring.add(self.ring_home, node)
self.ring_nodes.add(node)
self.non_ghost_count += 1
def __delitem__(self, oid):
......@@ -198,12 +200,18 @@ class PickleCache(object):
return False # marker return for tests
value = self.data[oid]
id_value = id(value)
node = _OGA(value, '_Persistent__ring')
if node is None: # tests
return
was_in_ring = bool(value._Persistent__ring.r_next)
ring.move_to_head(self.ring_home, value._Persistent__ring)
if not was_in_ring and _OGA(value, '_p_state') != GHOST:
self.non_ghost_count += 1
was_in_ring = bool(node.r_next)
if not was_in_ring:
if _OGA(value, '_p_state') != GHOST:
ring.add(self.ring_home, node)
self.ring_nodes.add(node)
self.non_ghost_count += 1
else:
ring.move_to_head(self.ring_home, node)
def ringlen(self):
""" See IPickleCache.
......@@ -350,14 +358,12 @@ class PickleCache(object):
def _sweep(self, target, target_size_bytes=0):
# lock
ejected = 0
for here in ring.iteritems(self.ring_home):
value = ring.get_object(here)
if value is None:
continue
here = here.r_next
for here in list(ring.iteritems(self.ring_home)):
if self.non_ghost_count <= target and (self.total_estimated_size <= target_size_bytes or not target_size_bytes):
break
value = ring.get_object(here)
here = here.r_next
if value._p_state == UPTODATE:
# The C implementation will only evict things that are specifically
......@@ -410,3 +416,4 @@ class PickleCache(object):
def _remove_from_ring(self, value):
if value._Persistent__ring.r_next:
ring.del_(value._Persistent__ring)
self.ring_nodes.discard(value._Persistent__ring)
......@@ -45,6 +45,9 @@ class CPersistentRing(object):
def __getattr__(self, name):
return getattr(self.node, name)
def get_object(self):
return get_object(self.node)
def CPersistentRingHead():
head = CPersistentRing()
head.node.r_next = head.node
......
......@@ -979,8 +979,9 @@ class PickleCacheTests(unittest.TestCase):
cache[p._p_oid] = p
self.assertEqual(cache.cache_non_ghost_count, 1)
self.assertEqual(cache.ring[0], p)
cache.ring[0] = None
from ..ring import get_object,ffi
self.assertEqual(get_object(cache.ring_home.r_next), p)
cache.ring_home.r_next.object = ffi.NULL
# Nothing to test, just that it doesn't break
cache._invalidate(p._p_oid)
......
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