MediaWiki  master
ReplicatedBagOStuff.php
Go to the documentation of this file.
1 <?php
21 use Wikimedia\ObjectFactory;
22 
36  private $writeStore;
38  private $readStore;
39 
43  private $lastKeyWrites = [];
44 
46  private const MAX_WRITE_DELAY = 5;
47 
60  public function __construct( $params ) {
61  parent::__construct( $params );
62 
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' );
69  }
70 
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 ] );
79  }
80 
81  public function setDebug( $enabled ) {
82  parent::setDebug( $enabled );
83  $this->writeStore->setDebug( $enabled );
84  $this->readStore->setDebug( $enabled );
85  }
86 
87  public function get( $key, $flags = 0 ) {
88  return (
89  $this->hadRecentSessionWrite( [ $key ] ) ||
90  $this->fieldHasFlags( $flags, self::READ_LATEST )
91  )
92  ? $this->writeStore->get( $key, $flags )
93  : $this->readStore->get( $key, $flags );
94  }
95 
96  public function set( $key, $value, $exptime = 0, $flags = 0 ) {
97  $this->remarkRecentSessionWrite( [ $key ] );
98 
99  return $this->writeStore->set( $key, $value, $exptime, $flags );
100  }
101 
102  public function delete( $key, $flags = 0 ) {
103  $this->remarkRecentSessionWrite( [ $key ] );
104 
105  return $this->writeStore->delete( $key, $flags );
106  }
107 
108  public function add( $key, $value, $exptime = 0, $flags = 0 ) {
109  $this->remarkRecentSessionWrite( [ $key ] );
110 
111  return $this->writeStore->add( $key, $value, $exptime, $flags );
112  }
113 
114  public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
115  $this->remarkRecentSessionWrite( [ $key ] );
116 
117  return $this->writeStore->merge( $key, $callback, $exptime, $attempts, $flags );
118  }
119 
120  public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
121  $this->remarkRecentSessionWrite( [ $key ] );
122 
123  return $this->writeStore->changeTTL( $key, $exptime, $flags );
124  }
125 
126  public function lock( $key, $timeout = 6, $expiry = 6, $rclass = '' ) {
127  return $this->writeStore->lock( $key, $timeout, $expiry, $rclass );
128  }
129 
130  public function unlock( $key ) {
131  return $this->writeStore->unlock( $key );
132  }
133 
135  $timestamp,
136  callable $progress = null,
137  $limit = INF
138  ) {
139  return $this->writeStore->deleteObjectsExpiringBefore( $timestamp, $progress, $limit );
140  }
141 
142  public function getMulti( array $keys, $flags = 0 ) {
143  return (
144  $this->hadRecentSessionWrite( $keys ) ||
145  $this->fieldHasFlags( $flags, self::READ_LATEST )
146  )
147  ? $this->writeStore->getMulti( $keys, $flags )
148  : $this->readStore->getMulti( $keys, $flags );
149  }
150 
151  public function setMulti( array $data, $exptime = 0, $flags = 0 ) {
152  $this->remarkRecentSessionWrite( array_keys( $data ) );
153 
154  return $this->writeStore->setMulti( $data, $exptime, $flags );
155  }
156 
157  public function deleteMulti( array $keys, $flags = 0 ) {
158  $this->remarkRecentSessionWrite( $keys );
159 
160  return $this->writeStore->deleteMulti( $keys, $flags );
161  }
162 
163  public function changeTTLMulti( array $keys, $exptime, $flags = 0 ) {
164  $this->remarkRecentSessionWrite( $keys );
165 
166  return $this->writeStore->changeTTLMulti( $keys, $exptime, $flags );
167  }
168 
169  public function incr( $key, $value = 1, $flags = 0 ) {
170  $this->remarkRecentSessionWrite( [ $key ] );
171 
172  return $this->writeStore->incr( $key, $value, $flags );
173  }
174 
175  public function decr( $key, $value = 1, $flags = 0 ) {
176  $this->remarkRecentSessionWrite( [ $key ] );
177 
178  return $this->writeStore->decr( $key, $value, $flags );
179  }
180 
181  public function incrWithInit( $key, $exptime, $value = 1, $init = null, $flags = 0 ) {
182  $this->remarkRecentSessionWrite( [ $key ] );
183 
184  return $this->writeStore->incrWithInit( $key, $exptime, $value, $init, $flags );
185  }
186 
187  public function getLastError() {
188  return ( $this->writeStore->getLastError() !== self::ERR_NONE )
189  ? $this->writeStore->getLastError()
190  : $this->readStore->getLastError();
191  }
192 
193  public function clearLastError() {
194  $this->writeStore->clearLastError();
195  $this->readStore->clearLastError();
196  }
197 
198  public function makeKeyInternal( $keyspace, $args ) {
199  return $this->writeStore->makeKeyInternal( ...func_get_args() );
200  }
201 
202  public function makeKey( $class, ...$components ) {
203  return $this->writeStore->makeKey( ...func_get_args() );
204  }
205 
206  public function makeGlobalKey( $class, ...$components ) {
207  return $this->writeStore->makeGlobalKey( ...func_get_args() );
208  }
209 
210  public function addBusyCallback( callable $workCallback ) {
211  $this->writeStore->addBusyCallback( $workCallback );
212  }
213 
214  public function setNewPreparedValues( array $valueByKey ) {
215  return $this->writeStore->setNewPreparedValues( $valueByKey );
216  }
217 
218  public function setMockTime( &$time ) {
219  parent::setMockTime( $time );
220  $this->writeStore->setMockTime( $time );
221  $this->readStore->setMockTime( $time );
222  }
223 
228  private function hadRecentSessionWrite( array $keys ) {
229  $now = $this->getCurrentTime();
230  foreach ( $keys as $key ) {
231  $ts = $this->lastKeyWrites[$key] ?? 0;
232  if ( $ts && ( $now - $ts ) <= $this->consistencyWindow ) {
233  return true;
234  }
235  }
236 
237  return false;
238  }
239 
243  private function remarkRecentSessionWrite( array $keys ) {
244  $now = $this->getCurrentTime();
245  foreach ( $keys as $key ) {
246  unset( $this->lastKeyWrites[$key] ); // move to the end
247  $this->lastKeyWrites[$key] = $now;
248  }
249  // Prune out the map if the first key is obsolete
250  if ( ( $now - reset( $this->lastKeyWrites ) ) > $this->consistencyWindow ) {
251  $this->lastKeyWrites = array_filter(
252  $this->lastKeyWrites,
253  function ( $timestamp ) use ( $now ) {
254  return ( ( $now - $timestamp ) <= $this->consistencyWindow );
255  }
256  );
257  }
258  }
259 }
ReplicatedBagOStuff\deleteObjectsExpiringBefore
deleteObjectsExpiringBefore( $timestamp, callable $progress=null, $limit=INF)
Delete all objects expiring before a certain date.
Definition: ReplicatedBagOStuff.php:134
ReplicatedBagOStuff\$readStore
BagOStuff $readStore
Definition: ReplicatedBagOStuff.php:38
ReplicatedBagOStuff\setMulti
setMulti(array $data, $exptime=0, $flags=0)
Batch insertion/replace.
Definition: ReplicatedBagOStuff.php:151
ReplicatedBagOStuff\getLastError
getLastError()
Get the "last error" registered; clearLastError() should be called manually.
Definition: ReplicatedBagOStuff.php:187
ReplicatedBagOStuff\makeKeyInternal
makeKeyInternal( $keyspace, $args)
Construct a cache key.
Definition: ReplicatedBagOStuff.php:198
ReplicatedBagOStuff\setDebug
setDebug( $enabled)
Definition: ReplicatedBagOStuff.php:81
ReplicatedBagOStuff\$writeStore
BagOStuff $writeStore
Definition: ReplicatedBagOStuff.php:36
BagOStuff
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:71
ReplicatedBagOStuff\lock
lock( $key, $timeout=6, $expiry=6, $rclass='')
Acquire an advisory lock on a key string.
Definition: ReplicatedBagOStuff.php:126
ReplicatedBagOStuff\addBusyCallback
addBusyCallback(callable $workCallback)
Let a callback be run to avoid wasting time on special blocking calls.
Definition: ReplicatedBagOStuff.php:210
ReplicatedBagOStuff\hadRecentSessionWrite
hadRecentSessionWrite(array $keys)
Definition: ReplicatedBagOStuff.php:228
ReplicatedBagOStuff\clearLastError
clearLastError()
Clear the "last error" registry.
Definition: ReplicatedBagOStuff.php:193
$args
if( $line===false) $args
Definition: mcc.php:124
ReplicatedBagOStuff\makeGlobalKey
makeGlobalKey( $class,... $components)
Make a global cache key.
Definition: ReplicatedBagOStuff.php:206
ReplicatedBagOStuff\decr
decr( $key, $value=1, $flags=0)
Decrease stored value of $key by $value while preserving its TTL.
Definition: ReplicatedBagOStuff.php:175
ReplicatedBagOStuff\makeKey
makeKey( $class,... $components)
Make a cache key, scoped to this instance's keyspace.
Definition: ReplicatedBagOStuff.php:202
BagOStuff\mergeFlagMaps
mergeFlagMaps(array $bags)
Merge the flag maps of one or more BagOStuff objects into a "lowest common denominator" map.
Definition: BagOStuff.php:519
ReplicatedBagOStuff\incrWithInit
incrWithInit( $key, $exptime, $value=1, $init=null, $flags=0)
Increase the value of the given key (no TTL change) if it exists or create it otherwise.
Definition: ReplicatedBagOStuff.php:181
ReplicatedBagOStuff\__construct
__construct( $params)
Constructor.
Definition: ReplicatedBagOStuff.php:60
ReplicatedBagOStuff\setNewPreparedValues
setNewPreparedValues(array $valueByKey)
Prepare values for storage and get their serialized sizes, or, estimate those sizes.
Definition: ReplicatedBagOStuff.php:214
ReplicatedBagOStuff\changeTTLMulti
changeTTLMulti(array $keys, $exptime, $flags=0)
Change the expiration of multiple keys that exist.
Definition: ReplicatedBagOStuff.php:163
ReplicatedBagOStuff\incr
incr( $key, $value=1, $flags=0)
Increase stored value of $key by $value while preserving its TTL.
Definition: ReplicatedBagOStuff.php:169
ReplicatedBagOStuff
A cache class that directs writes to one set of servers and reads to another.
Definition: ReplicatedBagOStuff.php:34
BagOStuff\fieldHasFlags
fieldHasFlags( $field, $flags)
Definition: BagOStuff.php:509
ReplicatedBagOStuff\$lastKeyWrites
float[] $lastKeyWrites
Map of (key => UNIX timestamp)
Definition: ReplicatedBagOStuff.php:43
$keys
$keys
Definition: testCompression.php:72
BagOStuff\getCurrentTime
getCurrentTime()
Definition: BagOStuff.php:566
ReplicatedBagOStuff\add
add( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
Definition: ReplicatedBagOStuff.php:108
ReplicatedBagOStuff\merge
merge( $key, callable $callback, $exptime=0, $attempts=10, $flags=0)
Merge changes into the existing cache value (possibly creating a new one)
Definition: ReplicatedBagOStuff.php:114
ReplicatedBagOStuff\unlock
unlock( $key)
Release an advisory lock on a key string.
Definition: ReplicatedBagOStuff.php:130
ReplicatedBagOStuff\$consistencyWindow
int $consistencyWindow
Seconds to read from the master source for a key after writing to it.
Definition: ReplicatedBagOStuff.php:41
ReplicatedBagOStuff\setMockTime
setMockTime(&$time)
Definition: ReplicatedBagOStuff.php:218
ReplicatedBagOStuff\getMulti
getMulti(array $keys, $flags=0)
Get an associative array containing the item for each of the keys that have items.
Definition: ReplicatedBagOStuff.php:142
ReplicatedBagOStuff\remarkRecentSessionWrite
remarkRecentSessionWrite(array $keys)
Definition: ReplicatedBagOStuff.php:243
ReplicatedBagOStuff\deleteMulti
deleteMulti(array $keys, $flags=0)
Batch deletion.
Definition: ReplicatedBagOStuff.php:157
ReplicatedBagOStuff\changeTTL
changeTTL( $key, $exptime=0, $flags=0)
Change the expiration on a key if it exists.
Definition: ReplicatedBagOStuff.php:120