Memcache ring queue instance implemented by PHP

Source: Internet
Author: User
This article mainly introduces the memcache ring queue implemented by PHP. The example analyzes the method of implementing the ring queue based on memcache, which involves the skills related to the memcache cache and queue, you can refer to the example in this article to describe the memcache ring queue class implemented by PHP. Share it with you for your reference. The details are as follows:

This section describes the memcache ring queue class implemented by PHP. I have never learned the data structure. because of the business needs, I just tried it! Refer to the PHP memcache queue code. 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!

<? Php/*** PHP memcache ring queue class * Original author LKK/lianq.net * modify FoxHunter * because the business needs to only retain Pop and Push in the queue, change the Expiration Time to 0 (permanent) */class MQueue {public static $ client; private $ expire; // expiration time, in seconds, 1 ~ 2592000, that is, private $ sleepTime within 30 days; // waiting for unlock time, microsecond private $ queueName; // queue name, unique value private $ retryNum; // number of attempts private $ MAXNUM; // maximum queue capacity private $ canRewrite; // whether the overwrite switch is allowed. the full content overwrites the original data private $ HEAD from the header; // the pointer to be accessed in the next step is private $ TAIL; // The pointer to be accessed in the next step is private $ LEN; // the current queue length const LOCK_KEY = '_ Fox_MQ_LOCK _'; // The Lock storage identifier const LENGTH_KEY = '_ Fox_MQ_LENGTH _'; // the current queue length identifier const VALU_KEY = '_ Fox_MQ_VAL _'; // The queue key value storage identifier co Nst HEAD_KEY = '_ Fox_MQ_HEAD _'; // The position of the HEAD pointer in the queue indicates const TAIL_KEY = '_ Fox_MQ_TAIL _'; // queue TAIL pointer position mark/** constructor * 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 */public function _ construct ($ queueName = '', $ maxqueue = 1, $ canRewrite = false, $ expire = 0, $ config = '') {if (empty ($ config) {self ::$ client = memcache_pconnect ('2017. 0.0.1 ', 11211);} elseif (is_array ($ config) {// array ('host' =>' 127.0.0.1 ', 'port' => '000000') self: $ client = memcache_pconnect ($ config ['host'], $ config ['port']);} elseif (is_string ($ config) {// "127.0.0.1: 11211" $ tmp = explode (':', $ config ); $ conf ['host'] = isset ($ tmp [0])? $ Tmp [0]: '192. 0.0.1 '; $ conf ['port'] = isset ($ tmp [1])? $ Tmp [1]: '000000'; self: $ client = memcache_pconnect ($ conf ['host'], $ conf ['port']);} if (! Self: $ client) return false; ignore_user_abort (true); // when the customer disconnects, set_time_limit (0) can be continued ); // cancel the maximum latency of script execution $ this-> access = false; $ this-> sleepTime = 1000; $ expire = (empty ($ expire ))? 0: (int) $ expire + 1; $ this-> expire = $ expire; $ this-> queueName = $ queueName; $ this-> retryNum = 20000; $ this-> MAXNUM = $ maxqueue! = Null? $ Maxqueue: 1; $ this-> canRewrite = $ canRewrite; $ this-> getHeadAndTail (); if (! Isset ($ this-> HEAD) | empty ($ this-> HEAD) $ this-> HEAD = 0; if (! Isset ($ this-> TAIL) | empty ($ this-> TAIL) $ this-> TAIL = 0; if (! Isset ($ this-> LEN) | empty ($ this-> LEN) $ this-> LEN = 0 ;} // obtain the first and end pointer information and length of the queue. private function getHeadAndTail () {$ this-> HEAD = (int) memcache_get (self ::$ client, $ this-> queueName. self: HEAD_KEY); $ this-> TAIL = (int) memcache_get (self: $ client, $ this-> queueName. self: TAIL_KEY); $ this-> LEN = (int) memcache_get (self: $ client, $ this-> queueName. self: LENGTH_KEY);} // use memcache_add atomicity to lock private funct Ion lock () {if ($ this-> access = false) {$ I = 0; while (! Memcache_add (self: $ client, $ this-> queueName. self: LOCK_KEY, 1, false, $ this-> expire) {usleep ($ this-> sleepTime); @ $ I ++; if ($ I >$ this-> retryNum) {// try to wait for N times return false; break;} return $ this-> access = true;} return false ;} // update the header pointer to the next position: private function incrHead () {// $ this-> getHeadAndTail (); // obtain the latest pointer information, because the method body is called within the lock, this method has been called in the lock. Note $ this-> HEAD ++; // Move the header pointer down if ($ this-> HEAD >=$ this-> M AXNUM) {$ this-> HEAD = 0; // fixed the boundary value}; $ this-> LEN --; // the movement of the Head is triggered by Pop, therefore, it is equivalent to reducing the number of if ($ this-> LEN <0) {$ this-> LEN = 0; // modifying the boundary value}; memcache_set (self: $ client, $ this-> queueName. self: HEAD_KEY, $ this-> HEAD, false, $ this-> expire); // update memcache_set (self ::$ client, $ this-> queueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update} // update tail pointer pointing to the next position private function incrTail () {// $ this-> get HeadAndTail (); // obtain the latest pointer information. because the method body is called within the lock, this method has been called in the lock. please note $ this-> TAIL ++; // move the TAIL pointer down if ($ this-> TAIL >=$ this-> MAXNUM) {$ this-> TAIL = 0; // modify the boundary value }; $ this-> LEN ++; // Head movement is triggered by Push, so it is equivalent to increasing the number of if ($ this-> LEN >=$ this-> MAXNUM) {$ this-> LEN = $ this-> MAXNUM; // fixed the length of the boundary value}; memcache_set (self: $ client, $ this-> queueName. self: TAIL_KEY, $ this-> TAIL, false, $ this-> expire); // update memcache_set (self ::$ client, $ this-> QueueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update} // unLock private function unLock () {memcache_delete (self :: $ client, $ this-> queueName. self: LOCK_KEY); $ this-> access = false;} // determines whether the queue is full. public function isFull () {// The value here is an approximate value because there is no lock in the external direct call, which is not very accurate, but the internal call has a lock in the front, so trusted if ($ this-> canRewrite) return false; return $ this-> LEN = $ this-> MAXNUM? True: false;} // judge whether it is null public function isEmpty () {// The value here is an approximate value because there is no lock during external direct calls, which is not very accurate, but the internal call has a lock, so the trusted return $ this-> LEN = 0? True: false;} public function getLen () {// The value here is not very accurate because it is not locked for external direct calls, but the internal call has a lock, so the trusted return $ this-> LEN ;} /** push value * @ param mixed value * @ return bool */public function push ($ data = '') {$ result = false; if (empty ($ data )) return $ result; if (! $ This-> lock () {return $ result;} $ this-> getHeadAndTail (); // obtain the latest pointer information if ($ this-> isFull ()) {// the Full concept $ this-> unLock (); return false;} if (memcache_set (self ::$ client, $ this-> queueName. self: VALU_KEY. $ this-> TAIL, $ data, MEMCACHE_COMPRESSED, $ this-> expire) {// after the push, it is found that the TAIL and the header overlap (the pointer has not been moved yet ), if there is still data not read by the Head on the right side, move the Head pointer, avoid trailing pointer crossing Head if ($ this-> TAIL ==$ this-> HEAD & $ this-> LEN> = 1) {$ this-> I NcrHead () ;}$ this-> incrTail (); // move the tail pointer $ result = true ;}$ this-> unLock (); return $ result ;} /** Pop a value * @ param [length] int queue length * @ return array */public function pop ($ length = 0) {if (! Is_numeric ($ length) return false; if (! $ This-> lock () return false; $ this-> getHeadAndTail (); if (empty ($ length) $ length = $ this-> LEN; // read all if ($ this-> isEmpty () {$ this-> unLock (); return false;} by default ;} // modify if ($ length> $ this-> LEN) $ length = $ this-> LEN; $ data = $ this-> popKeyArray ($ length); $ this-> unLock (); return $ data ;} /** value of the length of a certain pop segment * @ param [length] int queue length * @ return array */private function popKeyArray ($ length) {$ r Esult = array (); if (empty ($ length) return $ result; for ($ k = 0; $ k <$ length; $ k ++) {$ result [] = @ memcache_get (self: $ client, $ this-> queueName. self: VALU_KEY. $ this-> HEAD); @ memcache_delete (self: $ client, $ this-> queueName. self: VALU_KEY. $ this-> HEAD, 0); // after the value is extracted, it is found that the header and tail overlap (the pointer has not been moved yet), and there is no data on the right, that is, the last data in the queue is completely empty, and the pointer stays locally, the queue length is changed to 0 if ($ this-> TAIL ==$ this-> HEAD & $ this-> LEN <= 1) {$ this-> LEN = 0; memcache_set (self: $ client, $ this-> queueName. self: LENGTH_KEY, $ this-> LEN, false, $ this-> expire); // update break;} else {$ this-> incrHead (); // The beginning and end of the data are not overlapped, or there are still unread data. the HEAD pointer is moved to the next position to be read.} return $ result ;} /** reset the queue ** @ return NULL */private function reset ($ all = false) {if ($ all) {memcache_delete (self: $ client, $ this-> queueName. self: HEAD_KEY, 0); memcache_delete (self ::$ client, $ this-> QueueName. self: TAIL_KEY, 0); memcache_delete (self ::$ client, $ this-> queueName. self: LENGTH_KEY, 0);} else {$ this-> HEAD = $ this-> TAIL = $ this-> LEN = 0; memcache_set (self: $ client, $ this-> queueName. self: HEAD_KEY, 0, false, $ this-> expire); memcache_set (self: $ client, $ this-> queueName. self: TAIL_KEY, 0, false, $ this-> expire); memcache_set (self: $ client, $ this-> queueName. self: LENGTH_KEY, 0, false, $ this-> expire) ;}/ ** Clear all memcache Cache data * @ return NULL */public function memFlush () {memcache_flush (self :: $ client);} public function clear ($ all = false) {if (! $ This-> lock () return false; $ this-> getHeadAndTail (); $ Head = $ this-> HEAD; $ Length = $ this-> LEN; $ curr = 0; for ($ I = 0; $ I <$ Length; $ I ++) {$ curr = $ this-> $ Head + $ I; if ($ curr >=$ this-> MAXNUM) {$ this-> HEAD = $ curr = 0 ;}@ memcache_delete (self :$ client, $ this-> queueName. self: VALU_KEY. $ curr, 0) ;}$ this-> unLock (); $ this-> reset ($ all); return true ;}}

I hope this article will help you with php programming.

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.