changeset 1445:efe63f85605a

boost: Made DeferredList inherit from C Deferred.
author Marcel Keller <mkeller@cs.au.dk>
date Wed, 16 Jun 2010 14:00:18 +0200
parents 0ebed2045ec5
children feb70913ce98
files apps/aes.py viff/boost.py
diffstat 2 files changed, 90 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/apps/aes.py	Sun Jun 13 14:36:06 2010 +0200
+++ b/apps/aes.py	Wed Jun 16 14:00:18 2010 +0200
@@ -25,13 +25,13 @@
 from pprint import pformat
 import sys
 
+import viff.boost
+viff.boost.install()
+
 import viff.reactor
 viff.reactor.install()
 from twisted.internet import reactor
 
-import viff.boost
-viff.boost.install()
-
 from viff.field import GF256
 from viff.runtime import Runtime, create_runtime, gather_shares
 from viff.config import load_config
--- a/viff/boost.py	Sun Jun 13 14:36:06 2010 +0200
+++ b/viff/boost.py	Wed Jun 16 14:00:18 2010 +0200
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
 #
-# Copyright 2007, 2008, 2009 VIFF Development Team.
+# Copyright 2010 VIFF Development Team.
 #
 # This file is part of VIFF, the Virtual Ideal Functionality Framework.
 #
@@ -18,11 +18,94 @@
 # License along with VIFF. If not, see <http://www.gnu.org/licenses/>.
 
 import twisted.internet.defer
+from twisted.python import failure
+
 import viff.cdefer
+from viff.cdefer import Deferred
+
+
+# DeferredList copied here to base it on cdefer
+
+class DeferredList(Deferred):
+    """I combine a group of deferreds into one callback.
+
+    I track a list of L{Deferred}s for their callbacks, and make a single
+    callback when they have all completed, a list of (success, result)
+    tuples, 'success' being a boolean.
+
+    Note that you can still use a L{Deferred} after putting it in a
+    DeferredList.  For example, you can suppress 'Unhandled error in Deferred'
+    messages by adding errbacks to the Deferreds *after* putting them in the
+    DeferredList, as a DeferredList won't swallow the errors.  (Although a more
+    convenient way to do this is simply to set the consumeErrors flag)
+    """
+
+    fireOnOneCallback = 0
+    fireOnOneErrback = 0
+
+    def __init__(self, deferredList, fireOnOneCallback=0, fireOnOneErrback=0,
+                 consumeErrors=0):
+        """Initialize a DeferredList.
+
+        @type deferredList:  C{list} of L{Deferred}s
+        @param deferredList: The list of deferreds to track.
+        @param fireOnOneCallback: (keyword param) a flag indicating that
+                             only one callback needs to be fired for me to call
+                             my callback
+        @param fireOnOneErrback: (keyword param) a flag indicating that
+                            only one errback needs to be fired for me to call
+                            my errback
+        @param consumeErrors: (keyword param) a flag indicating that any errors
+                            raised in the original deferreds should be
+                            consumed by this DeferredList.  This is useful to
+                            prevent spurious warnings being logged.
+        """
+        self.resultList = [None] * len(deferredList)
+        Deferred.__init__(self)
+        if len(deferredList) == 0 and not fireOnOneCallback:
+            self.callback(self.resultList)
+
+        # These flags need to be set *before* attaching callbacks to the
+        # deferreds, because the callbacks use these flags, and will run
+        # synchronously if any of the deferreds are already fired.
+        self.fireOnOneCallback = fireOnOneCallback
+        self.fireOnOneErrback = fireOnOneErrback
+        self.consumeErrors = consumeErrors
+        self.finishedCount = 0
+
+        index = 0
+        for deferred in deferredList:
+            deferred.addCallbacks(self._cbDeferred, self._cbDeferred,
+                                  callbackArgs=(index,SUCCESS),
+                                  errbackArgs=(index,FAILURE))
+            index = index + 1
+
+    def _cbDeferred(self, result, index, succeeded):
+        """(internal) Callback for when one of my deferreds fires.
+        """
+        self.resultList[index] = (succeeded, result)
+
+        self.finishedCount += 1
+        if not self.called:
+            if succeeded == SUCCESS and self.fireOnOneCallback:
+                self.callback((result, index))
+            elif succeeded == FAILURE and self.fireOnOneErrback:
+                self.errback(failure.Failure(FirstError(result, index)))
+            elif self.finishedCount == len(self.resultList):
+                self.callback(self.resultList)
+
+        if succeeded == FAILURE and self.consumeErrors:
+            result = None
+
+        return result
+
+# Constants for use with DeferredList
+
+SUCCESS = True
+FAILURE = False
+
 
 def install():
     global viff
-    old_def = twisted.internet.defer.Deferred
     twisted.internet.defer.Deferred = viff.cdefer.Deferred
-    import viff.runtime
-    twisted.internet.defer.Deferred = old_def
+    twisted.internet.defer.DeferredList = DeferredList