PHP memcache Ring Queue class. Novice, did not learn the data structure, because the business needs, so just the bite-bullet simulation! The prototype is the PHP memcache queue code Lusi shared on Oschina. In order to make the queue readily available, and not by the int length cross-border danger (single chain take head self-increment words do not have to deal with the possibility of cross-border), so simply rewrite into a ring queue. There may be bugs, forget forgive!
-
- /**
- * PHP Memcache Ring Queue class
- * Original Author Lkk/lianq.net
- * Modify Foxhunter
- * Due to the business need to keep only the pop and push in the queue, the modification expires at 0 that is permanent
- */
- Class Mqueue
- {
- public static $client;
- Private $expire; Expiration time, seconds, 1~2592000, i.e. within 30 days
- Private $sleepTime; Wait for unlock time, microseconds
- Private $queueName; Queue name, unique value
- Private $retryNum; Number of attempts
- Private $MAXNUM; Maximum queue capacity
- Private $canRewrite; Whether the switch can be overwritten, the contents of the full out from the beginning overwrite the original data rewrite
- Private $HEAD; Next step to enter the pointer position
- Private $TAIL; Next step to enter the pointer position
- Private $LEN; Queue existing length
- Const Lock_key = ' _fox_mq_lock_ '; Lock Storage Indicator
- Const Length_key = ' _fox_mq_length_ '; Queue current length storage indication
- Const Valu_key = ' _fox_mq_val_ '; Queue key Value Storage indicator
- Const Head_key = ' _fox_mq_head_ '; Queue Head pointer position indication
- Const Tail_key = ' _fox_mq_tail_ '; Queue tail pointer position indication
- /*
- * Constructor function
- * For the same $queuename, the parameter values of the constructors must be guaranteed to be consistent when instantiated, otherwise the pop and push queue order is chaotic
- */
- Public function __construct ($queueName = ", $maxqueue = 1, $canRewrite = false, $expire = 0, $config = ')
- {
- if (empty ($config)) {
- Self:: $client = Memcache_pconnect (' 127.0.0.1 ', 11211);
- } elseif (Is_array ($config)) {//array (' host ' = ' 127.0.0.1 ', ' port ' = ' 11211 ')
- 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]: ' 127.0.0.1 ';
- $conf [' port '] = Isset ($tmp [1])? $tmp [1]: ' 11211 ';
- Self:: $client = Memcache_pconnect ($conf [' Host '], $conf [' Port '];
- }
- if (!self:: $client)
- return false;
- Ignore_user_abort (TRUE); Allow the client to continue execution when the customer disconnects
- Set_time_limit (0); Canceling the script execution delay limit
- $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;
- }
- Get the queue end-to-end pointer information and length
- 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);
- }
- The use of Memcache_add atomic lock
- Private Function 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 n times
- return false;
- Break
- }
- }
- return $this->access = true;
- }
- return false;
- }
- Update head pointer pointing to next position
- Private Function Incrhead ()
- {
- $this->getheadandtail (); Gets the latest pointer information, since the method body is called within the lock, and the method is called within its lock, the bank notes
- $this->head++; The head pointer moves down
- if ($this->head >= $this->maxnum) {
- $this->head = 0; Boundary value correction
- }
- ;
- $this->len--; The head movement is triggered by the pop, so the amount is reduced
- if ($this->len < 0) {
- $this->len = 0; Boundary value correction
- }
- ;
- 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 next position
- Private Function Incrtail ()
- {
- $this->getheadandtail (); Gets the latest pointer information, since the method body is called within the lock, and the method is called within its lock, the bank notes
- $this->tail++; The trailing pointer moves down
- if ($this->tail >= $this->maxnum) {
- $this->tail = 0; Boundary value correction
- }
- ;
- $this->len++; The head movement is triggered by push, so the amount is increased
- if ($this->len >= $this->maxnum) {
- $this->len = $this->maxnum; Boundary Value Length correction
- }
- ;
- 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;
- }
- Determine if the queue is full
- Public Function Isfull ()
- {
- External direct call because there is no lock so the value here is a approximate value, not very accurate, but the internal call because in front of the lock, so the trusted
- if ($this->canrewrite)
- return false;
- return $this->len = = $this->maxnum? True:false;
- }
- Determines whether the empty
- Public Function IsEmpty ()
- {
- External direct call because there is no lock so the value here is a approximate value, not very accurate, but the internal call because in front of the lock, so the trusted
- return $this->len = = 0? True:false;
- }
- Public Function Getlen ()
- {
- External direct call because there is no lock so the value here is a approximate value, not very accurate, but the internal call because in front of the 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 (); Get the latest pointer information
- if ($this->isfull ()) {//The full concept is only available for non-overwrite
- $this->unlock ();
- return false;
- }
- if (Memcache_set (self:: $client, $this->queuename. Self::valu_key. $this->tail, $data, memcache_compressed, $ This->expire)) {
- When the push is found to coincide with the tail and head (when the pointer has not moved), and there is still data not read by head on the right, move the head pointer to avoid the tail pointer spanning head
- if ($this->tail = = $this->head && $this->len >= 1) {
- $this->incrhead ();
- }
- $this->incrtail (); Move tail pointer
- $result = true;
- }
- $this->unlock ();
- return $result;
- }
- /*
- * Pop One 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; Default Read all
- if ($this->isempty ()) {
- $this->unlock ();
- return false;
- }
- Get fixed after length exceeds queue length
- if ($length > $this->len)
- $length = $this->len;
- $data = $this->popkeyarray ($length);
- $this->unlock ();
- return $data;
- }
- /*
- * Value of a segment length of pop
- * @param [length] int Queue Length
- * @return Array
- */
- Private Function Popkeyarray ($length)
- {
- $result = 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);
- When the value is extracted, the head and tail are coincident (when the pointer is not moved), and there is no data on the right, that is, the last data in the queue is completely hollowed out, the pointer stays locally and the queue length becomes 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 (); Not coincident, or coincident but still have unread data, move the head pointer to the next location to read
- }
- }
- return $result;
- }
- /*
- * Reset 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;
- }
- }
Copy Code |