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 = isset(
$options[
'logger'] )
86 : new \Psr\Log\NullLogger();
87 $this->connectTimeout =
$options[
'connectTimeout'];
88 $this->readTimeout =
$options[
'readTimeout'];
89 $this->persistent =
$options[
'persistent'];
90 $this->password =
$options[
'password'];
91 if ( !isset(
$options[
'serializer'] ) ||
$options[
'serializer'] ===
'php' ) {
92 $this->serializer = Redis::SERIALIZER_PHP;
93 } elseif (
$options[
'serializer'] ===
'igbinary' ) {
94 $this->serializer = Redis::SERIALIZER_IGBINARY;
95 } elseif (
$options[
'serializer'] ===
'none' ) {
96 $this->serializer = Redis::SERIALIZER_NONE;
98 throw new InvalidArgumentException(
"Invalid serializer specified." );
116 if ( !isset(
$options[
'connectTimeout'] ) ) {
119 if ( !isset(
$options[
'readTimeout'] ) ) {
122 if ( !isset(
$options[
'persistent'] ) ) {
125 if ( !isset(
$options[
'password'] ) ) {
153 if ( !isset( self::$instances[
$id] ) ) {
157 return self::$instances[
$id];
165 self::$instances = [];
182 if ( isset( $this->downServers[$server] ) ) {
184 if ( $now > $this->downServers[$server] ) {
186 unset( $this->downServers[$server] );
190 'Server "{redis_server}" is marked down for another ' .
191 ( $this->downServers[$server] - $now ) .
'seconds',
192 [
'redis_server' => $server ]
200 if ( isset( $this->connections[$server] ) ) {
201 foreach ( $this->connections[$server]
as &$connection ) {
202 if ( $connection[
'free'] ) {
203 $connection[
'free'] =
false;
207 $this, $server, $connection[
'conn'],
$logger
214 throw new InvalidArgumentException(
215 __CLASS__ .
": invalid configured server \"$server\"" );
216 } elseif ( substr( $server, 0, 1 ) ===
'/' ) {
224 if ( preg_match(
'/^\[(.+)\]:(\d+)$/', $server, $m ) ) {
225 list( $host, $port ) = [ $m[1], (int)$m[2] ];
226 } elseif ( preg_match(
'/^([^:]+):(\d+)$/', $server, $m ) ) {
227 list( $host, $port ) = [ $m[1], (int)$m[2] ];
229 list( $host, $port ) = [ $server, 6379 ];
235 if ( $this->persistent ) {
236 $result = $conn->pconnect( $host, $port, $this->connectTimeout, $this->
id );
238 $result = $conn->connect( $host, $port, $this->connectTimeout );
242 'Could not connect to server "{redis_server}"',
243 [
'redis_server' => $server ]
250 if ( $this->password !==
null ) {
251 if ( !$conn->auth( $this->password ) ) {
253 'Authentication error connecting to "{redis_server}"',
254 [
'redis_server' => $server ]
258 }
catch ( RedisException
$e ) {
261 'Redis exception connecting to "{redis_server}"',
263 'redis_server' => $server,
272 $conn->setOption( Redis::OPT_READ_TIMEOUT, $this->readTimeout );
273 $conn->setOption( Redis::OPT_SERIALIZER, $this->serializer );
274 $this->connections[$server][] = [
'conn' => $conn,
'free' =>
false ];
292 foreach ( $this->connections[$server]
as &$connection ) {
293 if ( $connection[
'conn'] === $conn && !$connection[
'free'] ) {
294 $connection[
'free'] =
true;
309 if ( $this->idlePoolSize <=
count( $this->connections ) ) {
313 foreach ( $this->connections
as &$serverConnections ) {
314 foreach ( $serverConnections
as $key => &$connection ) {
315 if ( $connection[
'free'] ) {
316 unset( $serverConnections[$key] );
317 if ( --$this->idlePoolSize <=
count( $this->connections ) ) {
336 $this->logger->error(
337 'Redis exception on server "{redis_server}"',
339 'redis_server' => $server,
343 foreach ( $this->connections[$server]
as $key => $connection ) {
345 $this->idlePoolSize -= $connection[
'free'] ? 1 : 0;
346 unset( $this->connections[$server][$key] );
369 if ( $this->password !==
null ) {
370 if ( !$conn->auth( $this->password ) ) {
371 $this->logger->error(
372 'Authentication error connecting to "{redis_server}"',
373 [
'redis_server' => $server ]
390 $conn->setOption( Redis::OPT_READ_TIMEOUT, $timeout ?: $this->readTimeout );
397 foreach ( $this->connections
as $server => &$serverConnections ) {
398 foreach ( $serverConnections
as $key => &$connection ) {
401 $conn = $connection[
'conn'];
403 }
catch ( RedisException
$e ) {