├── .gitmodules ├── Cm └── Cache │ └── Backend │ └── Redis.php ├── README.md ├── rediscache.php └── rediscli.php /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/Credis"] 2 | path = lib/Credis 3 | url = git://github.com/colinmollenhour/credis.git 4 | -------------------------------------------------------------------------------- /Cm/Cache/Backend/Redis.php: -------------------------------------------------------------------------------- 1 | _redis = new Credis_Client($options['server'], $options['port'], $timeout, $persistent); 97 | 98 | if ( isset($options['force_standalone']) && $options['force_standalone']) { 99 | $this->_redis->forceStandalone(); 100 | } 101 | 102 | $connectRetries = isset($options['connect_retries']) ? (int)$options['connect_retries'] : self::DEFAULT_CONNECT_RETRIES; 103 | $this->_redis->setMaxConnectRetries($connectRetries); 104 | 105 | if ( ! empty($options['read_timeout']) && $options['read_timeout'] > 0) { 106 | $this->_redis->setReadTimeout((float) $options['read_timeout']); 107 | } 108 | 109 | if ( ! empty($options['password'])) { 110 | $this->_redis->auth($options['password']) or Zend_Cache::throwException('Unable to authenticate with the redis server.'); 111 | } 112 | 113 | // Always select database on startup in case persistent connection is re-used by other code 114 | if (empty($options['database'])) { 115 | $options['database'] = 0; 116 | } 117 | $this->_redis->select( (int) $options['database']) or Zend_Cache::throwException('The redis database could not be selected.'); 118 | 119 | if ( isset($options['notMatchingTags']) ) { 120 | $this->_notMatchingTags = (bool) $options['notMatchingTags']; 121 | } 122 | 123 | if ( isset($options['compress_tags'])) { 124 | $this->_compressTags = (int) $options['compress_tags']; 125 | } 126 | 127 | if ( isset($options['compress_data'])) { 128 | $this->_compressData = (int) $options['compress_data']; 129 | } 130 | 131 | if ( isset($options['lifetimelimit'])) { 132 | $this->_lifetimelimit = (int) min($options['lifetimelimit'], self::MAX_LIFETIME); 133 | } 134 | 135 | if ( isset($options['compress_threshold'])) { 136 | $this->_compressThreshold = (int) $options['compress_threshold']; 137 | } 138 | 139 | if ( isset($options['automatic_cleaning_factor']) ) { 140 | $this->_options['automatic_cleaning_factor'] = (int) $options['automatic_cleaning_factor']; 141 | } else { 142 | $this->_options['automatic_cleaning_factor'] = 0; 143 | } 144 | 145 | if ( isset($options['compression_lib']) ) { 146 | $this->_compressionLib = $options['compression_lib']; 147 | } 148 | else if ( function_exists('snappy_compress') ) { 149 | $this->_compressionLib = 'snappy'; 150 | } 151 | else if ( function_exists('lzf_compress') ) { 152 | $this->_compressionLib = 'lzf'; 153 | } 154 | else { 155 | $this->_compressionLib = 'gzip'; 156 | } 157 | $this->_compressPrefix = substr($this->_compressionLib,0,2).self::COMPRESS_PREFIX; 158 | } 159 | 160 | /** 161 | * Load value with given id from cache 162 | * 163 | * @param string $id Cache id 164 | * @param boolean $doNotTestCacheValidity If set to true, the cache validity won't be tested 165 | * @return bool|string 166 | */ 167 | public function load($id, $doNotTestCacheValidity = false) 168 | { 169 | $data = $this->_redis->hGet(self::PREFIX_KEY.$id, self::FIELD_DATA); 170 | if ($data === NULL) { 171 | return FALSE; 172 | } 173 | return $this->_decodeData($data); 174 | } 175 | 176 | /** 177 | * Test if a cache is available or not (for the given id) 178 | * 179 | * @param string $id Cache id 180 | * @return bool|int False if record is not available or "last modified" timestamp of the available cache record 181 | */ 182 | public function test($id) 183 | { 184 | $mtime = $this->_redis->hGet(self::PREFIX_KEY.$id, self::FIELD_MTIME); 185 | return ($mtime ? $mtime : FALSE); 186 | } 187 | 188 | /** 189 | * Save some string datas into a cache record 190 | * 191 | * Note : $data is always "string" (serialization is done by the 192 | * core not by the backend) 193 | * 194 | * @param string $data Datas to cache 195 | * @param string $id Cache id 196 | * @param array $tags Array of strings, the cache record will be tagged by each string entry 197 | * @param bool|int $specificLifetime If != false, set a specific lifetime for this cache record (null => infinite lifetime) 198 | * @throws CredisException 199 | * @return boolean True if no problem 200 | */ 201 | public function save($data, $id, $tags = array(), $specificLifetime = false) 202 | { 203 | if ( ! is_array($tags)) $tags = $tags ? array($tags) : array(); 204 | 205 | $lifetime = $this->getLifetime($specificLifetime); 206 | 207 | // Get list of tags previously assigned 208 | $oldTags = $this->_decodeData($this->_redis->hGet(self::PREFIX_KEY.$id, self::FIELD_TAGS)); 209 | $oldTags = $oldTags ? explode(',', $oldTags) : array(); 210 | 211 | $this->_redis->pipeline()->multi(); 212 | 213 | // Set the data 214 | $result = $this->_redis->hMSet(self::PREFIX_KEY.$id, array( 215 | self::FIELD_DATA => $this->_encodeData($data, $this->_compressData), 216 | self::FIELD_TAGS => $this->_encodeData(implode(',',$tags), $this->_compressTags), 217 | self::FIELD_MTIME => time(), 218 | self::FIELD_INF => $lifetime ? 0 : 1, 219 | )); 220 | if( ! $result) { 221 | throw new CredisException("Could not set cache key $id"); 222 | } 223 | 224 | // Set expiration if specified 225 | if ($lifetime) { 226 | $this->_redis->expire(self::PREFIX_KEY.$id, min($lifetime, self::MAX_LIFETIME)); 227 | } 228 | 229 | // Process added tags 230 | if ($tags) 231 | { 232 | // Update the list with all the tags 233 | $this->_redis->sAdd( self::SET_TAGS, $tags); 234 | 235 | // Update the id list for each tag 236 | foreach($tags as $tag) 237 | { 238 | $this->_redis->sAdd(self::PREFIX_TAG_IDS . $tag, $id); 239 | } 240 | } 241 | 242 | // Process removed tags 243 | if ($remTags = ($oldTags ? array_diff($oldTags, $tags) : FALSE)) 244 | { 245 | // Update the id list for each tag 246 | foreach($remTags as $tag) 247 | { 248 | $this->_redis->sRem(self::PREFIX_TAG_IDS . $tag, $id); 249 | } 250 | } 251 | 252 | // Update the list with all the ids 253 | if($this->_notMatchingTags) { 254 | $this->_redis->sAdd(self::SET_IDS, $id); 255 | } 256 | 257 | $this->_redis->exec(); 258 | 259 | return TRUE; 260 | } 261 | 262 | /** 263 | * Remove a cache record 264 | * 265 | * @param string $id Cache id 266 | * @return boolean True if no problem 267 | */ 268 | public function remove($id) 269 | { 270 | // Get list of tags for this id 271 | $tags = explode(',', $this->_decodeData($this->_redis->hGet(self::PREFIX_KEY.$id, self::FIELD_TAGS))); 272 | 273 | $this->_redis->pipeline()->multi(); 274 | 275 | // Remove data 276 | $this->_redis->del(self::PREFIX_KEY.$id); 277 | 278 | // Remove id from list of all ids 279 | if($this->_notMatchingTags) { 280 | $this->_redis->sRem( self::SET_IDS, $id ); 281 | } 282 | 283 | // Update the id list for each tag 284 | foreach($tags as $tag) { 285 | $this->_redis->sRem(self::PREFIX_TAG_IDS . $tag, $id); 286 | } 287 | 288 | $result = $this->_redis->exec(); 289 | 290 | return (bool) $result[0]; 291 | } 292 | 293 | /** 294 | * @param array $tags 295 | */ 296 | protected function _removeByNotMatchingTags($tags) 297 | { 298 | $ids = $this->getIdsNotMatchingTags($tags); 299 | if($ids) 300 | { 301 | $this->_redis->pipeline()->multi(); 302 | 303 | // Remove data 304 | $this->_redis->del( $this->_preprocessIds($ids)); 305 | 306 | // Remove ids from list of all ids 307 | if($this->_notMatchingTags) { 308 | $this->_redis->sRem( self::SET_IDS, $ids); 309 | } 310 | 311 | $this->_redis->exec(); 312 | } 313 | } 314 | 315 | /** 316 | * @param array $tags 317 | */ 318 | protected function _removeByMatchingTags($tags) 319 | { 320 | $ids = $this->getIdsMatchingTags($tags); 321 | if($ids) 322 | { 323 | $this->_redis->pipeline()->multi(); 324 | 325 | // Remove data 326 | $this->_redis->del( $this->_preprocessIds($ids)); 327 | 328 | // Remove ids from list of all ids 329 | if($this->_notMatchingTags) { 330 | $this->_redis->sRem( self::SET_IDS, $ids); 331 | } 332 | 333 | $this->_redis->exec(); 334 | } 335 | } 336 | 337 | /** 338 | * @param array $tags 339 | */ 340 | protected function _removeByMatchingAnyTags($tags) 341 | { 342 | $ids = $this->getIdsMatchingAnyTags($tags); 343 | 344 | $this->_redis->pipeline()->multi(); 345 | 346 | if($ids) 347 | { 348 | // Remove data 349 | $this->_redis->del( $this->_preprocessIds($ids)); 350 | 351 | // Remove ids from list of all ids 352 | if($this->_notMatchingTags) { 353 | $this->_redis->sRem( self::SET_IDS, $ids); 354 | } 355 | } 356 | 357 | // Remove tag id lists 358 | $this->_redis->del( $this->_preprocessTagIds($tags)); 359 | 360 | // Remove tags from list of tags 361 | $this->_redis->sRem( self::SET_TAGS, $tags); 362 | 363 | $this->_redis->exec(); 364 | } 365 | 366 | /** 367 | * Clean up tag id lists since as keys expire the ids remain in the tag id lists 368 | */ 369 | protected function _collectGarbage() 370 | { 371 | // Clean up expired keys from tag id set and global id set 372 | $exists = array(); 373 | $tags = (array) $this->_redis->sMembers(self::SET_TAGS); 374 | foreach($tags as $tag) 375 | { 376 | // Get list of expired ids for each tag 377 | $tagMembers = $this->_redis->sMembers(self::PREFIX_TAG_IDS . $tag); 378 | $numTagMembers = count($tagMembers); 379 | $expired = array(); 380 | $numExpired = $numNotExpired = 0; 381 | if($numTagMembers) { 382 | while ($id = array_pop($tagMembers)) { 383 | if( ! isset($exists[$id])) { 384 | $exists[$id] = $this->_redis->exists(self::PREFIX_KEY.$id); 385 | } 386 | if ($exists[$id]) { 387 | $numNotExpired++; 388 | } 389 | else { 390 | $numExpired++; 391 | $expired[] = $id; 392 | 393 | // Remove incrementally to reduce memory usage 394 | if (count($expired) % 100 == 0 && $numNotExpired > 0) { 395 | $this->_redis->sRem( self::PREFIX_TAG_IDS . $tag, $expired); 396 | if($this->_notMatchingTags) { // Clean up expired ids from ids set 397 | $this->_redis->sRem( self::SET_IDS, $expired); 398 | } 399 | $expired = array(); 400 | } 401 | } 402 | } 403 | if( ! count($expired)) continue; 404 | } 405 | 406 | // Remove empty tags or completely expired tags 407 | if ($numExpired == $numTagMembers) { 408 | $this->_redis->del(self::PREFIX_TAG_IDS . $tag); 409 | $this->_redis->sRem(self::SET_TAGS, $tag); 410 | } 411 | // Clean up expired ids from tag ids set 412 | else if (count($expired)) { 413 | $this->_redis->sRem( self::PREFIX_TAG_IDS . $tag, $expired); 414 | if($this->_notMatchingTags) { // Clean up expired ids from ids set 415 | $this->_redis->sRem( self::SET_IDS, $expired); 416 | } 417 | } 418 | unset($expired); 419 | } 420 | 421 | // Clean up global list of ids for ids with no tag 422 | if($this->_notMatchingTags) { 423 | // TODO 424 | } 425 | } 426 | 427 | /** 428 | * Clean some cache records 429 | * 430 | * Available modes are : 431 | * 'all' (default) => remove all cache entries ($tags is not used) 432 | * 'old' => runs _collectGarbage() 433 | * 'matchingTag' => supported 434 | * 'notMatchingTag' => supported 435 | * 'matchingAnyTag' => supported 436 | * 437 | * @param string $mode Clean mode 438 | * @param array $tags Array of tags 439 | * @throws Zend_Cache_Exception 440 | * @return boolean True if no problem 441 | */ 442 | public function clean($mode = Zend_Cache::CLEANING_MODE_ALL, $tags = array()) 443 | { 444 | if( $tags && ! is_array($tags)) { 445 | $tags = array($tags); 446 | } 447 | 448 | if($mode == Zend_Cache::CLEANING_MODE_ALL) { 449 | return $this->_redis->flushDb(); 450 | } 451 | 452 | if($mode == Zend_Cache::CLEANING_MODE_OLD) { 453 | $this->_collectGarbage(); 454 | return TRUE; 455 | } 456 | 457 | if( ! count($tags)) { 458 | return TRUE; 459 | } 460 | 461 | $result = TRUE; 462 | 463 | switch ($mode) 464 | { 465 | case Zend_Cache::CLEANING_MODE_MATCHING_TAG: 466 | 467 | $this->_removeByMatchingTags($tags); 468 | break; 469 | 470 | case Zend_Cache::CLEANING_MODE_NOT_MATCHING_TAG: 471 | 472 | $this->_removeByNotMatchingTags($tags); 473 | break; 474 | 475 | case Zend_Cache::CLEANING_MODE_MATCHING_ANY_TAG: 476 | 477 | $this->_removeByMatchingAnyTags($tags); 478 | break; 479 | 480 | default: 481 | Zend_Cache::throwException('Invalid mode for clean() method: '.$mode); 482 | } 483 | return (bool) $result; 484 | } 485 | 486 | /** 487 | * Return true if the automatic cleaning is available for the backend 488 | * 489 | * @return boolean 490 | */ 491 | public function isAutomaticCleaningAvailable() 492 | { 493 | return TRUE; 494 | } 495 | 496 | /** 497 | * Set the frontend directives 498 | * 499 | * @param array $directives Assoc of directives 500 | * @throws Zend_Cache_Exception 501 | * @return void 502 | */ 503 | public function setDirectives($directives) 504 | { 505 | parent::setDirectives($directives); 506 | $lifetime = $this->getLifetime(false); 507 | if ($lifetime > self::MAX_LIFETIME) { 508 | Zend_Cache::throwException('Redis backend has a limit of 30 days (2592000 seconds) for the lifetime'); 509 | } 510 | } 511 | 512 | /** 513 | * Return an array of stored cache ids 514 | * 515 | * @return array array of stored cache ids (string) 516 | */ 517 | public function getIds() 518 | { 519 | if($this->_notMatchingTags) { 520 | return (array) $this->_redis->sMembers(self::SET_IDS); 521 | } else { 522 | $keys = $this->_redis->keys(self::PREFIX_KEY . '*'); 523 | $prefixLen = strlen(self::PREFIX_KEY); 524 | foreach($keys as $index => $key) { 525 | $keys[$index] = substr($key, $prefixLen); 526 | } 527 | return $keys; 528 | } 529 | } 530 | 531 | /** 532 | * Return an array of stored tags 533 | * 534 | * @return array array of stored tags (string) 535 | */ 536 | public function getTags() 537 | { 538 | return (array) $this->_redis->sMembers(self::SET_TAGS); 539 | } 540 | 541 | /** 542 | * Return an array of stored cache ids which match given tags 543 | * 544 | * In case of multiple tags, a logical AND is made between tags 545 | * 546 | * @param array $tags array of tags 547 | * @return array array of matching cache ids (string) 548 | */ 549 | public function getIdsMatchingTags($tags = array()) 550 | { 551 | if ($tags) { 552 | return (array) $this->_redis->sInter( $this->_preprocessTagIds($tags) ); 553 | } 554 | return array(); 555 | } 556 | 557 | /** 558 | * Return an array of stored cache ids which don't match given tags 559 | * 560 | * In case of multiple tags, a negated logical AND is made between tags 561 | * 562 | * @param array $tags array of tags 563 | * @return array array of not matching cache ids (string) 564 | */ 565 | public function getIdsNotMatchingTags($tags = array()) 566 | { 567 | if( ! $this->_notMatchingTags) { 568 | Zend_Cache::throwException("notMatchingTags is currently disabled."); 569 | } 570 | if ($tags) { 571 | return (array) $this->_redis->sDiff( self::SET_IDS, $this->_preprocessTagIds($tags) ); 572 | } 573 | return (array) $this->_redis->sMembers( self::SET_IDS ); 574 | } 575 | 576 | /** 577 | * Return an array of stored cache ids which match any given tags 578 | * 579 | * In case of multiple tags, a logical OR is made between tags 580 | * 581 | * @param array $tags array of tags 582 | * @return array array of any matching cache ids (string) 583 | */ 584 | public function getIdsMatchingAnyTags($tags = array()) 585 | { 586 | if ($tags) { 587 | return (array) $this->_redis->sUnion( $this->_preprocessTagIds($tags)); 588 | } 589 | return array(); 590 | } 591 | 592 | /** 593 | * Return the filling percentage of the backend storage 594 | * 595 | * @throws Zend_Cache_Exception 596 | * @return int integer between 0 and 100 597 | */ 598 | public function getFillingPercentage() 599 | { 600 | return 0; 601 | } 602 | 603 | /** 604 | * Return an array of metadatas for the given cache id 605 | * 606 | * The array must include these keys : 607 | * - expire : the expire timestamp 608 | * - tags : a string array of tags 609 | * - mtime : timestamp of last modification time 610 | * 611 | * @param string $id cache id 612 | * @return array array of metadatas (false if the cache id is not found) 613 | */ 614 | public function getMetadatas($id) 615 | { 616 | list($tags, $mtime, $inf) = $this->_redis->hMGet(self::PREFIX_KEY.$id, array(self::FIELD_TAGS, self::FIELD_MTIME, self::FIELD_INF)); 617 | if( ! $mtime) { 618 | return FALSE; 619 | } 620 | $tags = explode(',', $this->_decodeData($tags)); 621 | $expire = $inf === '1' ? FALSE : time() + $this->_redis->ttl(self::PREFIX_KEY.$id); 622 | 623 | return array( 624 | 'expire' => $expire, 625 | 'tags' => $tags, 626 | 'mtime' => $mtime, 627 | ); 628 | } 629 | 630 | /** 631 | * Give (if possible) an extra lifetime to the given cache id 632 | * 633 | * @param string $id cache id 634 | * @param int $extraLifetime 635 | * @return boolean true if ok 636 | */ 637 | public function touch($id, $extraLifetime) 638 | { 639 | list($inf) = $this->_redis->hGet(self::PREFIX_KEY.$id, self::FIELD_INF); 640 | if ($inf === '0') { 641 | $expireAt = time() + $this->_redis->ttl(self::PREFIX_KEY.$id) + $extraLifetime; 642 | return (bool) $this->_redis->expireAt(self::PREFIX_KEY.$id, $expireAt); 643 | } 644 | return false; 645 | } 646 | 647 | /** 648 | * Return an associative array of capabilities (booleans) of the backend 649 | * 650 | * The array must include these keys : 651 | * - automatic_cleaning (is automating cleaning necessary) 652 | * - tags (are tags supported) 653 | * - expired_read (is it possible to read expired cache records 654 | * (for doNotTestCacheValidity option for example)) 655 | * - priority does the backend deal with priority when saving 656 | * - infinite_lifetime (is infinite lifetime can work with this backend) 657 | * - get_list (is it possible to get the list of cache ids and the complete list of tags) 658 | * 659 | * @return array associative of with capabilities 660 | */ 661 | public function getCapabilities() 662 | { 663 | return array( 664 | 'automatic_cleaning' => ($this->_options['automatic_cleaning_factor'] > 0), 665 | 'tags' => true, 666 | 'expired_read' => false, 667 | 'priority' => false, 668 | 'infinite_lifetime' => true, 669 | 'get_list' => true, 670 | ); 671 | } 672 | 673 | /** 674 | * @param string $data 675 | * @param int $level 676 | * @throws CredisException 677 | * @return string 678 | */ 679 | protected function _encodeData($data, $level) 680 | { 681 | if ($level && strlen($data) >= $this->_compressThreshold) { 682 | switch($this->_compressionLib) { 683 | case 'snappy': $data = snappy_compress($data); break; 684 | case 'lzf': $data = lzf_compress($data); break; 685 | case 'gzip': $data = gzcompress($data, $level); break; 686 | } 687 | if( ! $data) { 688 | throw new CredisException("Could not compress cache data."); 689 | } 690 | return $this->_compressPrefix.$data; 691 | } 692 | return $data; 693 | } 694 | 695 | /** 696 | * @param bool|string $data 697 | * @return string 698 | */ 699 | protected function _decodeData($data) 700 | { 701 | if (substr($data,2,3) == self::COMPRESS_PREFIX) { 702 | switch(substr($data,0,2)) { 703 | case 'sn': return snappy_uncompress(substr($data,5)); 704 | case 'lz': return lzf_decompress(substr($data,5)); 705 | case 'gz': case 'zc': return gzuncompress(substr($data,5)); 706 | } 707 | } 708 | return $data; 709 | } 710 | 711 | /** 712 | * @param $item 713 | * @param $index 714 | * @param $prefix 715 | */ 716 | protected function _preprocess(&$item, $index, $prefix) 717 | { 718 | $item = $prefix . $item; 719 | } 720 | 721 | /** 722 | * @param $ids 723 | * @return array 724 | */ 725 | protected function _preprocessIds($ids) 726 | { 727 | array_walk($ids, array($this, '_preprocess'), self::PREFIX_KEY); 728 | return $ids; 729 | } 730 | 731 | /** 732 | * @param $tags 733 | * @return array 734 | */ 735 | protected function _preprocessTagIds($tags) 736 | { 737 | array_walk($tags, array($this, '_preprocess'), self::PREFIX_TAG_IDS); 738 | return $tags; 739 | } 740 | 741 | /** 742 | * Required to pass unit tests 743 | * 744 | * @param string $id 745 | * @return void 746 | */ 747 | public function ___expire($id) 748 | { 749 | $this->_redis->del(self::PREFIX_KEY.$id); 750 | } 751 | 752 | } 753 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tool to cleanup redis tags from cron 2 | ==================================== 3 | 4 | rediscli.php 5 | ------------ 6 | cleaning tags using Redis cache backend 7 | (https://github.com/colinmollenhour/Cm_Cache_Backend_Redis). 8 | 9 | Usage: rediscli.php 10 | -s - server address 11 | -p - server port 12 | -v - show process status 13 | -d - list of the databases, comma separated 14 | Example: rediscli.php -s 127.0.0.1 -p 6379 -d 0,1 15 | 16 | rediscache.php 17 | ------------- 18 | shows "map" of the cache interactively. "." indicates non-empty tag and + 19 | empty. 20 | -------------------------------------------------------------------------------- /rediscache.php: -------------------------------------------------------------------------------- 1 | connect('127.0.0.1', 6379); 7 | $redis->select(1); // select FPC 8 | 9 | 10 | $tags=$redis->sMembers(SET_TAGS); 11 | $tags_count=count($tags); 12 | $empty_tags_count=0; 13 | $slowttl=0; 14 | foreach($tags as $tag) 15 | { 16 | $tag="zc:ti:".$tag; 17 | $tag_members=$redis->sMembers($tag); 18 | $members_count=0; 19 | foreach($tag_members as $tag_member) { 20 | if($redis->exists("zc:k:".$tag_member)) { 21 | $members_count++; 22 | //$ttl=$redis->ttl("zc:k:".$tag_member); 23 | //if($ttl>43200) $slowttl++; 24 | } 25 | else { 26 | // $ttl=$redis->ttl("zc:k:".$tag_member); 27 | // echo $ttl."\n"; 28 | // echo "zc:k:".$tag_member."\n"; 29 | } 30 | // sleep(0.01); // dont kill the server 31 | } 32 | if($members_count == 0) { 33 | echo "+"; 34 | $empty_tags_count++; 35 | } 36 | else { 37 | echo "."; 38 | } 39 | } 40 | 41 | print "Tags count: $tags_count, empty tags count: $empty_tags_count, slowttl=$slowttl\n"; 42 | 43 | ?> -------------------------------------------------------------------------------- /rediscli.php: -------------------------------------------------------------------------------- 1 | - server address\n". 27 | "\t-p - server port\n". 28 | "\t-v show status messages\n". 29 | "\t-d - list of the databases, comma separated\n". 30 | "\t-a - The Redis password\n". 31 | "Example: rediscli.php -s 127.0.0.1 -p 6379 -d 0,1\n\n"; 32 | exit(0); 33 | } 34 | /* parsing command line options */ 35 | $opts = "s:a:p:vd:"; 36 | $options = getopt($opts); 37 | if(!isset($options["s"]) || !isset($options["p"]) || !isset($options["d"])) { 38 | showHelp(); 39 | } 40 | $databases=preg_split('/,/',$options["d"]); 41 | 42 | foreach($databases as $db) { 43 | $db = (int) $db; 44 | if(isset($options["v"])) 45 | echo "Cleaning database $db:"; 46 | 47 | 48 | try { 49 | // Check if we have a password 50 | if(isset($options['a'])) 51 | $cache = new Cm_Cache_Backend_Redis(array('server' => $options["s"], 'port' => $options["p"], 'database' => $db, 'password' => $options["a"])); 52 | else 53 | $cache = new Cm_Cache_Backend_Redis(array('server' => $options["s"], 'port' => $options["p"], 'database' => $db)); 54 | } catch (CredisException $e) { 55 | echo "\nError: ".$e->getMessage()."\n"; 56 | exit(1); 57 | } 58 | 59 | 60 | if($cache === false ){ 61 | echo "\nERROR: Unable to clean database $db\n"; 62 | } 63 | try { 64 | $cache->clean(Zend_Cache::CLEANING_MODE_OLD); 65 | } catch (CredisException $e) { 66 | echo "\nError: ".$e->getMessage()."\n"; 67 | exit(1); 68 | } 69 | 70 | if(isset($options["v"])) 71 | echo " [done]\n"; 72 | unset($cache); 73 | } 74 | 75 | ?> 76 | --------------------------------------------------------------------------------