- /*
- * Memcache Queue class
- * Support multi-process concurrent write, read
- * Writing side reading, AB rotation replacement
- * @author Guoyu
- * @create on 9:25 2014-9-28
- * @qq Technology Industry Exchange Group: 136112330
- *
- * @example:
- * $obj = new Memcachequeue (' Duilie ');
- * $obj->add (' 1asdf ');
- * $obj->getqueuelength ();
- * $obj->read (11);
- * $obj->get (8);
- */
- Class memcachequeue{
- public static $client; Memcache Client Connections
- Public $access; Whether the queue can be updated
- Private $currentSide; Current rotating queue face: A/b
- Private $lastSide; Last rotated queue face: A/b
- Private $sideAHead; A-side team first value
- Private $sideATail; Side A team tail value
- Private $sideBHead; B-Side Team first value
- Private $sideBTail; B-Side Team tail value
- Private $currentHead; Current team first value
- Private $currentTail; Current team Tail value
- Private $lastHead; Top of the team
- Private $lastTail; Tail value of the upper team
- Private $expire; Expiration time, seconds, 1~2592000, i.e. within 30 days; 0 to never expire
- Private $sleepTime; Wait for unlock time, microseconds
- Private $queueName; Queue name, unique value
- Private $retryNum; Number of retries, = 10 * Theoretical concurrency
- Const MAXNUM = 2000; Maximum number of queues (single-sided), recommended maximum 10K
- Const Head_key = ' _lkkqueuehead_ '; Queue first Kye
- Const Tail_key = ' _lkkqueuetail_ '; End of Queue key
- Const Valu_key = ' _lkkqueuevalu_ '; Queue Value Key
- Const Lock_key = ' _lkkqueuelock_ '; Queue Lock key
- Const Side_key = ' _lkkqueueside_ '; Rotating Face Key
- /*
- * Constructor function
- * @param [config] array memcache server parameters
- * @param [QueueName] string queue name
- * @param [expire] string expiration time
- * @return NULL
- */
- Public function __construct ($queueName = ', $expire = ', $config = ') {
- if (empty ($config)) {
- Self:: $client = memcache_pconnect (' localhost ', 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);//When the customer disconnects, allows execution to continue
- Set_time_limit (0);//Cancel script execution delay limit
- $this->access = false;
- $this->sleeptime = 1000;
- $expire = (Empty ($expire) && $expire!=0)? 3600: (int) $expire;
- $this->expire = $expire;
- $this->queuename = $queueName;
- $this->retrynum = 10000;
- $side = Memcache_add (self:: $client, $queueName. Self::side_key, ' A ', false, $expire);
- $this->getheadntail ($queueName);
- if (!isset ($this->sideahead) | | empty ($this->sideahead)) $this->sideahead = 0;
- if (!isset ($this->sideatail) | | empty ($this->sideatail)) $this->sideatail = 0;
- if (!isset ($this->sidebhead) | | empty ($this->sidebhead)) $this->sidebhead = 0;
- if (!isset ($this->sidebhead) | | empty ($this->sidebhead)) $this->sidebhead = 0;
- }
- /*
- * Get queue end and end values
- * @param [QueueName] string queue name
- * @return NULL
- */
- Private Function Getheadntail ($queueName) {
- $this->sideahead = (int) memcache_get (self:: $client, $queueName. ' A '. Self::head_key);
- $this->sideatail = (int) memcache_get (self:: $client, $queueName. ' A '. Self::tail_key);
- $this->sidebhead = (int) memcache_get (self:: $client, $queueName. ' B '. Self::head_key);
- $this->sidebtail = (int) memcache_get (self:: $client, $queueName. ' B '. Self::tail_key);
- }
- /*
- * Gets the queue face of the current rotation
- * @return string queue face name
- */
- Public Function Getcurrentside () {
- $currentSide = Memcache_get (self:: $client, $this->queuename. Self::side_key);
- if ($currentSide = = ' A ') {
- $this->currentside = ' A ';
- $this->lastside = ' B ';
- $this->currenthead = $this->sideahead;
- $this->currenttail = $this->sideatail;
- $this->lasthead = $this->sidebhead;
- $this->lasttail = $this->sidebtail;
- }else{
- $this->currentside = ' B ';
- $this->lastside = ' A ';
- $this->currenthead = $this->sidebhead;
- $this->currenttail = $this->sidebtail;
- $this->lasthead = $this->sideahead;
- $this->lasttail = $this->sideatail;
- }
- return $this->currentside;
- }
- /*
- * Queue plus Lock
- * @return Boolean
- */
- Private Function Getlock () {
- if ($this->access = = = False) {
- 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;
- }
- /*
- * Queue unlock
- * @return NULL
- */
- Private Function UnLock () {
- Memcache_delete (self:: $client, $this->queuename. Self::lock_key);
- $this->access = false;
- }
- /*
- * Add data
- * @param [Data] value to store
- * @return Boolean
- */
- Public function Add ($data) {
- $result = false;
- if (! $this->getlock ()) {
- return $result;
- }
- $this->getheadntail ($this->queuename);
- $this->getcurrentside ();
- if ($this->isfull ()) {
- $this->unlock ();
- return false;
- }
- if ($this->currenttail < Self::maxnum) {
- $value _key = $this->queuename. $this->currentside. Self::valu_key. $this->currenttail;
- if (Memcache_add (self:: $client, $value _key, $data, False, $this->expire)) {
- $this->changetail ();
- $result = true;
- }
- }else{//the current queue is full, replace the rotation plane
- $this->unlock ();
- $this->changecurrentside ();
- return $this->add ($data);
- }
- $this->unlock ();
- return $result;
- }
- /*
- * Take out data
- * Length of @param [length] int data
- * @return Array
- */
- Public function Get ($length =0) {
- if (!is_numeric ($length)) return false;
- if (empty ($length)) $length = Self::maxnum * 2;//Read all by default
- if (! $this->getlock ()) return false;
- if ($this->isempty ()) {
- $this->unlock ();
- return false;
- }
- $keyArray = $this->getkeyarray ($length);
- $lastKey = $keyArray [' Lastkey '];
- $currentKey = $keyArray [' Currentkey '];
- $keys = $keyArray [' Keys '];
- $this->changehead ($this->lastside, $lastKey);
- $this->changehead ($this->currentside, $currentKey);
- $data = @memcache_get (self:: $client, $keys);
- foreach ($keys as $v) {//Remove after removal
- @memcache_delete (self:: $client, $v, 0);
- }
- $this->unlock ();
- return $data;
- }
- /*
- * Read Data
- * Length of @param [length] int data
- * @return Array
- */
- Public function read ($length =0) {
- if (!is_numeric ($length)) return false;
- if (empty ($length)) $length = Self::maxnum * 2;//Read all by default
- $keyArray = $this->getkeyarray ($length);
- $data = @memcache_get (self:: $client, $keyArray [' Keys ']);
- return $data;
- }
- /*
- * Gets the key array for the length of a queue
- * @param [length] int Queue Length
- * @return Array
- */
- Private Function Getkeyarray ($length) {
- $result = Array (' Keys ' =>array (), ' Lastkey ' =>array (), ' Currentkey ' =>array ());
- $this->getheadntail ($this->queuename);
- $this->getcurrentside ();
- if (empty ($length)) return $result;
- Take the key on the first side
- $i = $result [' lastkey '] = 0;
- for ($i =0; $i < $length; $i + +) {
- $result [' lastkey '] = $this->lasthead + $i;
- if ($result [' Lastkey '] >= $this->lasttail) break;
- $result [' keys '] = $this->queuename. $this->lastside. Self::valu_key. $result [' Lastkey '];
- }
- Then take the key as the front
- $j = $length-$i;
- $k = $result [' currentkey '] = 0;
- for ($k =0; $k < $j; $k + +) {
- $result [' currentkey '] = $this->currenthead + $k;
- if ($result [' Currentkey '] >= $this->currenttail) break;
- $result [' keys '] = $this->queuename. $this->currentside. Self::valu_key. $result [' Currentkey '];
- }
- return $result;
- }
- /*
- * Update the value of the end of the current rotating plane queue
- * @return NULL
- */
- Private Function Changetail () {
- $tail _key = $this->queuename. $this->currentside. Self::tail_key;
- Memcache_add (self:: $client, $tail _key, 0,false, $this->expire);//if not, insert;
- Memcache_increment (self:: $client, $tail _key, 1);//end of queue +1
- $v = Memcache_get (self:: $client, $tail _key) +1;
- Memcache_set (self:: $client, $tail _key, $v, False, $this->expire);
- }
- /*
- * Update the value of queue header
- * @param [Side] string to update the face
- * @param [headvalue] int queue Header value
- * @return NULL
- */
- Private Function Changehead ($side, $headValue) {
- if ($headValue < 1) return false;
- $head _key = $this->queuename. $side. Self::head_key;
- $tail _key = $this->queuename. $side. Self::tail_key;
- $sideTail = Memcache_get (self:: $client, $tail _key);
- if ($headValue < $sideTail) {
- Memcache_set (self:: $client, $head _key, $headValue +1,false, $this->expire);
- }elseif ($headValue >= $sideTail) {
- $this->resetside ($side);
- }
- }
- /*
- * Resets the queue face, which will set the queue header and tail value to 0
- * @param [side] string to reset the face
- * @return NULL
- */
- Private Function Resetside ($side) {
- $head _key = $this->queuename. $side. Self::head_key;
- $tail _key = $this->queuename. $side. Self::tail_key;
- Memcache_set (self:: $client, $head _key,0,false, $this->expire);
- Memcache_set (self:: $client, $tail _key,0,false, $this->expire);
- }
- /*
- * Change the current rotation queue face
- * @return String
- */
- Private Function Changecurrentside () {
- $currentSide = Memcache_get (self:: $client, $this->queuename. Self::side_key);
- if ($currentSide = = ' A ') {
- Memcache_set (self:: $client, $this->queuename. Self::side_key, ' B ', false, $this->expire);
- $this->currentside = ' B ';
- }else{
- Memcache_set (self:: $client, $this->queuename. Self::side_key, ' A ', false, $this->expire);
- $this->currentside = ' A ';
- }
- return $this->currentside;
- }
- /*
- * Check whether the current queue is full
- * @return Boolean
- */
- Public Function Isfull () {
- $result = false;
- if ($this->sideatail = = Self::maxnum && $this->sidebtail = = self::maxnum) {
- $result = true;
- }
- return $result;
- }
- /*
- * Check whether the current queue is empty
- * @return Boolean
- */
- Public Function IsEmpty () {
- $result = true;
- if ($this->sideatail > 0 | | $this->sidebtail > 0) {
- $result = false;
- }
- return $result;
- }
- /*
- * Gets the length of the current queue
- * The length is theoretical length, some elements are lost due to expiration, the true length is less than or equal to that length
- * @return int
- */
- Public Function Getqueuelength () {
- $this->getheadntail ($this->queuename);
- $this->getcurrentside ();
- $sideALength = $this->sideatail-$this->sideahead;
- $sideBLength = $this->sidebtail-$this->sidebhead;
- $result = $sideALength + $sideBLength;
- return $result;
- }
- /*
- * Empty the current queue data, keep only Head_key, Tail_key, side_key three keys
- * @return Boolean
- */
- Public Function Clear () {
- if (! $this->getlock ()) return false;
- for ($i =0; $i
- @memcache_delete (self:: $client, $this->queuename. ' A '. Self::valu_key. $i, 0);
- @memcache_delete (self:: $client, $this->queuename. ' B '. Self::valu_key. $i, 0);
- }
- $this->unlock ();
- $this->resetside (' A ');
- $this->resetside (' B ');
- return true;
- }
- /*
- * Clear all Memcache cache data
- * @return NULL
- */
- Public Function Memflush () {
- Memcache_flush (self:: $client);
- }
- }
Copy Code
|