MemcacheQueue. class. php
Copy codeThe Code is as follows:
<? Php
/**
* PHP memcache queue class
* @ Author LKK/lianq.net
* @ Version 0.3
* @ Modify description:
* 1. abandoned the previous AB plane rotation idea, and used arrays like arrays to rewrite this class.
* 2. the queue is first-in-first-out by default, but the reverse reading function is added.
* 3. I would like to thank FoxHunter, a netizen, for his valuable comments.
* @ Example:
* $ Obj = new memcacheQueue ('duilie ');
* $ Obj-> add ('1asdf ');
* $ Obj-> getQueueLength ();
* $ Obj-> read (10 );
* $ Obj-> get (8 );
*/
Class memcacheQueue {
Public static $ client; // memcache client Connection
Public $ access; // whether the queue can be updated
Private $ expire; // expiration time, in seconds, 1 ~ 2592000, that is, within 30 days
Private $ sleepTime; // waiting for unlock time, in microseconds
Private $ queueName; // queue name, unique value
Private $ retryNum; // Number of retries, = 10 * theoretical concurrency
Public $ currentHead; // the first value of the current team.
Public $ currentTail; // current team end value
Const MAXNUM = 20000; // maximum number of queues. the maximum number of queues is 10 K.
Const HEAD_KEY = '_ lkqueuehead _'; // The first kye of the queue
Const TAIL_KEY = '_ lkqueuetail _'; // the end key of the queue.
Const VALU_KEY = '_ lkqueuevalu _'; // queue value key
Const LOCK_KEY = '_ lkqueuelock _'; // queue Lock key
/**
* Constructor
* @ Param string $ queueName queue name
* @ Param int $ expire expiration time
* @ Param array $ config memcache Configuration
*
* @ Return <type>
*/
Public function _ construct ($ queueName = '', $ expire = 0, $ config = ''){
If (empty ($ config )){
Self: $ client = memcache_pconnect ('2017. 0.0.1 ', 127 );
} Elseif (is_array ($ config) {// array ('host' => '2017. 0.0.1 ', 'Port' => '2016 ')
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]: '2017. 0.0.1 ';
$ Conf ['Port'] = isset ($ tmp [1])? $ Tmp [1]: '20140901 ';
Self: $ client = memcache_pconnect ($ conf ['host'], $ conf ['Port']);
}
If (! Self: $ client) return false;
Ignore_user_abort (true); // when the customer disconnects, continue execution is allowed.
Set_time_limit (0); // cancels the upper limit of script execution latency
$ This-> access = false;
$ This-& gt; sleepTime = 1000;
$ Expire = empty ($ expire )? 3600: intval ($ expire) + 1;
$ This-> expire = $ expire;
$ This-> queueName = $ queueName;
$ This-> retrynum= 1000;
$ This-> head_key = $ this-> queueName. self: HEAD_KEY;
$ This-> tail_key = $ this-> queueName. self: TAIL_KEY;
$ This-> lock_key = $ this-> queueName. self: LOCK_KEY;
$ This-> _ initSetHeadNTail ();
}
/**
* Initialize and set the first and end values of the queue.
*/
Private function _ initSetHeadNTail (){
// The first value of the current queue
$ This-> currentHead = memcache_get (self: $ client, $ this-> head_key );
If ($ this-> currentHead = false) $ this-> currentHead = 0;
// The value at the end of the current queue
$ This-> currentTail = memcache_get (self: $ client, $ this-> tail_key );
If ($ this-> currentTail = false) $ this-> currentTail = 0;
}
/**
* When an element is retrieved, the first value of the queue is changed.
* @ Param int $ step value
*/
Private function _ changeHead ($ step = 1 ){
$ This-> currentHead + = $ step;
Memcache_set (self: $ client, $ this-> head_key, $ this-> currentHead, false, $ this-> expire );
}
/**
* When an element is added, the value at the end of the queue is changed.
* @ Param int $ step value
* @ Param bool $ whether the reverse is reversed
* @ Return null
*/
Private function _ changeTail ($ step = 1, $ reverse = false ){
If (! $ Reverse ){
$ This-> currentTail + = $ step;
} Else {
$ This-> currentTail-= $ step;
}
Memcache_set (self: $ client, $ this-> tail_key, $ this-> currentTail, false, $ this-> expire );
}
/**
* Whether the queue is empty
* @ Return bool
*/
Private function _ isEmpty (){
Return (bool) ($ this-> currentHead ===$ this-> currentTail );
}
/**
* Whether the queue is full
* @ Return bool
*/
Private function _ isFull (){
$ Len = $ this-> currentTail-$ this-> currentHead;
Return (bool) ($ len = self: MAXNUM );
}
/**
* Queue locking
*/
Private function _ getLock (){
If ($ this-> access === false ){
While (! Memcache_add (self: $ client, $ this-> lock_key, 1, false, $ this-> expire )){
Usleep ($ this-> sleepTime );
@ $ I ++;
If ($ I> $ this-> retryNum) {// try to wait N times
Return false;
Break;
}
}
$ This-> _ initSetHeadNTail ();
Return $ this-> access = true;
}
Return $ this-> access;
}
/**
* Queue unlock
*/
Private function _ unLock (){
Memcache_delete (self: $ client, $ this-> lock_key, 0 );
$ This-> access = false;
}
/**
* Get the length of the current queue
* This length is the theoretical length. Some elements are lost due to expiration. The actual length <= this length
* @ Return int
*/
Public function getQueueLength (){
$ This-> _ initSetHeadNTail ();
Return intval ($ this-> currentTail-$ this-> currentHead );
}
/**
* Add queue data
* @ Param void $ data the data to be added
* @ Return bool
*/
Public function add ($ data ){
If (! $ This-> _ getLock () return false;
If ($ this-> _ isFull ()){
$ This-> _ unLock ();
Return false;
}
$ Value_key = $ this-> queueName. self: VALU_KEY. strval ($ this-> currentTail + 1 );
$ Result = memcache_set (self: $ client, $ value_key, $ data, MEMCACHE_COMPRESSED, $ this-> expire );
If ($ result ){
$ This-> _ changeTail ();
}
$ This-> _ unLock ();
Return $ result;
}
/**
* Reading queue data
* @ Param int $ length the length to be read (negative number is used for reverse READING)
* @ Return array
*/
Public function read ($ length = 0 ){
If (! Is_numeric ($ length) return false;
$ This-> _ initSetHeadNTail ();
If ($ this-> _ isEmpty ()){
Return false;
}
If (empty ($ length) $ length = self: MAXNUM; // all by default
$ KeyArr = array ();
If ($ length> 0) {// forward read (from the first to the end of the queue)
$ TmpMin = $ this-> currentHead;
$ TmpMax = $ tmpMin + $ length;
For ($ I = $ tmpMin; $ I <= $ tmpMax; $ I ++ ){
$ KeyArr [] = $ this-> queueName. self: VALU_KEY. $ I;
}
} Else {// reverse read (from the end of the queue to the first of the queue)
$ TmpMax = $ this-> currentTail;
$ TmpMin = $ tmpMax + $ length;
For ($ I = $ tmpMax; $ I> $ tmpMin; $ I --){
$ KeyArr [] = $ this-> queueName. self: VALU_KEY. $ I;
}
}
$ Result = @ memcache_get (self: $ client, $ keyArr );
Return $ result;
}
/**
* Retrieve queue data
* @ Param int $ length the length to be retrieved (negative number is used for reverse READING)
* @ Return array
*/
Public function get ($ length = 0 ){
If (! Is_numeric ($ length) return false;
If (! $ This-> _ getLock () return false;
If ($ this-> _ isEmpty ()){
$ This-> _ unLock ();
Return false;
}
If (empty ($ length) $ length = self: MAXNUM; // all by default
$ Length = intval ($ length );
$ KeyArr = array ();
If ($ length> 0) {// forward read (from the first to the end of the queue)
$ TmpMin = $ this-> currentHead;
$ TmpMax = $ tmpMin + $ length;
For ($ I = $ tmpMin; $ I <= $ tmpMax; $ I ++ ){
$ KeyArr [] = $ this-> queueName. self: VALU_KEY. $ I;
}
$ This-> _ changeHead ($ length );
} Else {// reverse read (from the end of the queue to the first of the queue)
$ TmpMax = $ this-> currentTail;
$ TmpMin = $ tmpMax + $ length;
For ($ I = $ tmpMax; $ I> $ tmpMin; $ I --){
$ KeyArr [] = $ this-> queueName. self: VALU_KEY. $ I;
}
$ This-> _ changeTail (abs ($ length), true );
}
$ Result = @ memcache_get (self: $ client, $ keyArr );
Foreach ($ keyArr as $ v) {// delete it after Removal
@ Memcache_delete (self: $ client, $ v, 0 );
}
$ This-> _ unLock ();
Return $ result;
}
/**
* Clear a queue
*/
Public function clear (){
If (! $ This-> _ getLock () return false;
If ($ this-> _ isEmpty ()){
$ This-> _ unLock ();
Return false;
}
$ TmpMin = $ this-> currentHead --;
$ TmpMax = $ this-> currentTail ++;
For ($ I = $ tmpMin; $ I <= $ tmpMax; $ I ++ ){
$ TmpKey = $ this-> queueName. self: VALU_KEY. $ I;
@ Memcache_delete (self: $ client, $ tmpKey, 0 );
}
$ This-> currentTail = $ this-> currentHead = 0;
Memcache_set (self: $ client, $ this-> head_key, $ this-> currentHead, false, $ this-> expire );
Memcache_set (self: $ client, $ this-> tail_key, $ this-> currentTail, false, $ this-> expire );
$ This-> _ unLock ();
}
/*
* Clear all memcache cache data
*/
Public function memFlush (){
Memcache_flush (self: $ client );
}
} // End class