diff options
author | Erik Johnston <erik@matrix.org> | 2016-11-10 16:29:51 +0000 |
---|---|---|
committer | Erik Johnston <erik@matrix.org> | 2016-11-10 16:29:51 +0000 |
commit | d073cb7ead62314ff14c59a9aaeac4f5f8470dd6 (patch) | |
tree | 3e2b7d103394fde7d3efcbf81117ec21fa6af2ec /synapse | |
parent | Merge pull request #1619 from matrix-org/erikj/pwd_provider_error (diff) | |
download | synapse-d073cb7ead62314ff14c59a9aaeac4f5f8470dd6.tar.xz |
Add Limiter: limit concurrent access to resource
Diffstat (limited to 'synapse')
-rw-r--r-- | synapse/util/async.py | 45 |
1 files changed, 45 insertions, 0 deletions
diff --git a/synapse/util/async.py b/synapse/util/async.py index 347fb1e380..2a680fff5e 100644 --- a/synapse/util/async.py +++ b/synapse/util/async.py @@ -197,6 +197,51 @@ class Linearizer(object): defer.returnValue(_ctx_manager()) +class Limiter(object): + """Limits concurrent access to resources based on a key. Useful to ensure + only a few thing happen at a time on a given resource. + + Example: + + with (yield limiter.queue("test_key")): + # do some work. + + """ + def __init__(self, max_count): + """ + Args: + max_count(int): The maximum number of concurrent access + """ + self.max_count = max_count + self.key_to_defer = {} + + @defer.inlineCallbacks + def queue(self, key): + entry = self.key_to_defer.setdefault(key, [0, []]) + + if entry[0] >= self.max_count: + new_defer = defer.Deferred() + entry[1].append(new_defer) + with PreserveLoggingContext(): + yield new_defer + + entry[0] += 1 + + @contextmanager + def _ctx_manager(): + try: + yield + finally: + entry[0] -= 1 + try: + entry[1].pop(0).callback(None) + except IndexError: + if entry[0] == 0: + self.key_to_defer.pop(key, None) + + defer.returnValue(_ctx_manager()) + + class ReadWriteLock(object): """A deferred style read write lock. |