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