API: Fix documentation for ApiBase::require*OneParameter
[lhc/web/wiklou.git] / includes / objectcache / BagOStuff.php
index 217142c..56f1be2 100644 (file)
 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,13 +143,13 @@ 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 ) {
+       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 = 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,10 +248,27 @@ abstract class BagOStuff {
        }
 
        /**
-        * @param $key string
-        * @param $value mixed
-        * @param $exptime integer
+        * 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 setMulti( array $data, $exptime = 0 ) {
+               $res = true;
+               foreach ( $data as $key => $value ) {
+                       if ( !$this->set( $key, $value, $exptime ) ) {
+                               $res = false;
+                       }
+               }
+               return $res;
+       }
+
+       /**
+        * @param string $key
+        * @param mixed $value
+        * @param int $exptime
+        * @return bool Success
         */
        public function add( $key, $value, $exptime = 0 ) {
                if ( $this->get( $key ) === false ) {
@@ -246,11 +278,11 @@ abstract class BagOStuff {
        }
 
        /**
-        * @param $key string
-        * @param $value mixed
-        * @param $exptime int
-        * @return bool success
-        * @deprecated 1.23
+        * @param string $key
+        * @param mixed $value
+        * @param int $exptime
+        * @return bool Success
+        * @deprecated since 1.23
         */
        public function replace( $key, $value, $exptime = 0 ) {
                wfDeprecated( __METHOD__, '1.23' );
@@ -263,8 +295,8 @@ abstract class BagOStuff {
        /**
         * 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 ) ) {
@@ -284,16 +316,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 integer $ttl
+        * @param integer $value
+        * @param integer $init
+        * @return bool
+        * @since 1.24
+        */
+       public function incrWithInit( $key, $ttl, $value = 1, $init = 1 ) {
+               return $this->incr( $key, $value ) ||
+                       $this->add( $key, $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 ) {
@@ -304,7 +379,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 ) {
@@ -319,8 +394,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 */ ) {
@@ -337,7 +412,7 @@ abstract class BagOStuff {
        /**
         * Check if a value is an integer
         *
-        * @param $value mixed
+        * @param mixed $value
         * @return bool
         */
        protected function isInteger( $value ) {