php自己實現memcached的隊列類

來源:互聯網
上載者:User
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天內;0為永不到期    private         $sleepTime;         //等待解鎖時間,微秒    private         $queueName;         //隊列名稱,唯一值    private         $retryNum;          //重試次數,= 10 * 理論並發數    const   MAXNUM      = 2000;                 //(單面)最大隊列數,建議上限10K    const   HEAD_KEY    = '_lkkQueueHead_';     //隊列首kye    const   TAIL_KEY    = '_lkkQueueTail_';     //隊列尾key    const   VALU_KEY    = '_lkkQueueValu_';     //隊列值key    const   LOCK_KEY    = '_lkkQueueLock_';     //隊列鎖key    const   SIDE_KEY    = '_lkkQueueSide_';     //輪值面key    /*     * 建構函式     * @param   [config]    array   memcache伺服器參數     * @param   [queueName] string  隊列名稱     * @param   [expire]    string  到期時間     * @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);//當客戶中斷連線,允許繼續執行        set_time_limit(0);//取消指令碼執行延時上限        $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;    }    /*     * 擷取隊列首尾值     * @param   [queueName] string  隊列名稱     * @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);    }    /*     * 擷取當前輪值的隊列面     * @return  string  隊列面名稱     */    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]  要儲存的值     * @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{//當前隊列已滿,更換輪值面            $this->unLock();            $this->changeCurrentSide();            return $this->add($data);        }        $this->unLock();        return $result;    }    /*     * 取出資料     * @param   [length]    int 資料的長度     * @return  array     */    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);        foreach($keys as $v){//取出之後刪除            @memcache_delete(self::$client, $v, 0);        }        $this->unLock();        return $data;    }    /*     * 讀取資料     * @param   [length]    int 資料的長度     * @return  array     */    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']);        return $data;    }    /*     * 擷取隊列某段長度的key數組     * @param   [length]    int 隊列長度     * @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;        //先取上一面的key        $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'];        }        //再取當前面的key        $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;    }    /*     * 更新當前輪值面隊列尾的值     * @return  NULL     */    private function changeTail(){        $tail_key = $this->queueName .$this->currentSide . self::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     */    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);        }    }    /*     * 重設隊列面,即將該隊列面的隊首、隊尾值置為0     * @param   [side]  string  要重設的面     * @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);    }    /*     * 改變當前輪值隊列面     * @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;    }    /*     * 檢查當前隊列是否已滿     * @return  boolean     */    public function isFull(){        $result = false;        if($this->sideATail == self::MAXNUM && $this->sideBTail == self::MAXNUM){            $result = true;        }        return $result;    }    /*     * 檢查當前隊列是否為空白     * @return  boolean     */    public function isEmpty(){        $result = true;        if($this->sideATail > 0  $this->sideBTail > 0){            $result = false;        }        return $result;    }    /*     * 擷取當前隊列的長度     * 該長度為理論長度,某些元素由於到期失效而丟失,真實長度小於或等於該長度     * @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;    }    /*     * 清空當前隊列資料,僅保留HEAD_KEY、TAIL_KEY、SIDE_KEY三個key     * @return  boolean     */    public function clear(){        if(!$this->getLock()) return false;        for($i=0;$iqueueName.'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;    }    /*     * 清除所有memcache快取資料     * @return  NULL     */    public function memFlush(){        memcache_flush(self::$client);    }}




相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.