- /*
- * memcache 대기열 클래스
- * 여러 프로세스에 의한 동시 쓰기 및 읽기 지원
- * 쓰는 동안 읽기, AB 문자 회전 교체
- * @author guoyu
- * @create on 9:25 2014-9-28
- * @qq 기술산업 교류회 : 136112330
- *
- * @예:
- * $obj = new memcacheQueue('duilie');
- * $obj->add('1asdf')
- * $obj->getQueueLength(); read(11); * $obj->get(8);
- */
-
- class memcacheQueue{
- public static $client
- 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 * 이론적인 동시성 수
-
- const MAXNUM = 2000; //(단면) 최대 대기열 수, 권장 상한은 10K입니다.
- const HEAD_KEY = '_lkkQueueHead_' // 대기열 헤드 키
- const TAIL_KEY = '_lkkQueueTail_' // 대기열 꼬리 키
- const VALU_KEY = '_lkkQueueValu_'; // 대기열 값 키
- const LOCK_KEY = '_lkkQueueLock_' // 대기열 잠금 키
- const SIDE_KEY = '_lkkQueueSide_' // 회전 표면 키
-
- /*
- * 생성자
- * @param [config] 배열 memcache 서버 매개변수
- * @param [queueName] 문자열 대기열 이름
- * @param [expire] 문자열 만료 시간
- * @return NULL
- */
- 공용 함수 __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 = 폭발(' :',$config);
- $conf['host'] = isset($tmp[0]) ? $tmp[0] : '127.0. 0.1';
- $conf['port'] = isset($tmp[1]) ? $tmp[1] : '11211'
- self::$client($conf['host') ],$conf['port']);
- }
- if(!self::$client) return false
-
- ignore_user_abort(TRUE);//클라이언트 연결이 끊어지면 실행을 허용합니다. 계속
- set_time_limit(0);//스크립트 실행 지연 상한
-
- $this->access = false
- $this->sleepTime = 1000; = (비어 있음($expire) && $expire!=0) ? 3600 : (int)$expire;
- $this->expire = $expire; 🎜> $this->retryNum = 10000;
-
- $side = memcache_add(self::$client, $queueName . self::SIDE_KEY, 'A',false, $expire)
- $ this->getHeadNTail($queueName);
- if (!isset($this->sideAHead) || 비어 있음($this->sideAHead)) $this->sideAHead = 0; (!isset($this->sideATail) || 비어 있음 ($this->sideATail)) $this->sideATail = 0
- if(!isset($this->sideBHead) || 비어 있음 ($this->sideBHead)) $this-> sideBHead = 0
- if(!isset($this->sideBHead) || 비어 있음($this->sideBHead)) $this-> sideBHead = 0
- }
-
- /*
- * 获取队列首尾值
- * @param [queueName] string 队列name称
- * @return NULL
- */
- 비공개 함수 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);
- }
-
- /*
- * 获取当前轮值的队列면
- * @return string 队列면명称
- */
- 공용 함수 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
- */
- 비공개 함수 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;
- 휴식;
- }
- }
- return $this->access = true;
- }
- false를 반환합니다.
- }
-
- /*
- * 队列解锁
- * @return NULL
- */
- 비공개 함수 unLock(){
- memcache_delete(self::$client, $this->queueName .self::LOCK_KEY);
- $this->access = false;
- }
-
- /*
- * 添加数据
- * @param [data] 要存储的值
- * @return boolean
- */
- 공용 함수 add( $data){
- $result = false;
- if(!$this->getLock()){
- return $result;
- }
- $this->getHeadNTail($this->queueName);
- $this->getCurrentSide();
-
- if($this->isFull()){
- $this->unLock();
- false를 반환합니다.
- }
-
- if($this->currentTail $value_key = $this->queueName .$this->currentSide . 자기::VALU_KEY . $this->currentTail;
- if(memcache_add(self::$client, $value_key, $data, false, $this->expire)){
- $this->changeTail();
- $결과 = 참;
- }
- }else{//当前队列已满,更换轮值面
- $this->unLock();
- $this->changeCurrentSide();
- return $this->add($data);
- }
-
- $this->unLock();
- $결과 반환;
- }
-
- /*
- * 取出数据
- * @param [length] int 数据的长titude
- * @return 배열
- */
- 공용 함수 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();
- 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){//출지后删除
- @memcache_delete(self::$client, $v, 0);
- }
- $this->unLock();
-
- $data를 반환합니다.
- }
-
- /*
- * 读取数据
- * @param [length] int 数据的长島
- * @return 배열
- */
- 공용 함수 읽기 ($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']);
- $data를 반환합니다.
- }
-
- /*
- * 获取队列某段长島的key数组
- * @param [length] int 队列长島
- * @return 배열
- */
- 개인 함수 getKeyArray($length){
- $result = array('keys'=>array(),'lastKey'=>array(),'currentKey'=>array());
- $this->getHeadNTail($this->queueName);
- $this->getCurrentSide();
- if(empty($length)) return $result;
-
- //상위 키
- $i = $result['lastKey'] = 0;
- for($i=0;$i $result['lastKey'] = $this->lastHead $i;
- if($result['lastKey'] >= $this->lastTail) break;
- $result['keys'][] = $this->queueName .$this->lastSide . 자기::VALU_KEY . $result['lastKey'];
- }
-
- //再取当앞면의 키
- $j = $length - $i;
- $k = $result['currentKey'] = 0;
- for($k=0;$k $result['currentKey'] = $this->currentHead $k;
- if($result['currentKey'] >= $this->currentTail) break;
- $result['keys'][] = $this->queueName .$this->currentSide . 자기::VALU_KEY . $result['현재키'];
- }
-
- $result 반환;
- }
-
- /*
- * 更新当前轮值면队列尾적值
- * @return NULL
- */
- 비공개 함수changeTail(){
- $tail_key = $this->queueName .$this->currentSide . 자기::TAIL_KEY;
- memcache_add(self::$client, $tail_key, 0,false, $this->expire);//如果没有,则插入;有则false;
- //memcache_increment(self::$client, $tail_key, 1);//队列尾 1
- $v = memcache_get(self::$client, $tail_key) 1;
- memcache_set(self::$client, $tail_key,$v,false,$this->expire);
- }
-
- /*
- * 更新队列首적值
- * @param [side] string 要更新的面
- * @param [headValue] int 队列首的值
- * @return NULL
- */
- 비공개 함수changeHead($side,$headValue){
- if($headValue $head_key = $this->queueName .$side . 자기::HEAD_KEY;
- $tail_key = $this->queueName .$side . 자기::TAIL_KEY;
- $sideTail = memcache_get(self::$client, $tail_key);
- if($headValue memcache_set(self::$client, $head_key,$headValue 1,false,$this->expire);
- }elseif($headValue >= $sideTail){
- $this->resetSide($side);
- }
- }
-
- /*
- * 큼 거대한 화면
- * @return NULL
- */
- 개인 함수 ResetSide($side){
- $head_key = $this->queueName .$side . 자기::HEAD_KEY;
- $tail_key = $this->queueName .$side . 자기::TAIL_KEY;
- memcache_set(self::$client, $head_key,0,false,$this->expire);
- memcache_set(self::$client, $tail_key,0,false,$this->expire);
- }
-
- /*
- * 改变当前轮值队列면
- * @return string
- */
- private functionchangeCurrentSide(){
- $currentSide = memcache_get(self::$ 클라이언트, $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;
- }
-
- /*
- * 检查当前队列是否已满
- * @return boolean
- */
- public function isFull(){
- $result = false ;
- if($this->sideATail == self::MAXNUM && $this->sideBTail == self::MAXNUM){
- $result = true;
- }
- $result 반환;
- }
-
- /*
- * 检查当前队列是否为空
- * @return boolean
- */
- public function isEmpty(){
- $result = true ;
- if($this->sideATail > 0 || $this->sideBTail > 0){
- $result = false;
- }
- $result 반환;
- }
-
- /*
- * 获取当前队列적 속도
- * 该长島为理论长島,某些元素由于过期失效而丢失,真实속도 小于或等于该长島
- * @return int
- */
- 공용 함수 getQueueLength(){
- $this->getHeadNTail($this->queueName);
- $this->getCurrentSide();
-
- $sideALength = $this->sideATail - $this->sideAHead;
- $sideBLength = $this->sideBTail - $this->sideBHead;
- $result = $sideALength $sideBLength;
-
- $result를 반환합니다.
- }
-
- /*
- * 清空当前队列数据,仅保留HEAD_KEY、TAIL_KEY、SIDE_KEY삼키key
- * @return boolean
- */
- 공개 함수 클리어( ){
- if(!$this->getLock()) return false;
- for($i=0;$i<:maxnum> @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');
- true를 반환합니다.
- }
-
- /*
- * 清除所有memcache缓存数据
- * @return NULL
- */
- 공용 함수 memFlush(){
- memcache_flush(self:: $클라이언트);
- }
-
- }
复제대码
|