Version 4.1.19

This commit is contained in:
Neo committed 2025-12-19 05:38:56 -08:00
1 parent 28bd025b35
commit 2bd5025018
2674 files changed
+233518 -77766

No files matched your search

+145 -35
View File
@@ -2,9 +2,9 @@
/**
* @brief Redis Cache Class
* @author <a href='http://www.invisionpower.com'>Invision Power Services, Inc.</a>
* @copyright (c) 2001 - SVN_YYYY Invision Power Services, Inc.
* @copyright (c) 2001 - 2016 Invision Power Services, Inc.
* @license http://www.invisionpower.com/legal/standards/
* @package IPS Social Suite
* @package IPS Community Suite
* @since 18 Oct 2013
* @version SVN_VERSION_NUMBER
*/
@@ -63,7 +63,17 @@ class _Redis extends \IPS\Data\Cache
/**
* @brief Connection resource
*/
protected $link = null;
protected static $links = array();
/**
* @brief Connection key
*/
protected $connectionKey = NULL;
/**
* @brief Connection timeout - keep low or you negate the benefits of caching
*/
protected $timeout = 2;
/**
* Constructor
@@ -73,71 +83,140 @@ class _Redis extends \IPS\Data\Cache
*/
public function __construct( $configuration )
{
/* Figure out our connection key, as you could theoretically attempt to connect to more than one Redis server */
$this->connectionKey = md5( $configuration['server'] . ':' . $configuration['port'] );
/* If we've already attempted to establish this link, just return now */
if( isset( static::$links[ $this->connectionKey ] ) )
{
return;
}
/* Connect to server */
try
{
$this->link = new \Redis;
static::$links[ $this->connectionKey ] = new \Redis;
if( $this->link->connect( $configuration['server'], $configuration['port'] ) === FALSE )
if( static::$links[ $this->connectionKey ]->connect( $configuration['server'], $configuration['port'], $this->timeout ) === FALSE )
{
$this->link = NULL;
$this->resetConnection();
throw new \RedisException;
}
else
{
if( $configuration['password'] )
{
if( $this->link->auth( $configuration['password'] ) === FALSE )
if( static::$links[ $this->connectionKey ]->auth( $configuration['password'] ) === FALSE )
{
$this->link = NULL;
$this->resetConnection();
throw new \RedisException;
}
}
}
if( $this->link !== NULL )
if( static::$links[ $this->connectionKey ] !== NULL )
{
$this->link->setOption( \Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP );
static::$links[ $this->connectionKey ]->setOption( \Redis::OPT_SERIALIZER, \Redis::SERIALIZER_PHP );
}
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Connected to Redis", 'cache' );
/* If connection times out, connect can return TRUE and we won't know until our next attempt to talk to the server,
so we should ping now to verify we were able to connect successfully */
static::$links[ $this->connectionKey ]->ping();
register_shutdown_function( function( $object ){
try
{
if( isset( static::$links[ $object->connectionKey ] ) AND static::$links[ $object->connectionKey ] )
{
static::$links[ $object->connectionKey ]->close();
unset( static::$links[ $object->connectionKey ] );
}
}
catch( \RedisException $e ){}
}, $this );
\IPS\Log::debug( "Connected to Redis", 'cache' );
}
catch( \RedisException $e )
{
$this->link = NULL;
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Connection to Redis failed", 'cache' );
$this->resetConnection( $e );
\IPS\Log::debug( "Connection to Redis failed", 'cache' );
}
}
/**
* Abstract Method: Get
*
* @param string $key Key
* @return string Value from the _datastore
* @param string $key
* @return string|FALSE Value from the _datastore; FALSE if key doesn't exist
*/
protected function get( $key )
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Get {$key} from Redis (already loaded)", 'cache' );
\IPS\Log::debug( "Get {$key} from Redis (already loaded)", 'cache' );
return $this->cache[ $key ];
}
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Get {$key} from Redis", 'cache' );
if ( static::$links[ $this->connectionKey ] )
{
\IPS\Log::debug( "Get {$key} from Redis", 'cache' );
$this->cache[ $key ] = $this->link->get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
return $this->cache[ $key ];
try
{
$this->cache[ $key ] = static::$links[ $this->connectionKey ]->get( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
return $this->cache[ $key ];
}
catch( \RedisException $e )
{
$this->resetConnection( $e );
return FALSE;
}
}
/* No connection */
return FALSE;
}
/**
* Abstract Method: Set
*
* @param string $key Key
* @param string $value Value
* @param string $key Key
* @param string $value Value
* @param \IPS\DateTime $expire Expreation time, or NULL for no expiration
* @return bool
*/
protected function set( $key, $value )
protected function set( $key, $value, \IPS\DateTime $expire = NULL )
{
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Set {$key} in Redis", 'cache' );
return (bool) $this->link->set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value );
if ( static::$links[ $this->connectionKey ] )
{
\IPS\Log::debug( "Set {$key} in Redis", 'cache' );
try
{
if ( $expire )
{
return (bool) static::$links[ $this->connectionKey ]->setex( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $expire->getTimestamp() - time(), $value );
}
else
{
return (bool) static::$links[ $this->connectionKey ]->set( \IPS\SUITE_UNIQUE_KEY . '_' . $key, $value );
}
}
catch( \RedisException $e )
{
$this->resetConnection( $e );
return FALSE;
}
}
/* No connection */
return FALSE;
}
/**
@@ -150,11 +229,12 @@ class _Redis extends \IPS\Data\Cache
{
if( isset( $this->cache[ $key ] ) )
{
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Check exists {$key} from Redis (already loaded)", 'cache' );
return TRUE;
\IPS\Log::debug( "Check exists {$key} from Redis (already loaded)", 'cache' );
return ( $this->cache[ $key ] === FALSE ) ? FALSE : TRUE;
}
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Check exists {$key} from Redis", 'cache' );
\IPS\Log::debug( "Check exists {$key} from Redis", 'cache' );
/* We do a get instead of an exists() check because it will cause the cache value to be fetched and cached inline, saving another call to the server */
return ( $this->get( $key ) === FALSE ) ? FALSE : TRUE;
}
@@ -167,22 +247,52 @@ class _Redis extends \IPS\Data\Cache
*/
protected function delete( $key )
{
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Delete {$key} from Redis", 'cache' );
return (bool) $this->link->delete( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
if ( static::$links[ $this->connectionKey ] )
{
\IPS\Log::debug( "Delete {$key} from Redis", 'cache' );
try
{
return (bool) static::$links[ $this->connectionKey ]->delete( \IPS\SUITE_UNIQUE_KEY . '_' . $key );
}
catch( \RedisException $e )
{
$this->resetConnection( $e );
}
}
/* No connection */
return FALSE;
}
/**
* Destructor
* Reset connection
*
* @param \RedisException|NULL If this was called as a result of an exception, log that to the debug log
* @return void
*/
protected function resetConnection( \RedisException $e = NULL )
{
if ( $e !== NULL )
{
\IPS\Log::debug( $e, 'redis_exception' );
}
static::$links[ $this->connectionKey ] = NULL;
throw new \IPS\Data\Cache\Exception;
}
/**
* Abstract Method: Clear All Caches
*
* @return void
*/
public function __destruct()
public function clearAll()
{
if( $this->link )
{
\IPS\Log::i( LOG_DEBUG )->setIpAddress( $_SERVER['REMOTE_ADDR'] )->write( "Disconnect from Redis", 'cache' );
parent::clearAll();
$this->link->close();
if ( static::$links[ $this->connectionKey ] )
{
static::$links[ $this->connectionKey ]->flushDb();
}
}
}