├── secache_no_flock.php ├── README.md ├── demo └── test.php └── secache.php /secache_no_flock.php: -------------------------------------------------------------------------------- 1 | __support_usleep = version_compare(PHP_VERSION,5,'>=')?20:1; 8 | } 9 | 10 | function lock($is_block,$whatever=false){ 11 | 12 | ignore_user_abort(1); 13 | $lockfile = $this->_file . '.lck'; 14 | 15 | if (file_exists($lockfile)) { 16 | if (time() - filemtime($lockfile) > 5){ 17 | unlink($lockfile); 18 | }elseif(!$is_block){ 19 | return false; 20 | } 21 | } 22 | 23 | $lock_ex = @fopen($lockfile, 'x'); 24 | for ($i=0; ($lock_ex === false) && ($whatever || $i < 20); $i++) { 25 | clearstatcache(); 26 | if($this->__support_usleep==1){ 27 | usleep(rand(9, 999)); 28 | }else{ 29 | sleep(1); 30 | } 31 | $lock_ex = @fopen($lockfile, 'x'); 32 | } 33 | 34 | return ($lock_ex !== false); 35 | } 36 | 37 | function unlock(){ 38 | ignore_user_abort(0); 39 | return unlink($this->_file.'.lck'); 40 | } 41 | } 42 | ?> -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](http://secache.googlecode.com/files/secache-logo.png) 2 | 3 | This class can be used to store and retrieve cached values from single file. 4 | It can store one or more keys in a single cache file. 5 | The class can also look up for a given key and retrieve the store value. 6 | 7 | It can lock the file during access to prevent corruption, but there is also a sub-class that can be used to access the cache file without locking it. 8 | 9 | It can automatically clean-up the least recently used entries to free space 10 | 11 | # php编写的文件型缓存解决方案 12 | * 纯php实现, 无须任何扩展,支持php4 / 5 13 | * 使用lru算法自动清理过期内容 14 | * 可以安全用于多进程并发 15 | * 最大支持1G缓存文件 16 | * 使用hash定位,读取迅速 17 | 18 | [用法样例](test.php) 19 | 20 | 21 | ``` 22 | require('../secache/secache.php'); 23 | $cache = new secache; 24 | $cache->workat('cachedata'); 25 | 26 | $key = md5('test'); //必须自己做hash,前4位是16进制0-f,最长32位。 27 | $value = '值数据'; //必须是字符串 28 | 29 | $cache->store($key,$value); 30 | 31 | if($cache->fetch($key,$return)){ 32 | echo '
  • '.$key.'=>'.$return.'
  • '; 33 | }else{ 34 | echo '
  • Data get failed! '.$key.'
  • '; 35 | } 36 | ``` 37 | 38 | ## 基于性能考虑,几点约束 39 | * 键需要自己做hash处理,最长32位. 40 | * 值必须是字符串。如果要存对象,请自己serialize 41 | 42 | ## 应用的项目 43 | * [shopex购物系统](http://www.shopex.cn) 44 | 45 | 46 | [![image](http://www.phpclasses.org/award/innovation/nominee.gif)
    April 2010 Number 4](http://www.phpclasses.org/package/6078-PHP-Store-and-retrieve-cached-values-from-single-file.html) 47 | -------------------------------------------------------------------------------- /demo/test.php: -------------------------------------------------------------------------------- 1 | workat($cacheFileName); 10 | 11 | function microtime_float(){ 12 | list($usec, $sec) = explode(" ", microtime()); 13 | return ((float)$usec + (float)$sec); 14 | } 15 | 16 | $begin_time = microtime_float(); 17 | 18 | for($i=0;$i<$insertCount;$i++){ 19 | 20 | $key = md5($i); //You must *HASH* it by your self 21 | $value = 'No. '.$i.' is ok'; // must be a *STRING* 22 | 23 | $cache->store($key,$value); 24 | } 25 | 26 | echo '================='. PHP_EOL; 27 | echo 'Insert '. $insertCount. ' Count Cost: ' .( microtime_float() - $begin_time) .' ms'. PHP_EOL; 28 | echo '================='. PHP_EOL; 29 | 30 | echo 'Test read'. PHP_EOL; 31 | echo '================='. PHP_EOL; 32 | testRead($cache, $insertCount); 33 | 34 | echo '================='. PHP_EOL; 35 | echo 'Test read again'. PHP_EOL; 36 | echo '================='. PHP_EOL; 37 | 38 | unset($cache); 39 | $cache = new secache(); 40 | $cache->workat($cacheFileName); 41 | testRead($cache, $insertCount); 42 | 43 | function testRead($cache, $insertCount){ 44 | 45 | for($i=0;$i<$insertCount;$i+=200){ 46 | 47 | $key = md5($i); //You must *HASH* it by your self 48 | 49 | if($cache->fetch($key,$value)){ 50 | echo $i. '[KEY='. $key.'] DATA: '.$value. PHP_EOL; 51 | }else{ 52 | echo $i. '[KEY='. $key.'] DATA GET FAILED '. PHP_EOL; 53 | exit(); 54 | } 55 | } 56 | 57 | } -------------------------------------------------------------------------------- /secache.php: -------------------------------------------------------------------------------- 1 | _file = $file.'.php'; 36 | $this->_bsize_list = array( 37 | 512=>10, 38 | 3<<10=>10, 39 | 8<<10=>10, 40 | 20<<10=>4, 41 | 30<<10=>2, 42 | 50<<10=>2, 43 | 80<<10=>2, 44 | 96<<10=>2, 45 | 128<<10=>2, 46 | 224<<10=>2, 47 | 256<<10=>2, 48 | 512<<10=>1, 49 | 1024<<10=>1, 50 | ); 51 | 52 | $this->_node_struct = array( 53 | 'next'=>array(0,'V'), 54 | 'prev'=>array(4,'V'), 55 | 'data'=>array(8,'V'), 56 | 'size'=>array(12,'V'), 57 | 'lru_right'=>array(16,'V'), 58 | 'lru_left'=>array(20,'V'), 59 | 'key'=>array(24,'H*'), 60 | ); 61 | 62 | if(!file_exists($this->_file)){ 63 | $this->create(); 64 | }else{ 65 | $this->_rs = fopen($this->_file,'rb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR); 66 | $this->_seek($this->header_padding); 67 | $info = unpack('V1max_size/a*ver',fread($this->_rs,$this->info_size)); 68 | $info['ver'] = trim($info['ver']); 69 | if($info['ver']!=$this->ver){ 70 | $this->_format(true); 71 | }else{ 72 | $this->max_size = $info['max_size']; 73 | } 74 | } 75 | 76 | $this->idx_node_base = $this->data_base_pos+$this->max_size; 77 | $this->_block_size_list = array_keys($this->_bsize_list); 78 | sort($this->_block_size_list); 79 | return true; 80 | } 81 | 82 | function create(){ 83 | $this->_rs = fopen($this->_file,'wb+') or $this->trigger_error('Can\'t open the cachefile: '.realpath($this->_file),E_USER_ERROR);; 84 | fseek($this->_rs,0); 85 | fputs($this->_rs,'<'.'?php exit()?'.'>'); 86 | return $this->_format(); 87 | } 88 | 89 | function _puts($offset,$data){ 90 | if($offset < $this->max_size*1.5){ 91 | $this->_seek($offset); 92 | return fputs($this->_rs,$data); 93 | }else{ 94 | $this->trigger_error('Offset over quota:'.$offset,E_USER_ERROR); 95 | } 96 | } 97 | 98 | function _seek($offset){ 99 | return fseek($this->_rs,$offset); 100 | } 101 | 102 | function clear(){ 103 | return $this->_format(true); 104 | } 105 | 106 | function fetch($key,&$return){ 107 | 108 | if($this->lock(false)){ 109 | $locked = true; 110 | } 111 | 112 | if($this->search($key,$offset)){ 113 | $info = $this->_get_node($offset); 114 | $schema_id = $this->_get_size_schema_id($info['size']); 115 | if($schema_id===false){ 116 | if($locked) $this->unlock(); 117 | return false; 118 | } 119 | 120 | $this->_seek($info['data']); 121 | $data = fread($this->_rs,$info['size']); 122 | $return = unserialize($data); 123 | 124 | if($return===false){ 125 | if($locked) $this->unlock(); 126 | return false; 127 | } 128 | 129 | if($locked){ 130 | $this->_lru_push($schema_id,$info['offset']); 131 | $this->_set_schema($schema_id,'hits',$this->_get_schema($schema_id,'hits')+1); 132 | return $this->unlock(); 133 | }else{ 134 | return true; 135 | } 136 | }else{ 137 | if($locked) $this->unlock(); 138 | return false; 139 | } 140 | } 141 | 142 | /** 143 | * lock 144 | * 如果flock不管用,请继承本类,并重载此方法 145 | * 146 | * @param mixed $is_block 是否阻塞 147 | * @access public 148 | * @return void 149 | */ 150 | function lock($is_block,$whatever=false){ 151 | ignore_user_abort(1); 152 | return flock($this->_rs, $is_block?LOCK_EX:LOCK_EX+LOCK_NB); 153 | } 154 | 155 | /** 156 | * unlock 157 | * 如果flock不管用,请继承本类,并重载此方法 158 | * 159 | * @access public 160 | * @return void 161 | */ 162 | function unlock(){ 163 | ignore_user_abort(0); 164 | return flock($this->_rs, LOCK_UN); 165 | } 166 | 167 | function delete($key,$pos=false){ 168 | if($pos || $this->search($key,$pos)){ 169 | if($info = $this->_get_node($pos)){ 170 | //删除data区域 171 | if($info['prev']){ 172 | $this->_set_node($info['prev'],'next',$info['next']); 173 | $this->_set_node($info['next'],'prev',$info['prev']); 174 | }else{ //改入口位置 175 | $this->_set_node($info['next'],'prev',0); 176 | $this->_set_node_root($key,$info['next']); 177 | } 178 | $this->_free_dspace($info['size'],$info['data']); 179 | $this->_lru_delete($info); 180 | $this->_free_node($pos); 181 | return $info['prev']; 182 | } 183 | } 184 | return false; 185 | } 186 | 187 | function store($key,$value){ 188 | 189 | if($this->lock(true)){ 190 | //save data 191 | $data = serialize($value); 192 | $size = strlen($data); 193 | 194 | //get list_idx 195 | $has_key = $this->search($key,$list_idx_offset); 196 | $schema_id = $this->_get_size_schema_id($size); 197 | if($schema_id===false){ 198 | $this->unlock(); 199 | return false; 200 | } 201 | if($has_key){ 202 | $hdseq = $list_idx_offset; 203 | 204 | $info = $this->_get_node($hdseq); 205 | if($schema_id == $this->_get_size_schema_id($info['size'])){ 206 | $dataoffset = $info['data']; 207 | }else{ 208 | //破掉原有lru 209 | $this->_lru_delete($info); 210 | if(!($dataoffset = $this->_dalloc($schema_id))){ 211 | $this->unlock(); 212 | return false; 213 | } 214 | $this->_free_dspace($info['size'],$info['data']); 215 | $this->_set_node($hdseq,'lru_left',0); 216 | $this->_set_node($hdseq,'lru_right',0); 217 | } 218 | 219 | $this->_set_node($hdseq,'size',$size); 220 | $this->_set_node($hdseq,'data',$dataoffset); 221 | }else{ 222 | 223 | if(!($dataoffset = $this->_dalloc($schema_id))){ 224 | $this->unlock(); 225 | return false; 226 | } 227 | $hdseq = $this->_alloc_idx(array( 228 | 'next'=>0, 229 | 'prev'=>$list_idx_offset, 230 | 'data'=>$dataoffset, 231 | 'size'=>$size, 232 | 'lru_right'=>0, 233 | 'lru_left'=>0, 234 | 'key'=>$key, 235 | )); 236 | 237 | if($list_idx_offset>0){ 238 | $this->_set_node($list_idx_offset,'next',$hdseq); 239 | }else{ 240 | $this->_set_node_root($key,$hdseq); 241 | } 242 | } 243 | 244 | if($dataoffset>$this->max_size){ 245 | $this->trigger_error('alloc datasize:'.$dataoffset,E_USER_WARNING); 246 | return false; 247 | } 248 | $this->_puts($dataoffset,$data); 249 | 250 | $this->_set_schema($schema_id,'miss',$this->_get_schema($schema_id,'miss')+1); 251 | 252 | $this->_lru_push($schema_id,$hdseq); 253 | $this->unlock(); 254 | return true; 255 | }else{ 256 | $this->trigger_error("Couldn't lock the file !",E_USER_WARNING); 257 | return false; 258 | } 259 | 260 | } 261 | 262 | /** 263 | * search 264 | * 查找指定的key 265 | * 如果找到节点则$pos=节点本身 返回true 266 | * 否则 $pos=树的末端 返回false 267 | * 268 | * @param mixed $key 269 | * @access public 270 | * @return void 271 | */ 272 | function search($key,&$pos){ 273 | return $this->_get_pos_by_key($this->_get_node_root($key),$key,$pos); 274 | } 275 | 276 | function _get_size_schema_id($size){ 277 | foreach($this->_block_size_list as $k=>$block_size){ 278 | if($size <= $block_size){ 279 | return $k; 280 | } 281 | } 282 | return false; 283 | } 284 | 285 | function _parse_str_size($str_size,$default){ 286 | if(preg_match('/^([0-9]+)\s*([gmk]|)$/i',$str_size,$match)){ 287 | switch(strtolower($match[2])){ 288 | case 'g': 289 | if($match[1]>1){ 290 | $this->trigger_error('Max cache size 1G',E_USER_ERROR); 291 | } 292 | $size = $match[1]<<30; 293 | break; 294 | case 'm': 295 | $size = $match[1]<<20; 296 | break; 297 | case 'k': 298 | $size = $match[1]<<10; 299 | break; 300 | default: 301 | $size = $match[1]; 302 | } 303 | if($size<=0){ 304 | $this->trigger_error('Error cache size '.$this->max_size,E_USER_ERROR); 305 | return false; 306 | }elseif($size<10485760){ 307 | return 10485760; 308 | }else{ 309 | return $size; 310 | } 311 | }else{ 312 | return $default; 313 | } 314 | } 315 | 316 | 317 | function _format($truncate=false){ 318 | if($this->lock(true,true)){ 319 | 320 | if($truncate){ 321 | $this->_seek(0); 322 | ftruncate($this->_rs,$this->idx_node_base); 323 | } 324 | 325 | $this->max_size = $this->_parse_str_size(SECACHE_SIZE,15728640); //default:15m 326 | $this->_puts($this->header_padding,pack('V1a*',$this->max_size,$this->ver)); 327 | 328 | ksort($this->_bsize_list); 329 | $ds_offset = $this->data_base_pos; 330 | $i=0; 331 | foreach($this->_bsize_list as $size=>$count){ 332 | 333 | //将预分配的空间注册到free链表里 334 | $count *= min(3,floor($this->max_size/10485760)); 335 | $next_free_node = 0; 336 | for($j=0;$j<$count;$j++){ 337 | $this->_puts($ds_offset,pack('V',$next_free_node)); 338 | $next_free_node = $ds_offset; 339 | $ds_offset+=intval($size); 340 | } 341 | 342 | $code = pack(str_repeat('V1',count($this->schema_struct)),$size,$next_free_node,0,0,0,0); 343 | 344 | $this->_puts(60+$i*$this->schema_item_size,$code); 345 | $i++; 346 | } 347 | $this->_set_dcur_pos($ds_offset); 348 | 349 | $this->_puts($this->idx_base_pos,str_repeat("\0",262144)); 350 | $this->_puts($this->idx_seq_pos,pack('V',1)); 351 | $this->unlock(); 352 | return true; 353 | }else{ 354 | $this->trigger_error("Couldn't lock the file !",E_USER_ERROR); 355 | return false; 356 | } 357 | } 358 | 359 | function _get_node_root($key){ 360 | $this->_seek(hexdec(substr($key,0,4))*4+$this->idx_base_pos); 361 | $a= fread($this->_rs,4); 362 | list(,$offset) = unpack('V',$a); 363 | return $offset; 364 | } 365 | 366 | function _set_node_root($key,$value){ 367 | return $this->_puts(hexdec(substr($key,0,4))*4+$this->idx_base_pos,pack('V',$value)); 368 | } 369 | 370 | function _set_node($pos,$key,$value){ 371 | 372 | if(!$pos){ 373 | return false; 374 | } 375 | 376 | if(isset($this->_node_struct[$key])){ 377 | return $this->_puts($pos*$this->idx_node_size+$this->idx_node_base+$this->_node_struct[$key][0],pack($this->_node_struct[$key][1],$value)); 378 | }else{ 379 | return false; 380 | } 381 | } 382 | 383 | function _get_pos_by_key($offset,$key,&$pos){ 384 | if(!$offset){ 385 | $pos = 0; 386 | return false; 387 | } 388 | 389 | $info = $this->_get_node($offset); 390 | 391 | if($info['key']==$key){ 392 | $pos = $info['offset']; 393 | return true; 394 | }elseif($info['next'] && $info['next']!=$offset){ 395 | return $this->_get_pos_by_key($info['next'],$key,$pos); 396 | }else{ 397 | $pos = $offset; 398 | return false; 399 | } 400 | } 401 | 402 | function _lru_delete($info){ 403 | 404 | if($info['lru_right']){ 405 | $this->_set_node($info['lru_right'],'lru_left',$info['lru_left']); 406 | }else{ 407 | $this->_set_schema($this->_get_size_schema_id($info['size']),'lru_tail',$info['lru_left']); 408 | } 409 | 410 | if($info['lru_left']){ 411 | $this->_set_node($info['lru_left'],'lru_right',$info['lru_right']); 412 | }else{ 413 | $this->_set_schema($this->_get_size_schema_id($info['size']),'lru_head',$info['lru_right']); 414 | } 415 | 416 | return true; 417 | } 418 | 419 | function _lru_push($schema_id,$offset){ 420 | $lru_head = $this->_get_schema($schema_id,'lru_head'); 421 | $lru_tail = $this->_get_schema($schema_id,'lru_tail'); 422 | 423 | if((!$offset) || ($lru_head==$offset))return; 424 | 425 | $info = $this->_get_node($offset); 426 | 427 | $this->_set_node($info['lru_right'],'lru_left',$info['lru_left']); 428 | $this->_set_node($info['lru_left'],'lru_right',$info['lru_right']); 429 | 430 | $this->_set_node($offset,'lru_right',$lru_head); 431 | $this->_set_node($offset,'lru_left',0); 432 | 433 | $this->_set_node($lru_head,'lru_left',$offset); 434 | $this->_set_schema($schema_id,'lru_head',$offset); 435 | 436 | if($lru_tail==0){ 437 | $this->_set_schema($schema_id,'lru_tail',$offset); 438 | }elseif($lru_tail==$offset && $info['lru_left']){ 439 | $this->_set_schema($schema_id,'lru_tail',$info['lru_left']); 440 | } 441 | return true; 442 | } 443 | 444 | function _get_node($offset){ 445 | $this->_seek($offset*$this->idx_node_size + $this->idx_node_base); 446 | $info = unpack('V1next/V1prev/V1data/V1size/V1lru_right/V1lru_left/H*key',fread($this->_rs,$this->idx_node_size)); 447 | $info['offset'] = $offset; 448 | return $info; 449 | } 450 | 451 | function _lru_pop($schema_id){ 452 | if($node = $this->_get_schema($schema_id,'lru_tail')){ 453 | $info = $this->_get_node($node); 454 | if(!$info['data']){ 455 | return false; 456 | } 457 | $this->delete($info['key'],$info['offset']); 458 | if(!$this->_get_schema($schema_id,'free')){ 459 | $this->trigger_error('pop lru,But nothing free...',E_USER_ERROR); 460 | } 461 | return $info; 462 | }else{ 463 | return false; 464 | } 465 | } 466 | 467 | function _dalloc($schema_id,$lru_freed=false){ 468 | 469 | if($free = $this->_get_schema($schema_id,'free')){ //如果lru里有链表 470 | $this->_seek($free); 471 | list(,$next) = unpack('V',fread($this->_rs,4)); 472 | $this->_set_schema($schema_id,'free',$next); 473 | return $free; 474 | }elseif($lru_freed){ 475 | $this->trigger_error('Bat lru poped freesize',E_USER_ERROR); 476 | return false; 477 | }else{ 478 | $ds_offset = $this->_get_dcur_pos(); 479 | $size = $this->_get_schema($schema_id,'size'); 480 | 481 | if($size+$ds_offset > $this->max_size){ 482 | if($info = $this->_lru_pop($schema_id)){ 483 | return $this->_dalloc($schema_id,$info); 484 | }else{ 485 | $this->trigger_error('Can\'t alloc dataspace',E_USER_ERROR); 486 | return false; 487 | } 488 | }else{ 489 | $this->_set_dcur_pos($ds_offset+$size); 490 | return $ds_offset; 491 | } 492 | } 493 | } 494 | 495 | function _get_dcur_pos(){ 496 | $this->_seek($this->dfile_cur_pos); 497 | list(,$ds_offset) = unpack('V',fread($this->_rs,4)); 498 | return $ds_offset; 499 | } 500 | function _set_dcur_pos($pos){ 501 | return $this->_puts($this->dfile_cur_pos,pack('V',$pos)); 502 | } 503 | 504 | function _free_dspace($size,$pos){ 505 | 506 | if($pos>$this->max_size){ 507 | $this->trigger_error('free dspace over quota:'.$pos,E_USER_ERROR); 508 | return false; 509 | } 510 | 511 | $schema_id = $this->_get_size_schema_id($size); 512 | if($free = $this->_get_schema($schema_id,'free')){ 513 | $this->_puts($free,pack('V1',$pos)); 514 | }else{ 515 | $this->_set_schema($schema_id,'free',$pos); 516 | } 517 | $this->_puts($pos,pack('V1',0)); 518 | } 519 | 520 | function _dfollow($pos,&$c){ 521 | $c++; 522 | $this->_seek($pos); 523 | list(,$next) = unpack('V1',fread($this->_rs,4)); 524 | if($next){ 525 | return $this->_dfollow($next,$c); 526 | }else{ 527 | return $pos; 528 | } 529 | } 530 | 531 | function _free_node($pos){ 532 | $this->_seek($this->idx_free_pos); 533 | list(,$prev_free_node) = unpack('V',fread($this->_rs,4)); 534 | $this->_puts($pos*$this->idx_node_size+$this->idx_node_base,pack('V',$prev_free_node).str_repeat("\0",$this->idx_node_size-4)); 535 | return $this->_puts($this->idx_free_pos,pack('V',$pos)); 536 | } 537 | 538 | function _alloc_idx($data){ 539 | $this->_seek($this->idx_free_pos); 540 | list(,$list_pos) = unpack('V',fread($this->_rs,4)); 541 | if($list_pos){ 542 | 543 | $this->_seek($list_pos*$this->idx_node_size+$this->idx_node_base); 544 | list(,$prev_free_node) = unpack('V',fread($this->_rs,4)); 545 | $this->_puts($this->idx_free_pos,pack('V',$prev_free_node)); 546 | 547 | }else{ 548 | $this->_seek($this->idx_seq_pos); 549 | list(,$list_pos) = unpack('V',fread($this->_rs,4)); 550 | $this->_puts($this->idx_seq_pos,pack('V',$list_pos+1)); 551 | } 552 | return $this->_create_node($list_pos,$data); 553 | } 554 | 555 | function _create_node($pos,$data){ 556 | $this->_puts($pos*$this->idx_node_size + $this->idx_node_base 557 | ,pack('V1V1V1V1V1V1H*',$data['next'],$data['prev'],$data['data'],$data['size'],$data['lru_right'],$data['lru_left'],$data['key'])); 558 | return $pos; 559 | } 560 | 561 | function _set_schema($schema_id,$key,$value){ 562 | $info = array_flip($this->schema_struct); 563 | return $this->_puts(60+$schema_id*$this->schema_item_size + $info[$key]*4,pack('V',$value)); 564 | } 565 | 566 | function _get_schema($id,$key){ 567 | $info = array_flip($this->schema_struct); 568 | 569 | $this->_seek(60+$id*$this->schema_item_size); 570 | unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size)); 571 | 572 | $this->_seek(60+$id*$this->schema_item_size + $info[$key]*4); 573 | list(,$value) =unpack('V',fread($this->_rs,4)); 574 | return $value; 575 | } 576 | 577 | function _all_schemas(){ 578 | $schema = array(); 579 | for($i=0;$i<16;$i++){ 580 | $this->_seek(60+$i*$this->schema_item_size); 581 | $info = unpack('V1'.implode('/V1',$this->schema_struct),fread($this->_rs,$this->schema_item_size)); 582 | if($info['size']){ 583 | $info['id'] = $i; 584 | $schema[$i] = $info; 585 | }else{ 586 | return $schema; 587 | } 588 | } 589 | } 590 | 591 | function schemaStatus(){ 592 | $return = array(); 593 | foreach($this->_all_schemas() as $k=>$schemaItem){ 594 | if($schemaItem['free']){ 595 | $this->_dfollow($schemaItem['free'],$schemaItem['freecount']); 596 | } 597 | $return[] = $schemaItem; 598 | } 599 | return $return; 600 | } 601 | 602 | function status(&$curBytes,&$totalBytes){ 603 | $totalBytes = $curBytes = 0; 604 | $hits = $miss = 0; 605 | 606 | $schemaStatus = $this->schemaStatus(); 607 | $totalBytes = $this->max_size; 608 | $freeBytes = $this->max_size - $this->_get_dcur_pos(); 609 | 610 | foreach($schemaStatus as $schema){ 611 | $freeBytes+=$schema['freecount']*$schema['size']; 612 | $miss += $schema['miss']; 613 | $hits += $schema['hits']; 614 | } 615 | $curBytes = $totalBytes-$freeBytes; 616 | 617 | $return[] = array('name'=>'缓存命中','value'=>$hits); 618 | $return[] = array('name'=>'缓存未命中','value'=>$miss); 619 | return $return; 620 | } 621 | 622 | function trigger_error($errstr,$errno){ 623 | trigger_error($errstr,$errno); 624 | } 625 | 626 | } 627 | ?> 628 | --------------------------------------------------------------------------------