PHP Memcache 링 큐 클래스. 저는 초보자이고 비즈니스 요구 때문에 데이터 구조에 대해 많이 배우지 않았습니다. 프로토타입은 oschina에서 lusi가 공유하는 PHP memcache 대기열 코드입니다. int 길이가 경계를 넘을 위험 없이 언제든지 대기열에 들어가고 나갈 수 있도록 하기 위해(단일 체인이 헤드 자동 증가를 채택하는 경우 처리하지 않고 경계를 넘을 가능성이 있습니다) 단순히 순환 대기열로 다시 작성됩니다.버그가 있을 수 있습니다. 죄송합니다!
- /**
- * PHP memcache 링 큐 클래스
- * 원저자 LKK/lianq.net
- * FoxHunter 수정
- * 비즈니스 요구로 인해 큐의 Pop 및 Push만 유지되도록 수정합니다. 0(영구적임)
- */
- class MQueue
- {
- public static $client;
-
- private $expire; //만료 시간, 초, 1~2592000, 즉 30일 이내
- private $sleepTime; //잠금 해제 대기 시간, 마이크로초
- private $queueName; , 고유 값
- private $retryNum; //시도 횟수
- private $MAXNUM; //최대 대기열 용량
- private $canRewrite; //스위치를 덮어쓸 수 있는지 여부에 관계없이 전체 내용이 원본을 덮어씁니다. 헤드 데이터에서
-
- private $HEAD; //다음 단계로 들어가는 포인터 위치
- private $TAIL; //다음 단계로 들어가는 포인터 위치
- private $LEN;
-
- const LOCK_KEY = '_Fox_MQ_LOCK_'; //잠금 저장 표시
- const LENGTH_KEY = '_Fox_MQ_LENGTH_'; //큐 현재 길이 저장 표시
- const VALU_KEY = '_Fox_MQ_VAL_'; 저장소 표시
- const HEAD_KEY = '_Fox_MQ_HEAD_'; // 큐 HEAD 포인터 위치 표시
- const TAIL_KEY = '_Fox_MQ_TAIL_' // 큐 TAIL 포인터 위치 표시
-
- /*
- * 생성자
- * 동일한 $queueName의 경우 생성자의 매개변수 값은 인스턴스화 시 일관되어야 합니다. 그렇지 않으면 pop 및 push가 대기열 순서에 혼란을 야기합니다.
- */
- public function __construct($queueName = ' ', $ maxqueue = 1, $canRewrite = false, $expire = 0, $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 = 폭발(':', $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)) ? 0 : (int ) $expire 1;
- $this->expire = $expire;
- $this->queueName = $queueName;
- $this->retryNum = 20000;
- $this-> ;MAXNUM = $maxqueue != null ? $maxqueue : 1;
- $this->canRewrite = $canRewrite;
- $this->getHeadAndTail();
- if (! isset($this- >HEAD) || 비어 있음($this->HEAD))
- $this->HEAD = 0;
- if (!isset($this->TAIL) || 비어 있음($this- >TAIL))
- $this->TAIL = 0;
- if (!isset($this->LEN) || 비어 있음($this->LEN))
- $this- >LEN = 0;
-
- }
-
- //큐 헤드 및 테일 포인터 정보와 길이 가져오기
- 비공개 함수 getHeadAndTail()
- {
- $this->HEAD = (int) memcache_get(self::$client, $this->queueName . self::HEAD_KEY);
- $this->TAIL = (int) memcache_get(self:: $client, $this-> queueName . self::TAIL_KEY);
- $this->LEN = (int) memcache_get(self::$client, $this->queueName . self::LENGTH_KEY);
- }
-
-
- // memcache_add 원자 잠금 사용
- 개인 함수 lock()
- {
- if ($this->access === false) {
- $i = 0;
- 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;
- }
-
- //가리키도록 헤드 포인터 업데이트 다음 위치
- private function incrHead()
- {
- //$this->getHeadAndTail(); //이 메소드 본문은 잠금에서 호출되므로 이 메소드는 이 줄은 Comment
- $this->HEAD; //헤드 포인터를 아래로 이동합니다
- if ($this->HEAD >= $this->MAXNUM) {
- $this->HEAD = 0; //경계값 수정
- }
- ;
- $this->LEN--; //Head의 움직임은 Pop에 의해 발생하므로 수량을 줄이는 것과 같습니다
- if ($this->LEN < 0 ) {
- $ this->LEN = 0; //경계 값 수정
- }
- ;
- memcache_set(self::$client, $this->queueName . self::HEAD_KEY, $this->HEAD , false, $this->expire) //업데이트
- memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, $this->LEN, false, $this-> ;expire); //업데이트
-
- }
-
- //다음 위치를 가리키도록 테일 포인터 업데이트
- private function incrTail()
- {
-
- / /$this->getHeadAndTail(); //최신 포인터 정보를 가져옵니다. 이 메소드 본문이 잠금에서 호출되었으므로 이 행에 주석을 달았습니다. > $this->TAIL ; / /꼬리 포인터를 아래로 이동
- if ($this->TAIL >= $this->MAXNUM) {
- $this->TAIL = 0; /경계값 수정
- }
- ;
- $this->LEN ; //머리의 움직임은 Push에 의해 발생하므로 수량 증가와 같습니다
- if ($this-> LEN >= $this->MAXNUM) {
- $this->LEN = $this->MAXNUM; //경계 값 길이 수정
- }
- ;
- memcache_set(self: :$client, $this->queueName . self:: TAIL_KEY, $this->TAIL, false, $this->expire) //업데이트
- memcache_set(self::$client, $this- >queueName . self::LENGTH_KEY, $this-> LEN, false, $this->expire) //업데이트
- }
-
-
- // 잠금 해제
- unLock()
- {
- memcache_delete(self: :$client, $this->queueName . self::LOCK_KEY);
- $this->access = false;
- }
-
- //큐가 꽉 찼는지 판단
- public function isFull()
- {
- //외부 호출을 직접 할 경우에는 락이 걸려 있지 않으므로 여기서의 값은 대략적인 값이며, 이는 그다지 정확하지는 않습니다. 그러나 내부 호출은 앞에 잠금 장치가 있으므로 신뢰할 수 있습니다.
- if ($this->canRewrite)
- return false;
- return $this->LEN = = $this->MAXNUM ? true : false;
- }
-
- //판단 비어 있습니까?
- public function isEmpty()
- {
- // 외부에는 잠금 장치가 없으므로 여기에 있는 값은 대략적인 값이며 그다지 정확하지는 않습니다. 그러나 내부적으로 호출하면 앞에 잠금 장치가 있으므로 신뢰할 수 있습니다
- return $this->LEN == 0 ? true : false;
- }
-
- public function getLen()
- {
- //외부에서 직접 호출 이때는 lock이 없기 때문에 여기서의 값은 대략적인 값으로 매우 정확하지는 않습니다. 그러나 내부 호출 앞에 자물쇠가 있으므로 신뢰할 수 있습니다.
- return $this->LEN;
- }
-
- /*
- * 푸시 값
- * @param 혼합 값
- * @return bool
- */
- 공개 함수 push($data = '')
- {
-
- $result = false ;
- if (empty($data))
- return $result;
-
- if (!$this->lock()) {
- return $result ;
- }
-
- $this->getHeadAndTail(); //최신 포인터 정보 가져오기
-
- if ($this->isFull()) { //재정의되지 않은 경우에만 적어두는 방법으로만 가능 Full
- $this->unLock();
- return false;
- }
-
- if (memcache_set(self::$client, $this->queueName) 개념이 있습니다. . self::VALU_KEY . $this->TAIL, $data, MEMCACHE_COMPRESSED, $this->expire)) {
- //푸시한 후 꼬리와 머리가 겹치는 것을 발견했습니다(포인터가 일치하지 않음). 아직 이동됨)이고 오른쪽에는 여전히 Head에서 읽지 않은 데이터가 있습니다. 그런 다음 Head 포인터를 이동하여 Tail 포인터가 Head를 가로지르는 것을 방지하세요
- if ($this->TAIL == $this-> HEAD && $this->LEN > ;= 1) {
- $this->incrHead();
- }
- $this->incrTail() //꼬리 포인터 이동
- $result = true;
- }
-
- $this->unLock();
- return $result;
- }
-
-
- /*
- * 값 팝
- * @param [length] int 큐 길이
- * @return array
- */
- public function pop($length = 0)
- {
- if (! is_numeric($length))
- false 반환;
-
- if (!$this->lock())
- false 반환;
-
- $this->getHeadAndTail() ;
-
- if (empty ($length))
- $length = $this->LEN //기본적으로
-
- 모두 읽기 if ($this->isEmpty() ) {
- $this-> unLock();
- return false;
- }
- //얻은 길이가 대기열 길이를 초과한 후 수정
- if ($length > $this- >LEN)
- $length = $this->LEN;
-
- $data = $this->popKeyArray($length);
- $this->unLock();
- $data 반환;
- }
-
-
- /*
- * 특정 길이의 값 팝
- * @param [length] int queue length
- * @return array
- */
- private function popKeyArray($length)
- {
-
- $result = array();
- if (empty($length))
- return $result;
- for ($k = 0 ; $k < $length; $k ) {
- $result[] = @memcache_get(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD);
- @memcache_delete(self::$client, $this->queueName . self::VALU_KEY . $this->HEAD, 0);
- //값을 추출한 결과 head와 테일 오버랩(포인터가 이동하지 않은 경우), 오른쪽에 데이터가 없습니다. 즉, 큐의 마지막 데이터가 완전히 비워집니다. 이 때 포인터는 로컬로 유지되고 이동하지 않으며 큐는 길이는 0이 됩니다
- if ($this->TAIL == $this->HEAD && $this->LEN <= 1) {
- $this->LEN = 0;
- memcache_set(self::$client, $this->queueName . self ::LENGTH_KEY, $this->LEN, false, $this->expire) //업데이트
- break;
- } else {
- $this->incrHead(); //첫 번째와 마지막 중복이 없거나, 중복이 있지만 아직 읽지 않은 데이터가 있는 경우 읽을 다음 위치로 HEAD 포인터를 이동합니다.
- }
- }
- return $result;
- }
-
- /*
- * 대기열 재설정
- * * @return NULL
- */
- 개인 함수 재설정( $all = false)
- {
-
- if ($all ) {
- memcache_delete(self::$client, $this->queueName . self::HEAD_KEY, 0);
- memcache_delete(self::$client, $this->queueName . self::TAIL_KEY , 0);
- memcache_delete(self::$client, $this->queueName . self::LENGTH_KEY, 0);
- } else {
- $this->HEAD = $this-> ;TAIL = $this->LEN = 0;
- memcache_set(self::$client, $this->queueName . self ::HEAD_KEY, 0, false, $this->expire);
- memcache_set(self::$client, $this->queueName . self::TAIL_KEY, 0, false, $this->expire) ;
- memcache_set(self::$client, $this->queueName . self::LENGTH_KEY, 0, false, $this->expire);
- }
- }
-
- /*
- * 모든 Memcache 캐시 데이터 지우기
- * @return NULL
- */
- 공용 함수 memFlush()
- {
- memcache_flush(self::$client);
- }
-
-
- 공용 함수 Clear($all = false)
- {
- if (!$this->lock())
- return false;
- $this- >getHeadAndTail();
- $Head = $this->HEAD;
- $Length = $this->LEN;
- $curr = 0;
- for ($i = 0; $i < $Length; $i ) {
- $curr = $this ->$Head $i;
- if ($curr >= $this->MAXNUM) {
- $this ->HEAD = $curr = 0;
- }
- @memcache_delete (self::$client, $this->queueName . self::VALU_KEY . $curr, 0);
- }
-
-
- $this->unLock();
- $this->reset($all);
- true를 반환합니다.
- }
-
-
- }
코드 복사
|