You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

69 lines
2.2 KiB

4 years ago
  1. from collections import deque
  2. class RoundRobinQueue(object):
  3. """A round robin queue implemented using multiple internal queues (typically,
  4. FIFO queues). The internal queue must implement the following methods:
  5. * push(obj)
  6. * pop()
  7. * close()
  8. * __len__()
  9. The constructor receives a qfactory argument, which is a callable used to
  10. instantiate a new (internal) queue when a new key is allocated. The
  11. qfactory function is called with the key number as first and only
  12. argument.
  13. start_keys is a sequence of domains to start with. If the queue was
  14. previously closed leaving some domain buckets non-empty, those domains
  15. should be passed in start_keys.
  16. The queue maintains a fifo queue of keys. The key that went last is
  17. poped first and the next queue for that key is then poped. This allows
  18. for a round robin
  19. """
  20. def __init__(self, qfactory, start_domains=()):
  21. self.queues = {}
  22. self.qfactory = qfactory
  23. for key in start_domains:
  24. self.queues[key] = self.qfactory(key)
  25. self.key_queue = deque(start_domains)
  26. def push(self, obj, key):
  27. if key not in self.key_queue:
  28. self.queues[key] = self.qfactory(key)
  29. self.key_queue.appendleft(key) # it's new, might as well pop first
  30. q = self.queues[key]
  31. q.push(obj) # this may fail (eg. serialization error)
  32. def pop(self):
  33. m = None
  34. # pop until we find a valid object, closing necessary queues
  35. while m is None:
  36. try:
  37. key = self.key_queue.pop()
  38. except IndexError:
  39. return
  40. q = self.queues[key]
  41. m = q.pop()
  42. if len(q) == 0:
  43. del self.queues[key]
  44. q.close()
  45. else:
  46. self.key_queue.appendleft(key)
  47. if m:
  48. return m
  49. def close(self):
  50. active = []
  51. for k, q in self.queues.items():
  52. if len(q):
  53. active.append(k)
  54. q.close()
  55. return active
  56. def __len__(self):
  57. return sum(len(x) for x in self.queues.values()) if self.queues else 0