[Zodb-checkins] CVS: Packages/StorageGC - GCableGraph.py:1.3

tim@digicool.com tim@digicool.com
Thu, 19 Apr 2001 17:05:24 -0400 (EDT)


Update of /cvs-repository/Packages/StorageGC
In directory korak:/tmp/cvs-serv31123

Modified Files:
	GCableGraph.py 
Log Message:
Teach the GCable graph "storage" how to compute trash via mark-&-sweep too.
Since the M&S approach has nothing in common with the CycleGC approach (for
example, M&S doesn't even look at refcounts), this should be an excellent
check on CycleGC's results.  And since the M&S code is just for testing,
it's very simple code that doesn't worry about time or space efficiency
(unlike CycleGC, which worries about both, so is orders of magnitude hairier).



--- Updated File GCableGraph.py in package Packages/StorageGC --
--- GCableGraph.py	2001/04/19 19:41:44	1.2
+++ GCableGraph.py	2001/04/19 21:05:24	1.3
@@ -24,6 +24,10 @@
         self.succs[x].append(y)
         self.rc[y] += 1
 
+    def getnodes(self):
+        "Return list of all nodes."
+        return self.succs.keys()
+
     def dump(self, file=None):
         print >> file, "# nodes", len(self.rc)
 
@@ -58,6 +62,46 @@
             self.trash.sort()
         return self.trash
 
+    # Alternative (mark-&-sweep) method of computing trash.  Since
+    # this has nothing in common with CycleGC's approach (e.g., it
+    # doesn't use refcounts at all), it should be an excellent check
+    # on CycleGC's results.
+
+    def _transitive_closure(self, roots):
+        "Return all nodes reachable from roots, as a set (dict)."
+        tc = {}
+        alreadyknown = tc.has_key
+        candidates = roots[:]
+        push = candidates.append
+        pop = candidates.pop
+        while candidates:
+            c = pop()
+            if alreadyknown(c):
+                continue
+            tc[c] = 1
+            for kid in self.succs[c]:
+                if not alreadyknown(kid):
+                    push(kid)
+        return tc
+
+    def altTrash(self, startnodes, sorted=1):
+        "Compute the same trash list as CycleGC but via a different method."
+        tc = self._transitive_closure(startnodes)
+        # The result is everything in tc not reachable from outside tc.
+        outside_tc = {}
+        for x in self.getnodes():
+            if not tc.has_key(x):
+                outside_tc[x] = 1
+        reachable = self._transitive_closure(outside_tc.keys())
+        result = {}
+        for x in tc.keys():
+            if not reachable.has_key(x):
+                result[x] = 1
+        result = result.keys()
+        if sorted:
+            result.sort()
+        return result
+
 from CyclicGC import CycleGC
 
 g = RCGraph()
@@ -79,7 +123,7 @@
 g.addedge(8, 7)
 g.addedge(8, 6)
 g.addedge(6, 8)
-g.addedge(10, 2)  # should stop any trash collection
+#g.addedge(10, 2)  # should stop any trash collection
 g.dump()
 
 gc = CycleGC(g)
@@ -91,4 +135,8 @@
     gc.start(s)
     while not gc.done():
         gc.resume()
-    print "    trash found:", g.getTrash()
+    trash = g.getTrash()
+    print "    trash found:", trash
+    alt_trash = g.altTrash(s)
+    if trash != alt_trash:
+        raise ValueError("OOPS! altTrash returned %s" % alt_trash)