PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/SQLAlchemy-0.7.8/lib/sqlalchemy/util/queue.py

#
Python | 191 lines | 184 code | 2 blank | 5 comment | 1 complexity | 96e0ec6280b7230db1fa34b924964129 MD5 | raw file
  1. # util/queue.py
  2. # Copyright (C) 2005-2012 the SQLAlchemy authors and contributors <see AUTHORS file>
  3. #
  4. # This module is part of SQLAlchemy and is released under
  5. # the MIT License: http://www.opensource.org/licenses/mit-license.php
  6. """An adaptation of Py2.3/2.4's Queue module which supports reentrant
  7. behavior, using RLock instead of Lock for its mutex object.
  8. This is to support the connection pool's usage of weakref callbacks to return
  9. connections to the underlying Queue, which can in extremely
  10. rare cases be invoked within the ``get()`` method of the Queue itself,
  11. producing a ``put()`` inside the ``get()`` and therefore a reentrant
  12. condition."""
  13. from collections import deque
  14. from time import time as _time
  15. from sqlalchemy.util import threading
  16. __all__ = ['Empty', 'Full', 'Queue']
  17. class Empty(Exception):
  18. "Exception raised by Queue.get(block=0)/get_nowait()."
  19. pass
  20. class Full(Exception):
  21. "Exception raised by Queue.put(block=0)/put_nowait()."
  22. pass
  23. class Queue:
  24. def __init__(self, maxsize=0):
  25. """Initialize a queue object with a given maximum size.
  26. If `maxsize` is <= 0, the queue size is infinite.
  27. """
  28. self._init(maxsize)
  29. # mutex must be held whenever the queue is mutating. All methods
  30. # that acquire mutex must release it before returning. mutex
  31. # is shared between the two conditions, so acquiring and
  32. # releasing the conditions also acquires and releases mutex.
  33. self.mutex = threading.RLock()
  34. # Notify not_empty whenever an item is added to the queue; a
  35. # thread waiting to get is notified then.
  36. self.not_empty = threading.Condition(self.mutex)
  37. # Notify not_full whenever an item is removed from the queue;
  38. # a thread waiting to put is notified then.
  39. self.not_full = threading.Condition(self.mutex)
  40. def qsize(self):
  41. """Return the approximate size of the queue (not reliable!)."""
  42. self.mutex.acquire()
  43. n = self._qsize()
  44. self.mutex.release()
  45. return n
  46. def empty(self):
  47. """Return True if the queue is empty, False otherwise (not
  48. reliable!)."""
  49. self.mutex.acquire()
  50. n = self._empty()
  51. self.mutex.release()
  52. return n
  53. def full(self):
  54. """Return True if the queue is full, False otherwise (not
  55. reliable!)."""
  56. self.mutex.acquire()
  57. n = self._full()
  58. self.mutex.release()
  59. return n
  60. def put(self, item, block=True, timeout=None):
  61. """Put an item into the queue.
  62. If optional args `block` is True and `timeout` is None (the
  63. default), block if necessary until a free slot is
  64. available. If `timeout` is a positive number, it blocks at
  65. most `timeout` seconds and raises the ``Full`` exception if no
  66. free slot was available within that time. Otherwise (`block`
  67. is false), put an item on the queue if a free slot is
  68. immediately available, else raise the ``Full`` exception
  69. (`timeout` is ignored in that case).
  70. """
  71. self.not_full.acquire()
  72. try:
  73. if not block:
  74. if self._full():
  75. raise Full
  76. elif timeout is None:
  77. while self._full():
  78. self.not_full.wait()
  79. else:
  80. if timeout < 0:
  81. raise ValueError("'timeout' must be a positive number")
  82. endtime = _time() + timeout
  83. while self._full():
  84. remaining = endtime - _time()
  85. if remaining <= 0.0:
  86. raise Full
  87. self.not_full.wait(remaining)
  88. self._put(item)
  89. self.not_empty.notify()
  90. finally:
  91. self.not_full.release()
  92. def put_nowait(self, item):
  93. """Put an item into the queue without blocking.
  94. Only enqueue the item if a free slot is immediately available.
  95. Otherwise raise the ``Full`` exception.
  96. """
  97. return self.put(item, False)
  98. def get(self, block=True, timeout=None):
  99. """Remove and return an item from the queue.
  100. If optional args `block` is True and `timeout` is None (the
  101. default), block if necessary until an item is available. If
  102. `timeout` is a positive number, it blocks at most `timeout`
  103. seconds and raises the ``Empty`` exception if no item was
  104. available within that time. Otherwise (`block` is false),
  105. return an item if one is immediately available, else raise the
  106. ``Empty`` exception (`timeout` is ignored in that case).
  107. """
  108. self.not_empty.acquire()
  109. try:
  110. if not block:
  111. if self._empty():
  112. raise Empty
  113. elif timeout is None:
  114. while self._empty():
  115. self.not_empty.wait()
  116. else:
  117. if timeout < 0:
  118. raise ValueError("'timeout' must be a positive number")
  119. endtime = _time() + timeout
  120. while self._empty():
  121. remaining = endtime - _time()
  122. if remaining <= 0.0:
  123. raise Empty
  124. self.not_empty.wait(remaining)
  125. item = self._get()
  126. self.not_full.notify()
  127. return item
  128. finally:
  129. self.not_empty.release()
  130. def get_nowait(self):
  131. """Remove and return an item from the queue without blocking.
  132. Only get an item if one is immediately available. Otherwise
  133. raise the ``Empty`` exception.
  134. """
  135. return self.get(False)
  136. # Override these methods to implement other queue organizations
  137. # (e.g. stack or priority queue).
  138. # These will only be called with appropriate locks held
  139. # Initialize the queue representation
  140. def _init(self, maxsize):
  141. self.maxsize = maxsize
  142. self.queue = deque()
  143. def _qsize(self):
  144. return len(self.queue)
  145. # Check whether the queue is empty
  146. def _empty(self):
  147. return not self.queue
  148. # Check whether the queue is full
  149. def _full(self):
  150. return self.maxsize > 0 and len(self.queue) == self.maxsize
  151. # Put a new item in the queue
  152. def _put(self, item):
  153. self.queue.append(item)
  154. # Get an item from the queue
  155. def _get(self):
  156. return self.queue.popleft()