* @defgroup Cache Cache
*/
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
/**
* interface is intended to be more or less compatible with
* the PHP memcached client.
*
* @ingroup Cache
*/
-abstract class BagOStuff {
+abstract class BagOStuff implements LoggerAwareInterface {
private $debugMode = false;
protected $lastError = self::ERR_NONE;
+ /**
+ * @var LoggerInterface
+ */
+ protected $logger;
+
/** Possible values for getLastError() */
const ERR_NONE = 0; // no error
const ERR_NO_RESPONSE = 1; // no response
const ERR_UNREACHABLE = 2; // can't connect
const ERR_UNEXPECTED = 3; // response gave some error
+ public function __construct( array $params = array() ) {
+ if ( isset( $params['logger'] ) ) {
+ $this->setLogger( $params['logger'] );
+ } else {
+ $this->setLogger( new NullLogger() );
+ }
+ }
+
+ /**
+ * @param LoggerInterface $logger
+ * @return null
+ */
+ public function setLogger( LoggerInterface $logger ) {
+ $this->logger = $logger;
+ }
+
/**
* @param bool $bool
*/
$this->debugMode = $bool;
}
- /* *** THE GUTS OF THE OPERATION *** */
- /* Override these with functional things in subclasses */
-
/**
* Get an item with the given key. Returns false if it does not exist.
* @param string $key
*/
abstract public function set( $key, $value, $exptime = 0 );
- /**
- * Check and set an item.
- * @param mixed $casToken
- * @param string $key
- * @param mixed $value
- * @param int $exptime Either an interval in seconds or a unix timestamp for expiry
- * @return bool Success
- */
- abstract public function cas( $casToken, $key, $value, $exptime = 0 );
-
/**
* Delete an item.
* @param string $key
- * @param int $time Amount of time to delay the operation (mostly memcached-specific)
* @return bool True if the item was deleted or not found, false on failure
*/
- abstract public function delete( $key, $time = 0 );
+ abstract public function delete( $key );
/**
* Merge changes into the existing cache value (possibly creating a new one).
* and takes the arguments: (this BagOStuff object, cache key, current value).
*
* @param string $key
- * @param Closure $callback Callback method to be executed
+ * @param callable $callback Callback method to be executed
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
* @param int $attempts The amount of times to attempt a merge in case of failure
* @return bool Success
*/
- public function merge( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
+ public function merge( $key, $callback, $exptime = 0, $attempts = 10 ) {
+ if ( !is_callable( $callback ) ) {
+ throw new Exception( "Got invalid callback." );
+ }
+
return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
}
* @see BagOStuff::merge()
*
* @param string $key
- * @param Closure $callback Callback method to be executed
+ * @param callable $callback Callback method to be executed
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
* @param int $attempts The amount of times to attempt a merge in case of failure
* @return bool Success
*/
- protected function mergeViaCas( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
+ protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10 ) {
do {
$casToken = null; // passed by reference
- $currentValue = $this->get( $key, $casToken ); // get the old value
- $value = $callback( $this, $key, $currentValue ); // derive the new value
+ $currentValue = $this->get( $key, $casToken );
+ // Derive the new value from the old value
+ $value = call_user_func( $callback, $this, $key, $currentValue );
if ( $value === false ) {
$success = true; // do nothing
return $success;
}
+ /**
+ * Check and set an item.
+ * @param mixed $casToken
+ * @param string $key
+ * @param mixed $value
+ * @param int $exptime Either an interval in seconds or a unix timestamp for expiry
+ * @return bool Success
+ */
+ abstract protected function cas( $casToken, $key, $value, $exptime = 0 );
+
/**
* @see BagOStuff::merge()
*
* @param string $key
- * @param Closure $callback Callback method to be executed
+ * @param callable $callback Callback method to be executed
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
* @param int $attempts The amount of times to attempt a merge in case of failure
* @return bool Success
*/
- protected function mergeViaLock( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
+ protected function mergeViaLock( $key, $callback, $exptime = 0, $attempts = 10 ) {
if ( !$this->lock( $key, 6 ) ) {
return false;
}
- $currentValue = $this->get( $key ); // get the old value
- $value = $callback( $this, $key, $currentValue ); // derive the new value
+ $currentValue = $this->get( $key );
+ // Derive the new value from the old value
+ $value = call_user_func( $callback, $this, $key, $currentValue );
if ( $value === false ) {
$success = true; // do nothing
$locked = false; // lock acquired
$attempts = 0; // failed attempts
do {
- if ( ++$attempts >= 3 && $sleep <= 1e6 ) {
+ if ( ++$attempts >= 3 && $sleep <= 5e5 ) {
// Exponentially back off after failed attempts to avoid network spam.
// About 2*$uRTT*(2^n-1) us of "sleep" happen for the next n attempts.
$sleep *= 2;
/**
* @param string $text
*/
- public function debug( $text ) {
+ protected function debug( $text ) {
if ( $this->debugMode ) {
- $class = get_class( $this );
- wfDebug( "$class debug: $text\n" );
+ $this->logger->debug( "{class} debug: $text", array(
+ 'class' => get_class( $this ),
+ ) );
}
}