MediaWiki  REL1_24
BloomCache.php
Go to the documentation of this file.
00001 <?php
00027 abstract class BloomCache {
00029     protected $cacheID;
00030 
00032     protected static $instances = array();
00033 
00038     final public static function get( $id ) {
00039         global $wgBloomFilterStores;
00040 
00041         if ( !isset( self::$instances[$id] ) ) {
00042             if ( isset( $wgBloomFilterStores[$id] ) ) {
00043                 $class = $wgBloomFilterStores[$id]['class'];
00044                 self::$instances[$id] = new $class( $wgBloomFilterStores[$id] );
00045             } else {
00046                 wfDebug( "No bloom filter store '$id'; using EmptyBloomCache." );
00047                 return new EmptyBloomCache( array() );
00048             }
00049         }
00050 
00051         return self::$instances[$id];
00052     }
00053 
00064     public function __construct( array $config ) {
00065         $this->cacheID = $config['cacheId'];
00066         if ( !preg_match( '!^[a-zA-Z0-9-_]{1,32}$!', $this->cacheID ) ) {
00067             throw new MWException( "Cache ID '{$this->cacheID}' is invalid." );
00068         }
00069     }
00070 
00095     final public function check( $domain, $type, $member ) {
00096         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00097 
00098         if ( method_exists( "BloomFilter{$type}", 'mergeAndCheck' ) ) {
00099             try {
00100                 $virtualKey = "$domain:$type";
00101 
00102                 $status = $this->getStatus( $virtualKey );
00103                 if ( $status == false ) {
00104                     wfDebug( "Could not query virtual bloom filter '$virtualKey'." );
00105                     return null;
00106                 }
00107 
00108                 $useFilter = call_user_func_array(
00109                     array( "BloomFilter{$type}", 'mergeAndCheck' ),
00110                     array( $this, $domain, $virtualKey, $status )
00111                 );
00112 
00113                 if ( $useFilter ) {
00114                     return ( $this->isHit( 'shared', "$virtualKey:$member" ) !== false );
00115                 }
00116             } catch ( MWException $e ) {
00117                 MWExceptionHandler::logException( $e );
00118                 return true;
00119             }
00120         }
00121 
00122         return true;
00123     }
00124 
00133     final public function insert( $domain, $type, $members ) {
00134         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00135 
00136         if ( method_exists( "BloomFilter{$type}", 'mergeAndCheck' ) ) {
00137             try {
00138                 $virtualKey = "$domain:$type";
00139                 $prefixedMembers = array();
00140                 foreach ( (array)$members as $member ) {
00141                     $prefixedMembers[] = "$virtualKey:$member";
00142                 }
00143 
00144                 return $this->add( 'shared', $prefixedMembers );
00145             } catch ( MWException $e ) {
00146                 MWExceptionHandler::logException( $e );
00147                 return false;
00148             }
00149         }
00150 
00151         return true;
00152     }
00153 
00162     final public function init( $key, $size = 1000000, $precision = .001 ) {
00163         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00164 
00165         return $this->doInit( "{$this->cacheID}:$key", $size, min( .1, $precision ) );
00166     }
00167 
00175     final public function add( $key, $members ) {
00176         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00177 
00178         return $this->doAdd( "{$this->cacheID}:$key", (array)$members );
00179     }
00180 
00194     final public function isHit( $key, $member ) {
00195         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00196 
00197         return $this->doIsHit( "{$this->cacheID}:$key", $member );
00198     }
00199 
00206     final public function delete( $key ) {
00207         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00208 
00209         return $this->doDelete( "{$this->cacheID}:$key" );
00210     }
00211 
00219     final public function setStatus( $virtualKey, array $values ) {
00220         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00221 
00222         return $this->doSetStatus( "{$this->cacheID}:$virtualKey", $values );
00223     }
00224 
00237     final public function getStatus( $virtualKey ) {
00238         $section = new ProfileSection( get_class( $this ) . '::' . __FUNCTION__ );
00239 
00240         return $this->doGetStatus( "{$this->cacheID}:$virtualKey" );
00241     }
00242 
00249     public function getScopedLock( $virtualKey ) {
00250         return null;
00251     }
00252 
00259     abstract protected function doInit( $key, $size, $precision );
00260 
00266     abstract protected function doAdd( $key, array $members );
00267 
00273     abstract protected function doIsHit( $key, $member );
00274 
00279     abstract protected function doDelete( $key );
00280 
00286     abstract protected function doSetStatus( $virtualKey, array $values );
00287 
00292     abstract protected function doGetStatus( $key );
00293 }
00294 
00295 class EmptyBloomCache extends BloomCache {
00296     public function __construct( array $config ) {
00297         parent::__construct( array( 'cacheId' => 'none' ) );
00298     }
00299 
00300     protected function doInit( $key, $size, $precision ) {
00301         return true;
00302     }
00303 
00304     protected function doAdd( $key, array $members ) {
00305         return true;
00306     }
00307 
00308     protected function doIsHit( $key, $member ) {
00309         return true;
00310     }
00311 
00312     protected function doDelete( $key ) {
00313         return true;
00314     }
00315 
00316     protected function doSetStatus( $virtualKey, array $values ) {
00317         return true;
00318     }
00319 
00320     protected function doGetStatus( $virtualKey ) {
00321         return array( 'lastID' => null, 'asOfTime' => null, 'epoch' => null ) ;
00322     }
00323 }