91 if ( !class_exists( Redis::class ) ) {
92 throw new RuntimeException(
93 __CLASS__ .
' requires a Redis client library. ' .
94 'See https://www.mediawiki.org/wiki/Redis#Setup' );
96 $this->logger = $options[
'logger'] ??
new NullLogger();
97 $this->connectTimeout = $options[
'connectTimeout'];
98 $this->readTimeout = $options[
'readTimeout'];
99 $this->persistent = $options[
'persistent'];
100 $this->password = $options[
'password'];
101 $this->prefix = $options[
'prefix'];
102 if ( !isset( $options[
'serializer'] ) || $options[
'serializer'] ===
'php' ) {
103 $this->serializer = Redis::SERIALIZER_PHP;
104 } elseif ( $options[
'serializer'] ===
'igbinary' ) {
105 if ( !defined(
'Redis::SERIALIZER_IGBINARY' ) ) {
106 throw new InvalidArgumentException(
107 __CLASS__ .
': configured serializer "igbinary" not available' );
109 $this->serializer = Redis::SERIALIZER_IGBINARY;
110 } elseif ( $options[
'serializer'] ===
'none' ) {
111 $this->serializer = Redis::SERIALIZER_NONE;
113 throw new InvalidArgumentException(
"Invalid serializer specified." );
199 if ( isset( $this->downServers[$server] ) ) {
201 if ( $now > $this->downServers[$server] ) {
203 unset( $this->downServers[$server] );
207 'Server "{redis_server}" is marked down for another ' .
208 ( $this->downServers[$server] - $now ) .
' seconds',
209 [
'redis_server' => $server ]
217 if ( isset( $this->connections[$server] ) ) {
218 foreach ( $this->connections[$server] as &$connection ) {
219 if ( $connection[
'free'] ) {
220 $connection[
'free'] =
false;
224 $this, $server, $connection[
'conn'],
$logger
231 throw new InvalidArgumentException(
232 __CLASS__ .
": invalid configured server \"$server\"" );
233 } elseif ( substr( $server, 0, 1 ) ===
'/' ) {
241 if ( preg_match(
'/^\[(.+)\]:(\d+)$/', $server, $m ) ) {
243 [ $host, $port ] = [ $m[1], (int)$m[2] ];
244 } elseif ( preg_match(
'/^((?:[\w]+\:\/\/)?[^:]+):(\d+)$/', $server, $m ) ) {
246 [ $host, $port ] = [ $m[1], (int)$m[2] ];
248 substr( $host, 0, 6 ) ===
'tls://'
249 && version_compare( phpversion(
'redis' ),
'5.0.0' ) < 0
251 throw new RuntimeException(
252 'A newer version of the Redis client library is required to use TLS. ' .
253 'See https://www.mediawiki.org/wiki/Redis#Setup' );
257 [ $host, $port ] = [ $server, 6379 ];
263 if ( $this->persistent ) {
264 $result = $conn->pconnect( $host, $port, $this->connectTimeout, $this->
id );
266 $result = $conn->connect( $host, $port, $this->connectTimeout );
270 'Could not connect to server "{redis_server}"',
271 [
'redis_server' => $server ]
274 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
278 if ( ( $this->password !==
null ) && !$conn->auth( $this->password ) ) {
280 'Authentication error connecting to "{redis_server}"',
281 [
'redis_server' => $server ]
284 }
catch ( RedisException $e ) {
285 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
287 'Redis exception connecting to "{redis_server}"',
289 'redis_server' => $server,
297 if ( $this->prefix !==
null ) {
298 $conn->setOption( Redis::OPT_PREFIX, $this->prefix );
301 $conn->setOption( Redis::OPT_READ_TIMEOUT, $this->readTimeout );
302 $conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
303 $this->connections[$server][] = [
'conn' => $conn,
'free' => false ];
335 if ( $this->idlePoolSize <= count( $this->connections ) ) {
339 foreach ( $this->connections as &$serverConnections ) {
340 foreach ( $serverConnections as $key => &$connection ) {
341 if ( $connection[
'free'] ) {
342 unset( $serverConnections[$key] );
343 if ( --$this->idlePoolSize <= count( $this->connections ) ) {