MediaWiki REL1_33
MemcachedPeclBagOStuff.php
Go to the documentation of this file.
1<?php
30
47 function __construct( $params ) {
48 parent::__construct( $params );
50
51 if ( $params['persistent'] ) {
52 // The pool ID must be unique to the server/option combination.
53 // The Memcached object is essentially shared for each pool ID.
54 // We can only reuse a pool ID if we keep the config consistent.
55 $this->client = new Memcached( md5( serialize( $params ) ) );
56 if ( count( $this->client->getServerList() ) ) {
57 $this->logger->debug( __METHOD__ . ": persistent Memcached object already loaded." );
58 return; // already initialized; don't add duplicate servers
59 }
60 } else {
61 $this->client = new Memcached;
62 }
63
64 if ( $params['use_binary_protocol'] ) {
65 $this->client->setOption( Memcached::OPT_BINARY_PROTOCOL, true );
66 }
67
68 if ( isset( $params['retry_timeout'] ) ) {
69 $this->client->setOption( Memcached::OPT_RETRY_TIMEOUT, $params['retry_timeout'] );
70 }
71
72 if ( isset( $params['server_failure_limit'] ) ) {
73 $this->client->setOption( Memcached::OPT_SERVER_FAILURE_LIMIT, $params['server_failure_limit'] );
74 }
75
76 // The compression threshold is an undocumented php.ini option for some
77 // reason. There's probably not much harm in setting it globally, for
78 // compatibility with the settings for the PHP client.
79 ini_set( 'memcached.compression_threshold', $params['compress_threshold'] );
80
81 // Set timeouts
82 $this->client->setOption( Memcached::OPT_CONNECT_TIMEOUT, $params['connect_timeout'] * 1000 );
83 $this->client->setOption( Memcached::OPT_SEND_TIMEOUT, $params['timeout'] );
84 $this->client->setOption( Memcached::OPT_RECV_TIMEOUT, $params['timeout'] );
85 $this->client->setOption( Memcached::OPT_POLL_TIMEOUT, $params['timeout'] / 1000 );
86
87 // Set libketama mode since it's recommended by the documentation and
88 // is as good as any. There's no way to configure libmemcached to use
89 // hashes identical to the ones currently in use by the PHP client, and
90 // even implementing one of the libmemcached hashes in pure PHP for
91 // forwards compatibility would require MemcachedClient::get_sock() to be
92 // rewritten.
93 $this->client->setOption( Memcached::OPT_LIBKETAMA_COMPATIBLE, true );
94
95 // Set the serializer
96 switch ( $params['serializer'] ) {
97 case 'php':
98 $this->client->setOption( Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_PHP );
99 break;
100 case 'igbinary':
101 if ( !Memcached::HAVE_IGBINARY ) {
102 throw new InvalidArgumentException(
103 __CLASS__ . ': the igbinary extension is not available ' .
104 'but igbinary serialization was requested.'
105 );
106 }
107 $this->client->setOption( Memcached::OPT_SERIALIZER, Memcached::SERIALIZER_IGBINARY );
108 break;
109 default:
110 throw new InvalidArgumentException(
111 __CLASS__ . ': invalid value for serializer parameter'
112 );
113 }
114 $servers = [];
115 foreach ( $params['servers'] as $host ) {
116 if ( preg_match( '/^\[(.+)\]:(\d+)$/', $host, $m ) ) {
117 $servers[] = [ $m[1], (int)$m[2] ]; // (ip, port)
118 } elseif ( preg_match( '/^([^:]+):(\d+)$/', $host, $m ) ) {
119 $servers[] = [ $m[1], (int)$m[2] ]; // (ip or path, port)
120 } else {
121 $servers[] = [ $host, false ]; // (ip or path, port)
122 }
123 }
124 $this->client->addServers( $servers );
125 }
126
127 protected function applyDefaultParams( $params ) {
128 $params = parent::applyDefaultParams( $params );
129
130 if ( !isset( $params['use_binary_protocol'] ) ) {
131 $params['use_binary_protocol'] = false;
132 }
133
134 if ( !isset( $params['serializer'] ) ) {
135 $params['serializer'] = 'php';
136 }
137
138 return $params;
139 }
140
144 protected function doGet( $key, $flags = 0, &$casToken = null ) {
145 $this->debugLog( "get($key)" );
146 if ( defined( Memcached::class . '::GET_EXTENDED' ) ) { // v3.0.0
147 $flags = Memcached::GET_EXTENDED;
148 $res = $this->client->get( $this->validateKeyEncoding( $key ), null, $flags );
149 if ( is_array( $res ) ) {
150 $result = $res['value'];
151 $casToken = $res['cas'];
152 } else {
153 $result = false;
154 $casToken = null;
155 }
156 } else {
157 $result = $this->client->get( $this->validateKeyEncoding( $key ), null, $casToken );
158 }
159 $result = $this->checkResult( $key, $result );
160 return $result;
161 }
162
163 public function set( $key, $value, $exptime = 0, $flags = 0 ) {
164 $this->debugLog( "set($key)" );
165 $result = parent::set( $key, $value, $exptime, $flags = 0 );
166 if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTSTORED ) {
167 // "Not stored" is always used as the mcrouter response with AllAsyncRoute
168 return true;
169 }
170 return $this->checkResult( $key, $result );
171 }
172
173 protected function cas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
174 $this->debugLog( "cas($key)" );
175 return $this->checkResult( $key, parent::cas( $casToken, $key, $value, $exptime, $flags ) );
176 }
177
178 public function delete( $key, $flags = 0 ) {
179 $this->debugLog( "delete($key)" );
180 $result = parent::delete( $key );
181 if ( $result === false && $this->client->getResultCode() === Memcached::RES_NOTFOUND ) {
182 // "Not found" is counted as success in our interface
183 return true;
184 }
185 return $this->checkResult( $key, $result );
186 }
187
188 public function add( $key, $value, $exptime = 0, $flags = 0 ) {
189 $this->debugLog( "add($key)" );
190 return $this->checkResult( $key, parent::add( $key, $value, $exptime ) );
191 }
192
193 public function incr( $key, $value = 1 ) {
194 $this->debugLog( "incr($key)" );
195 $result = $this->client->increment( $key, $value );
196 return $this->checkResult( $key, $result );
197 }
198
199 public function decr( $key, $value = 1 ) {
200 $this->debugLog( "decr($key)" );
201 $result = $this->client->decrement( $key, $value );
202 return $this->checkResult( $key, $result );
203 }
204
216 protected function checkResult( $key, $result ) {
217 if ( $result !== false ) {
218 return $result;
219 }
220 switch ( $this->client->getResultCode() ) {
221 case Memcached::RES_SUCCESS:
222 break;
223 case Memcached::RES_DATA_EXISTS:
224 case Memcached::RES_NOTSTORED:
225 case Memcached::RES_NOTFOUND:
226 $this->debugLog( "result: " . $this->client->getResultMessage() );
227 break;
228 default:
229 $msg = $this->client->getResultMessage();
230 $logCtx = [];
231 if ( $key !== false ) {
232 $server = $this->client->getServerByKey( $key );
233 $logCtx['memcached-server'] = "{$server['host']}:{$server['port']}";
234 $logCtx['memcached-key'] = $key;
235 $msg = "Memcached error for key \"{memcached-key}\" on server \"{memcached-server}\": $msg";
236 } else {
237 $msg = "Memcached error: $msg";
238 }
239 $this->logger->error( $msg, $logCtx );
241 }
242 return $result;
243 }
244
245 public function getMulti( array $keys, $flags = 0 ) {
246 $this->debugLog( 'getMulti(' . implode( ', ', $keys ) . ')' );
247 foreach ( $keys as $key ) {
248 $this->validateKeyEncoding( $key );
249 }
250 $result = $this->client->getMulti( $keys ) ?: [];
251 return $this->checkResult( false, $result );
252 }
253
254 public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
255 $this->debugLog( 'setMulti(' . implode( ', ', array_keys( $data ) ) . ')' );
256 foreach ( array_keys( $data ) as $key ) {
257 $this->validateKeyEncoding( $key );
258 }
259 $result = $this->client->setMulti( $data, $this->fixExpiry( $exptime ) );
260 return $this->checkResult( false, $result );
261 }
262
263 public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
264 $this->debugLog( "touch($key)" );
265 $result = $this->client->touch( $key, $expiry );
266 return $this->checkResult( $key, $result );
267 }
268}
serialize()
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
setLastError( $err)
Set the "last error" registry.
Base class for memcached clients.
validateKeyEncoding( $key)
Ensure that a key is safe to use (contains no control characters and no characters above the ASCII ra...
debugLog( $text)
Send a debug message to the log.
fixExpiry( $expiry)
TTLs higher than 30 days will be detected as absolute TTLs (UNIX timestamps), and will result in the ...
A wrapper class for the PECL memcached client.
setMulti(array $data, $exptime=0, $flags=0)
Batch insertion/replace.
doGet( $key, $flags=0, &$casToken=null)
@suppress PhanTypeNonVarPassByRef
decr( $key, $value=1)
Decrease stored value of $key by $value while preserving its TTL.
cas( $casToken, $key, $value, $exptime=0, $flags=0)
Check and set an item.
getMulti(array $keys, $flags=0)
Get an associative array containing the item for each of the keys that have items.
checkResult( $key, $result)
Check the return value from a client method call and take any necessary action.
__construct( $params)
Available parameters are:
incr( $key, $value=1)
Increase stored value of $key by $value while preserving its TTL.
add( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
applyDefaultParams( $params)
Fill in some defaults for missing keys in $params.
changeTTL( $key, $expiry=0, $flags=0)
Change the expiration on a key if it exists.
$res
Definition database.txt:21
namespace being checked & $result
Definition hooks.txt:2340
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
$params