summaryrefslogtreecommitdiff
path: root/includes/objectcache/BagOStuff.php
diff options
context:
space:
mode:
Diffstat (limited to 'includes/objectcache/BagOStuff.php')
-rw-r--r--includes/objectcache/BagOStuff.php180
1 files changed, 121 insertions, 59 deletions
diff --git a/includes/objectcache/BagOStuff.php b/includes/objectcache/BagOStuff.php
index 857943ee..1978c3ea 100644
--- a/includes/objectcache/BagOStuff.php
+++ b/includes/objectcache/BagOStuff.php
@@ -3,7 +3,7 @@
* Classes to cache objects in PHP accelerators, SQL database or DBA files
*
* Copyright © 2003-2004 Brion Vibber <brion@pobox.com>
- * http://www.mediawiki.org/
+ * https://www.mediawiki.org/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -43,8 +43,16 @@
abstract class BagOStuff {
private $debugMode = false;
+ protected $lastError = self::ERR_NONE;
+
+ /** 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
+
/**
- * @param $bool bool
+ * @param bool $bool
*/
public function setDebug( $bool ) {
$this->debugMode = $bool;
@@ -55,34 +63,34 @@ abstract class BagOStuff {
/**
* Get an item with the given key. Returns false if it does not exist.
- * @param $key string
- * @param $casToken[optional] mixed
+ * @param string $key
+ * @param mixed $casToken [optional]
* @return mixed Returns false on failure
*/
abstract public function get( $key, &$casToken = null );
/**
* Set an item.
- * @param $key string
- * @param $value mixed
+ * @param string $key
+ * @param mixed $value
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
- * @return bool success
+ * @return bool Success
*/
abstract public function set( $key, $value, $exptime = 0 );
/**
* Check and set an item.
- * @param $casToken mixed
- * @param $key string
- * @param $value mixed
+ * @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
+ * @return bool Success
*/
abstract public function cas( $casToken, $key, $value, $exptime = 0 );
/**
* Delete an item.
- * @param $key string
+ * @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
*/
@@ -93,26 +101,26 @@ abstract class BagOStuff {
* The callback function returns the new value given the current value (possibly false),
* and takes the arguments: (this BagOStuff object, cache key, current value).
*
- * @param $key string
- * @param $callback closure Callback method to be executed
+ * @param string $key
+ * @param Closure $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
+ * @return bool Success
*/
- public function merge( $key, closure $callback, $exptime = 0, $attempts = 10 ) {
+ public function merge( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
return $this->mergeViaCas( $key, $callback, $exptime, $attempts );
}
/**
* @see BagOStuff::merge()
*
- * @param $key string
- * @param $callback closure Callback method to be executed
+ * @param string $key
+ * @param Closure $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
+ * @return bool Success
*/
- protected function mergeViaCas( $key, closure $callback, $exptime = 0, $attempts = 10 ) {
+ protected function mergeViaCas( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
do {
$casToken = null; // passed by reference
$currentValue = $this->get( $key, $casToken ); // get the old value
@@ -135,14 +143,14 @@ abstract class BagOStuff {
/**
* @see BagOStuff::merge()
*
- * @param $key string
- * @param $callback closure Callback method to be executed
+ * @param string $key
+ * @param Closure $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
+ * @return bool Success
*/
- protected function mergeViaLock( $key, closure $callback, $exptime = 0, $attempts = 10 ) {
- if ( !$this->lock( $key, 60 ) ) {
+ protected function mergeViaLock( $key, Closure $callback, $exptime = 0, $attempts = 10 ) {
+ if ( !$this->lock( $key, 6 ) ) {
return false;
}
@@ -164,14 +172,17 @@ abstract class BagOStuff {
}
/**
- * @param $key string
- * @param $timeout integer [optional]
- * @return bool success
+ * @param string $key
+ * @param int $timeout [optional]
+ * @return bool Success
*/
- public function lock( $key, $timeout = 60 ) {
+ public function lock( $key, $timeout = 6 ) {
+ $this->clearLastError();
$timestamp = microtime( true ); // starting UNIX timestamp
if ( $this->add( "{$key}:lock", 1, $timeout ) ) {
return true;
+ } elseif ( $this->getLastError() ) {
+ return false;
}
$uRTT = ceil( 1e6 * ( microtime( true ) - $timestamp ) ); // estimate RTT (us)
@@ -186,15 +197,19 @@ abstract class BagOStuff {
$sleep *= 2;
}
usleep( $sleep ); // back off
+ $this->clearLastError();
$locked = $this->add( "{$key}:lock", 1, $timeout );
+ if ( $this->getLastError() ) {
+ return false;
+ }
} while ( !$locked );
return $locked;
}
/**
- * @param $key string
- * @return bool success
+ * @param string $key
+ * @return bool Success
*/
public function unlock( $key ) {
return $this->delete( "{$key}:lock" );
@@ -203,11 +218,11 @@ abstract class BagOStuff {
/**
* Delete all objects expiring before a certain date.
* @param string $date The reference date in MW format
- * @param $progressCallback callback|bool Optional, a function which will be called
+ * @param callable|bool $progressCallback Optional, a function which will be called
* regularly during long-running operations with the percentage progress
* as the first parameter.
*
- * @return bool on success, false if unimplemented
+ * @return bool Success, false if unimplemented
*/
public function deleteObjectsExpiringBefore( $date, $progressCallback = false ) {
// stub
@@ -219,7 +234,7 @@ abstract class BagOStuff {
/**
* Get an associative array containing the item for each of the keys that have items.
* @param array $keys List of strings
- * @return Array
+ * @return array
*/
public function getMulti( array $keys ) {
$res = array();
@@ -233,36 +248,40 @@ abstract class BagOStuff {
}
/**
- * @param $key string
- * @param $value mixed
- * @param $exptime integer
- * @return bool success
+ * Batch insertion
+ * @param array $data $key => $value assoc array
+ * @param int $exptime Either an interval in seconds or a unix timestamp for expiry
+ * @return bool Success
+ * @since 1.24
*/
- public function add( $key, $value, $exptime = 0 ) {
- if ( $this->get( $key ) === false ) {
- return $this->set( $key, $value, $exptime );
+ public function setMulti( array $data, $exptime = 0 ) {
+ $res = true;
+ foreach ( $data as $key => $value ) {
+ if ( !$this->set( $key, $value, $exptime ) ) {
+ $res = false;
+ }
}
- return false; // key already set
+ return $res;
}
/**
- * @param $key string
- * @param $value mixed
- * @param $exptime int
- * @return bool success
+ * @param string $key
+ * @param mixed $value
+ * @param int $exptime
+ * @return bool Success
*/
- public function replace( $key, $value, $exptime = 0 ) {
- if ( $this->get( $key ) !== false ) {
+ public function add( $key, $value, $exptime = 0 ) {
+ if ( $this->get( $key ) === false ) {
return $this->set( $key, $value, $exptime );
}
- return false; // key not already set
+ return false; // key already set
}
/**
* Increase stored value of $key by $value while preserving its TTL
* @param string $key Key to increase
- * @param $value Integer: Value to add to $key (Default 1)
- * @return integer|bool New value or false on failure
+ * @param int $value Value to add to $key (Default 1)
+ * @return int|bool New value or false on failure
*/
public function incr( $key, $value = 1 ) {
if ( !$this->lock( $key ) ) {
@@ -282,16 +301,59 @@ abstract class BagOStuff {
/**
* Decrease stored value of $key by $value while preserving its TTL
- * @param $key String
- * @param $value Integer
- * @return integer
+ * @param string $key
+ * @param int $value
+ * @return int
*/
public function decr( $key, $value = 1 ) {
return $this->incr( $key, - $value );
}
/**
- * @param $text string
+ * Increase stored value of $key by $value while preserving its TTL
+ *
+ * This will create the key with value $init and TTL $ttl if not present
+ *
+ * @param string $key
+ * @param int $ttl
+ * @param int $value
+ * @param int $init
+ * @return bool
+ * @since 1.24
+ */
+ public function incrWithInit( $key, $ttl, $value = 1, $init = 1 ) {
+ return $this->incr( $key, $value ) ||
+ $this->add( $key, (int)$init, $ttl ) || $this->incr( $key, $value );
+ }
+
+ /**
+ * Get the "last error" registered; clearLastError() should be called manually
+ * @return int ERR_* constant for the "last error" registry
+ * @since 1.23
+ */
+ public function getLastError() {
+ return $this->lastError;
+ }
+
+ /**
+ * Clear the "last error" registry
+ * @since 1.23
+ */
+ public function clearLastError() {
+ $this->lastError = self::ERR_NONE;
+ }
+
+ /**
+ * Set the "last error" registry
+ * @param int $err ERR_* constant
+ * @since 1.23
+ */
+ protected function setLastError( $err ) {
+ $this->lastError = $err;
+ }
+
+ /**
+ * @param string $text
*/
public function debug( $text ) {
if ( $this->debugMode ) {
@@ -302,7 +364,7 @@ abstract class BagOStuff {
/**
* Convert an optionally relative time to an absolute time
- * @param $exptime integer
+ * @param int $exptime
* @return int
*/
protected function convertExpiry( $exptime ) {
@@ -317,8 +379,8 @@ abstract class BagOStuff {
* Convert an optionally absolute expiry time to a relative time. If an
* absolute time is specified which is in the past, use a short expiry time.
*
- * @param $exptime integer
- * @return integer
+ * @param int $exptime
+ * @return int
*/
protected function convertToRelative( $exptime ) {
if ( $exptime >= 86400 * 3650 /* 10 years */ ) {
@@ -335,7 +397,7 @@ abstract class BagOStuff {
/**
* Check if a value is an integer
*
- * @param $value mixed
+ * @param mixed $value
* @return bool
*/
protected function isInteger( $value ) {