/carbono/buffer_manager/work_manager.py

https://github.com/igorbonadio/carbono
Python | 156 lines | 113 code | 24 blank | 19 comment | 28 complexity | 29db96d9c46953f243634906e3acb341 MD5 | raw file
  1. #!/usr/bin/python
  2. # coding: utf-8
  3. # Copyright (C) 2011 Lucas Alvares Gomes <lucasagomes@gmail.com>
  4. #
  5. # This program is free software; you can redistribute it and/or modify
  6. # it under the terms of the GNU General Public License as published by
  7. # the Free Software Foundation; either version 2 of the License, or
  8. # (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU General Public License
  16. # along with this program; if not, see <http://www.gnu.org/licenses/>.
  17. import time
  18. import Queue
  19. from multiprocessing import Process, Manager, Event
  20. from multiprocessing.managers import BaseManager
  21. from threading import Thread
  22. from copy import deepcopy
  23. from carbono.buffer_manager.reorder_buffer import ReoderBuffer
  24. from carbono.utils import *
  25. from carbono.config import *
  26. from carbono.exception import *
  27. class Worker(Process):
  28. def __init__(self, buffer, reorder_buffer, job):
  29. Process.__init__(self)
  30. self.buffer = buffer
  31. self.reorder_buffer = reorder_buffer
  32. self.job = job
  33. self.event = Event()
  34. def run(self):
  35. self.event.set()
  36. while self.event.is_set():
  37. try:
  38. block_number, data = self.buffer.get()
  39. except IOError, e:
  40. if e.errno == errno.EINTR:
  41. data = EOF
  42. if data == EOF:
  43. self.stop()
  44. break
  45. worked_data = self.job(data)
  46. while self.event.is_set():
  47. try:
  48. self.reorder_buffer.put(block_number, worked_data)
  49. break
  50. except IndexError:
  51. # Block num bigger than expected,
  52. # wait untill ReorderBuffer start
  53. # processing blocks in this range
  54. time.sleep(0.1)
  55. except IOError, e:
  56. if e.errno == errno.EINTR:
  57. self.stop()
  58. def stop(self):
  59. self.event.clear()
  60. try:
  61. self.terminate()
  62. except AttributeError:
  63. pass
  64. class WorkManager(Thread):
  65. def __init__(self, read_callback, job_callback):
  66. Thread.__init__(self)
  67. self.read_block = read_callback
  68. self.job = job_callback
  69. self.manager = Manager()
  70. self.num_cores = available_processors()
  71. self._block_number = 0
  72. self._worker_list = list()
  73. self.active = False
  74. self._setup()
  75. self._start_workers()
  76. def _setup(self):
  77. free_phy_mem = available_memory(percent=35)
  78. maxsize = int(free_phy_mem / BLOCK_SIZE)
  79. self._input_buffer = self.manager.Queue(maxsize)
  80. self.output_buffer = self.manager.Queue(maxsize)
  81. BaseManager.register("ReoderBuffer", ReoderBuffer)
  82. bm = BaseManager()
  83. bm.start()
  84. self.reorder_buffer = bm.ReoderBuffer(self.output_buffer, 50)
  85. def _start_workers(self):
  86. for cpu in xrange(self.num_cores):
  87. worker = Worker(self._input_buffer,
  88. self.reorder_buffer,
  89. self.job)
  90. worker.start()
  91. self._worker_list.append(worker)
  92. def run(self):
  93. self.active = True
  94. while self.active:
  95. try:
  96. data = self.read_block()
  97. except ErrorReadingFromDevice, e:
  98. self.stop()
  99. raise e
  100. if not data:
  101. self._finish()
  102. break
  103. self.put(data)
  104. def put(self, data):
  105. while self.active:
  106. try:
  107. self._input_buffer.put((deepcopy(self._block_number), data),
  108. timeout=1)
  109. except Queue.Full:
  110. continue
  111. self._block_number += 1
  112. break
  113. def _finish(self):
  114. self.active = False
  115. for worker in self._worker_list:
  116. self._input_buffer.put((EOF, EOF))
  117. for worker in self._worker_list:
  118. try:
  119. worker.join()
  120. except AssertionError:
  121. pass
  122. self.reorder_buffer.sync()
  123. self.output_buffer.put(EOF)
  124. def stop(self):
  125. self.active = False
  126. for worker in self._worker_list:
  127. worker.stop()
  128. for worker in self._worker_list:
  129. try:
  130. worker.join()
  131. except AssertionError:
  132. pass