PHP implementation of the Memcached queue class

Source: Internet
Author: User
  1. /*
  2. * Memcache Queue class
  3. * Support multi-process concurrent write, read
  4. * Writing side reading, AB rotation replacement
  5. * @author Guoyu
  6. * @create on 9:25 2014-9-28
  7. * @qq Technology Industry Exchange Group: 136112330
  8. *
  9. * @example:
  10. * $obj = new Memcachequeue (' Duilie ');
  11. * $obj->add (' 1asdf ');
  12. * $obj->getqueuelength ();
  13. * $obj->read (11);
  14. * $obj->get (8);
  15. */
  16. Class memcachequeue{
  17. public static $client; Memcache Client Connections
  18. Public $access; Whether the queue can be updated
  19. Private $currentSide; Current rotating queue face: A/b
  20. Private $lastSide; Last rotated queue face: A/b
  21. Private $sideAHead; A-side team first value
  22. Private $sideATail; Side A team tail value
  23. Private $sideBHead; B-Side Team first value
  24. Private $sideBTail; B-Side Team tail value
  25. Private $currentHead; Current team first value
  26. Private $currentTail; Current team Tail value
  27. Private $lastHead; Top of the team
  28. Private $lastTail; Tail value of the upper team
  29. Private $expire; Expiration time, seconds, 1~2592000, i.e. within 30 days; 0 to never expire
  30. Private $sleepTime; Wait for unlock time, microseconds
  31. Private $queueName; Queue name, unique value
  32. Private $retryNum; Number of retries, = 10 * Theoretical concurrency
  33. Const MAXNUM = 2000; Maximum number of queues (single-sided), recommended maximum 10K
  34. Const Head_key = ' _lkkqueuehead_ '; Queue first Kye
  35. Const Tail_key = ' _lkkqueuetail_ '; End of Queue key
  36. Const Valu_key = ' _lkkqueuevalu_ '; Queue Value Key
  37. Const Lock_key = ' _lkkqueuelock_ '; Queue Lock key
  38. Const Side_key = ' _lkkqueueside_ '; Rotating Face Key
  39. /*
  40. * Constructor function
  41. * @param [config] array memcache server parameters
  42. * @param [QueueName] string queue name
  43. * @param [expire] string expiration time
  44. * @return NULL
  45. */
  46. Public function __construct ($queueName = ', $expire = ', $config = ') {
  47. if (empty ($config)) {
  48. Self:: $client = memcache_pconnect (' localhost ', 11211);
  49. }elseif (Is_array ($config)) {//array (' host ' = ' 127.0.0.1 ', ' port ' = ' 11211 ')
  50. Self:: $client = Memcache_pconnect ($config [' Host '], $config [' Port '];
  51. }elseif (is_string ($config)) {//"127.0.0.1:11211"
  52. $tmp = Explode (': ', $config);
  53. $conf [' host '] = isset ($tmp [0])? $tmp [0]: ' 127.0.0.1 ';
  54. $conf [' port '] = Isset ($tmp [1])? $tmp [1]: ' 11211 ';
  55. Self:: $client = Memcache_pconnect ($conf [' Host '], $conf [' Port '];
  56. }
  57. if (!self:: $client) return false;
  58. Ignore_user_abort (TRUE);//When the customer disconnects, allows execution to continue
  59. Set_time_limit (0);//Cancel script execution delay limit
  60. $this->access = false;
  61. $this->sleeptime = 1000;
  62. $expire = (Empty ($expire) && $expire!=0)? 3600: (int) $expire;
  63. $this->expire = $expire;
  64. $this->queuename = $queueName;
  65. $this->retrynum = 10000;
  66. $side = Memcache_add (self:: $client, $queueName. Self::side_key, ' A ', false, $expire);
  67. $this->getheadntail ($queueName);
  68. if (!isset ($this->sideahead) | | empty ($this->sideahead)) $this->sideahead = 0;
  69. if (!isset ($this->sideatail) | | empty ($this->sideatail)) $this->sideatail = 0;
  70. if (!isset ($this->sidebhead) | | empty ($this->sidebhead)) $this->sidebhead = 0;
  71. if (!isset ($this->sidebhead) | | empty ($this->sidebhead)) $this->sidebhead = 0;
  72. }
  73. /*
  74. * Get queue end and end values
  75. * @param [QueueName] string queue name
  76. * @return NULL
  77. */
  78. Private Function Getheadntail ($queueName) {
  79. $this->sideahead = (int) memcache_get (self:: $client, $queueName. ' A '. Self::head_key);
  80. $this->sideatail = (int) memcache_get (self:: $client, $queueName. ' A '. Self::tail_key);
  81. $this->sidebhead = (int) memcache_get (self:: $client, $queueName. ' B '. Self::head_key);
  82. $this->sidebtail = (int) memcache_get (self:: $client, $queueName. ' B '. Self::tail_key);
  83. }
  84. /*
  85. * Gets the queue face of the current rotation
  86. * @return string queue face name
  87. */
  88. Public Function Getcurrentside () {
  89. $currentSide = Memcache_get (self:: $client, $this->queuename. Self::side_key);
  90. if ($currentSide = = ' A ') {
  91. $this->currentside = ' A ';
  92. $this->lastside = ' B ';
  93. $this->currenthead = $this->sideahead;
  94. $this->currenttail = $this->sideatail;
  95. $this->lasthead = $this->sidebhead;
  96. $this->lasttail = $this->sidebtail;
  97. }else{
  98. $this->currentside = ' B ';
  99. $this->lastside = ' A ';
  100. $this->currenthead = $this->sidebhead;
  101. $this->currenttail = $this->sidebtail;
  102. $this->lasthead = $this->sideahead;
  103. $this->lasttail = $this->sideatail;
  104. }
  105. return $this->currentside;
  106. }
  107. /*
  108. * Queue plus Lock
  109. * @return Boolean
  110. */
  111. Private Function Getlock () {
  112. if ($this->access = = = False) {
  113. while (!memcache_add (self:: $client, $this->queuename. Self::lock_key, 1, False, $this->expire)) {
  114. Usleep ($this->sleeptime);
  115. @ $i + +;
  116. if ($i > $this->retrynum) {//try to wait n times
  117. return false;
  118. Break
  119. }
  120. }
  121. return $this->access = true;
  122. }
  123. return false;
  124. }
  125. /*
  126. * Queue unlock
  127. * @return NULL
  128. */
  129. Private Function UnLock () {
  130. Memcache_delete (self:: $client, $this->queuename. Self::lock_key);
  131. $this->access = false;
  132. }
  133. /*
  134. * Add data
  135. * @param [Data] value to store
  136. * @return Boolean
  137. */
  138. Public function Add ($data) {
  139. $result = false;
  140. if (! $this->getlock ()) {
  141. return $result;
  142. }
  143. $this->getheadntail ($this->queuename);
  144. $this->getcurrentside ();
  145. if ($this->isfull ()) {
  146. $this->unlock ();
  147. return false;
  148. }
  149. if ($this->currenttail < Self::maxnum) {
  150. $value _key = $this->queuename. $this->currentside. Self::valu_key. $this->currenttail;
  151. if (Memcache_add (self:: $client, $value _key, $data, False, $this->expire)) {
  152. $this->changetail ();
  153. $result = true;
  154. }
  155. }else{//the current queue is full, replace the rotation plane
  156. $this->unlock ();
  157. $this->changecurrentside ();
  158. return $this->add ($data);
  159. }
  160. $this->unlock ();
  161. return $result;
  162. }
  163. /*
  164. * Take out data
  165. * Length of @param [length] int data
  166. * @return Array
  167. */
  168. Public function Get ($length =0) {
  169. if (!is_numeric ($length)) return false;
  170. if (empty ($length)) $length = Self::maxnum * 2;//Read all by default
  171. if (! $this->getlock ()) return false;
  172. if ($this->isempty ()) {
  173. $this->unlock ();
  174. return false;
  175. }
  176. $keyArray = $this->getkeyarray ($length);
  177. $lastKey = $keyArray [' Lastkey '];
  178. $currentKey = $keyArray [' Currentkey '];
  179. $keys = $keyArray [' Keys '];
  180. $this->changehead ($this->lastside, $lastKey);
  181. $this->changehead ($this->currentside, $currentKey);
  182. $data = @memcache_get (self:: $client, $keys);
  183. foreach ($keys as $v) {//Remove after removal
  184. @memcache_delete (self:: $client, $v, 0);
  185. }
  186. $this->unlock ();
  187. return $data;
  188. }
  189. /*
  190. * Read Data
  191. * Length of @param [length] int data
  192. * @return Array
  193. */
  194. Public function read ($length =0) {
  195. if (!is_numeric ($length)) return false;
  196. if (empty ($length)) $length = Self::maxnum * 2;//Read all by default
  197. $keyArray = $this->getkeyarray ($length);
  198. $data = @memcache_get (self:: $client, $keyArray [' Keys ']);
  199. return $data;
  200. }
  201. /*
  202. * Gets the key array for the length of a queue
  203. * @param [length] int Queue Length
  204. * @return Array
  205. */
  206. Private Function Getkeyarray ($length) {
  207. $result = Array (' Keys ' =>array (), ' Lastkey ' =>array (), ' Currentkey ' =>array ());
  208. $this->getheadntail ($this->queuename);
  209. $this->getcurrentside ();
  210. if (empty ($length)) return $result;
  211. Take the key on the first side
  212. $i = $result [' lastkey '] = 0;
  213. for ($i =0; $i < $length; $i + +) {
  214. $result [' lastkey '] = $this->lasthead + $i;
  215. if ($result [' Lastkey '] >= $this->lasttail) break;
  216. $result [' keys '] = $this->queuename. $this->lastside. Self::valu_key. $result [' Lastkey '];
  217. }
  218. Then take the key as the front
  219. $j = $length-$i;
  220. $k = $result [' currentkey '] = 0;
  221. for ($k =0; $k < $j; $k + +) {
  222. $result [' currentkey '] = $this->currenthead + $k;
  223. if ($result [' Currentkey '] >= $this->currenttail) break;
  224. $result [' keys '] = $this->queuename. $this->currentside. Self::valu_key. $result [' Currentkey '];
  225. }
  226. return $result;
  227. }
  228. /*
  229. * Update the value of the end of the current rotating plane queue
  230. * @return NULL
  231. */
  232. Private Function Changetail () {
  233. $tail _key = $this->queuename. $this->currentside. Self::tail_key;
  234. Memcache_add (self:: $client, $tail _key, 0,false, $this->expire);//if not, insert;
  235. Memcache_increment (self:: $client, $tail _key, 1);//end of queue +1
  236. $v = Memcache_get (self:: $client, $tail _key) +1;
  237. Memcache_set (self:: $client, $tail _key, $v, False, $this->expire);
  238. }
  239. /*
  240. * Update the value of queue header
  241. * @param [Side] string to update the face
  242. * @param [headvalue] int queue Header value
  243. * @return NULL
  244. */
  245. Private Function Changehead ($side, $headValue) {
  246. if ($headValue < 1) return false;
  247. $head _key = $this->queuename. $side. Self::head_key;
  248. $tail _key = $this->queuename. $side. Self::tail_key;
  249. $sideTail = Memcache_get (self:: $client, $tail _key);
  250. if ($headValue < $sideTail) {
  251. Memcache_set (self:: $client, $head _key, $headValue +1,false, $this->expire);
  252. }elseif ($headValue >= $sideTail) {
  253. $this->resetside ($side);
  254. }
  255. }
  256. /*
  257. * Resets the queue face, which will set the queue header and tail value to 0
  258. * @param [side] string to reset the face
  259. * @return NULL
  260. */
  261. Private Function Resetside ($side) {
  262. $head _key = $this->queuename. $side. Self::head_key;
  263. $tail _key = $this->queuename. $side. Self::tail_key;
  264. Memcache_set (self:: $client, $head _key,0,false, $this->expire);
  265. Memcache_set (self:: $client, $tail _key,0,false, $this->expire);
  266. }
  267. /*
  268. * Change the current rotation queue face
  269. * @return String
  270. */
  271. Private Function Changecurrentside () {
  272. $currentSide = Memcache_get (self:: $client, $this->queuename. Self::side_key);
  273. if ($currentSide = = ' A ') {
  274. Memcache_set (self:: $client, $this->queuename. Self::side_key, ' B ', false, $this->expire);
  275. $this->currentside = ' B ';
  276. }else{
  277. Memcache_set (self:: $client, $this->queuename. Self::side_key, ' A ', false, $this->expire);
  278. $this->currentside = ' A ';
  279. }
  280. return $this->currentside;
  281. }
  282. /*
  283. * Check whether the current queue is full
  284. * @return Boolean
  285. */
  286. Public Function Isfull () {
  287. $result = false;
  288. if ($this->sideatail = = Self::maxnum && $this->sidebtail = = self::maxnum) {
  289. $result = true;
  290. }
  291. return $result;
  292. }
  293. /*
  294. * Check whether the current queue is empty
  295. * @return Boolean
  296. */
  297. Public Function IsEmpty () {
  298. $result = true;
  299. if ($this->sideatail > 0 | | $this->sidebtail > 0) {
  300. $result = false;
  301. }
  302. return $result;
  303. }
  304. /*
  305. * Gets the length of the current queue
  306. * The length is theoretical length, some elements are lost due to expiration, the true length is less than or equal to that length
  307. * @return int
  308. */
  309. Public Function Getqueuelength () {
  310. $this->getheadntail ($this->queuename);
  311. $this->getcurrentside ();
  312. $sideALength = $this->sideatail-$this->sideahead;
  313. $sideBLength = $this->sidebtail-$this->sidebhead;
  314. $result = $sideALength + $sideBLength;
  315. return $result;
  316. }
  317. /*
  318. * Empty the current queue data, keep only Head_key, Tail_key, side_key three keys
  319. * @return Boolean
  320. */
  321. Public Function Clear () {
  322. if (! $this->getlock ()) return false;
  323. for ($i =0; $i
  324. @memcache_delete (self:: $client, $this->queuename. ' A '. Self::valu_key. $i, 0);
  325. @memcache_delete (self:: $client, $this->queuename. ' B '. Self::valu_key. $i, 0);
  326. }
  327. $this->unlock ();
  328. $this->resetside (' A ');
  329. $this->resetside (' B ');
  330. return true;
  331. }
  332. /*
  333. * Clear all Memcache cache data
  334. * @return NULL
  335. */
  336. Public Function Memflush () {
  337. Memcache_flush (self:: $client);
  338. }
  339. }
Copy Code
PHP, memcached
  • 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.