24 use Psr\Log\LoggerAwareInterface;
25 use Psr\Log\LoggerInterface;
79 if ( !class_exists(
'Redis' ) ) {
80 throw new RuntimeException(
81 __CLASS__ .
' requires a Redis client library. ' .
82 'See https://www.mediawiki.org/wiki/Redis#Setup' );
84 $this->logger =
$options[
'logger'] ?? new \Psr\Log\NullLogger();
85 $this->connectTimeout =
$options[
'connectTimeout'];
86 $this->readTimeout =
$options[
'readTimeout'];
87 $this->persistent =
$options[
'persistent'];
88 $this->password =
$options[
'password'];
89 if ( !isset(
$options[
'serializer'] ) ||
$options[
'serializer'] ===
'php' ) {
90 $this->serializer = Redis::SERIALIZER_PHP;
91 } elseif (
$options[
'serializer'] ===
'igbinary' ) {
92 $this->serializer = Redis::SERIALIZER_IGBINARY;
93 } elseif (
$options[
'serializer'] ===
'none' ) {
94 $this->serializer = Redis::SERIALIZER_NONE;
96 throw new InvalidArgumentException(
"Invalid serializer specified." );
114 if ( !isset(
$options[
'connectTimeout'] ) ) {
117 if ( !isset(
$options[
'readTimeout'] ) ) {
120 if ( !isset(
$options[
'persistent'] ) ) {
123 if ( !isset(
$options[
'password'] ) ) {
151 if ( !isset( self::$instances[
$id] ) ) {
155 return self::$instances[
$id];
163 self::$instances = [];
180 if ( isset( $this->downServers[$server] ) ) {
182 if ( $now > $this->downServers[$server] ) {
184 unset( $this->downServers[$server] );
188 'Server "{redis_server}" is marked down for another ' .
189 ( $this->downServers[$server] - $now ) .
'seconds',
190 [
'redis_server' => $server ]
198 if ( isset( $this->connections[$server] ) ) {
199 foreach ( $this->connections[$server]
as &$connection ) {
200 if ( $connection[
'free'] ) {
201 $connection[
'free'] =
false;
205 $this, $server, $connection[
'conn'],
$logger
212 throw new InvalidArgumentException(
213 __CLASS__ .
": invalid configured server \"$server\"" );
214 } elseif ( substr( $server, 0, 1 ) ===
'/' ) {
222 if ( preg_match(
'/^\[(.+)\]:(\d+)$/', $server, $m ) ) {
223 list( $host, $port ) = [ $m[1], (int)$m[2] ];
224 } elseif ( preg_match(
'/^([^:]+):(\d+)$/', $server, $m ) ) {
225 list( $host, $port ) = [ $m[1], (int)$m[2] ];
227 list( $host, $port ) = [ $server, 6379 ];
233 if ( $this->persistent ) {
234 $result = $conn->pconnect( $host, $port, $this->connectTimeout, $this->
id );
236 $result = $conn->connect( $host, $port, $this->connectTimeout );
240 'Could not connect to server "{redis_server}"',
241 [
'redis_server' => $server ]
248 if ( ( $this->password !==
null ) && !$conn->auth( $this->password ) ) {
250 'Authentication error connecting to "{redis_server}"',
251 [
'redis_server' => $server ]
254 }
catch ( RedisException
$e ) {
257 'Redis exception connecting to "{redis_server}"',
259 'redis_server' => $server,
268 $conn->setOption( Redis::OPT_READ_TIMEOUT, $this->readTimeout );
269 $conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
270 $this->connections[$server][] = [
'conn' => $conn,
'free' =>
false ];
288 foreach ( $this->connections[$server]
as &$connection ) {
289 if ( $connection[
'conn'] === $conn && !$connection[
'free'] ) {
290 $connection[
'free'] =
true;
305 if ( $this->idlePoolSize <=
count( $this->connections ) ) {
309 foreach ( $this->connections
as &$serverConnections ) {
310 foreach ( $serverConnections
as $key => &$connection ) {
311 if ( $connection[
'free'] ) {
312 unset( $serverConnections[$key] );
313 if ( --$this->idlePoolSize <=
count( $this->connections ) ) {
332 $this->logger->error(
333 'Redis exception on server "{redis_server}"',
335 'redis_server' => $server,
339 foreach ( $this->connections[$server]
as $key => $connection ) {
341 $this->idlePoolSize -= $connection[
'free'] ? 1 : 0;
342 unset( $this->connections[$server][$key] );
365 if ( $this->password !==
null && !$conn->auth( $this->password ) ) {
366 $this->logger->error(
367 'Authentication error connecting to "{redis_server}"',
368 [
'redis_server' => $server ]
384 $conn->setOption( Redis::OPT_READ_TIMEOUT, $timeout ?: $this->readTimeout );
391 foreach ( $this->connections
as $server => &$serverConnections ) {
392 foreach ( $serverConnections
as $key => &$connection ) {
395 $conn = $connection[
'conn'];
397 }
catch ( RedisException
$e ) {