wingo - in flumotion/trunk: . flumotion/common flumotion/component flumotion/test

flumotion-commit at lists.fluendo.com flumotion-commit at lists.fluendo.com
Tue Jul 24 12:56:20 CEST 2007


Author: wingo
Date: Tue Jul 24 12:46:51 2007
New Revision: 5347

Modified:
   flumotion/trunk/ChangeLog
   flumotion/trunk/flumotion/common/debug.py
   flumotion/trunk/flumotion/component/feed.py
   flumotion/trunk/flumotion/test/test_component_feed.py
Log:
2007-07-24  Andy Wingo  <wingo at pobox.com>

	* flumotion/component/feed.py (FeedMedium.stopConnecting): Drop
	any remote reference, just in case.
	(FeedMedium._doFeedTo): Drop the remote reference after the pb
	handshaking is finished and the transport is closed. Fixes
	uncollectable object leaks when reconnecting feeds.

	* flumotion/common/debug.py (AllocMonitor.analyze)
	(AllocMonitor._printCycle, AllocMonitor._printParents)
	(AllocMonitor._printKids): More informative printing of object
	cycles.

	* flumotion/test/test_component_feed.py (TestUpstreamFeedClient):
	Add assertions regarding the state of the feedmedium's reference
	to the RemoteReference.



Modified: flumotion/trunk/ChangeLog
==============================================================================
--- flumotion/trunk/ChangeLog	(original)
+++ flumotion/trunk/ChangeLog	Tue Jul 24 12:46:51 2007
@@ -1,3 +1,20 @@
+2007-07-24  Andy Wingo  <wingo at pobox.com>
+
+	* flumotion/component/feed.py (FeedMedium.stopConnecting): Drop
+	any remote reference, just in case.
+	(FeedMedium._doFeedTo): Drop the remote reference after the pb
+	handshaking is finished and the transport is closed. Fixes
+	uncollectable object leaks when reconnecting feeds.
+
+	* flumotion/common/debug.py (AllocMonitor.analyze)
+	(AllocMonitor._printCycle, AllocMonitor._printParents)
+	(AllocMonitor._printKids): More informative printing of object
+	cycles.
+
+	* flumotion/test/test_component_feed.py (TestUpstreamFeedClient):
+	Add assertions regarding the state of the feedmedium's reference
+	to the RemoteReference.
+
 2007-07-24  Michael Smith <msmith at fluendo.com>
 
 	* flumotion/component/feedcomponent010.py:

Modified: flumotion/trunk/flumotion/common/debug.py
==============================================================================
--- flumotion/trunk/flumotion/common/debug.py	(original)
+++ flumotion/trunk/flumotion/common/debug.py	Tue Jul 24 12:46:51 2007
@@ -179,7 +179,27 @@
             else:
                 self.allocPrint(p, allocators[p])
         import gc
-        print '\ngc.garbage:', gc.garbage
+        for o in gc.garbage:
+            print '\nUncollectable object cycle in gc.garbage:'
+            self._printCycle(new[id(o)])
+
+    def _printCycle(self, root):
+        print "Parents:"
+        self._printParents(root, 2)
+        print "Kids:"
+        self._printKids(root, 2)
+
+    def _printParents(self, wrap, level, indent='  '):
+        print indent, self._wrapperRepr(wrap)
+        if level > 0:
+            for p in wrap.parents:
+                self._printParents(p, level - 1, indent + '  ')
+
+    def _printKids(self, wrap, level, indent='  '):
+        print indent, self._wrapperRepr(wrap)
+        if level > 0:
+            for kid in wrap.children:
+                self._printKids(kid, level - 1, indent + '  ')
 
     def _allocStack(self, wrap, stack):
         stack.append(wrap)

Modified: flumotion/trunk/flumotion/component/feed.py
==============================================================================
--- flumotion/trunk/flumotion/component/feed.py	(original)
+++ flumotion/trunk/flumotion/component/feed.py	Tue Jul 24 12:46:51 2007
@@ -191,6 +191,9 @@
         if self._factory:
             self._factory.disconnect()
             self._factory = None
+        # not sure if this is necessary; call it just in case, so we
+        # don't leave a lingering reference cycle
+        self.setRemoteReference(None)
 
     ### IMedium methods
     def setRemoteReference(self, remoteReference):
@@ -239,6 +242,10 @@
         # on the transport.
         t.connectionLost(failure.Failure(main.CONNECTION_DONE))
 
+        # This medium object is of no use any more; drop our reference
+        # to the remote so we can avoid cycles.
+        self.setRemoteReference(None)
+
         (flowName, componentName, feedName) = common.parseFullFeedId(fullFeedId)
         feedId = common.feedId(componentName, feedName)
 

Modified: flumotion/trunk/flumotion/test/test_component_feed.py
==============================================================================
--- flumotion/trunk/flumotion/test/test_component_feed.py	(original)
+++ flumotion/trunk/flumotion/test/test_component_feed.py	Tue Jul 24 12:46:51 2007
@@ -143,6 +143,8 @@
         client = feed.FeedMedium(component)
         factory = feed.FeedClientFactory(client)
 
+        self.failIf(client.hasRemoteReference())
+
         def login():
             port = self.feedServer.getPortNum()
             self.assertAdditionalFDsOpen(1, 'connect (socket)')
@@ -152,6 +154,9 @@
                                                    password='test'))
 
         def cleanup(res):
+            # We're not using requestFeed, so no reference should be set
+            self.failIf(client.hasRemoteReference())
+
             self.assertAdditionalFDsOpen(3, 'cleanup (socket, client, server)')
             factory.disconnect()
 
@@ -179,6 +184,8 @@
         client = feed.FeedMedium(component)
         factory = feed.FeedClientFactory(client)
 
+        self.failIf(client.hasRemoteReference())
+
         def login():
             port = self.feedServer.getPortNum()
             self.assertAdditionalFDsOpen(1, 'connect (socket)')
@@ -189,7 +196,9 @@
 
         def sendFeed(remote):
             # apparently one has to do magic to get the feed to work
+            self.failIf(client.hasRemoteReference())
             client.setRemoteReference(remote)
+            self.failUnless(client.hasRemoteReference())
             self.assertAdditionalFDsOpen(3, 'feed (socket, client, server)')
             return remote.callRemote('sendFeed', '/foo/bar:baz')
 
@@ -212,6 +221,9 @@
             # this likely fires directly, not having dropped into the
             # reactor.
 
+            # The feed medium should have dropped its reference already
+            self.failIf(client.hasRemoteReference())
+
             # this fd is not ours, we should dup it if we want to hold
             # onto it
             return self.feedServer.waitForAvatarExit()
@@ -265,6 +277,9 @@
             # this likely fires directly, not having dropped into the
             # reactor.
 
+            # The feed medium should have dropped its reference already
+            self.failIf(client.hasRemoteReference())
+
             # this fd is not ours, we should dup it if we want to hold
             # onto it
             return self.feedServer.waitForAvatarExit()
@@ -324,6 +339,8 @@
     def testRequestFeed(self):
         client = feed.FeedMedium(logName='frobby')
 
+        self.failIf(client.hasRemoteReference())
+
         def requestFeed():
             port = self.feedServer.getPortNum()
             self.assertAdditionalFDsOpen(1, 'connect (socket)')
@@ -331,10 +348,17 @@
                                    fpb.Authenticator(username='user',
                                                      password='test'),
                                    '/foo/bar:baz')
+            self.failIf(client.hasRemoteReference())
             self.assertAdditionalFDsOpen(2, 'connect (socket, client)')
             return d
 
         def gotFeed((feedId, fd)):
+            # the feed medium should have dropped its reference to the
+            # remotereference by now, otherwise we get cycles, and
+            # remote references can't exist in cycles because they have
+            # a __del__ method
+            self.failIf(client.hasRemoteReference())
+
             self.assertEquals(feedId, 'bar:baz')
             self.assertAdditionalFDsOpen(3, 'cleanup (socket, client, server)')
             # our responsibility to close fd


More information about the flumotion-commit mailing list