Skip to content

Instantly share code, notes, and snippets.

@terrycojones
Created August 26, 2013 21:37
Show Gist options
  • Save terrycojones/6346959 to your computer and use it in GitHub Desktop.
Save terrycojones/6346959 to your computer and use it in GitHub Desktop.
# Copyright 2013 Terry Jones ([email protected]). All Rights Reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. The name of the author may not be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY [LICENSOR] "AS IS" AND ANY EXPRESS OR IMPLIED
# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
# EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
# OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
# IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
# OF SUCH DAMAGE.
from twisted.internet import defer
class DeferredPool(object):
"""
Maintain a pool of not-yet-fired deferreds and provide a mechanism to
request a deferred that fires when the pool size goes to zero.
"""
def __init__(self):
self._pool = set()
self._waiting = []
def _fired(self, result, d):
"""
Callback/errback each pooled deferred runs when it fires. The
deferred first removes itself from the pool. If the pool is then
empty, fire all the waiting deferreds (which were returned by
notifyWhenEmpty).
"""
self._pool.remove(d)
if not self._pool:
waiting, self._waiting = self._waiting, []
for waiter in waiting:
waiter.callback(None)
return result
def add(self, d):
"""
Add a deferred to the pool.
"""
d.addBoth(self._fired, d)
self._pool.add(d)
return d
def notifyWhenEmpty(self, testImmediately=True):
"""
Return a deferred that fires (with None) when the pool empties. If
testImmediately is True and the pool is empty, return an already
fired deferred (via succeed).
"""
if testImmediately and not self._pool:
return defer.succeed(None)
else:
d = defer.Deferred()
self._waiting.append(d)
return d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment