PHPmemcache ring queue

Source: Internet
Author: User
PHPmemcache ring queue
PHP memcache ring queue class. Beginner, I have never learned the data structure. because of the business needs, I just tried it hard! The original form is the PHP memcache queue code shared by lusi on oschina. To enable the queue to enter and exit at any time, and avoid the danger of the int length crossing the border (if a single chain uses the Head auto-increment function, it is possible that the process does not cross the border), simply rewrite the queue to a ring queue. There may be bugs. sorry!

  1. /**
  2. * PHP memcache ring queue
  3. * Original author LKK/lianq.net
  4. * Modify FoxHunter
  5. * Because the business only needs to retain Pop and Push in the queue, the modification of the Expiration Time to 0 is permanent
  6. */
  7. Class MQueue
  8. {
  9. Public static $ client;
  10. Private $ expire; // expiration time, in seconds, 1 ~ 2592000, that is, within 30 days
  11. Private $ sleepTime; // waiting for unlock time, in microseconds
  12. Private $ queueName; // queue name, unique value
  13. Private $ retryNum; // number of attempts
  14. Private $ MAXNUM; // maximum queue capacity
  15. Private $ canRewrite; // whether the write overwrite switch is enabled. the full content overwrites the original data from the header.
  16. Private $ HEAD; // The pointer position to be entered Next
  17. Private $ TAIL; // pointer position to be entered Next
  18. Private $ LEN; // existing queue length
  19. Const LOCK_KEY = '_ Fox_MQ_LOCK _'; // lock storage identifier
  20. Const LENGTH_KEY = '_ Fox_MQ_LENGTH _'; // storage ID of the current queue length
  21. Const VALU_KEY = '_ Fox_MQ_VAL _'; // queue key value storage identifier
  22. Const HEAD_KEY = '_ Fox_MQ_HEAD _'; // specifies the position of the HEAD pointer in the queue.
  23. Const TAIL_KEY = '_ Fox_MQ_TAIL _'; // specifies the position of the TAIL pointer in the queue.
  24. /*
  25. * Constructor
  26. * For the same $ queueName, the parameter values of the constructor must be consistent during instantiation. otherwise, pop and push will lead to disordered queue order.
  27. */
  28. Public function _ construct ($ queueName = '', $ maxqueue = 1, $ canRewrite = false, $ expire = 0, $ config = '')
  29. {
  30. If (empty ($ config )){
  31. Self: $ client = memcache_pconnect ('2017. 0.0.1 ', 127 );
  32. } Elseif (is_array ($ config) {// array ('host' => '2017. 0.0.1 ', 'port' => '2016 ')
  33. Self: $ client = memcache_pconnect ($ config ['host'], $ config ['port']);
  34. } Elseif (is_string ($ config) {// "127.0.0.1: 11211"
  35. $ Tmp = explode (':', $ config );
  36. $ Conf ['host'] = isset ($ tmp [0])? $ Tmp [0]: '2017. 0.0.1 ';
  37. $ Conf ['port'] = isset ($ tmp [1])? $ Tmp [1]: '20140901 ';
  38. Self: $ client = memcache_pconnect ($ conf ['host'], $ conf ['port']);
  39. }
  40. If (! Self: $ client)
  41. Return false;
  42. Ignore_user_abort (true); // when the customer disconnects, continue execution is allowed.
  43. Set_time_limit (0); // cancels the upper limit of script execution latency
  44. $ This-> access = false;
  45. $ This-& gt; sleepTime = 1000;
  46. $ Expire = (empty ($ expire ))? 0: (int) $ expire + 1;
  47. $ This-> expire = $ expire;
  48. $ This-> queueName = $ queueName;
  49. $ This-> retrynum= 20000;
  50. $ This-> MAXNUM = $ maxqueue! = Null? $ Maxqueue: 1;
  51. $ This-> canRewrite = $ canRewrite;
  52. $ This-> getHeadAndTail ();
  53. If (! Isset ($ this-> HEAD) | empty ($ this-> HEAD ))
  54. $ This-> HEAD = 0;
  55. If (! Isset ($ this-> TAIL) | empty ($ this-> TAIL ))
  56. $ This-> TAIL = 0;
  57. If (! Isset ($ this-> LEN) | empty ($ this-> LEN ))
  58. $ This-> LEN = 0;
  59. }
  60. // Obtain the beginning and end pointer information and length of the queue.
  61. Private function getHeadAndTail ()
  62. {
  63. $ This-> HEAD = (int) memcache_get (self: $ client, $ this-> queueName. self: HEAD_KEY );
  64. $ This-> TAIL = (int) memcache_get (self: $ client, $ this-> queueName. self: TAIL_KEY );
  65. $ This-> LEN = (int) memcache_get (self: $ client, $ this-> queueName. self: LENGTH_KEY );
  66. }
  67. // Use memcache_add atomic lock
  68. Private function lock ()
  69. {
  70. If ($ this-> access === false ){
  71. $ I = 0;
  72. While (! Memcache_add (self ::$ client, $ this-> queueName. self: LOCK_KEY, 1, false, $ this-> expire )){
  73. Usleep ($ this-> sleepTime );
  74. @ $ I ++;
  75. If ($ I> $ this-> retryNum) {// try to wait N times
  76. Return false;
  77. Break;
  78. }
  79. }
  80. Return $ this-> access = true;
  81. }
  82. Return false;
  83. }
  84. // Update the header pointer to the next position
  85. Private function incrHead ()
  86. {
  87. // $ This-> getHeadAndTail (); // obtain the latest pointer information. because the method bodies are called within the lock, this method has been called in the lock. this method is commented out in this row.
  88. $ This-> HEAD ++; // move the HEAD pointer down
  89. If ($ this-> HEAD >=$ this-> MAXNUM ){
  90. $ This-> HEAD = 0; // modify the boundary value
  91. }
  92. ;
  93. $ This-> LEN --; // Head movement is triggered by Pop, so the number is reduced.
  94. If ($ this-> LEN <0 ){
  95. $ This-> LEN = 0; // modify the boundary value
  96. }
  97. ;
  98. Memcache_set (self ::$ client, $ this-> queueName. self: HEAD_KEY, $ this-> HEAD, false, $ this-> expire); // update
  99. Memcache_set (self ::$ client, $ this-> queueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update
  100. }
  101. // Update the tail pointer to the next position
  102. Private function incrTail ()
  103. {
  104. // $ This-> getHeadAndTail (); // obtain the latest pointer information. because the method bodies are called within the lock, this method has been called in the lock. this method is commented out in this row.
  105. $ This-> TAIL ++; // move the TAIL pointer down
  106. If ($ this-> TAIL >=$ this-> MAXNUM ){
  107. $ This-> TAIL = 0; // fixed the boundary value
  108. }
  109. ;
  110. $ This-> LEN ++; // Head movement is triggered by Push, so it is equivalent to an increase in the number.
  111. If ($ this-> LEN >=$ this-> MAXNUM ){
  112. $ This-> LEN = $ this-> MAXNUM; // fixed the length of the boundary value.
  113. }
  114. ;
  115. Memcache_set (self: $ client, $ this-> queueName. self: TAIL_KEY, $ this-> TAIL, false, $ this-> expire); // update
  116. Memcache_set (self ::$ client, $ this-> queueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update
  117. }
  118. // Unlock
  119. Private function unLock ()
  120. {
  121. Memcache_delete (self ::$ client, $ this-> queueName. self: LOCK_KEY );
  122. $ This-> access = false;
  123. }
  124. // Determine whether the queue is full
  125. Public function isFull ()
  126. {
  127. // The value here is an approximate value because there is no lock in the external direct call, which is not very accurate. However, the internal call is credible because the lock exists in the front.
  128. If ($ this-> canRewrite)
  129. Return false;
  130. Return $ this-> LEN = $ this-> MAXNUM? True: false;
  131. }
  132. // Judge whether it is null
  133. Public function isEmpty ()
  134. {
  135. // The value here is an approximate value because there is no lock in the external direct call, which is not very accurate. However, the internal call is credible because the lock exists in the front.
  136. Return $ this-> LEN = 0? True: false;
  137. }
  138. Public function getLen ()
  139. {
  140. // The value here is an approximate value because there is no lock in the external direct call, which is not very accurate. However, the internal call is credible because the lock exists in the front.
  141. Return $ this-> LEN;
  142. }
  143. /*
  144. * Push value
  145. * @ Param mixed value
  146. * @ Return bool
  147. */
  148. Public function push ($ data = '')
  149. {
  150. $ Result = false;
  151. If (empty ($ data ))
  152. Return $ result;
  153. If (! $ This-> lock ()){
  154. Return $ result;
  155. }
  156. $ This-> getHeadAndTail (); // Get the latest pointer information
  157. If ($ this-> isFull () {// The concept of "Full" is available only when the write is not overwritten.
  158. $ This-> unLock ();
  159. Return false;
  160. }
  161. If (memcache_set (self: $ client, $ this-> queueName. self: VALU_KEY. $ this-> TAIL, $ data, MEMCACHE_COMPRESSED, $ this-> expire )){
  162. // After the push, it is found that the tail and the header overlap (at this time the pointer has not been moved), and there is still data not read by the Head on the right side, so move the Head pointer to avoid the tail pointer crossing the Head
  163. If ($ this-> TAIL ==$ this-> HEAD & $ this-> LEN> = 1 ){
  164. $ This-> incrHead ();
  165. }
  166. $ This-> incrTail (); // move the tail pointer
  167. $ Result = true;
  168. }
  169. $ This-> unLock ();
  170. Return $ result;
  171. }
  172. /*
  173. * Pop a value
  174. * @ Param [length] int queue length
  175. * @ Return array
  176. */
  177. Public function pop ($ length = 0)
  178. {
  179. If (! Is_numeric ($ length ))
  180. Return false;
  181. If (! $ This-> lock ())
  182. Return false;
  183. $ This-> getHeadAndTail ();
  184. If (empty ($ length ))
  185. $ Length = $ this-> LEN; // read all
  186. If ($ this-> isEmpty ()){
  187. $ This-> unLock ();
  188. Return false;
  189. }
  190. // Modify the value after the length of the queue is exceeded.
  191. If ($ length> $ this-> LEN)
  192. $ Length = $ this-> LEN;
  193. $ Data = $ this-> popKeyArray ($ length );
  194. $ This-> unLock ();
  195. Return $ data;
  196. }
  197. /*
  198. * The value of a certain pop segment length
  199. * @ Param [length] int queue length
  200. * @ Return array
  201. */
  202. Private function popKeyArray ($ length)
  203. {
  204. $ Result = array ();
  205. If (empty ($ length ))
  206. Return $ result;
  207. For ($ k = 0; $ k <$ length; $ k ++ ){
  208. $ Result [] = @ memcache_get (self: $ client, $ this-> queueName. self: VALU_KEY. $ this-> HEAD );
  209. @ Memcache_delete (self: $ client, $ this-> queueName. self: VALU_KEY. $ this-> HEAD, 0 );
  210. // When the value is extracted, it is found that the header and tail overlap (at this time the pointer has not been moved), and there is no data on the right side, that is, the last data in the queue is completely hollowed out, at this time, the pointer stays locally and the queue length changes to 0.
  211. If ($ this-> TAIL ==$ this-> HEAD & $ this-> LEN <= 1 ){
  212. $ This-> LEN = 0;
  213. Memcache_set (self ::$ client, $ this-> queueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update
  214. Break;
  215. } Else {
  216. $ This-> incrHead (); // The beginning and end of the HEAD are not overlapped, or overlap, but there are still unread data, move the HEAD pointer to the next location to be read
  217. }
  218. }
  219. Return $ result;
  220. }
  221. /*
  222. * Reset the queue
  223. ** @ Return NULL
  224. */
  225. Private function reset ($ all = false)
  226. {
  227. If ($ all ){
  228. Memcache_delete (self ::$ client, $ this-> queueName. self: HEAD_KEY, 0 );
  229. Memcache_delete (self ::$ client, $ this-> queueName. self: TAIL_KEY, 0 );
  230. Memcache_delete (self ::$ client, $ this-> queueName. self: LENGTH_KEY, 0 );
  231. } Else {
  232. $ This-> HEAD = $ this-> TAIL = $ this-> LEN = 0;
  233. Memcache_set (self: $ client, $ this-> queueName. self: HEAD_KEY, 0, false, $ this-> expire );
  234. Memcache_set (self: $ client, $ this-> queueName. self: TAIL_KEY, 0, false, $ this-> expire );
  235. Memcache_set (self: $ client, $ this-> queueName. self: LENGTH_KEY, 0, false, $ this-> expire );
  236. }
  237. }
  238. /*
  239. * Clear all memcache cache data
  240. * @ Return NULL
  241. */
  242. Public function memFlush ()
  243. {
  244. Memcache_flush (self: $ client );
  245. }
  246. Public function clear ($ all = false)
  247. {
  248. If (! $ This-> lock ())
  249. Return false;
  250. $ This-> getHeadAndTail ();
  251. $ Head = $ this-> HEAD;
  252. $ Length = $ this-> LEN;
  253. $ Curr = 0;
  254. For ($ I = 0; $ I <$ Length; $ I ++ ){
  255. $ Curr = $ this-> $ Head + $ I;
  256. If ($ curr >=$ this-> MAXNUM ){
  257. $ This-> HEAD = $ curr = 0;
  258. }
  259. @ Memcache_delete (self: $ client, $ this-> queueName. self: VALU_KEY. $ curr, 0 );
  260. }
  261. $ This-> unLock ();
  262. $ This-> reset ($ all );
  263. Return true;
  264. }
  265. }

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.