Rev 141: When removing an item from the collection, store it in the proxy. in http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection
John Arbash Meinel
john at arbash-meinel.com
Mon Dec 28 19:59:07 GMT 2009
At http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection
------------------------------------------------------------
revno: 141
revision-id: john at arbash-meinel.com-20091228195848-y0ici6c6l4humkdp
parent: john at arbash-meinel.com-20091228052742-5a4pyc9lmwpukvy5
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: mem-object-collection
timestamp: Mon 2009-12-28 13:58:48 -0600
message:
When removing an item from the collection, store it in the proxy.
This allows the proxy to continue working even after the item
is removed from the collection. This is used by the compute_referrers
code.
-------------- next part --------------
=== modified file 'meliae/_loader.pyx'
--- a/meliae/_loader.pyx 2009-12-28 05:27:42 +0000
+++ b/meliae/_loader.pyx 2009-12-28 19:58:48 +0000
@@ -149,6 +149,29 @@
unsigned long total_size
+cdef int _free_mem_object(_MemObject *cur) except -1:
+ if cur == NULL: # Already cleared
+ return 0
+ if cur == _dummy:
+ return 0
+ if cur.address == NULL:
+ raise RuntimeError('clering something that doesn\'t have address')
+ Py_XDECREF(cur.address)
+ cur.address = NULL
+ Py_XDECREF(cur.type_str)
+ cur.type_str = NULL
+ _free_ref_list(cur.ref_list)
+ cur.ref_list = NULL
+ Py_XDECREF(cur.value)
+ cur.value = NULL
+ Py_XDECREF(cur.name)
+ cur.name = NULL
+ _free_ref_list(cur.referrer_list)
+ cur.referrer_list = NULL
+ PyMem_Free(cur)
+ return 1
+
+
cdef _MemObject *_dummy
_dummy = <_MemObject*>(-1)
@@ -166,59 +189,52 @@
"""
cdef MemObjectCollection collection
+ # This must be set immediately after construction, before accessing any
+ # member vars
cdef _MemObject *_obj
+ # If not NULL, this will be freed when this object is deallocated
+ cdef _MemObject *_managed_obj
cdef object __weakref__
def __init__(self, collection):
self.collection = collection
self._obj = NULL
-
- cdef _MemObject *_ensure_obj(self) except NULL:
- if self._obj is NULL:
- raise RuntimeError('_MemObjectProxy was deleted underneath it.')
- return self._obj
-
- def is_valid(self):
- if self._obj is NULL:
- return False
- return True
+ self._managed_obj = NULL
+
+ def __dealloc__(self):
+ if self._managed_obj != NULL:
+ _free_mem_object(self._managed_obj)
+ self._managed_obj = NULL
property address:
def __get__(self):
- self._ensure_obj()
return <object>(self._obj.address)
property type_str:
"""The type of this object."""
def __get__(self):
- self._ensure_obj()
return <object>(self._obj.type_str)
property size:
"""The number of bytes allocated for this object."""
def __get__(self):
- self._ensure_obj()
return self._obj.size
def __set__(self, value):
- self._ensure_obj()
self._obj.size = value
property name:
"""Name associated with this object."""
def __get__(self):
- self._ensure_obj()
return <object>self._obj.name
property value:
"""Value for this object (for strings and ints)"""
def __get__(self):
- self._ensure_obj()
return <object>self._obj.value
def __set__(self, value):
cdef PyObject *new_val
- self._ensure_obj()
new_val = <PyObject *>value
# INCREF first, just in case value is self._obj.value
Py_INCREF(new_val)
@@ -228,15 +244,12 @@
property total_size:
"""Mean to hold the size of this plus size of all referenced objects."""
def __get__(self):
- self._ensure_obj()
return self._obj.total_size
def __set__(self, value):
- self._ensure_obj()
self._obj.total_size = value
def __len__(self):
- self._ensure_obj()
if self._obj.ref_list == NULL:
return 0
return self._obj.ref_list.size
@@ -246,7 +259,6 @@
return self.__len__()
def _intern_from_cache(self, cache):
- self._ensure_obj()
address = _set_default(cache, <object>self._obj.address)
if (<PyObject *>address) != self._obj.address:
Py_DECREF(self._obj.address)
@@ -261,11 +273,9 @@
property ref_list:
"""The list of objects referenced by this object."""
def __get__(self):
- self._ensure_obj()
return _ref_list_to_list(self._obj.ref_list)
def __set__(self, value):
- self._ensure_obj()
_free_ref_list(self._obj.ref_list)
self._obj.ref_list = _list_to_ref_list(value)
@@ -275,18 +285,15 @@
Original set to None, can be computed on demand.
"""
def __get__(self):
- self._ensure_obj()
return _ref_list_to_list(self._obj.referrer_list)
def __set__(self, value):
- self._ensure_obj()
_free_ref_list(self._obj.referrer_list)
self._obj.referrer_list = _list_to_ref_list(value)
property num_referrers:
"""The length of the referrers list."""
def __get__(self):
- self._ensure_obj()
if self._obj.referrer_list == NULL:
return 0
return self._obj.referrer_list.size
@@ -294,7 +301,6 @@
def __getitem__(self, offset):
cdef long off
- self._ensure_obj()
if self._obj.ref_list == NULL:
raise IndexError('%s has no references' % (self,))
@@ -367,26 +373,7 @@
% (n_lookup))
cdef int _clear_slot(self, _MemObject **slot) except -1:
- if slot[0] == NULL: # Already cleared
- return 0
- if slot[0] == _dummy:
- slot[0] = NULL
- return 0
- if slot[0].address == NULL:
- raise RuntimeError('clering something that doesn\'t have address')
- Py_XDECREF(slot[0].address)
- slot[0].address = NULL
- Py_XDECREF(slot[0].type_str)
- slot[0].type_str = NULL
- _free_ref_list(slot[0].ref_list)
- slot[0].ref_list = NULL
- Py_XDECREF(slot[0].value)
- slot[0].value = NULL
- Py_XDECREF(slot[0].name)
- slot[0].name = NULL
- _free_ref_list(slot[0].referrer_list)
- slot[0].referrer_list = NULL
- PyMem_Free(slot[0])
+ _free_mem_object(slot[0])
slot[0] = NULL
return 1
@@ -453,8 +440,10 @@
raise KeyError('address %s not present' % (at,))
proxy = self._proxies.get(address, None)
if proxy is not None:
- proxy._obj = NULL
- self._clear_slot(slot)
+ # Have the proxy take over the memory lifetime
+ proxy._managed_obj = proxy._obj
+ else:
+ self._clear_slot(slot)
slot[0] = _dummy
self._active -= 1
# TODO: Shrink
=== modified file 'meliae/tests/test__loader.py'
--- a/meliae/tests/test__loader.py 2009-12-28 05:27:42 +0000
+++ b/meliae/tests/test__loader.py 2009-12-28 19:58:48 +0000
@@ -300,10 +300,9 @@
def test_deleted_proxy(self):
mop = self.moc[0]
del self.moc[0]
- self.assertFalse(mop.is_valid())
- self.assertRaises(RuntimeError, lambda: mop.type_str)
- self.assertRaises(RuntimeError, lambda: mop.size)
- self.assertRaises(RuntimeError, len, mop)
+ self.assertEqual('foo', mop.type_str)
+ self.assertEqual(100, mop.size)
+ self.assertEqual(0, len(mop))
def test_value(self):
mop = self.moc.add(1234, 'type', 256, value='testval')
More information about the bazaar-commits
mailing list