MediaWiki
REL1_21
|
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 reuse 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 00110 public function get( $key, &$casToken = null ) { 00111 wfProfileIn( __METHOD__ ); 00112 $this->debugLog( "get($key)" ); 00113 $result = $this->client->get( $this->encodeKey( $key ), null, $casToken ); 00114 $result = $this->checkResult( $key, $result ); 00115 wfProfileOut( __METHOD__ ); 00116 return $result; 00117 } 00118 00125 public function set( $key, $value, $exptime = 0 ) { 00126 $this->debugLog( "set($key)" ); 00127 return $this->checkResult( $key, parent::set( $key, $value, $exptime ) ); 00128 } 00129 00137 public function cas( $casToken, $key, $value, $exptime = 0 ) { 00138 $this->debugLog( "cas($key)" ); 00139 return $this->checkResult( $key, parent::cas( $casToken, $key, $value, $exptime ) ); 00140 } 00141 00147 public function delete( $key, $time = 0 ) { 00148 $this->debugLog( "delete($key)" ); 00149 $result = parent::delete( $key, $time ); 00150 if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTFOUND ) { 00151 // "Not found" is counted as success in our interface 00152 return true; 00153 } else { 00154 return $this->checkResult( $key, $result ); 00155 } 00156 } 00157 00164 public function add( $key, $value, $exptime = 0 ) { 00165 $this->debugLog( "add($key)" ); 00166 return $this->checkResult( $key, parent::add( $key, $value, $exptime ) ); 00167 } 00168 00175 public function replace( $key, $value, $exptime = 0 ) { 00176 $this->debugLog( "replace($key)" ); 00177 return $this->checkResult( $key, parent::replace( $key, $value, $exptime ) ); 00178 } 00179 00185 public function incr( $key, $value = 1 ) { 00186 $this->debugLog( "incr($key)" ); 00187 $result = $this->client->increment( $key, $value ); 00188 return $this->checkResult( $key, $result ); 00189 } 00190 00196 public function decr( $key, $value = 1 ) { 00197 $this->debugLog( "decr($key)" ); 00198 $result = $this->client->decrement( $key, $value ); 00199 return $this->checkResult( $key, $result ); 00200 } 00201 00213 protected function checkResult( $key, $result ) { 00214 if ( $result !== false ) { 00215 return $result; 00216 } 00217 switch ( $this->client->getResultCode() ) { 00218 case Memcached::RES_SUCCESS: 00219 break; 00220 case Memcached::RES_DATA_EXISTS: 00221 case Memcached::RES_NOTSTORED: 00222 case Memcached::RES_NOTFOUND: 00223 $this->debugLog( "result: " . $this->client->getResultMessage() ); 00224 break; 00225 default: 00226 $msg = $this->client->getResultMessage(); 00227 if ( $key !== false ) { 00228 $server = $this->client->getServerByKey( $key ); 00229 $serverName = "{$server['host']}:{$server['port']}"; 00230 $msg = "Memcached error for key \"$key\" on server \"$serverName\": $msg"; 00231 } else { 00232 $msg = "Memcached error: $msg"; 00233 } 00234 wfDebugLog( 'memcached-serious', $msg ); 00235 } 00236 return $result; 00237 } 00238 00243 public function getMulti( array $keys ) { 00244 wfProfileIn( __METHOD__ ); 00245 $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' ); 00246 $callback = array( $this, 'encodeKey' ); 00247 $result = $this->client->getMulti( array_map( $callback, $keys ) ); 00248 wfProfileOut( __METHOD__ ); 00249 return $this->checkResult( false, $result ); 00250 } 00251 00252 /* NOTE: there is no cas() method here because it is currently not supported 00253 * by the BagOStuff interface and other BagOStuff subclasses, such as 00254 * SqlBagOStuff. 00255 */ 00256 }