MediaWiki REL1_33
MapCacheLRU.php
Go to the documentation of this file.
1<?php
24
37class MapCacheLRU implements IExpiringStore, Serializable {
39 private $cache = [];
41 private $timestamps = [];
43 private $epoch;
44
47
50
51 const RANK_TOP = 1.0;
52
54 const SIMPLE = 0;
56 const FIELDS = 1;
57
62 public function __construct( $maxKeys ) {
63 Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
64 Assert::parameter( $maxKeys > 0, '$maxKeys', 'must be above zero' );
65
66 $this->maxCacheKeys = $maxKeys;
67 // Use the current time as the default "as of" timestamp of entries
68 $this->epoch = $this->getCurrentTime();
69 }
70
77 public static function newFromArray( array $values, $maxKeys ) {
78 $mapCache = new self( $maxKeys );
79 $mapCache->cache = ( count( $values ) > $maxKeys )
80 ? array_slice( $values, -$maxKeys, null, true )
81 : $values;
82
83 return $mapCache;
84 }
85
90 public function toArray() {
91 return $this->cache;
92 }
93
109 public function set( $key, $value, $rank = self::RANK_TOP ) {
110 if ( $this->has( $key ) ) {
111 $this->ping( $key );
112 } elseif ( count( $this->cache ) >= $this->maxCacheKeys ) {
113 reset( $this->cache );
114 $evictKey = key( $this->cache );
115 unset( $this->cache[$evictKey] );
116 unset( $this->timestamps[$evictKey] );
117 }
118
119 if ( $rank < 1.0 && $rank > 0 ) {
120 $offset = intval( $rank * count( $this->cache ) );
121 $this->cache = array_slice( $this->cache, 0, $offset, true )
122 + [ $key => $value ]
123 + array_slice( $this->cache, $offset, null, true );
124 } else {
125 $this->cache[$key] = $value;
126 }
127
128 $this->timestamps[$key] = [
129 self::SIMPLE => $this->getCurrentTime(),
130 self::FIELDS => []
131 ];
132 }
133
141 public function has( $key, $maxAge = 0.0 ) {
142 if ( !is_int( $key ) && !is_string( $key ) ) {
143 throw new UnexpectedValueException(
144 __METHOD__ . ': invalid key; must be string or integer.' );
145 }
146
147 if ( !array_key_exists( $key, $this->cache ) ) {
148 return false;
149 }
150
151 return ( $maxAge <= 0 || $this->getAge( $key ) <= $maxAge );
152 }
153
163 public function get( $key, $maxAge = 0.0 ) {
164 if ( !$this->has( $key, $maxAge ) ) {
165 return null;
166 }
167
168 $this->ping( $key );
169
170 return $this->cache[$key];
171 }
172
179 public function setField( $key, $field, $value, $initRank = self::RANK_TOP ) {
180 if ( $this->has( $key ) ) {
181 $this->ping( $key );
182 } else {
183 $this->set( $key, [], $initRank );
184 }
185
186 if ( !is_int( $field ) && !is_string( $field ) ) {
187 throw new UnexpectedValueException(
188 __METHOD__ . ": invalid field for '$key'; must be string or integer." );
189 }
190
191 if ( !is_array( $this->cache[$key] ) ) {
192 $type = gettype( $this->cache[$key] );
193
194 throw new UnexpectedValueException( "The value of '$key' ($type) is not an array." );
195 }
196
197 $this->cache[$key][$field] = $value;
198 $this->timestamps[$key][self::FIELDS][$field] = $this->getCurrentTime();
199 }
200
207 public function hasField( $key, $field, $maxAge = 0.0 ) {
208 $value = $this->get( $key );
209
210 if ( !is_int( $field ) && !is_string( $field ) ) {
211 throw new UnexpectedValueException(
212 __METHOD__ . ": invalid field for '$key'; must be string or integer." );
213 }
214
215 if ( !is_array( $value ) || !array_key_exists( $field, $value ) ) {
216 return false;
217 }
218
219 return ( $maxAge <= 0 || $this->getAge( $key, $field ) <= $maxAge );
220 }
221
228 public function getField( $key, $field, $maxAge = 0.0 ) {
229 if ( !$this->hasField( $key, $field, $maxAge ) ) {
230 return null;
231 }
232
233 return $this->cache[$key][$field];
234 }
235
240 public function getAllKeys() {
241 return array_keys( $this->cache );
242 }
243
256 public function getWithSetCallback(
257 $key, callable $callback, $rank = self::RANK_TOP, $maxAge = 0.0
258 ) {
259 if ( $this->has( $key, $maxAge ) ) {
260 $value = $this->get( $key );
261 } else {
262 $value = call_user_func( $callback );
263 if ( $value !== false ) {
264 $this->set( $key, $value, $rank );
265 }
266 }
267
268 return $value;
269 }
270
277 public function clear( $keys = null ) {
278 if ( func_num_args() == 0 ) {
279 $this->cache = [];
280 $this->timestamps = [];
281 } else {
282 foreach ( (array)$keys as $key ) {
283 unset( $this->cache[$key] );
284 unset( $this->timestamps[$key] );
285 }
286 }
287 }
288
295 public function getMaxSize() {
296 return $this->maxCacheKeys;
297 }
298
307 public function setMaxSize( $maxKeys ) {
308 Assert::parameterType( 'integer', $maxKeys, '$maxKeys' );
309 Assert::parameter( $maxKeys > 0, '$maxKeys', 'must be above zero' );
310
311 $this->maxCacheKeys = $maxKeys;
312 while ( count( $this->cache ) > $this->maxCacheKeys ) {
313 reset( $this->cache );
314 $evictKey = key( $this->cache );
315 unset( $this->cache[$evictKey] );
316 unset( $this->timestamps[$evictKey] );
317 }
318 }
319
325 private function ping( $key ) {
326 $item = $this->cache[$key];
327 unset( $this->cache[$key] );
328 $this->cache[$key] = $item;
329 }
330
336 private function getAge( $key, $field = null ) {
337 if ( $field !== null ) {
338 $mtime = $this->timestamps[$key][self::FIELDS][$field] ?? $this->epoch;
339 } else {
340 $mtime = $this->timestamps[$key][self::SIMPLE] ?? $this->epoch;
341 }
342
343 return ( $this->getCurrentTime() - $mtime );
344 }
345
346 public function serialize() {
347 return serialize( [
348 'entries' => $this->cache,
349 'timestamps' => $this->timestamps
350 ] );
351 }
352
353 public function unserialize( $serialized ) {
355 $this->cache = $data['entries'] ?? [];
356 $this->timestamps = $data['timestamps'] ?? [];
357 $this->epoch = $this->getCurrentTime();
358 }
359
364 protected function getCurrentTime() {
365 return $this->wallClockOverride ?: microtime( true );
366 }
367
372 public function setMockTime( &$time ) {
373 $this->wallClockOverride =& $time;
374 }
375}
serialize()
unserialize( $serialized)
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
Handles a simple LRU key/value map with a maximum number of entries.
getField( $key, $field, $maxAge=0.0)
getAge( $key, $field=null)
int $maxCacheKeys
Max number of entries.
static newFromArray(array $values, $maxKeys)
__construct( $maxKeys)
hasField( $key, $field, $maxAge=0.0)
ping( $key)
Push an entry to the top of the cache.
setMockTime(&$time)
float $epoch
Default entry timestamp if not specified.
unserialize( $serialized)
clear( $keys=null)
Clear one or several cache entries, or all cache entries.
setMaxSize( $maxKeys)
Resize the maximum number of cache entries, removing older entries as needed.
getMaxSize()
Get the maximum number of keys allowed.
setField( $key, $field, $value, $initRank=self::RANK_TOP)
has( $key, $maxAge=0.0)
Check if a key exists.
array $timestamps
Map of (key => (UNIX timestamp, (field => UNIX timestamp)))
float null $wallClockOverride
getWithSetCallback( $key, callable $callback, $rank=self::RANK_TOP, $maxAge=0.0)
Get an item with the given key, producing and setting it if not found.
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition hooks.txt:1802
either a unescaped string or a HtmlArmor object after in associative array form externallinks including delete and has completed for all link tables whether this was an auto creation use $formDescriptor instead default is conds Array Extra conditions for the No matching items in log is displayed if loglist is empty msgKey Array If you want a nice box with a set this to the key of the message First element is the message key
Definition hooks.txt:2163
$data
Utility to generate mapping file used in mw.Title (phpCharToUpper.json)
Generic interface for lightweight expiring object stores.
you have access to all of the normal MediaWiki so you can get a DB use the cache
$cache
Definition mcc.php:33
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))
foreach( $res as $row) $serialized