Fix compatibility with twisted 8.x
authorIustin Pop <iustin@google.com>
Mon, 7 Jul 2008 08:00:10 +0000 (08:00 +0000)
committerIustin Pop <iustin@google.com>
Mon, 7 Jul 2008 08:00:10 +0000 (08:00 +0000)
After much investigation, I realized that our old method of restarting
the reactor will not work easily (if at all) with twisted 8.x. So the
logical consequence is that we must not restart the reactor, but instead
create one fully anew.

Since twisted doesn't allow one to re-install a new reactor, we just
pretend there was no reactor ever installed; this works as the old
reactor was (or should have been, as otherwise we wouldn't have returned
from the reactor.run() call in Client.run()) already stopped and since
we delete it, no other references to it should exist and it should be
cleared away.

The actual implementation is as follows:
  - we remove the ReReactor class, as we don't need it, as instead we
    use a standard PollReactor
  - at each rpc.Client creation, we:
    - delete the twisted.internet.reactor from the list of loaded
      modules
    - create a new PollReactor()
    - replace the twisted main reactor with it
  - we move the use of the install_twisted_signal_handlers from the
    ReReactor class to the Client.run() function

The deletion from sys.modules is needed to skip twisted checks and
should be safe (per the python documentation of sys.modules:
"sys.modules... can be manipulated to force reloading of modules and
other tricks").

The patch has been tested and passes burnin on both debian stable
(twisted 2.4.0) and unstable (twisted 8.1.0).

Reviewed-by: imsnah

lib/rpc.py

index b6e0c3a..5b7a1c0 100644 (file)
 
 # pylint: disable-msg=C0103
 
+import sys
 import os
 
-from twisted.internet.pollreactor import PollReactor
-
-
 install_twisted_signal_handlers = True
 
-
-class ReReactor(PollReactor):
-  """A re-startable Reactor implementation.
-
-  """
-  def run(self, installSignalHandlers=None):
-    """Custom run method.
-
-    This is customized run that, before calling Reactor.run, will
-    reinstall the shutdown events and re-create the threadpool in case
-    these are not present (as will happen on the second run of the
-    reactor).
-
-    """
-    if installSignalHandlers is None:
-      installSignalHandlers = install_twisted_signal_handlers
-    if not 'shutdown' in self._eventTriggers:
-      # the shutdown queue has been killed, we are most probably
-      # at the second run, thus recreate the queue
-      self.addSystemEventTrigger('during', 'shutdown', self.crash)
-      self.addSystemEventTrigger('during', 'shutdown', self.disconnectAll)
-    if self.threadpool is not None and self.threadpool.joined == 1:
-      # in case the threadpool has been stopped, re-start it
-      # and add a trigger to stop it at reactor shutdown
-      self.threadpool.start()
-      self.addSystemEventTrigger('during', 'shutdown', self.threadpool.stop)
-
-    return PollReactor.run(self, installSignalHandlers)
-
-
+from twisted.internet.pollreactor import PollReactor
 import twisted.internet.main
-twisted.internet.main.installReactor(ReReactor())
-
 from twisted.spread import pb
 from twisted.internet import reactor
 from twisted.cred import credentials
@@ -217,6 +184,13 @@ class Client:
     self.results = {}
     self.procedure = procedure
     self.args = args
+    global reactor
+    try:
+      del sys.modules['twisted.internet.reactor']
+    except KeyError:
+      pass
+    reactor = PollReactor()
+    twisted.internet.main.installReactor(reactor)
 
   #--- generic connector -------------
 
@@ -253,7 +227,7 @@ class Client:
 
     """
     if self.nc:
-      reactor.run()
+      reactor.run(install_twisted_signal_handlers)
 
 
 def call_volume_list(node_list, vg_name):