php memcache 源码,memcache队列类

add('1asdf');

*$obj->getQueueLength();

*$obj->read(11);

*$obj->get(8);

*/

class memcacheQueue{

public static$client;//memcache客户端连接

public$access;//队列是否可更新

private $currentSide;//当前轮值的队列面:A/B

private$lastSide;//上一轮值的队列面:A/B

private $sideAHead;//A面队首值

private $sideATail;//A面队尾值

private $sideBHead;//B面队首值

private $sideBTail;//B面队尾值

private$currentHead;//当前队首值

private$currentTail;//当前队尾值

private$lastHead;//上轮队首值

private$lastTail;//上轮队尾值

private $expire;//过期时间,秒,1~2592000,即30天内

private$sleepTime;//等待解锁时间,微秒

private$queueName;//队列名称,唯一值

private$retryNum;//重试次数,= 10 * 理论并发数

constMAXNUM= 10000;//(单面)最大队列数,建议上限10K

constHEAD_KEY= '_lkkQueueHead_';//队列首kye

constTAIL_KEY= '_lkkQueueTail_';//队列尾key

constVALU_KEY= '_lkkQueueValu_';//队列值key

constLOCK_KEY= '_lkkQueueLock_';//队列锁key

constSIDE_KEY= '_lkkQueueSide_';//轮值面key

/*

* 构造函数

* @param[queueName]string队列名称

* @param[expire]string过期时间

* @param[config]arraymemcache服务器参数

* @returnNULL

*/

public function __construct($queueName ='',$expire='',$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);//当客户断开连接,允许继续执行

set_time_limit(0);//取消脚本执行延时上限

$this->access = false;

$this->sleepTime = 1000;

$expire = (empty($expire)) ? 3600 : (int)$expire+1;

$this->expire = $expire;

$this->queueName = $queueName;

$this->retryNum = 20000;

$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->sideBTail) || empty($this->sideBTail)) $this->sideBTail = 0;

}

/*

* 获取队列首尾值

* @param[queueName]string队列名称

* @returnNULL

*/

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);

}

/*

* 获取当前轮值的队列面

* @returnstring队列面名称

*/

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;

}

/*

* 队列加锁

* @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){//尝试等待N次

return false;

break;

}

}

return $this->access = true;

}

return false;

}

/*

* 队列解锁

* @return NULL

*/

private function unLock(){

memcache_delete(self::$client, $this->queueName .self::LOCK_KEY);

$this->access = false;

}

/*

* 添加数据

* @param[data]要存储的值

* @returnboolean

*/

public function add($data=''){

$result = false;

if(empty($data)) return $result;

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_set(self::$client, $value_key, $data, false, $this->expire)){

$this->changeTail();

$result = true;

}

}else{//当前队列已满,更换轮值面

$this->unLock();

$this->changeCurrentSide();

return $this->add($data);

}

$this->unLock();

return $result;

}

/*

* 取出数据

* @param[length]int数据的长度

* @returnarray

*/

public function get($length=0){

if(!is_numeric($length)) return false;

if(empty($length)) $length = self::MAXNUM * 2;//默认读取所有

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);

if(empty($data)) $data = array();

foreach($keys as $v){//取出之后删除

@memcache_delete(self::$client, $v, 0);

}

$this->unLock();

return $data;

}

/*

* 读取数据

* @param[length]int数据的长度

* @returnarray

*/

public function read($length=0){

if(!is_numeric($length)) return false;

if(empty($length)) $length = self::MAXNUM * 2;//默认读取所有

$keyArray= $this->getKeyArray($length);

$data= @memcache_get(self::$client, $keyArray['keys']);

if(empty($data)) $data = array();

return $data;

}

/*

* 获取队列某段长度的key数组

* @param[length]int队列长度

* @returnarray

*/

private function getKeyArray($length){

$result = array('keys'=>array(),'lastKey'=>null,'currentKey'=>null);

$this->getHeadNTail($this->queueName);

$this->getCurrentSide();

if(empty($length)) return $result;

//先取上一面的key

$i = $result['lastKey'] = 0;

for($i=0;$ilastHead + $i;

if($result['lastKey'] >= $this->lastTail) break;

$result['keys'][] = $this->queueName .$this->lastSide . self::VALU_KEY . $result['lastKey'];

}

//再取当前面的key

$j = $length - $i;

$k = $result['currentKey'] = 0;

for($k=0;$kcurrentHead + $k;

if($result['currentKey'] >= $this->currentTail) break;

$result['keys'][] = $this->queueName .$this->currentSide . self::VALU_KEY . $result['currentKey'];

}

return $result;

}

/*

* 更新当前轮值面队列尾的值

* @returnNULL

*/

private function changeTail(){

$tail_key = $this->queueName .$this->currentSide . self::TAIL_KEY;

memcache_add(self::$client, $tail_key, 0,false, $this->expire);//如果没有,则插入;有则false;

$v = memcache_get(self::$client, $tail_key) +1;

memcache_set(self::$client, $tail_key,$v,false,$this->expire);

}

/*

* 更新队列首的值

* @param[side]string要更新的面

* @param[headValue]int队列首的值

* @returnNULL

*/

private function changeHead($side,$headValue){

$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);

}

}

/*

* 重置队列面,即将该队列面的队首、队尾值置为0

* @param[side]string要重置的面

* @returnNULL

*/

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);

}

/*

* 改变当前轮值队列面

* @returnstring

*/

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;

}

/*

* 检查当前队列是否已满

* @returnboolean

*/

public function isFull(){

$result = false;

if($this->sideATail == self::MAXNUM && $this->sideBTail == self::MAXNUM){

$result = true;

}

return $result;

}

/*

* 检查当前队列是否为空

* @returnboolean

*/

public function isEmpty(){

$result = true;

if($this->sideATail > 0 || $this->sideBTail > 0){

$result = false;

}

return $result;

}

/*

* 获取当前队列的长度

* 该长度为理论长度,某些元素由于过期失效而丢失,真实长度小于或等于该长度

* @returnint

*/

public function getQueueLength(){

$this->getHeadNTail($this->queueName);

$sideALength = $this->sideATail - $this->sideAHead;

$sideBLength = $this->sideBTail - $this->sideBHead;

$result = $sideALength + $sideBLength;

return $result;

}

/*

* 清空当前队列数据,仅保留HEAD_KEY、TAIL_KEY、SIDE_KEY三个key

* @returnboolean

*/

public function clear(){

if(!$this->getLock()) return false;

$this->getHeadNTail($this->queueName);

$AHead = $this->sideAHead;$AHead--;

$ATail = $this->sideATail;$ATail++;

$BHead = $this->sideBHead;$BHead--;

$BTail = $this->sideBTail;$BTail++;

//删除A面

for($i=$AHead;$iqueueName.'A'. self::VALU_KEY .$i, 0);

}

//删除B面

for($j=$BHead;$jqueueName.'A'. self::VALU_KEY .$j, 0);

}

$this->unLock();

$this->resetSide('A');

$this->resetSide('B');

return true;

}

/*

* 清除所有memcache缓存数据

* @returnNULL

*/

public function memFlush(){

memcache_flush(self::$client);

}

}

2.[文件]test.php ~ 3KB

//memcacheQueue队列类测试

header("Content-type: text/html; charset=utf-8;private, must-revalidate");

require_once('memcacheQueue.class.php');

//获取时间,精度微秒

function microtimeFloat(){

list($usec, $sec) = explode(" ", microtime());

return ((float)$usec + (float)$sec);

}

$queObj = new memcacheQueue('duilie');

$client = memcache_pconnect('127.0.0.1',11211);

$length = 20000;

/*------------------------------------------

* 队列类测试

*------------------------------------------

*/

//写数据

$time_add_start = microtimeFloat();

for($i=1;$i

本文原创发布php中文网,转载请注明出处,感谢您的尊重!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值