MediaWiki  master
CachedBagOStuff.php
Go to the documentation of this file.
1 <?php
37 class CachedBagOStuff extends BagOStuff {
39  protected $store;
41  protected $procCache;
42 
48  public function __construct( BagOStuff $backend, $params = [] ) {
49  $params['keyspace'] = $backend->keyspace;
50  parent::__construct( $params );
51 
52  $this->store = $backend;
53  $this->procCache = new HashBagOStuff( $params );
54 
55  $this->attrMap = $backend->attrMap;
56  }
57 
58  public function get( $key, $flags = 0 ) {
59  $value = $this->procCache->get( $key, $flags );
60  if ( $value !== false || $this->procCache->hasKey( $key ) ) {
61  return $value;
62  }
63 
64  $value = $this->store->proxyCall(
65  __FUNCTION__,
66  self::ARG0_KEY,
67  self::RES_NONKEY,
68  func_get_args(),
69  $this
70  );
71  $this->set( $key, $value, self::TTL_INDEFINITE, self::WRITE_CACHE_ONLY );
72 
73  return $value;
74  }
75 
76  public function getMulti( array $keys, $flags = 0 ) {
77  $valueByKeyCached = [];
78 
79  $keysFetch = [];
80  foreach ( $keys as $key ) {
81  $value = $this->procCache->get( $key, $flags );
82  if ( $value === false && !$this->procCache->hasKey( $key ) ) {
83  $keysFetch[] = $key;
84  } else {
85  $valueByKeyCached[$key] = $value;
86  }
87  }
88 
89  $valueByKeyFetched = $this->store->proxyCall(
90  __FUNCTION__,
91  self::ARG0_KEYARR,
92  self::RES_KEYMAP,
93  [ $keysFetch, $flags ],
94  $this
95  );
96  $this->setMulti( $valueByKeyFetched, self::TTL_INDEFINITE, self::WRITE_CACHE_ONLY );
97 
98  return $valueByKeyCached + $valueByKeyFetched;
99  }
100 
101  public function set( $key, $value, $exptime = 0, $flags = 0 ) {
102  $this->procCache->set( $key, $value, $exptime, $flags );
103 
104  if ( $this->fieldHasFlags( $flags, self::WRITE_CACHE_ONLY ) ) {
105  return true;
106  }
107 
108  return $this->store->proxyCall(
109  __FUNCTION__,
110  self::ARG0_KEY,
111  self::RES_NONKEY,
112  func_get_args(),
113  $this
114  );
115  }
116 
117  public function delete( $key, $flags = 0 ) {
118  $this->procCache->delete( $key, $flags );
119 
120  if ( $this->fieldHasFlags( $flags, self::WRITE_CACHE_ONLY ) ) {
121  return true;
122  }
123 
124  return $this->store->proxyCall(
125  __FUNCTION__,
126  self::ARG0_KEY,
127  self::RES_NONKEY,
128  func_get_args(),
129  $this
130  );
131  }
132 
133  public function add( $key, $value, $exptime = 0, $flags = 0 ) {
134  if ( $this->get( $key ) === false ) {
135  return $this->set( $key, $value, $exptime, $flags );
136  }
137 
138  // key already set
139  return false;
140  }
141 
142  // These just call the backend (tested elsewhere)
143  // @codeCoverageIgnoreStart
144 
145  public function merge( $key, callable $callback, $exptime = 0, $attempts = 10, $flags = 0 ) {
146  $this->procCache->delete( $key );
147 
148  return $this->store->proxyCall(
149  __FUNCTION__,
150  self::ARG0_KEY,
151  self::RES_NONKEY,
152  func_get_args(),
153  $this
154  );
155  }
156 
157  public function changeTTL( $key, $exptime = 0, $flags = 0 ) {
158  $this->procCache->delete( $key );
159 
160  return $this->store->proxyCall(
161  __FUNCTION__,
162  self::ARG0_KEY,
163  self::RES_NONKEY,
164  func_get_args(),
165  $this
166  );
167  }
168 
169  public function lock( $key, $timeout = 6, $exptime = 6, $rclass = '' ) {
170  return $this->store->proxyCall(
171  __FUNCTION__,
172  self::ARG0_KEY,
173  self::RES_NONKEY,
174  func_get_args(),
175  $this
176  );
177  }
178 
179  public function unlock( $key ) {
180  return $this->store->proxyCall(
181  __FUNCTION__,
182  self::ARG0_KEY,
183  self::RES_NONKEY,
184  func_get_args(),
185  $this
186  );
187  }
188 
190  $timestamp,
191  callable $progress = null,
192  $limit = INF,
193  string $tag = null
194  ) {
195  $this->procCache->deleteObjectsExpiringBefore( $timestamp, $progress, $limit, $tag );
196 
197  return $this->store->proxyCall(
198  __FUNCTION__,
199  self::ARG0_NONKEY,
200  self::RES_NONKEY,
201  func_get_args(),
202  $this
203  );
204  }
205 
206  public function makeKeyInternal( $keyspace, $components ) {
207  return $this->genericKeyFromComponents( $keyspace, ...$components );
208  }
209 
210  public function makeKey( $collection, ...$components ) {
211  return $this->genericKeyFromComponents( $this->keyspace, $collection, ...$components );
212  }
213 
214  public function makeGlobalKey( $collection, ...$components ) {
215  return $this->genericKeyFromComponents( self::GLOBAL_KEYSPACE, $collection, ...$components );
216  }
217 
218  protected function convertGenericKey( $key ) {
219  // short-circuit; already uses "generic" keys
220  return $key;
221  }
222 
223  public function setMulti( array $valueByKey, $exptime = 0, $flags = 0 ) {
224  $this->procCache->setMulti( $valueByKey, $exptime, $flags );
225 
226  if ( $this->fieldHasFlags( $flags, self::WRITE_CACHE_ONLY ) ) {
227  return true;
228  }
229 
230  return $this->store->proxyCall(
231  __FUNCTION__,
232  self::ARG0_KEYMAP,
233  self::RES_NONKEY,
234  func_get_args(),
235  $this
236  );
237  }
238 
239  public function deleteMulti( array $keys, $flags = 0 ) {
240  $this->procCache->deleteMulti( $keys, $flags );
241 
242  if ( $this->fieldHasFlags( $flags, self::WRITE_CACHE_ONLY ) ) {
243  return true;
244  }
245 
246  return $this->store->proxyCall(
247  __FUNCTION__,
248  self::ARG0_KEYARR,
249  self::RES_NONKEY,
250  func_get_args(),
251  $this
252  );
253  }
254 
255  public function changeTTLMulti( array $keys, $exptime, $flags = 0 ) {
256  $this->procCache->changeTTLMulti( $keys, $exptime, $flags );
257 
258  if ( $this->fieldHasFlags( $flags, self::WRITE_CACHE_ONLY ) ) {
259  return true;
260  }
261 
262  return $this->store->proxyCall(
263  __FUNCTION__,
264  self::ARG0_KEYARR,
265  self::RES_NONKEY,
266  func_get_args(),
267  $this
268  );
269  }
270 
271  public function incr( $key, $value = 1, $flags = 0 ) {
272  $this->procCache->delete( $key );
273 
274  return $this->store->proxyCall(
275  __FUNCTION__,
276  self::ARG0_KEY,
277  self::RES_NONKEY,
278  func_get_args(),
279  $this
280  );
281  }
282 
283  public function decr( $key, $value = 1, $flags = 0 ) {
284  $this->procCache->delete( $key );
285 
286  return $this->store->proxyCall(
287  __FUNCTION__,
288  self::ARG0_KEY,
289  self::RES_NONKEY,
290  func_get_args(),
291  $this
292  );
293  }
294 
295  public function incrWithInit( $key, $exptime, $step = 1, $init = null, $flags = 0 ) {
296  $this->procCache->delete( $key );
297 
298  return $this->store->proxyCall(
299  __FUNCTION__,
300  self::ARG0_KEY,
301  self::RES_NONKEY,
302  func_get_args(),
303  $this
304  );
305  }
306 
307  public function addBusyCallback( callable $workCallback ) {
308  $this->store->addBusyCallback( $workCallback );
309  }
310 
311  public function setMockTime( &$time ) {
312  parent::setMockTime( $time );
313  $this->procCache->setMockTime( $time );
314  $this->store->setMockTime( $time );
315  }
316 
317  // @codeCoverageIgnoreEnd
318 }
Class representing a cache/ephemeral data store.
Definition: BagOStuff.php:85
get( $key, $flags=0)
Get an item.
genericKeyFromComponents(... $components)
At a minimum, there must be a keyspace and collection name component.
Definition: BagOStuff.php:703
const WRITE_CACHE_ONLY
Bitfield constants for set()/merge(); these are only advisory.
Definition: BagOStuff.php:122
string $keyspace
Default keyspace; used by makeKey()
Definition: BagOStuff.php:101
fieldHasFlags( $field, $flags)
Definition: BagOStuff.php:612
Wrapper around a BagOStuff that caches data in memory.
__construct(BagOStuff $backend, $params=[])
decr( $key, $value=1, $flags=0)
Decrease stored value of $key by $value while preserving its TTL.
getMulti(array $keys, $flags=0)
Get a batch of items.
makeGlobalKey( $collection,... $components)
Make a cache key for the default keyspace and given components.
unlock( $key)
Release an advisory lock on a key string.
makeKeyInternal( $keyspace, $components)
deleteMulti(array $keys, $flags=0)
Delete a batch of items.
makeKey( $collection,... $components)
Make a cache key for the global keyspace and given components.
deleteObjectsExpiringBefore( $timestamp, callable $progress=null, $limit=INF, string $tag=null)
Delete all objects expiring before a certain date.
changeTTLMulti(array $keys, $exptime, $flags=0)
Change the expiration of multiple items.
add( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
HashBagOStuff $procCache
lock( $key, $timeout=6, $exptime=6, $rclass='')
Acquire an advisory lock on a key string, exclusive to the caller.
changeTTL( $key, $exptime=0, $flags=0)
Change the expiration on an item.
addBusyCallback(callable $workCallback)
Let a callback be run to avoid wasting time on special blocking calls.
merge( $key, callable $callback, $exptime=0, $attempts=10, $flags=0)
Merge changes into the existing cache value (possibly creating a new one)
setMulti(array $valueByKey, $exptime=0, $flags=0)
Set a batch of 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.
incr( $key, $value=1, $flags=0)
Increase stored value of $key by $value while preserving its TTL.
convertGenericKey( $key)
Convert a "generic" reversible cache key into one for this cache.
Simple store for keeping values in an associative array for the current process.