Stack.php 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. /**
  3. * @category Thinkopen
  4. * @package Mooses_Mongodb_Mongo
  5. * @copyright Thinkopen s.r.l.
  6. * @license New BSD License
  7. * @author Coen Hyde
  8. */
  9. class Mooses_Mongodb_Mongo_Connection_Stack implements SeekableIterator, Countable, ArrayAccess
  10. {
  11. protected $_position = 0;
  12. protected $_nodes = array();
  13. protected $_weights = array();
  14. protected $_options = array(
  15. 'cacheConnectionSelection' => true
  16. );
  17. protected $_cacheConnectionSelection = true;
  18. protected $_cachedConnection = null;
  19. /**
  20. * Get an option
  21. *
  22. * @param string $option
  23. */
  24. public function getOption($option)
  25. {
  26. if (!array_key_exists($option, $this->_options)) {
  27. return null;
  28. }
  29. return $this->_options[$option];
  30. }
  31. /**
  32. * Set an option
  33. *
  34. * @param string $option
  35. * @param mixed $value
  36. */
  37. public function setOption($option, $value)
  38. {
  39. $this->_options[$option] = $value;
  40. }
  41. /**
  42. * Set Options
  43. *
  44. * @param array $options
  45. */
  46. public function setOptions(array $options)
  47. {
  48. $this->_options = array_merge($this->_options, $options);
  49. }
  50. /**
  51. * Add node to connection stack
  52. *
  53. * @param Mooses_Mongodb_Mongo_Connection $connection
  54. * @param int $weight
  55. */
  56. public function addNode(Mooses_Mongodb_Mongo_Connection $connection, $weight = 1)
  57. {
  58. $this->_nodes[] = $connection;
  59. $this->_weights[] = (int) $weight;
  60. }
  61. /**
  62. * Select a node from the connection stack.
  63. *
  64. * @return Mooses_Mongodb_Mongo_Connection
  65. */
  66. public function selectNode()
  67. {
  68. if (count($this) == 0) {
  69. // no nodes to select from
  70. return null;
  71. }
  72. // Return the cached connection if available
  73. if ($this->cacheConnectionSelection() && $this->hasCachedConnection()) {
  74. return $this->getCachedConnection();
  75. }
  76. // Select a new connection
  77. $r = mt_rand(1,array_sum($this->_weights));
  78. $offset = 0;
  79. foreach ($this->_weights as $k => $weight) {
  80. $offset += $weight;
  81. if ($r <= $offset) {
  82. $connection = $this->_nodes[$k];
  83. break;
  84. }
  85. }
  86. // Cache the connection for later use
  87. if ($this->cacheConnectionSelection()) {
  88. $this->_cachedConnection = $connection;
  89. }
  90. return $connection;
  91. }
  92. /**
  93. * Determine if this connection stack has a cached connection
  94. *
  95. * @return boolean
  96. */
  97. public function hasCachedConnection()
  98. {
  99. return !is_null($this->_cachedConnection);
  100. }
  101. /**
  102. * Get the cached connection
  103. *
  104. * @return Mooses_Mongodb_Mongo_Connection
  105. */
  106. public function getCachedConnection()
  107. {
  108. return $this->_cachedConnection;
  109. }
  110. /**
  111. * Get or set the flag to determine if the first connection selection should be cached
  112. *
  113. * @param boolean $value
  114. */
  115. public function cacheConnectionSelection($value = null)
  116. {
  117. if (!is_null($value)) {
  118. $this->_options['cacheConnectionSelection'] = (boolean) $value;
  119. }
  120. return $this->_options['cacheConnectionSelection'];
  121. }
  122. /**
  123. * Seek to a particular connection
  124. *
  125. * @param $position
  126. */
  127. public function seek($position)
  128. {
  129. if (!is_numeric($position)) {
  130. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  131. throw new Mooses_Mongodb_Mongo_Exception("Position must be numeric");
  132. }
  133. $this->_position = $position;
  134. if (!$this->valid()) {
  135. throw new OutOfBoundsException("invalid seek position ($position)");
  136. }
  137. }
  138. /**
  139. * Get the current connection
  140. *
  141. * @return Mooses_Mongodb_Mongo_Connection
  142. */
  143. public function current()
  144. {
  145. return $this->_nodes[$this->_position];
  146. }
  147. /**
  148. * Get teh current key
  149. *
  150. * @return int
  151. */
  152. public function key()
  153. {
  154. return $this->_position;
  155. }
  156. /**
  157. * Move the pointer to the next connection
  158. */
  159. public function next()
  160. {
  161. $this->_position +=1;
  162. }
  163. /**
  164. * Rewind the pointer to the begining of the stack
  165. */
  166. public function rewind()
  167. {
  168. $this->_position = 0;
  169. }
  170. /**
  171. * Is the location of the current pointer valid
  172. */
  173. public function valid()
  174. {
  175. return $this->offsetExists($this->_position);
  176. }
  177. /**
  178. * Count all the connections
  179. */
  180. public function count()
  181. {
  182. return count($this->_nodes);
  183. }
  184. /**
  185. * Test if an offset exists
  186. *
  187. * @param int $offset
  188. */
  189. public function offsetExists($offset)
  190. {
  191. return array_key_exists($offset, $this->_nodes);
  192. }
  193. /**
  194. * Get an offset
  195. *
  196. * @param int $offset
  197. */
  198. public function offsetGet($offset)
  199. {
  200. if (!$this->offsetExists($offset)) return null;
  201. return $this->_nodes[$offset];
  202. }
  203. /**
  204. * Set an offset
  205. *
  206. * @param Mooses_Mongodb_Mongo_Connection $offset
  207. * @param $connection
  208. */
  209. public function offsetSet($offset, $connection)
  210. {
  211. if (!is_numeric($offset)) {
  212. require_once 'Thinkopen/Mongodb/Mongo/Exception.php';
  213. throw new Mooses_Mongodb_Mongo_Exception("Offset must be numeric");
  214. }
  215. $this->_nodes[$offset] = $connection;
  216. $this->_weights[$offset] = 1;
  217. }
  218. /**
  219. * Unset an offset
  220. *
  221. * @param int $offset
  222. */
  223. public function offsetUnset($offset)
  224. {
  225. unset($this->_nodes[$offset]);
  226. unset($this->_weights[$offset]);
  227. }
  228. }