77 if ( !class_exists( Redis::class ) ) {
78 throw new RuntimeException(
79 __CLASS__ .
' requires a Redis client library. ' .
80 'See https://www.mediawiki.org/wiki/Redis#Setup' );
82 $this->logger = $options[
'logger'] ??
new NullLogger();
83 $this->connectTimeout = $options[
'connectTimeout'];
84 $this->readTimeout = $options[
'readTimeout'];
85 $this->persistent = $options[
'persistent'];
86 $this->password = $options[
'password'];
87 $this->prefix = $options[
'prefix'];
88 if ( !isset( $options[
'serializer'] ) || $options[
'serializer'] ===
'php' ) {
89 $this->serializer = Redis::SERIALIZER_PHP;
90 } elseif ( $options[
'serializer'] ===
'igbinary' ) {
91 if ( !defined(
'Redis::SERIALIZER_IGBINARY' ) ) {
92 throw new InvalidArgumentException(
93 __CLASS__ .
': configured serializer "igbinary" not available' );
95 $this->serializer = Redis::SERIALIZER_IGBINARY;
96 } elseif ( $options[
'serializer'] ===
'none' ) {
97 $this->serializer = Redis::SERIALIZER_NONE;
99 throw new InvalidArgumentException(
"Invalid serializer specified." );
181 $logger = $logger ?: $this->logger;
185 if ( isset( $this->downServers[$server] ) ) {
187 if ( $now > $this->downServers[$server] ) {
189 unset( $this->downServers[$server] );
193 'Server "{redis_server}" is marked down for another ' .
194 ( $this->downServers[$server] - $now ) .
' seconds',
195 [
'redis_server' => $server ]
203 if ( isset( $this->connections[$server] ) ) {
204 foreach ( $this->connections[$server] as &$connection ) {
205 if ( $connection[
'free'] ) {
206 $connection[
'free'] =
false;
207 --$this->idlePoolSize;
210 $this, $server, $connection[
'conn'], $logger
217 throw new InvalidArgumentException(
218 __CLASS__ .
": invalid configured server \"$server\"" );
219 } elseif ( str_starts_with( $server,
'/' ) ) {
227 if ( preg_match(
'/^\[(.+)\]:(\d+)$/', $server, $m ) ) {
229 [ $host, $port ] = [ $m[1], (int)$m[2] ];
230 } elseif ( preg_match(
'/^((?:[\w]+\:\/\/)?[^:]+):(\d+)$/', $server, $m ) ) {
232 [ $host, $port ] = [ $m[1], (int)$m[2] ];
234 str_starts_with( $host,
'tls://' )
235 && version_compare( phpversion(
'redis' ),
'5.0.0' ) < 0
237 throw new RuntimeException(
238 'A newer version of the Redis client library is required to use TLS. ' .
239 'See https://www.mediawiki.org/wiki/Redis#Setup' );
243 [ $host, $port ] = [ $server, 6379 ];
249 if ( $this->persistent ) {
250 $result = $conn->pconnect( $host, $port, $this->connectTimeout, $this->
id );
252 $result = $conn->connect( $host, $port, $this->connectTimeout );
256 'Could not connect to server "{redis_server}"',
257 [
'redis_server' => $server ]
260 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
264 if ( ( $this->password !==
null ) && !$conn->auth( $this->password ) ) {
266 'Authentication error connecting to "{redis_server}"',
267 [
'redis_server' => $server ]
270 }
catch ( RedisException $e ) {
271 $this->downServers[$server] = time() + self::SERVER_DOWN_TTL;
273 'Redis exception connecting to "{redis_server}"',
275 'redis_server' => $server,
283 if ( $this->prefix !==
null ) {
284 $conn->setOption( Redis::OPT_PREFIX, $this->prefix );
287 $conn->setOption( Redis::OPT_READ_TIMEOUT, $this->readTimeout );
288 $conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
289 $this->connections[$server][] = [
'conn' => $conn,
'free' => false ];
291 return new RedisConnRef( $this, $server, $conn, $logger );
321 if ( $this->idlePoolSize <= count( $this->connections ) ) {
325 foreach ( $this->connections as &$serverConnections ) {
326 foreach ( $serverConnections as $key => &$connection ) {
327 if ( $connection[
'free'] ) {
328 unset( $serverConnections[$key] );
329 if ( --$this->idlePoolSize <= count( $this->connections ) ) {