Rev 152: Some doc updates and fix a bug in itervalues() in http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection
John Arbash Meinel
john at arbash-meinel.com
Tue Dec 29 15:40:46 GMT 2009
At http://bazaar.launchpad.net/~jameinel/meliae/mem-object-collection
------------------------------------------------------------
revno: 152
revision-id: john at arbash-meinel.com-20091229154023-w9v5rcer8382ihp1
parent: john at arbash-meinel.com-20091229045910-5tjwea1ap86aizsp
committer: John Arbash Meinel <john at arbash-meinel.com>
branch nick: mem-object-collection
timestamp: Tue 2009-12-29 09:40:23 -0600
message:
Some doc updates and fix a bug in itervalues()
The logic was wrong at the end of the list causing segfaults, etc.
-------------- next part --------------
=== modified file 'meliae/_loader.pyx'
--- a/meliae/_loader.pyx 2009-12-29 04:59:10 +0000
+++ b/meliae/_loader.pyx 2009-12-29 15:40:23 +0000
@@ -82,15 +82,18 @@
return 1
-cdef _free_ref_list(RefList *ref_list):
+cdef int _free_ref_list(RefList *ref_list) except -1:
"""Decref and free the list."""
cdef long i
if ref_list == NULL:
- return
+ return 0
for i from 0 <= i < ref_list.size:
+ if ref_list.refs[i] == NULL:
+ raise RuntimeError('Somehow we got a NULL reference.')
Py_DECREF(ref_list.refs[i])
PyMem_Free(ref_list)
+ return 1
cdef object _ref_list_to_list(RefList *ref_list):
@@ -106,8 +109,9 @@
if ref_list == NULL:
return ()
refs = []
+ refs_append = refs.append
for i from 0 <= i < ref_list.size:
- refs.append(<object>(ref_list.refs[i]))
+ refs_append(<object>(ref_list.refs[i]))
return refs
@@ -204,12 +208,29 @@
cdef class _MemObjectProxy:
- """This class proxies between a real Python object and MOC's data.
-
- MOC stores the data as a fairly efficient table, without the overhead of
- having a regular python object for every data point. However, the rest of
- python code needs to interact with a real python object, so we generate
- these on-the-fly.
+ """The standard interface for understanding memory consumption.
+
+ MemObjectCollection stores the data as a fairly efficient table, without
+ the overhead of having a regular python object for every data point.
+ However, the rest of python code needs to interact with a real python
+ object, so we generate these on-the-fly.
+
+ Most attributes are properties, which thunk over to the actual data table
+ entry.
+
+ :ivar address: The address in memory of the original object. This is used
+ as the 'handle' to this object.
+ :ivar type_str: The type of this object
+ :ivar size: The number of bytes consumed for just this object. So for a
+ dict, this would be the basic_size + the size of the allocated array to
+ store the reference pointers
+ :ivar ref_list: A list of items referenced from this object
+ :ivar num_refs: Count of references, you can also use len()
+ :ivar value: A PyObject representing the Value for this object. (For
+ strings, it is the first 100 bytes, it may be None if we have no value,
+ or it may be an integer, etc.) This is also where the 'name' is stored
+ for objects like 'module'.
+ :ivar
"""
cdef MemObjectCollection collection
@@ -238,6 +259,7 @@
self._managed_obj = NULL
property address:
+ """The identifier for the tracked object."""
def __get__(self):
return <object>(self._obj.address)
@@ -313,11 +335,10 @@
# TODO: deprecated for clarity
property referrers:
def __get__(self):
- return _ref_list_to_list(self._obj.parent_list)
+ return self.parents
def __set__(self, value):
- _free_ref_list(self._obj.parent_list)
- self._obj.parent_list = _list_to_ref_list(value)
+ self.parents = value
property parents:
"""The list of objects that reference this object.
@@ -753,15 +774,19 @@
if self.collection._active != self.initial_active:
raise RuntimeError('MemObjectCollection changed size during'
' iteration')
- cur = NULL
- while (cur == NULL or cur == _dummy
- and self.table_pos <= self.collection._table_mask):
+ while (self.table_pos <= self.collection._table_mask):
cur = self.collection._table[self.table_pos]
+ if cur != NULL and cur != _dummy:
+ break
self.table_pos += 1
- # self.table_pos points to the *next* entry, so make sure it is fully
- # off the table
- if self.table_pos > self.collection._table_mask + 1:
+ if self.table_pos > self.collection._table_mask:
raise StopIteration()
+ # This entry is 'consumed', go on to the next
+ self.table_pos += 1
+ if cur == NULL or cur == _dummy:
+ raise RuntimeError('didn\'t run off the end, but got null/dummy'
+ ' %d, %d %d' % (<int>cur, self.table_pos,
+ self.collection._table_mask))
return self.collection._proxy_for(<object>cur.address, cur)
=== modified file 'meliae/tests/test__loader.py'
--- a/meliae/tests/test__loader.py 2009-12-29 04:59:10 +0000
+++ b/meliae/tests/test__loader.py 2009-12-29 15:40:23 +0000
@@ -221,17 +221,22 @@
self.assertEqual(1024, mop.address)
self.assertEqual(1124, mop.size)
- def test_itervalues(self):
+ def test_itervalues_to_tip(self):
moc = _loader.MemObjectCollection()
moc.add(0, 'bar', 100)
moc.add(1024, 'baz', 102)
+ moc.add(512, 'bing', 104)
+ self.assertEqual([0, 1024, 512],
+ [x.address for x in moc.itervalues()])
+ del moc[0]
+ self.assertEqual([1024, 512],
+ [x.address for x in moc.itervalues()])
moc.add(1023, 'booze', 103)
- moc.add(512, 'bing', 104)
- self.assertEqual([0, 1024, 512, 1023],
- [x.address for x in moc.itervalues()])
- del moc[0]
self.assertEqual([1024, 512, 1023],
[x.address for x in moc.itervalues()])
+ del moc[1023]
+ self.assertEqual([1024, 512],
+ [x.address for x in moc.itervalues()])
def test_items(self):
moc = _loader.MemObjectCollection()
More information about the bazaar-commits
mailing list