21use Wikimedia\ObjectFactory\ObjectFactory;
41 private $consistencyWindow;
43 private $lastKeyWrites = [];
46 private const MAX_WRITE_DELAY = 5;
61 parent::__construct( $params );
63 if ( !isset( $params[
'writeFactory'] ) ) {
64 throw new InvalidArgumentException(
65 __METHOD__ .
': the "writeFactory" parameter is required' );
66 } elseif ( !isset( $params[
'readFactory'] ) ) {
67 throw new InvalidArgumentException(
68 __METHOD__ .
': the "readFactory" parameter is required' );
71 $this->consistencyWindow = $params[
'sessionConsistencyWindow'] ?? self::MAX_WRITE_DELAY;
72 $this->writeStore = ( $params[
'writeFactory'] instanceof
BagOStuff )
73 ? $params[
'writeFactory']
74 : ObjectFactory::getObjectFromSpec( $params[
'writeFactory'] );
75 $this->readStore = ( $params[
'readFactory'] instanceof
BagOStuff )
76 ? $params[
'readFactory']
77 : ObjectFactory::getObjectFromSpec( $params[
'readFactory'] );
78 $this->attrMap = $this->
mergeFlagMaps( [ $this->readStore, $this->writeStore ] );
81 public function get( $key, $flags = 0 ) {
83 $this->hadRecentSessionWrite( [ $key ] ) ||
91 return $store->proxyCall(
100 public function set( $key, $value, $exptime = 0, $flags = 0 ) {
101 $this->remarkRecentSessionWrite( [ $key ] );
103 return $this->writeStore->proxyCall(
112 public function delete( $key, $flags = 0 ) {
113 $this->remarkRecentSessionWrite( [ $key ] );
115 return $this->writeStore->proxyCall(
124 public function add( $key, $value, $exptime = 0, $flags = 0 ) {
125 $this->remarkRecentSessionWrite( [ $key ] );
127 return $this->writeStore->proxyCall(
136 public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
137 $this->remarkRecentSessionWrite( [ $key ] );
139 return $this->writeStore->proxyCall(
148 public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
149 $this->remarkRecentSessionWrite( [ $key ] );
151 return $this->writeStore->proxyCall(
160 public function lock( $key, $timeout = 6, $exptime = 6, $rclass =
'' ) {
161 return $this->writeStore->proxyCall(
171 return $this->writeStore->proxyCall(
182 callable $progress =
null,
186 return $this->writeStore->proxyCall(
197 $this->hadRecentSessionWrite(
$keys ) ||
205 return $store->proxyCall(
214 public function setMulti( array $valueByKey, $exptime = 0, $flags = 0 ) {
215 $this->remarkRecentSessionWrite( array_keys( $valueByKey ) );
217 return $this->writeStore->proxyCall(
227 $this->remarkRecentSessionWrite(
$keys );
229 return $this->writeStore->proxyCall(
239 $this->remarkRecentSessionWrite(
$keys );
241 return $this->writeStore->proxyCall(
250 public function incrWithInit( $key, $exptime, $step = 1, $init =
null, $flags = 0 ) {
251 $this->remarkRecentSessionWrite( [ $key ] );
253 return $this->writeStore->proxyCall(
266 public function makeKey( $collection, ...$components ) {
280 return $this->writeStore->addBusyCallback( $workCallback );
284 parent::setMockTime( $time );
285 $this->writeStore->setMockTime( $time );
286 $this->readStore->setMockTime( $time );
293 private function hadRecentSessionWrite( array
$keys ) {
294 $now = $this->getCurrentTime();
295 foreach (
$keys as $key ) {
296 $ts = $this->lastKeyWrites[$key] ?? 0;
297 if ( $ts && ( $now - $ts ) <= $this->consistencyWindow ) {
308 private function remarkRecentSessionWrite( array
$keys ) {
310 foreach (
$keys as $key ) {
312 unset( $this->lastKeyWrites[$key] );
313 $this->lastKeyWrites[$key] = $now;
316 if ( ( $now - reset( $this->lastKeyWrites ) ) > $this->consistencyWindow ) {
317 $this->lastKeyWrites = array_filter(
318 $this->lastKeyWrites,
319 function ( $timestamp ) use ( $now ) {
320 return ( ( $now - $timestamp ) <= $this->consistencyWindow );
Class representing a cache/ephemeral data store.
mergeFlagMaps(array $bags)
Merge the flag maps of one or more BagOStuff objects into a "lowest common denominator" map.
genericKeyFromComponents(... $components)
At a minimum, there must be a keyspace and collection name component.
string $keyspace
Default keyspace; used by makeKey()
fieldHasFlags( $field, $flags)
A cache class that directs writes to one set of servers and reads to another.
add( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
deleteObjectsExpiringBefore( $timestamp, callable $progress=null, $limit=INF, string $tag=null)
Delete all objects expiring before a certain date.
__construct( $params)
Constructor.
changeTTLMulti(array $keys, $exptime, $flags=0)
Change the expiration of multiple items.
incrWithInit( $key, $exptime, $step=1, $init=null, $flags=0)
Increase the value of the given key (no TTL change) if it exists or create it otherwise.
lock( $key, $timeout=6, $exptime=6, $rclass='')
Acquire an advisory lock on a key string, exclusive to the caller.
makeGlobalKey( $collection,... $components)
Make a cache key for the default keyspace and given components.
convertGenericKey( $key)
Convert a "generic" reversible cache key into one for this cache.
deleteMulti(array $keys, $flags=0)
Delete a batch of items.
getMulti(array $keys, $flags=0)
Get a batch of items.
changeTTL( $key, $exptime=0, $flags=0)
Change the expiration on an item.
setMulti(array $valueByKey, $exptime=0, $flags=0)
Set a batch of items.
addBusyCallback(callable $workCallback)
Let a callback be run to avoid wasting time on special blocking calls.
makeKeyInternal( $keyspace, $components)
merge( $key, callable $callback, $exptime=0, $attempts=10, $flags=0)
Merge changes into the existing cache value (possibly creating a new one)
unlock( $key)
Release an advisory lock on a key string.
makeKey( $collection,... $components)
Make a cache key for the global keyspace and given components.