/** @var int[] Map of (ATTR_* class constant => QOS_* class constant) */
protected $attrMap = [];
- /** 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
-
/** Bitfield constants for get()/getMulti() */
const READ_LATEST = 1; // use latest data for replicated stores
const READ_VERIFIED = 2; // promise that caller can tell when keys are stale
/** Bitfield constants for set()/merge() */
- const WRITE_SYNC = 1; // synchronously write to all locations for replicated stores
- const WRITE_CACHE_ONLY = 2; // Only change state of the in-memory cache
+ const WRITE_SYNC = 4; // synchronously write to all locations for replicated stores
+ const WRITE_CACHE_ONLY = 8; // Only change state of the in-memory cache
/**
* $params include:
* @param string $key
* @param int $ttl Time-to-live (seconds)
* @param callable $callback Callback that derives the new value
- * @param int $flags Bitfield of BagOStuff::READ_* constants [optional]
+ * @param int $flags Bitfield of BagOStuff::READ_* or BagOStuff::WRITE_* constants [optional]
* @return mixed The cached value if found or the result of $callback otherwise
* @since 1.27
*/
}
$value = call_user_func( $callback );
if ( $value !== false ) {
- $this->set( $key, $value, $ttl );
+ $this->set( $key, $value, $ttl, $flags );
}
}
*
* @param string $key
* @return bool True if the item was deleted or not found, false on failure
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants
*/
- abstract public function delete( $key );
+ abstract public function delete( $key, $flags = 0 );
/**
* Merge changes into the existing cache value (possibly creating a new one)
* (which will be false if not present), and takes the arguments:
* (this BagOStuff, cache key, current value, TTL).
* The TTL parameter is reference set to $exptime. It can be overriden in the callback.
+ * If the callback returns false, then the current value will be unchanged (including TTL).
*
* @param string $key
* @param callable $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
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants
* @return bool Success
*/
- protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10 ) {
+ protected function mergeViaCas( $key, $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
do {
$this->clearLastError();
$reportDupes = $this->reportDupes;
$success = true; // do nothing
} elseif ( $currentValue === false ) {
// Try to create the key, failing if it gets created in the meantime
- $success = $this->add( $key, $value, $exptime );
+ $success = $this->add( $key, $value, $exptime, $flags );
} else {
// Try to update the key, failing if it gets changed in the meantime
- $success = $this->cas( $casToken, $key, $value, $exptime );
+ $success = $this->cas( $casToken, $key, $value, $exptime, $flags );
}
if ( $this->getLastError() ) {
$this->logger->warning(
* @param string $key
* @param mixed $value
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants
* @return bool Success
* @throws Exception
*/
- protected function cas( $casToken, $key, $value, $exptime = 0 ) {
+ protected function cas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) {
if ( !$this->lock( $key, 0 ) ) {
return false; // non-blocking
}
$curCasToken = null; // passed by reference
$this->getWithToken( $key, $curCasToken, self::READ_LATEST );
if ( $casToken === $curCasToken ) {
- $success = $this->set( $key, $value, $exptime );
+ $success = $this->set( $key, $value, $exptime, $flags );
} else {
$this->logger->info(
__METHOD__ . ' failed due to race condition for {key}.',
*
* @param string $key
* @param int $expiry
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
* @return bool Success Returns false if there is no key
* @since 1.28
*/
- public function changeTTL( $key, $expiry = 0 ) {
+ public function changeTTL( $key, $expiry = 0, $flags = 0 ) {
$value = $this->get( $key );
- return ( $value === false ) ? false : $this->set( $key, $value, $expiry );
+ return ( $value === false ) ? false : $this->set( $key, $value, $expiry, $flags );
}
/**
function () use ( $key, $expiry, $fname ) {
$this->clearLastError();
if ( $this->add( "{$key}:lock", 1, $expiry ) ) {
- return true; // locked!
+ return WaitConditionLoop::CONDITION_REACHED; // locked!
} elseif ( $this->getLastError() ) {
$this->logger->warning(
$fname . ' failed due to I/O error for {key}.',
/**
* Get an associative array containing the item for each of the keys that have items.
- * @param array $keys List of strings
+ * @param string[] $keys List of keys
* @param int $flags Bitfield; supports READ_LATEST [optional]
* @return array
*/
public function getMulti( array $keys, $flags = 0 ) {
$res = [];
foreach ( $keys as $key ) {
- $val = $this->get( $key );
+ $val = $this->get( $key, $flags );
if ( $val !== false ) {
$res[$key] = $val;
}
}
+
return $res;
}
/**
- * Batch insertion
- * @param array $data $key => $value assoc array
+ * Batch insertion/replace
+ * @param mixed[] $data Map of (key => value)
* @param int $exptime Either an interval in seconds or a unix timestamp for expiry
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
* @return bool Success
* @since 1.24
*/
- public function setMulti( array $data, $exptime = 0 ) {
+ public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
$res = true;
foreach ( $data as $key => $value ) {
- if ( !$this->set( $key, $value, $exptime ) ) {
+ if ( !$this->set( $key, $value, $exptime, $flags ) ) {
$res = false;
}
}
+
+ return $res;
+ }
+
+ /**
+ * Batch deletion
+ * @param string[] $keys List of keys
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants
+ * @return bool Success
+ * @since 1.33
+ */
+ public function deleteMulti( array $keys, $flags = 0 ) {
+ $res = true;
+ foreach ( $keys as $key ) {
+ $res = $this->delete( $key, $flags ) && $res;
+ }
+
return $res;
}
/**
+ * Insertion
* @param string $key
* @param mixed $value
* @param int $exptime
+ * @param int $flags Bitfield of BagOStuff::WRITE_* constants (since 1.33)
* @return bool Success
*/
- public function add( $key, $value, $exptime = 0 ) {
- // @note: avoid lock() here since that method uses *this* method by default
- if ( $this->get( $key ) === false ) {
- return $this->set( $key, $value, $exptime );
- }
- return false; // key already set
- }
+ abstract public function add( $key, $value, $exptime = 0, $flags = 0 );
/**
* Increase stored value of $key by $value while preserving its TTL
if ( !$this->lock( $key, 1 ) ) {
return false;
}
- $n = $this->get( $key );
+ $n = $this->get( $key, self::READ_LATEST );
if ( $this->isInteger( $n ) ) { // key exists?
$n += intval( $value );
$this->set( $key, max( 0, $n ) ); // exptime?
$this->busyCallbacks[] = $workCallback;
}
- /**
- * Modify a cache update operation array for EventRelayer::notify()
- *
- * This is used for relayed writes, e.g. for broadcasting a change
- * to multiple data-centers. If the array contains a 'val' field
- * then the command involves setting a key to that value. Note that
- * for simplicity, 'val' is always a simple scalar value. This method
- * is used to possibly serialize the value and add any cache-specific
- * key/values needed for the relayer daemon (e.g. memcached flags).
- *
- * @param array $event
- * @return array
- * @since 1.26
- */
- public function modifySimpleRelayEvent( array $event ) {
- return $event;
- }
-
/**
* @param string $text
*/
public function makeKeyInternal( $keyspace, $args ) {
$key = $keyspace;
foreach ( $args as $arg ) {
- $arg = str_replace( ':', '%3A', $arg );
- $key = $key . ':' . $arg;
+ $key .= ':' . str_replace( ':', '%3A', $arg );
}
return strtr( $key, ' ', '_' );
}