MediaWiki  REL1_20
MemcachedPeclBagOStuff.php
Go to the documentation of this file.
00001 <?php
00029 class MemcachedPeclBagOStuff extends MemcachedBagOStuff {
00030 
00044         function __construct( $params ) {
00045                 $params = $this->applyDefaultParams( $params );
00046 
00047                 if ( $params['persistent'] ) {
00048                         // The pool ID must be unique to the server/option combination.
00049                         // The Memcached object is essentially shared for each pool ID.
00050                         // We can only resuse a pool ID if we keep the config consistent.
00051                         $this->client = new Memcached( md5( serialize( $params ) ) );
00052                         if ( count( $this->client->getServerList() ) ) {
00053                                 wfDebug( __METHOD__ . ": persistent Memcached object already loaded.\n" );
00054                                 return; // already initialized; don't add duplicate servers
00055                         }
00056                 } else {
00057                         $this->client = new Memcached;
00058                 }
00059 
00060                 if ( !isset( $params['serializer'] ) ) {
00061                         $params['serializer'] = 'php';
00062                 }
00063 
00064                 // The compression threshold is an undocumented php.ini option for some
00065                 // reason. There's probably not much harm in setting it globally, for
00066                 // compatibility with the settings for the PHP client.
00067                 ini_set( 'memcached.compression_threshold', $params['compress_threshold'] );
00068 
00069                 // Set timeouts
00070                 $this->client->setOption( Memcached::OPT_CONNECT_TIMEOUT, $params['connect_timeout'] * 1000 );
00071                 $this->client->setOption( Memcached::OPT_SEND_TIMEOUT, $params['timeout'] );
00072                 $this->client->setOption( Memcached::OPT_RECV_TIMEOUT, $params['timeout'] );
00073                 $this->client->setOption( Memcached::OPT_POLL_TIMEOUT, $params['timeout'] / 1000 );
00074 
00075                 // Set libketama mode since it's recommended by the documentation and
00076                 // is as good as any. There's no way to configure libmemcached to use
00077                 // hashes identical to the ones currently in use by the PHP client, and
00078                 // even implementing one of the libmemcached hashes in pure PHP for
00079                 // forwards compatibility would require MWMemcached::get_sock() to be
00080                 // rewritten.
00081                 $this->client->setOption( Memcached::OPT_LIBKETAMA_COMPATIBLE, true );
00082 
00083                 // Set the serializer
00084                 switch ( $params['serializer'] ) {
00085                         case 'php':
00086                                 $this->client->setOption( Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP );
00087                                 break;
00088                         case 'igbinary':
00089                                 if ( !Memcached::HAVE_IGBINARY ) {
00090                                         throw new MWException( __CLASS__.': the igbinary extension is not available ' .
00091                                                 'but igbinary serialization was requested.' );
00092                                 }
00093                                 $this->client->setOption( Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_IGBINARY );
00094                                 break;
00095                         default:
00096                                 throw new MWException( __CLASS__.': invalid value for serializer parameter' );
00097                 }
00098                 $servers = array();
00099                 foreach ( $params['servers'] as $host ) {
00100                         $servers[] = IP::splitHostAndPort( $host ); // (ip, port)
00101                 }
00102                 $this->client->addServers( $servers );
00103         }
00104 
00109         public function get( $key ) {
00110                 $this->debugLog( "get($key)" );
00111                 return $this->checkResult( $key, parent::get( $key ) );
00112         }
00113 
00120         public function set( $key, $value, $exptime = 0 ) {
00121                 $this->debugLog( "set($key)" );
00122                 return $this->checkResult( $key, parent::set( $key, $value, $exptime ) );
00123         }
00124 
00130         public function delete( $key, $time = 0 ) {
00131                 $this->debugLog( "delete($key)" );
00132                 $result = parent::delete( $key, $time );
00133                 if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTFOUND ) {
00134                         // "Not found" is counted as success in our interface
00135                         return true;
00136                 } else {
00137                         return $this->checkResult( $key, $result );
00138                 }
00139         }
00140 
00147         public function add( $key, $value, $exptime = 0 ) {
00148                 $this->debugLog( "add($key)" );
00149                 return $this->checkResult( $key, parent::add( $key, $value, $exptime ) );
00150         }
00151 
00158         public function replace( $key, $value, $exptime = 0 ) {
00159                 $this->debugLog( "replace($key)" );
00160                 return $this->checkResult( $key, parent::replace( $key, $value, $exptime ) );
00161         }
00162 
00168         public function incr( $key, $value = 1 ) {
00169                 $this->debugLog( "incr($key)" );
00170                 $result = $this->client->increment( $key, $value );
00171                 return $this->checkResult( $key, $result );
00172         }
00173 
00179         public function decr( $key, $value = 1 ) {
00180                 $this->debugLog( "decr($key)" );
00181                 $result = $this->client->decrement( $key, $value );
00182                 return $this->checkResult( $key, $result );
00183         }
00184 
00196         protected function checkResult( $key, $result ) {
00197                 if ( $result !== false ) {
00198                         return $result;
00199                 }
00200                 switch ( $this->client->getResultCode() ) {
00201                         case Memcached::RES_SUCCESS:
00202                                 break;
00203                         case Memcached::RES_DATA_EXISTS:
00204                         case Memcached::RES_NOTSTORED:
00205                         case Memcached::RES_NOTFOUND:
00206                                 $this->debugLog( "result: " . $this->client->getResultMessage() );
00207                                 break;
00208                         default:
00209                                 $msg = $this->client->getResultMessage();
00210                                 if ( $key !== false ) {
00211                                         $server = $this->client->getServerByKey( $key );
00212                                         $serverName = "{$server['host']}:{$server['port']}";
00213                                         $msg = "Memcached error for key \"$key\" on server \"$serverName\": $msg";
00214                                 } else {
00215                                         $msg = "Memcached error: $msg";
00216                                 }
00217                                 wfDebugLog( 'memcached-serious', $msg );
00218                 }
00219                 return $result;
00220         }
00221 
00226         public function getMulti( array $keys ) {
00227                 $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' );
00228                 $callback = array( $this, 'encodeKey' );
00229                 $result = $this->client->getMulti( array_map( $callback, $keys ) );
00230                 return $this->checkResult( false, $result );
00231         }
00232 
00233         /* NOTE: there is no cas() method here because it is currently not supported
00234          * by the BagOStuff interface and other BagOStuff subclasses, such as
00235          * SqlBagOStuff.
00236          */
00237 }