MediaWiki
REL1_20
|
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 }