83 if ( !class_exists( Redis::class ) ) {
84 throw new RuntimeException(
85 __CLASS__ .
' requires a Redis client library. ' .
86 'See https://www.mediawiki.org/wiki/Redis#Setup' );
88 $this->logger = $options[
'logger'] ??
new NullLogger();
89 $this->connectTimeout = $options[
'connectTimeout'];
90 $this->readTimeout = $options[
'readTimeout'];
91 $this->persistent = $options[
'persistent'];
92 $this->password = $options[
'password'];
93 if ( !isset( $options[
'serializer'] ) || $options[
'serializer'] ===
'php' ) {
94 $this->serializer = Redis::SERIALIZER_PHP;
95 } elseif ( $options[
'serializer'] ===
'igbinary' ) {
96 if ( !defined(
'Redis::SERIALIZER_IGBINARY' ) ) {
97 throw new InvalidArgumentException(
98 __CLASS__ .
': configured serializer "igbinary" not available' );
100 $this->serializer = Redis::SERIALIZER_IGBINARY;
101 } elseif ( $options[
'serializer'] ===
'none' ) {
102 $this->serializer = Redis::SERIALIZER_NONE;
104 throw new InvalidArgumentException(
"Invalid serializer specified." );
187 if ( isset( $this->downServers[$server] ) ) {
189 if ( $now > $this->downServers[$server] ) {
191 unset( $this->downServers[$server] );
195 'Server "{redis_server}" is marked down for another ' .
196 ( $this->downServers[$server] - $now ) .
'seconds',
197 [
'redis_server' => $server ]
205 if ( isset( $this->connections[$server] ) ) {
206 foreach ( $this->connections[$server] as &$connection ) {
207 if ( $connection[
'free'] ) {
208 $connection[
'free'] =
false;
212 $this, $server, $connection[
'conn'],
$logger
219 throw new InvalidArgumentException(
220 __CLASS__ .
": invalid configured server \"$server\"" );
221 } elseif ( substr( $server, 0, 1 ) ===
'/' ) {
229 if ( preg_match(
'/^\[(.+)\]:(\d+)$/', $server, $m ) ) {
231 list( $host, $port ) = [ $m[1], (int)$m[2] ];
232 } elseif ( preg_match(
'/^((?:[\w]+\:\/\/)?[^:]+):(\d+)$/', $server, $m ) ) {
234 list( $host, $port ) = [ $m[1], (int)$m[2] ];
236 substr( $host, 0, 6 ) ===
'tls://'
237 && version_compare( phpversion(
'redis' ),
'5.0.0' ) < 0
239 throw new RuntimeException(
240 'A newer version of the Redis client library is required to use TLS. ' .
241 'See https://www.mediawiki.org/wiki/Redis#Setup' );
245 list( $host, $port ) = [ $server, 6379 ];
251 if ( $this->persistent ) {
252 $result = $conn->pconnect( $host, $port, $this->connectTimeout, $this->
id );
254 $result = $conn->connect( $host, $port, $this->connectTimeout );
258 'Could not connect to server "{redis_server}"',
259 [
'redis_server' => $server ]
262 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
266 if ( ( $this->password !==
null ) && !$conn->auth( $this->password ) ) {
268 'Authentication error connecting to "{redis_server}"',
269 [
'redis_server' => $server ]
272 }
catch ( RedisException $e ) {
273 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
275 'Redis exception connecting to "{redis_server}"',
277 'redis_server' => $server,
285 $conn->setOption( Redis::OPT_READ_TIMEOUT, $this->readTimeout );
286 $conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
287 $this->connections[$server][] = [
'conn' => $conn,
'free' => false ];
319 if ( $this->idlePoolSize <= count( $this->connections ) ) {
323 foreach ( $this->connections as &$serverConnections ) {
324 foreach ( $serverConnections as $key => &$connection ) {
325 if ( $connection[
'free'] ) {
326 unset( $serverConnections[$key] );
327 if ( --$this->idlePoolSize <= count( $this->connections ) ) {