├── 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 | 
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 | [
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 |
--------------------------------------------------------------------------------