ホームページ  >  記事  >  バックエンド開発  >  PHPで実装されたmemcachedキュークラス

PHPで実装されたmemcachedキュークラス

WBOY
WBOYオリジナル
2016-07-25 08:43:27831ブラウズ
  1. /*
  2. * memcache キュークラス
  3. * 複数プロセスの同時書き込みと読み取りをサポート
  4. * 書き込み中の読み取り、AB 側ローテーション置換
  5. * @author guoyu
  6. * @create on 9:25 2014 -9-28
  7. * @qq テクノロジー産業交流グループ: 136112330
  8. *
  9. * @example:
  10. * $obj = new memcacheQueue('duilie')
  11. * $obj->add('1asdf'); $obj->getQueueLength();
  12. * $obj->read(11);
  13. */
  14. class memcacheQueue{
  15. public static $client;クライアント接続
  16. public $access; //キューを更新できるかどうか
  17. private $currentSide; //現在のローテーションのキューサイド: A/B
  18. private $lastSide; //前のローテーションのキューサイド: A/ B
  19. private $sideAHead; // サイド A
  20. の最初の値 private $sideATail; // サイド A
  21. の最初の値 private $sideBTail;サイド B の
  22. private $ currentHead; // チームの現在の先頭の値
  23. private $currentTail; // チームの現在の末尾の値
  24. private $; lastTail; // チームの最後のラウンドの最後の値
  25. private $expire // 有効期限、秒、つまり 30 日以内 0 は有効期限が切れないことを意味します
  26. private $sleepTime;ロック解除, マイクロ秒
  27. private $queueName; // キュー名、一意の値
  28. private $retryNum; // 再試行数 = 10 * 理論上の同時実行数
  29. const MAXNUM = 2000; // (片面) キューの最大数推奨される上限は 10K です
  30. const HEAD_KEY = '_lkkQueueHead_' // キューのヘッド
  31. const TAIL_KEY = '_lkkQueueTail_' // キューの末尾のキー
  32. const VALU_KEY = '_lkkQueueValu_' // キューの値のキー
  33. LOCK_KEY = ' _lkkQueueLock_'; // キューのロック キー
  34. const SIDE_KEY = '_lkkQueueSide_'; // ローテーション サイド キー
  35. /*
  36. * コンストラクター
  37. * @param [config] 配列 memcache サーバー パラメーター
  38. * @param [queueName] 文字列キュー名
  39. * @param [expire] 文字列の有効期限
  40. * @return NULL
  41. */
  42. public function __construct($queueName = '',$expire='',$config =''){
  43. if(empty($config)) {
  44. self::$client = memcache_pconnect('localhost',11211);
  45. }elseif(is_array($config )){//array('host'=>'127.0.0.1','port'=> '11211')
  46. self::$client = memcache_pconnect($config['host'],$config[' port']);
  47. }elseif(is_string($config)){//"127.0.0.1:11211"
  48. $tmp =explode(':',$config);
  49. $conf['host'] = isset( $tmp[0]) $tmp[0] : '127.0.0.1'; '] = isset($tmp[1]) ? $tmp[1] : '11211'; :$client = memcache_pconnect($conf['host'],$conf['port']);
  50. if(!self::$client) return false;
  51. ignore_user_abort(TRUE);//クライアント切断時 接続を開いて継続実行を許可
  52. set_time_limit(0);//スクリプト実行遅延の上限を解除
  53. $this->access = false;
  54. $this->sleepTime = 1000;
  55. $expire = (empty($expire) && $expire!=0) : (int)$expire; >expire = $expire;
  56. $this->queueName = $queueName;
  57. $side = memcache_add(self::$client, $queueName, ' A',false, $expire);
  58. $this->getHeadNTail($queueName);
  59. if(!isset($this ->sideAHead) || empty($this->sideAHead)) $this-> ;sideAHead = 0;
  60. if(!isset($this->sideATail) || empty($this->sideATail) ) $this->sideATail = 0;
  61. if(!isset($this-> SideBHead) || empty($this->sideBHead)) $this->sideBHead = 0;
  62. if(!isset( $this->sideBHead) || empty($this->sideBHead) ->sideBHead = 0;
  63. /*
  64. * 获取队列首尾值
  65. * @param [queueName] string 队列名
  66. * @return NULL
  67. */
  68. private function getHeadNTail($queueName){
  69. $this->sideAHead = (int)memcache_get( self::$client, $queueName.'A'.self::HEAD_KEY);
  70. $this->sideATail = (int)memcache_get(self::$client, $queueName.'A'. self::TAIL_KEY);
  71. $this->sideBHead = (int)memcache_get(self::$client, $queueName.'B'.self::HEAD_KEY);
  72. $this->sideBTail = (int)memcache_get(self::$client, $queueName.'B'.self::TAIL_KEY);
  73. }
  74. /*
  75. * 获取当前轮值の队列面
  76. * @return string 队列面名
  77. */
  78. public function getCurrentSide(){
  79. $currentSide = memcache_get(self::$client, $this->queueName .self::SIDE_KEY);
  80. if($currentSide == 'A'){
  81. $this->currentSide = 'A';
  82. $this->lastSide = 'B';
  83. $this->currentHead = $this->sideAHead;
  84. $this->currentTail = $this->sideATail;
  85. $this->lastHead = $this->sideBHead;
  86. $this->lastTail = $this->sideBTail;
  87. }else{
  88. $this->currentSide = 'B';
  89. $this->lastSide = 'A';
  90. $this->currentHead = $this->sideBHead;
  91. $this->currentTail = $this->sideBTail;
  92. $this->lastHead = $this->sideAHead;
  93. $this->lastTail = $this->sideATail;
  94. }
  95. return $this->currentSide;
  96. }
  97. /*
  98. * 队列加锁
  99. * @return boolean
  100. */
  101. private function getLock(){
  102. if($this->access === false){
  103. while(!memcache_add(self:: $client, $this->queueName .self::LOCK_KEY, 1, false, $this->expire) ){
  104. usleep($this->sleepTime);
  105. @$i++;
  106. if($i > $this->retryNum){//尝试等待ちN次
  107. return false;
  108. 休憩;
  109. }
  110. }
  111. return $this->access = true;
  112. }
  113. false を返します。
  114. }
  115. /*
  116. * 队列解锁
  117. * @return NULL
  118. */
  119. private function unLock(){
  120. memcache_delete(self::$client, $this->queueName .self::LOCK_KEY);
  121. $this->access = false;
  122. }
  123. /*
  124. * 追加データ
  125. * @param [data] 要存储的值
  126. * @return boolean
  127. */
  128. public function add($data){
  129. $result = false;
  130. if(!$this->getLock()){
  131. return $result;
  132. }
  133. $this->getHeadNTail($this->queueName);
  134. $this->getCurrentSide();
  135. if($this->isFull()){
  136. $this->unLock();
  137. false を返します。
  138. }
  139. if($this->currentTail < self::MAXNUM){
  140. $value_key = $this->queueName .$this->currentSide 。 self::VALU_KEY 。 $this->currentTail;
  141. if(memcache_add(self::$client, $value_key, $data, false, $this->expire)){
  142. $this->changeTail();
  143. $result = true;
  144. }
  145. }else{//当前队列已满,更换轮值面
  146. $this->unLock();
  147. $this->changeCurrentSide();
  148. return $this->add($data);
  149. }
  150. $this->unLock();
  151. $result を返す;
  152. }
  153. /*
  154. * 取出データデータ
  155. * @param [length] int データの長さ
  156. * @return array
  157. */
  158. public function get($length=0){
  159. if(!is_numeric($length)) false を返します。
  160. if(empty($length)) $length = self::MAXNUM * 2;//默认读取すべて
  161. if(!$this->getLock()) return false;
  162. if($this->isEmpty()){
  163. $this->unLock();
  164. false を返します。
  165. }
  166. $keyArray = $this->getKeyArray($length);
  167. $lastKey = $keyArray['lastKey'];
  168. $currentKey = $keyArray['currentKey'];
  169. $keys = $keyArray['keys'];
  170. $this->changeHead($this->lastSide,$lastKey);
  171. $this->changeHead($this->currentSide,$currentKey);
  172. $data = @memcache_get(self::$client, $keys);
  173. foreach($keys as $v){//取出之後删除
  174. @memcache_delete(self::$client, $v, 0);
  175. }
  176. $this->unLock();
  177. $data を返します。
  178. }
  179. /*
  180. * 读取数据
  181. * @param [length] int データの長さ
  182. * @return array
  183. */
  184. public function read($length=0){
  185. if(!is_numeric($length) ) false を返します。
  186. if(empty($length)) $length = self::MAXNUM * 2;//默认读取すべて
  187. $keyArray = $this->getKeyArray($length);
  188. $data = @memcache_get(self::$client, $keyArray['keys']);
  189. $data を返します。
  190. }
  191. /*
  192. * 获取队列の特定の段数のキー数组
  193. * @param [length] int 队列长度
  194. * @return array
  195. */
  196. private function getKeyArray($length){
  197. $result = array('キー'=>array()、'lastKey'=>array()、'currentKey'=>array());
  198. $this->getHeadNTail($this->queueName);
  199. $this->getCurrentSide();
  200. if(empty($length)) $result を返します。
  201. //先取上一面のキー
  202. $i = $result['lastKey'] = 0;
  203. for($i=0;$i $result['lastKey'] = $this->lastHead + $i;
  204. if($result['lastKey'] >= $this->lastTail) Break;
  205. $result['keys'][] = $this->queueName .$this->lastSide 。 self::VALU_KEY 。 $result['lastKey'];
  206. }
  207. //再取得当前のキー
  208. $j = $length - $i;
  209. $k = $result['currentKey'] = 0;
  210. for($k=0;$k $result['currentKey'] = $this->currentHead + $k;
  211. if($result['currentKey'] >= $this->currentTail) Break;
  212. $result['keys'][] = $this->queueName .$this->currentSide 。 self::VALU_KEY 。 $result['currentKey'];
  213. }
  214. $result を返します。
  215. }
  216. /*
  217. * 当前轮值面队列尾の值
  218. * @return NULL
  219. */
  220. private function changeTail(){
  221. $tail_key = $this->queueName .$this->currentSide 。自分::TAIL_KEY;
  222. memcache_add(self::$client, $tail_key, 0,false, $this->expire);//如果没有,则插入;有则false;
  223. //memcache_increment(self::$client, $tail_key, 1);//队列尾+1
  224. $v = memcache_get(self::$client, $tail_key) +1;
  225. memcache_set(self::$client, $tail_key,$v,false,$this->expire);
  226. }
  227. /*
  228. * 更新队列首の值
  229. * @param [side] string 要更新的面
  230. * @param [headValue] int 队列首の值
  231. * @return NULL
  232. */
  233. private function changeHead( $side,$headValue){
  234. if($headValue $head_key = $this->queueName .$side 。自分::HEAD_KEY;
  235. $tail_key = $this->queueName .$side 。自分::TAIL_KEY;
  236. $sideTail = memcache_get(self::$client, $tail_key);
  237. if($headValue < $sideTail){
  238. memcache_set(self::$client, $head_key,$headValue+1,false,$this->expire);
  239. }elseif($headValue >= $sideTail){
  240. $this->resetSide($side);
  241. }
  242. }
  243. /*
  244. * 重置队列面、即将该队列面の队首、队尾值置は0
  245. * @param [side] string 要重置面
  246. * @return NULL
  247. */
  248. プライベート関数resetSide($side){
  249. $head_key = $this->queueName .$side .自分::HEAD_KEY;
  250. $tail_key = $this->queueName .$side 。自分自身::TAIL_KEY;
  251. memcache_set(self::$client, $head_key,0,false,$this->expire);
  252. memcache_set(self::$client, $tail_key,0,false,$this->expire);
  253. }
  254. /*
  255. * 改变当前轮值队列面
  256. * @return string
  257. */
  258. private function changeCurrentSide(){
  259. $currentSide = memcache_get(self::$client, $this->queueName . self::SIDE_KEY) ;
  260. if($currentSide == 'A'){
  261. memcache_set(self::$client, $this->queueName . self::SIDE_KEY,'B',false,$this->expire);
  262. $this->currentSide = 'B';
  263. }else{
  264. memcache_set(self::$client, $this->queueName . self::SIDE_KEY,'A',false,$this->expire);
  265. $this->currentSide = 'A';
  266. }
  267. return $this->currentSide;
  268. }
  269. /*
  270. * 检查当前队列否否已满
  271. * @return boolean
  272. */
  273. public function isFull(){
  274. $result = false;
  275. if($this->sideATail == self::MAXNUM && $this->sideBTail == self::MAXNUM){
  276. $result = true;
  277. }
  278. $result を返します。
  279. }
  280. /*
  281. * 检查当前队列否か空
  282. * @return boolean
  283. */
  284. public function isEmpty(){
  285. $result = true;
  286. if($this->sideATail > 0 || $this->sideBTail > 0){
  287. $result = false;
  288. }
  289. $result を返します。
  290. }
  291. /*
  292. * 取当前队列の長さ
  293. * この長さは理论長さです、特定の要素は期限切れによる損失、真实長さはこの長さ以下です
  294. * @return int
  295. */
  296. パブリック関数 getQueueLength( ){
  297. $this->getHeadNTail($this->queueName);
  298. $this->getCurrentSide();
  299. $sideALength = $this->sideATail - $this->sideAHead;
  300. $sideBLength = $this->sideBTail - $this->sideBHead;
  301. $result = $sideALength + $sideBLength;
  302. $result を返す;
  303. }
  304. /*
  305. * 清空当前队列データ、仅保持HEAD_KEY、TAIL_KEY、SIDE_KEY三个key
  306. * @return boolean
  307. */
  308. public function clear(){
  309. if(!$this->getLock() ) false を返します。
  310. for($i=0;$i @memcache_delete(self::$client, $this->queueName.'A'. self::VALU_KEY .$i, 0 );
  311. @memcache_delete(self::$client, $this->queueName.'B'. self::VALU_KEY .$i, 0);
  312. }
  313. $this->unLock();
  314. $this->resetSide('A');
  315. $this->resetSide('B');
  316. true を返します。
  317. }
  318. /*
  319. * 清除すべてmemcache缓存数据
  320. * @return NULL
  321. */
  322. public function memFlush(){
  323. memcache_flush(self::$client);
  324. }
  325. }
复制代

php、memcached


声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。