MediaWiki  1.30.0
WANObjectCache.php
Go to the documentation of this file.
1 <?php
22 use Psr\Log\LoggerAwareInterface;
23 use Psr\Log\LoggerInterface;
24 use Psr\Log\NullLogger;
25 
80 class WANObjectCache implements IExpiringStore, LoggerAwareInterface {
82  protected $cache;
84  protected $processCaches = [];
86  protected $purgeChannel;
88  protected $purgeRelayer;
90  protected $logger;
91 
94 
96  private $callbackDepth = 0;
98  private $warmupCache = [];
100  private $warmupKeyMisses = 0;
101 
103  const MAX_COMMIT_DELAY = 3;
105  const MAX_READ_LAG = 7;
107  const HOLDOFF_TTL = 11; // MAX_COMMIT_DELAY + MAX_READ_LAG + 1
108 
112  const LOCK_TTL = 10;
114  const LOW_TTL = 30;
116  const LOCK_TSE = 1;
117 
119  const AGE_NEW = 60;
121  const HOT_TTR = 900;
123  const HIT_RATE_HIGH = 1;
125  const RAMPUP_TTL = 30;
126 
128  const TTL_UNCACHEABLE = -1;
130  const TSE_NONE = -1;
132  const TTL_LAGGED = 30;
134  const HOLDOFF_NONE = 0;
136  const MIN_TIMESTAMP_NONE = 0.0;
137 
139  const TINY_NEGATIVE = -0.000001;
140 
142  const VERSION = 1;
143 
144  const FLD_VERSION = 0; // key to cache version number
145  const FLD_VALUE = 1; // key to the cached value
146  const FLD_TTL = 2; // key to the original TTL
147  const FLD_TIME = 3; // key to the cache time
148  const FLD_FLAGS = 4; // key to the flags bitfield
149  const FLD_HOLDOFF = 5; // key to any hold-off TTL
150 
152  const FLG_STALE = 1;
153 
154  const ERR_NONE = 0; // no error
155  const ERR_NO_RESPONSE = 1; // no response
156  const ERR_UNREACHABLE = 2; // can't connect
157  const ERR_UNEXPECTED = 3; // response gave some error
158  const ERR_RELAY = 4; // relay broadcast failed
159 
160  const VALUE_KEY_PREFIX = 'WANCache:v:';
161  const INTERIM_KEY_PREFIX = 'WANCache:i:';
162  const TIME_KEY_PREFIX = 'WANCache:t:';
163  const MUTEX_KEY_PREFIX = 'WANCache:m:';
164 
165  const PURGE_VAL_PREFIX = 'PURGED:';
166 
167  const VFLD_DATA = 'WOC:d'; // key to the value of versioned data
168  const VFLD_VERSION = 'WOC:v'; // key to the version of the value present
169 
170  const PC_PRIMARY = 'primary:1000'; // process cache name and max key count
171 
172  const DEFAULT_PURGE_CHANNEL = 'wancache-purge';
173 
181  public function __construct( array $params ) {
182  $this->cache = $params['cache'];
183  $this->purgeChannel = isset( $params['channels']['purge'] )
184  ? $params['channels']['purge']
186  $this->purgeRelayer = isset( $params['relayers']['purge'] )
187  ? $params['relayers']['purge']
188  : new EventRelayerNull( [] );
189  $this->setLogger( isset( $params['logger'] ) ? $params['logger'] : new NullLogger() );
190  }
191 
192  public function setLogger( LoggerInterface $logger ) {
193  $this->logger = $logger;
194  }
195 
201  public static function newEmpty() {
202  return new self( [
203  'cache' => new EmptyBagOStuff(),
204  'pool' => 'empty'
205  ] );
206  }
207 
248  final public function get( $key, &$curTTL = null, array $checkKeys = [], &$asOf = null ) {
249  $curTTLs = [];
250  $asOfs = [];
251  $values = $this->getMulti( [ $key ], $curTTLs, $checkKeys, $asOfs );
252  $curTTL = isset( $curTTLs[$key] ) ? $curTTLs[$key] : null;
253  $asOf = isset( $asOfs[$key] ) ? $asOfs[$key] : null;
254 
255  return isset( $values[$key] ) ? $values[$key] : false;
256  }
257 
270  final public function getMulti(
271  array $keys, &$curTTLs = [], array $checkKeys = [], array &$asOfs = []
272  ) {
273  $result = [];
274  $curTTLs = [];
275  $asOfs = [];
276 
277  $vPrefixLen = strlen( self::VALUE_KEY_PREFIX );
278  $valueKeys = self::prefixCacheKeys( $keys, self::VALUE_KEY_PREFIX );
279 
280  $checkKeysForAll = [];
281  $checkKeysByKey = [];
282  $checkKeysFlat = [];
283  foreach ( $checkKeys as $i => $checkKeyGroup ) {
284  $prefixed = self::prefixCacheKeys( (array)$checkKeyGroup, self::TIME_KEY_PREFIX );
285  $checkKeysFlat = array_merge( $checkKeysFlat, $prefixed );
286  // Is this check keys for a specific cache key, or for all keys being fetched?
287  if ( is_int( $i ) ) {
288  $checkKeysForAll = array_merge( $checkKeysForAll, $prefixed );
289  } else {
290  $checkKeysByKey[$i] = isset( $checkKeysByKey[$i] )
291  ? array_merge( $checkKeysByKey[$i], $prefixed )
292  : $prefixed;
293  }
294  }
295 
296  // Fetch all of the raw values
297  $keysGet = array_merge( $valueKeys, $checkKeysFlat );
298  if ( $this->warmupCache ) {
299  $wrappedValues = array_intersect_key( $this->warmupCache, array_flip( $keysGet ) );
300  $keysGet = array_diff( $keysGet, array_keys( $wrappedValues ) ); // keys left to fetch
301  $this->warmupKeyMisses += count( $keysGet );
302  } else {
303  $wrappedValues = [];
304  }
305  if ( $keysGet ) {
306  $wrappedValues += $this->cache->getMulti( $keysGet );
307  }
308  // Time used to compare/init "check" keys (derived after getMulti() to be pessimistic)
309  $now = microtime( true );
310 
311  // Collect timestamps from all "check" keys
312  $purgeValuesForAll = $this->processCheckKeys( $checkKeysForAll, $wrappedValues, $now );
313  $purgeValuesByKey = [];
314  foreach ( $checkKeysByKey as $cacheKey => $checks ) {
315  $purgeValuesByKey[$cacheKey] =
316  $this->processCheckKeys( $checks, $wrappedValues, $now );
317  }
318 
319  // Get the main cache value for each key and validate them
320  foreach ( $valueKeys as $vKey ) {
321  if ( !isset( $wrappedValues[$vKey] ) ) {
322  continue; // not found
323  }
324 
325  $key = substr( $vKey, $vPrefixLen ); // unprefix
326 
327  list( $value, $curTTL ) = $this->unwrap( $wrappedValues[$vKey], $now );
328  if ( $value !== false ) {
329  $result[$key] = $value;
330 
331  // Force dependant keys to be invalid for a while after purging
332  // to reduce race conditions involving stale data getting cached
333  $purgeValues = $purgeValuesForAll;
334  if ( isset( $purgeValuesByKey[$key] ) ) {
335  $purgeValues = array_merge( $purgeValues, $purgeValuesByKey[$key] );
336  }
337  foreach ( $purgeValues as $purge ) {
338  $safeTimestamp = $purge[self::FLD_TIME] + $purge[self::FLD_HOLDOFF];
339  if ( $safeTimestamp >= $wrappedValues[$vKey][self::FLD_TIME] ) {
340  // How long ago this value was expired by *this* check key
341  $ago = min( $purge[self::FLD_TIME] - $now, self::TINY_NEGATIVE );
342  // How long ago this value was expired by *any* known check key
343  $curTTL = min( $curTTL, $ago );
344  }
345  }
346  }
347  $curTTLs[$key] = $curTTL;
348  $asOfs[$key] = ( $value !== false ) ? $wrappedValues[$vKey][self::FLD_TIME] : null;
349  }
350 
351  return $result;
352  }
353 
361  private function processCheckKeys( array $timeKeys, array $wrappedValues, $now ) {
362  $purgeValues = [];
363  foreach ( $timeKeys as $timeKey ) {
364  $purge = isset( $wrappedValues[$timeKey] )
365  ? self::parsePurgeValue( $wrappedValues[$timeKey] )
366  : false;
367  if ( $purge === false ) {
368  // Key is not set or invalid; regenerate
369  $newVal = $this->makePurgeValue( $now, self::HOLDOFF_TTL );
370  $this->cache->add( $timeKey, $newVal, self::CHECK_KEY_TTL );
371  $purge = self::parsePurgeValue( $newVal );
372  }
373  $purgeValues[] = $purge;
374  }
375  return $purgeValues;
376  }
377 
436  final public function set( $key, $value, $ttl = 0, array $opts = [] ) {
437  $now = microtime( true );
438  $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
439  $age = isset( $opts['since'] ) ? max( 0, $now - $opts['since'] ) : 0;
440  $lag = isset( $opts['lag'] ) ? $opts['lag'] : 0;
441  $staleTTL = isset( $opts['staleTTL'] ) ? $opts['staleTTL'] : 0;
442 
443  // Do not cache potentially uncommitted data as it might get rolled back
444  if ( !empty( $opts['pending'] ) ) {
445  $this->logger->info( "Rejected set() for $key due to pending writes." );
446 
447  return true; // no-op the write for being unsafe
448  }
449 
450  $wrapExtra = []; // additional wrapped value fields
451  // Check if there's a risk of writing stale data after the purge tombstone expired
452  if ( $lag === false || ( $lag + $age ) > self::MAX_READ_LAG ) {
453  // Case A: read lag with "lockTSE"; save but record value as stale
454  if ( $lockTSE >= 0 ) {
455  $ttl = max( 1, (int)$lockTSE ); // set() expects seconds
456  $wrapExtra[self::FLD_FLAGS] = self::FLG_STALE; // mark as stale
457  // Case B: any long-running transaction; ignore this set()
458  } elseif ( $age > self::MAX_READ_LAG ) {
459  $this->logger->info( "Rejected set() for $key due to snapshot lag." );
460 
461  return true; // no-op the write for being unsafe
462  // Case C: high replication lag; lower TTL instead of ignoring all set()s
463  } elseif ( $lag === false || $lag > self::MAX_READ_LAG ) {
464  $ttl = $ttl ? min( $ttl, self::TTL_LAGGED ) : self::TTL_LAGGED;
465  $this->logger->warning( "Lowered set() TTL for $key due to replication lag." );
466  // Case D: medium length request with medium replication lag; ignore this set()
467  } else {
468  $this->logger->info( "Rejected set() for $key due to high read lag." );
469 
470  return true; // no-op the write for being unsafe
471  }
472  }
473 
474  // Wrap that value with time/TTL/version metadata
475  $wrapped = $this->wrap( $value, $ttl, $now ) + $wrapExtra;
476 
477  $func = function ( $cache, $key, $cWrapped ) use ( $wrapped ) {
478  return ( is_string( $cWrapped ) )
479  ? false // key is tombstoned; do nothing
480  : $wrapped;
481  };
482 
483  return $this->cache->merge( self::VALUE_KEY_PREFIX . $key, $func, $ttl + $staleTTL, 1 );
484  }
485 
543  final public function delete( $key, $ttl = self::HOLDOFF_TTL ) {
544  $key = self::VALUE_KEY_PREFIX . $key;
545 
546  if ( $ttl <= 0 ) {
547  // Publish the purge to all datacenters
548  $ok = $this->relayDelete( $key );
549  } else {
550  // Publish the purge to all datacenters
551  $ok = $this->relayPurge( $key, $ttl, self::HOLDOFF_NONE );
552  }
553 
554  return $ok;
555  }
556 
576  final public function getCheckKeyTime( $key ) {
577  $key = self::TIME_KEY_PREFIX . $key;
578 
579  $purge = self::parsePurgeValue( $this->cache->get( $key ) );
580  if ( $purge !== false ) {
581  $time = $purge[self::FLD_TIME];
582  } else {
583  // Casting assures identical floats for the next getCheckKeyTime() calls
584  $now = (string)microtime( true );
585  $this->cache->add( $key,
586  $this->makePurgeValue( $now, self::HOLDOFF_TTL ),
587  self::CHECK_KEY_TTL
588  );
589  $time = (float)$now;
590  }
591 
592  return $time;
593  }
594 
628  final public function touchCheckKey( $key, $holdoff = self::HOLDOFF_TTL ) {
629  // Publish the purge to all datacenters
630  return $this->relayPurge( self::TIME_KEY_PREFIX . $key, self::CHECK_KEY_TTL, $holdoff );
631  }
632 
663  final public function resetCheckKey( $key ) {
664  // Publish the purge to all datacenters
665  return $this->relayDelete( self::TIME_KEY_PREFIX . $key );
666  }
667 
857  final public function getWithSetCallback( $key, $ttl, $callback, array $opts = [] ) {
858  $pcTTL = isset( $opts['pcTTL'] ) ? $opts['pcTTL'] : self::TTL_UNCACHEABLE;
859 
860  // Try the process cache if enabled and the cache callback is not within a cache callback.
861  // Process cache use in nested callbacks is not lag-safe with regard to HOLDOFF_TTL since
862  // the in-memory value is further lagged than the shared one since it uses a blind TTL.
863  if ( $pcTTL >= 0 && $this->callbackDepth == 0 ) {
864  $group = isset( $opts['pcGroup'] ) ? $opts['pcGroup'] : self::PC_PRIMARY;
865  $procCache = $this->getProcessCache( $group );
866  $value = $procCache->get( $key );
867  } else {
868  $procCache = false;
869  $value = false;
870  }
871 
872  if ( $value === false ) {
873  // Fetch the value over the network
874  if ( isset( $opts['version'] ) ) {
875  $version = $opts['version'];
876  $asOf = null;
877  $cur = $this->doGetWithSetCallback(
878  $key,
879  $ttl,
880  function ( $oldValue, &$ttl, &$setOpts, $oldAsOf )
881  use ( $callback, $version ) {
882  if ( is_array( $oldValue )
883  && array_key_exists( self::VFLD_DATA, $oldValue )
884  ) {
885  $oldData = $oldValue[self::VFLD_DATA];
886  } else {
887  // VFLD_DATA is not set if an old, unversioned, key is present
888  $oldData = false;
889  }
890 
891  return [
892  self::VFLD_DATA => $callback( $oldData, $ttl, $setOpts, $oldAsOf ),
893  self::VFLD_VERSION => $version
894  ];
895  },
896  $opts,
897  $asOf
898  );
899  if ( $cur[self::VFLD_VERSION] === $version ) {
900  // Value created or existed before with version; use it
901  $value = $cur[self::VFLD_DATA];
902  } else {
903  // Value existed before with a different version; use variant key.
904  // Reflect purges to $key by requiring that this key value be newer.
905  $value = $this->doGetWithSetCallback(
906  'cache-variant:' . md5( $key ) . ":$version",
907  $ttl,
908  $callback,
909  // Regenerate value if not newer than $key
910  [ 'version' => null, 'minAsOf' => $asOf ] + $opts
911  );
912  }
913  } else {
914  $value = $this->doGetWithSetCallback( $key, $ttl, $callback, $opts );
915  }
916 
917  // Update the process cache if enabled
918  if ( $procCache && $value !== false ) {
919  $procCache->set( $key, $value, $pcTTL );
920  }
921  }
922 
923  return $value;
924  }
925 
939  protected function doGetWithSetCallback( $key, $ttl, $callback, array $opts, &$asOf = null ) {
940  $lowTTL = isset( $opts['lowTTL'] ) ? $opts['lowTTL'] : min( self::LOW_TTL, $ttl );
941  $lockTSE = isset( $opts['lockTSE'] ) ? $opts['lockTSE'] : self::TSE_NONE;
942  $checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : [];
943  $busyValue = isset( $opts['busyValue'] ) ? $opts['busyValue'] : null;
944  $popWindow = isset( $opts['hotTTR'] ) ? $opts['hotTTR'] : self::HOT_TTR;
945  $ageNew = isset( $opts['ageNew'] ) ? $opts['ageNew'] : self::AGE_NEW;
946  $minTime = isset( $opts['minAsOf'] ) ? $opts['minAsOf'] : self::MIN_TIMESTAMP_NONE;
947  $versioned = isset( $opts['version'] );
948 
949  // Get the current key value
950  $curTTL = null;
951  $cValue = $this->get( $key, $curTTL, $checkKeys, $asOf ); // current value
952  $value = $cValue; // return value
953 
954  $preCallbackTime = microtime( true );
955  // Determine if a cached value regeneration is needed or desired
956  if ( $value !== false
957  && $curTTL > 0
958  && $this->isValid( $value, $versioned, $asOf, $minTime )
959  && !$this->worthRefreshExpiring( $curTTL, $lowTTL )
960  && !$this->worthRefreshPopular( $asOf, $ageNew, $popWindow, $preCallbackTime )
961  ) {
962  return $value;
963  }
964 
965  // A deleted key with a negative TTL left must be tombstoned
966  $isTombstone = ( $curTTL !== null && $value === false );
967  // Assume a key is hot if requested soon after invalidation
968  $isHot = ( $curTTL !== null && $curTTL <= 0 && abs( $curTTL ) <= $lockTSE );
969  // Use the mutex if there is no value and a busy fallback is given
970  $checkBusy = ( $busyValue !== null && $value === false );
971  // Decide whether a single thread should handle regenerations.
972  // This avoids stampedes when $checkKeys are bumped and when preemptive
973  // renegerations take too long. It also reduces regenerations while $key
974  // is tombstoned. This balances cache freshness with avoiding DB load.
975  $useMutex = ( $isHot || ( $isTombstone && $lockTSE > 0 ) || $checkBusy );
976 
977  $lockAcquired = false;
978  if ( $useMutex ) {
979  // Acquire a datacenter-local non-blocking lock
980  if ( $this->cache->add( self::MUTEX_KEY_PREFIX . $key, 1, self::LOCK_TTL ) ) {
981  // Lock acquired; this thread should update the key
982  $lockAcquired = true;
983  } elseif ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) {
984  // If it cannot be acquired; then the stale value can be used
985  return $value;
986  } else {
987  // Use the INTERIM value for tombstoned keys to reduce regeneration load.
988  // For hot keys, either another thread has the lock or the lock failed;
989  // use the INTERIM value from the last thread that regenerated it.
990  $wrapped = $this->cache->get( self::INTERIM_KEY_PREFIX . $key );
991  list( $value ) = $this->unwrap( $wrapped, microtime( true ) );
992  if ( $value !== false && $this->isValid( $value, $versioned, $asOf, $minTime ) ) {
993  $asOf = $wrapped[self::FLD_TIME];
994 
995  return $value;
996  }
997  // Use the busy fallback value if nothing else
998  if ( $busyValue !== null ) {
999  return is_callable( $busyValue ) ? $busyValue() : $busyValue;
1000  }
1001  }
1002  }
1003 
1004  if ( !is_callable( $callback ) ) {
1005  throw new InvalidArgumentException( "Invalid cache miss callback provided." );
1006  }
1007 
1008  // Generate the new value from the callback...
1009  $setOpts = [];
1011  try {
1012  $value = call_user_func_array( $callback, [ $cValue, &$ttl, &$setOpts, $asOf ] );
1013  } finally {
1015  }
1016  // When delete() is called, writes are write-holed by the tombstone,
1017  // so use a special INTERIM key to pass the new value around threads.
1018  if ( ( $isTombstone && $lockTSE > 0 ) && $value !== false && $ttl >= 0 ) {
1019  $tempTTL = max( 1, (int)$lockTSE ); // set() expects seconds
1020  $newAsOf = microtime( true );
1021  $wrapped = $this->wrap( $value, $tempTTL, $newAsOf );
1022  // Avoid using set() to avoid pointless mcrouter broadcasting
1023  $this->cache->merge(
1024  self::INTERIM_KEY_PREFIX . $key,
1025  function () use ( $wrapped ) {
1026  return $wrapped;
1027  },
1028  $tempTTL,
1029  1
1030  );
1031  }
1032 
1033  if ( $value !== false && $ttl >= 0 ) {
1034  $setOpts['lockTSE'] = $lockTSE;
1035  // Use best known "since" timestamp if not provided
1036  $setOpts += [ 'since' => $preCallbackTime ];
1037  // Update the cache; this will fail if the key is tombstoned
1038  $this->set( $key, $value, $ttl, $setOpts );
1039  }
1040 
1041  if ( $lockAcquired ) {
1042  // Avoid using delete() to avoid pointless mcrouter broadcasting
1043  $this->cache->changeTTL( self::MUTEX_KEY_PREFIX . $key, 1 );
1044  }
1045 
1046  return $value;
1047  }
1048 
1107  final public function getMultiWithSetCallback(
1108  ArrayIterator $keyedIds, $ttl, callable $callback, array $opts = []
1109  ) {
1110  $valueKeys = array_keys( $keyedIds->getArrayCopy() );
1111  $checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : [];
1112 
1113  // Load required keys into process cache in one go
1114  $this->warmupCache = $this->getRawKeysForWarmup(
1115  $this->getNonProcessCachedKeys( $valueKeys, $opts ),
1116  $checkKeys
1117  );
1118  $this->warmupKeyMisses = 0;
1119 
1120  // Wrap $callback to match the getWithSetCallback() format while passing $id to $callback
1121  $id = null; // current entity ID
1122  $func = function ( $oldValue, &$ttl, &$setOpts, $oldAsOf ) use ( $callback, &$id ) {
1123  return $callback( $id, $oldValue, $ttl, $setOpts, $oldAsOf );
1124  };
1125 
1126  $values = [];
1127  foreach ( $keyedIds as $key => $id ) { // preserve order
1128  $values[$key] = $this->getWithSetCallback( $key, $ttl, $func, $opts );
1129  }
1130 
1131  $this->warmupCache = [];
1132 
1133  return $values;
1134  }
1135 
1193  final public function getMultiWithUnionSetCallback(
1194  ArrayIterator $keyedIds, $ttl, callable $callback, array $opts = []
1195  ) {
1196  $idsByValueKey = $keyedIds->getArrayCopy();
1197  $valueKeys = array_keys( $idsByValueKey );
1198  $checkKeys = isset( $opts['checkKeys'] ) ? $opts['checkKeys'] : [];
1199  unset( $opts['lockTSE'] ); // incompatible
1200  unset( $opts['busyValue'] ); // incompatible
1201 
1202  // Load required keys into process cache in one go
1203  $keysGet = $this->getNonProcessCachedKeys( $valueKeys, $opts );
1204  $this->warmupCache = $this->getRawKeysForWarmup( $keysGet, $checkKeys );
1205  $this->warmupKeyMisses = 0;
1206 
1207  // IDs of entities known to be in need of regeneration
1208  $idsRegen = [];
1209 
1210  // Find out which keys are missing/deleted/stale
1211  $curTTLs = [];
1212  $asOfs = [];
1213  $curByKey = $this->getMulti( $keysGet, $curTTLs, $checkKeys, $asOfs );
1214  foreach ( $keysGet as $key ) {
1215  if ( !array_key_exists( $key, $curByKey ) || $curTTLs[$key] < 0 ) {
1216  $idsRegen[] = $idsByValueKey[$key];
1217  }
1218  }
1219 
1220  // Run the callback to populate the regeneration value map for all required IDs
1221  $newSetOpts = [];
1222  $newTTLsById = array_fill_keys( $idsRegen, $ttl );
1223  $newValsById = $idsRegen ? $callback( $idsRegen, $newTTLsById, $newSetOpts ) : [];
1224 
1225  // Wrap $callback to match the getWithSetCallback() format while passing $id to $callback
1226  $id = null; // current entity ID
1227  $func = function ( $oldValue, &$ttl, &$setOpts, $oldAsOf )
1228  use ( $callback, &$id, $newValsById, $newTTLsById, $newSetOpts )
1229  {
1230  if ( array_key_exists( $id, $newValsById ) ) {
1231  // Value was already regerated as expected, so use the value in $newValsById
1232  $newValue = $newValsById[$id];
1233  $ttl = $newTTLsById[$id];
1234  $setOpts = $newSetOpts;
1235  } else {
1236  // Pre-emptive/popularity refresh and version mismatch cases are not detected
1237  // above and thus $newValsById has no entry. Run $callback on this single entity.
1238  $ttls = [ $id => $ttl ];
1239  $newValue = $callback( [ $id ], $ttls, $setOpts )[$id];
1240  $ttl = $ttls[$id];
1241  }
1242 
1243  return $newValue;
1244  };
1245 
1246  // Run the cache-aside logic using warmupCache instead of persistent cache queries
1247  $values = [];
1248  foreach ( $idsByValueKey as $key => $id ) { // preserve order
1249  $values[$key] = $this->getWithSetCallback( $key, $ttl, $func, $opts );
1250  }
1251 
1252  $this->warmupCache = [];
1253 
1254  return $values;
1255  }
1256 
1269  public function reap( $key, $purgeTimestamp, &$isStale = false ) {
1270  $minAsOf = $purgeTimestamp + self::HOLDOFF_TTL;
1271  $wrapped = $this->cache->get( self::VALUE_KEY_PREFIX . $key );
1272  if ( is_array( $wrapped ) && $wrapped[self::FLD_TIME] < $minAsOf ) {
1273  $isStale = true;
1274  $this->logger->warning( "Reaping stale value key '$key'." );
1275  $ttlReap = self::HOLDOFF_TTL; // avoids races with tombstone creation
1276  $ok = $this->cache->changeTTL( self::VALUE_KEY_PREFIX . $key, $ttlReap );
1277  if ( !$ok ) {
1278  $this->logger->error( "Could not complete reap of key '$key'." );
1279  }
1280 
1281  return $ok;
1282  }
1283 
1284  $isStale = false;
1285 
1286  return true;
1287  }
1288 
1298  public function reapCheckKey( $key, $purgeTimestamp, &$isStale = false ) {
1299  $purge = $this->parsePurgeValue( $this->cache->get( self::TIME_KEY_PREFIX . $key ) );
1300  if ( $purge && $purge[self::FLD_TIME] < $purgeTimestamp ) {
1301  $isStale = true;
1302  $this->logger->warning( "Reaping stale check key '$key'." );
1303  $ok = $this->cache->changeTTL( self::TIME_KEY_PREFIX . $key, 1 );
1304  if ( !$ok ) {
1305  $this->logger->error( "Could not complete reap of check key '$key'." );
1306  }
1307 
1308  return $ok;
1309  }
1310 
1311  $isStale = false;
1312 
1313  return false;
1314  }
1315 
1322  public function makeKey() {
1323  return call_user_func_array( [ $this->cache, __FUNCTION__ ], func_get_args() );
1324  }
1325 
1332  public function makeGlobalKey() {
1333  return call_user_func_array( [ $this->cache, __FUNCTION__ ], func_get_args() );
1334  }
1335 
1342  public function makeMultiKeys( array $entities, callable $keyFunc ) {
1343  $map = [];
1344  foreach ( $entities as $entity ) {
1345  $map[$keyFunc( $entity, $this )] = $entity;
1346  }
1347 
1348  return new ArrayIterator( $map );
1349  }
1350 
1355  final public function getLastError() {
1356  if ( $this->lastRelayError ) {
1357  // If the cache and the relayer failed, focus on the latter.
1358  // An update not making it to the relayer means it won't show up
1359  // in other DCs (nor will consistent re-hashing see up-to-date values).
1360  // On the other hand, if just the cache update failed, then it should
1361  // eventually be applied by the relayer.
1362  return $this->lastRelayError;
1363  }
1364 
1365  $code = $this->cache->getLastError();
1366  switch ( $code ) {
1367  case BagOStuff::ERR_NONE:
1368  return self::ERR_NONE;
1370  return self::ERR_NO_RESPONSE;
1372  return self::ERR_UNREACHABLE;
1373  default:
1374  return self::ERR_UNEXPECTED;
1375  }
1376  }
1377 
1381  final public function clearLastError() {
1382  $this->cache->clearLastError();
1383  $this->lastRelayError = self::ERR_NONE;
1384  }
1385 
1391  public function clearProcessCache() {
1392  $this->processCaches = [];
1393  }
1394 
1400  public function getQoS( $flag ) {
1401  return $this->cache->getQoS( $flag );
1402  }
1403 
1427  public function adaptiveTTL( $mtime, $maxTTL, $minTTL = 30, $factor = 0.2 ) {
1428  if ( is_float( $mtime ) || ctype_digit( $mtime ) ) {
1429  $mtime = (int)$mtime; // handle fractional seconds and string integers
1430  }
1431 
1432  if ( !is_int( $mtime ) || $mtime <= 0 ) {
1433  return $minTTL; // no last-modified time provided
1434  }
1435 
1436  $age = time() - $mtime;
1437 
1438  return (int)min( $maxTTL, max( $minTTL, $factor * $age ) );
1439  }
1440 
1445  public function getWarmupKeyMisses() {
1446  return $this->warmupKeyMisses;
1447  }
1448 
1459  protected function relayPurge( $key, $ttl, $holdoff ) {
1460  if ( $this->purgeRelayer instanceof EventRelayerNull ) {
1461  // This handles the mcrouter and the single-DC case
1462  $ok = $this->cache->set( $key,
1463  $this->makePurgeValue( microtime( true ), self::HOLDOFF_NONE ),
1464  $ttl
1465  );
1466  } else {
1467  $event = $this->cache->modifySimpleRelayEvent( [
1468  'cmd' => 'set',
1469  'key' => $key,
1470  'val' => 'PURGED:$UNIXTIME$:' . (int)$holdoff,
1471  'ttl' => max( $ttl, 1 ),
1472  'sbt' => true, // substitute $UNIXTIME$ with actual microtime
1473  ] );
1474 
1475  $ok = $this->purgeRelayer->notify( $this->purgeChannel, $event );
1476  if ( !$ok ) {
1477  $this->lastRelayError = self::ERR_RELAY;
1478  }
1479  }
1480 
1481  return $ok;
1482  }
1483 
1490  protected function relayDelete( $key ) {
1491  if ( $this->purgeRelayer instanceof EventRelayerNull ) {
1492  // This handles the mcrouter and the single-DC case
1493  $ok = $this->cache->delete( $key );
1494  } else {
1495  $event = $this->cache->modifySimpleRelayEvent( [
1496  'cmd' => 'delete',
1497  'key' => $key,
1498  ] );
1499 
1500  $ok = $this->purgeRelayer->notify( $this->purgeChannel, $event );
1501  if ( !$ok ) {
1502  $this->lastRelayError = self::ERR_RELAY;
1503  }
1504  }
1505 
1506  return $ok;
1507  }
1508 
1521  protected function worthRefreshExpiring( $curTTL, $lowTTL ) {
1522  if ( $curTTL >= $lowTTL ) {
1523  return false;
1524  } elseif ( $curTTL <= 0 ) {
1525  return true;
1526  }
1527 
1528  $chance = ( 1 - $curTTL / $lowTTL );
1529 
1530  return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
1531  }
1532 
1548  protected function worthRefreshPopular( $asOf, $ageNew, $timeTillRefresh, $now ) {
1549  $age = $now - $asOf;
1550  $timeOld = $age - $ageNew;
1551  if ( $timeOld <= 0 ) {
1552  return false;
1553  }
1554 
1555  // Lifecycle is: new, ramp-up refresh chance, full refresh chance.
1556  // Note that the "expected # of refreshes" for the ramp-up time range is half of what it
1557  // would be if P(refresh) was at its full value during that time range.
1558  $refreshWindowSec = max( $timeTillRefresh - $ageNew - self::RAMPUP_TTL / 2, 1 );
1559  // P(refresh) * (# hits in $refreshWindowSec) = (expected # of refreshes)
1560  // P(refresh) * ($refreshWindowSec * $popularHitsPerSec) = 1
1561  // P(refresh) = 1/($refreshWindowSec * $popularHitsPerSec)
1562  $chance = 1 / ( self::HIT_RATE_HIGH * $refreshWindowSec );
1563 
1564  // Ramp up $chance from 0 to its nominal value over RAMPUP_TTL seconds to avoid stampedes
1565  $chance *= ( $timeOld <= self::RAMPUP_TTL ) ? $timeOld / self::RAMPUP_TTL : 1;
1566 
1567  return mt_rand( 1, 1e9 ) <= 1e9 * $chance;
1568  }
1569 
1579  protected function isValid( $value, $versioned, $asOf, $minTime ) {
1580  if ( $versioned && !isset( $value[self::VFLD_VERSION] ) ) {
1581  return false;
1582  } elseif ( $minTime > 0 && $asOf < $minTime ) {
1583  return false;
1584  }
1585 
1586  return true;
1587  }
1588 
1597  protected function wrap( $value, $ttl, $now ) {
1598  return [
1599  self::FLD_VERSION => self::VERSION,
1600  self::FLD_VALUE => $value,
1601  self::FLD_TTL => $ttl,
1602  self::FLD_TIME => $now
1603  ];
1604  }
1605 
1613  protected function unwrap( $wrapped, $now ) {
1614  // Check if the value is a tombstone
1615  $purge = self::parsePurgeValue( $wrapped );
1616  if ( $purge !== false ) {
1617  // Purged values should always have a negative current $ttl
1618  $curTTL = min( $purge[self::FLD_TIME] - $now, self::TINY_NEGATIVE );
1619  return [ false, $curTTL ];
1620  }
1621 
1622  if ( !is_array( $wrapped ) // not found
1623  || !isset( $wrapped[self::FLD_VERSION] ) // wrong format
1624  || $wrapped[self::FLD_VERSION] !== self::VERSION // wrong version
1625  ) {
1626  return [ false, null ];
1627  }
1628 
1629  $flags = isset( $wrapped[self::FLD_FLAGS] ) ? $wrapped[self::FLD_FLAGS] : 0;
1630  if ( ( $flags & self::FLG_STALE ) == self::FLG_STALE ) {
1631  // Treat as expired, with the cache time as the expiration
1632  $age = $now - $wrapped[self::FLD_TIME];
1633  $curTTL = min( -$age, self::TINY_NEGATIVE );
1634  } elseif ( $wrapped[self::FLD_TTL] > 0 ) {
1635  // Get the approximate time left on the key
1636  $age = $now - $wrapped[self::FLD_TIME];
1637  $curTTL = max( $wrapped[self::FLD_TTL] - $age, 0.0 );
1638  } else {
1639  // Key had no TTL, so the time left is unbounded
1640  $curTTL = INF;
1641  }
1642 
1643  return [ $wrapped[self::FLD_VALUE], $curTTL ];
1644  }
1645 
1651  protected static function prefixCacheKeys( array $keys, $prefix ) {
1652  $res = [];
1653  foreach ( $keys as $key ) {
1654  $res[] = $prefix . $key;
1655  }
1656 
1657  return $res;
1658  }
1659 
1665  protected static function parsePurgeValue( $value ) {
1666  if ( !is_string( $value ) ) {
1667  return false;
1668  }
1669  $segments = explode( ':', $value, 3 );
1670  if ( !isset( $segments[0] ) || !isset( $segments[1] )
1671  || "{$segments[0]}:" !== self::PURGE_VAL_PREFIX
1672  ) {
1673  return false;
1674  }
1675  if ( !isset( $segments[2] ) ) {
1676  // Back-compat with old purge values without holdoff
1677  $segments[2] = self::HOLDOFF_TTL;
1678  }
1679  return [
1680  self::FLD_TIME => (float)$segments[1],
1681  self::FLD_HOLDOFF => (int)$segments[2],
1682  ];
1683  }
1684 
1690  protected function makePurgeValue( $timestamp, $holdoff ) {
1691  return self::PURGE_VAL_PREFIX . (float)$timestamp . ':' . (int)$holdoff;
1692  }
1693 
1698  protected function getProcessCache( $group ) {
1699  if ( !isset( $this->processCaches[$group] ) ) {
1700  list( , $n ) = explode( ':', $group );
1701  $this->processCaches[$group] = new HashBagOStuff( [ 'maxKeys' => (int)$n ] );
1702  }
1703 
1704  return $this->processCaches[$group];
1705  }
1706 
1712  private function getNonProcessCachedKeys( array $keys, array $opts ) {
1713  $keysFound = [];
1714  if ( isset( $opts['pcTTL'] ) && $opts['pcTTL'] > 0 && $this->callbackDepth == 0 ) {
1715  $pcGroup = isset( $opts['pcGroup'] ) ? $opts['pcGroup'] : self::PC_PRIMARY;
1716  $procCache = $this->getProcessCache( $pcGroup );
1717  foreach ( $keys as $key ) {
1718  if ( $procCache->get( $key ) !== false ) {
1719  $keysFound[] = $key;
1720  }
1721  }
1722  }
1723 
1724  return array_diff( $keys, $keysFound );
1725  }
1726 
1732  private function getRawKeysForWarmup( array $keys, array $checkKeys ) {
1733  if ( !$keys ) {
1734  return [];
1735  }
1736 
1737  $keysWarmUp = [];
1738  // Get all the value keys to fetch...
1739  foreach ( $keys as $key ) {
1740  $keysWarmUp[] = self::VALUE_KEY_PREFIX . $key;
1741  }
1742  // Get all the check keys to fetch...
1743  foreach ( $checkKeys as $i => $checkKeyOrKeys ) {
1744  if ( is_int( $i ) ) {
1745  // Single check key that applies to all value keys
1746  $keysWarmUp[] = self::TIME_KEY_PREFIX . $checkKeyOrKeys;
1747  } else {
1748  // List of check keys that apply to value key $i
1749  $keysWarmUp = array_merge(
1750  $keysWarmUp,
1751  self::prefixCacheKeys( $checkKeyOrKeys, self::TIME_KEY_PREFIX )
1752  );
1753  }
1754  }
1755 
1756  $warmupCache = $this->cache->getMulti( $keysWarmUp );
1757  $warmupCache += array_fill_keys( $keysWarmUp, false );
1758 
1759  return $warmupCache;
1760  }
1761 }
WANObjectCache\ERR_UNREACHABLE
const ERR_UNREACHABLE
Definition: WANObjectCache.php:156
WANObjectCache\getQoS
getQoS( $flag)
Definition: WANObjectCache.php:1400
WANObjectCache\relayDelete
relayDelete( $key)
Do the actual async bus delete of a key.
Definition: WANObjectCache.php:1490
WANObjectCache\getNonProcessCachedKeys
getNonProcessCachedKeys(array $keys, array $opts)
Definition: WANObjectCache.php:1712
WANObjectCache\VALUE_KEY_PREFIX
const VALUE_KEY_PREFIX
Definition: WANObjectCache.php:160
WANObjectCache\TTL_UNCACHEABLE
const TTL_UNCACHEABLE
Idiom for getWithSetCallback() callbacks to avoid calling set()
Definition: WANObjectCache.php:128
WANObjectCache\makePurgeValue
makePurgeValue( $timestamp, $holdoff)
Definition: WANObjectCache.php:1690
false
processing should stop and the error should be shown to the user * false
Definition: hooks.txt:187
WANObjectCache\$warmupCache
mixed[] $warmupCache
Temporary warm-up cache.
Definition: WANObjectCache.php:98
BagOStuff\ERR_UNREACHABLE
const ERR_UNREACHABLE
Definition: BagOStuff.php:79
HashBagOStuff
Simple store for keeping values in an associative array for the current process.
Definition: HashBagOStuff.php:31
EmptyBagOStuff
A BagOStuff object with no objects in it.
Definition: EmptyBagOStuff.php:29
WANObjectCache\$cache
BagOStuff $cache
The local datacenter cache.
Definition: WANObjectCache.php:82
WANObjectCache\MAX_READ_LAG
const MAX_READ_LAG
Max replication+snapshot lag before applying TTL_LAGGED or disallowing set()
Definition: WANObjectCache.php:105
captcha-old.count
count
Definition: captcha-old.py:249
WANObjectCache\$purgeChannel
string $purgeChannel
Purge channel name.
Definition: WANObjectCache.php:86
WANObjectCache\FLD_VERSION
const FLD_VERSION
Definition: WANObjectCache.php:144
WANObjectCache\FLD_VALUE
const FLD_VALUE
Definition: WANObjectCache.php:145
WANObjectCache\MAX_COMMIT_DELAY
const MAX_COMMIT_DELAY
Max time expected to pass between delete() and DB commit finishing.
Definition: WANObjectCache.php:103
WANObjectCache\isValid
isValid( $value, $versioned, $asOf, $minTime)
Check whether $value is appropriately versioned and not older than $minTime (if set)
Definition: WANObjectCache.php:1579
$result
The index of the header message $result[1]=The index of the body text message $result[2 through n]=Parameters passed to body text message. Please note the header message cannot receive/use parameters. 'ImportHandleLogItemXMLTag':When parsing a XML tag in a log item. Return false to stop further processing of the tag $reader:XMLReader object $logInfo:Array of information 'ImportHandlePageXMLTag':When parsing a XML tag in a page. Return false to stop further processing of the tag $reader:XMLReader object & $pageInfo:Array of information 'ImportHandleRevisionXMLTag':When parsing a XML tag in a page revision. Return false to stop further processing of the tag $reader:XMLReader object $pageInfo:Array of page information $revisionInfo:Array of revision information 'ImportHandleToplevelXMLTag':When parsing a top level XML tag. Return false to stop further processing of the tag $reader:XMLReader object 'ImportHandleUploadXMLTag':When parsing a XML tag in a file upload. Return false to stop further processing of the tag $reader:XMLReader object $revisionInfo:Array of information 'ImportLogInterwikiLink':Hook to change the interwiki link used in log entries and edit summaries for transwiki imports. & $fullInterwikiPrefix:Interwiki prefix, may contain colons. & $pageTitle:String that contains page title. 'ImportSources':Called when reading from the $wgImportSources configuration variable. Can be used to lazy-load the import sources list. & $importSources:The value of $wgImportSources. Modify as necessary. See the comment in DefaultSettings.php for the detail of how to structure this array. 'InfoAction':When building information to display on the action=info page. $context:IContextSource object & $pageInfo:Array of information 'InitializeArticleMaybeRedirect':MediaWiki check to see if title is a redirect. & $title:Title object for the current page & $request:WebRequest & $ignoreRedirect:boolean to skip redirect check & $target:Title/string of redirect target & $article:Article object 'InternalParseBeforeLinks':during Parser 's internalParse method before links but after nowiki/noinclude/includeonly/onlyinclude and other processings. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InternalParseBeforeSanitize':during Parser 's internalParse method just before the parser removes unwanted/dangerous HTML tags and after nowiki/noinclude/includeonly/onlyinclude and other processings. Ideal for syntax-extensions after template/parser function execution which respect nowiki and HTML-comments. & $parser:Parser object & $text:string containing partially parsed text & $stripState:Parser 's internal StripState object 'InterwikiLoadPrefix':When resolving if a given prefix is an interwiki or not. Return true without providing an interwiki to continue interwiki search. $prefix:interwiki prefix we are looking for. & $iwData:output array describing the interwiki with keys iw_url, iw_local, iw_trans and optionally iw_api and iw_wikiid. 'InvalidateEmailComplete':Called after a user 's email has been invalidated successfully. $user:user(object) whose email is being invalidated 'IRCLineURL':When constructing the URL to use in an IRC notification. Callee may modify $url and $query, URL will be constructed as $url . $query & $url:URL to index.php & $query:Query string $rc:RecentChange object that triggered url generation 'IsFileCacheable':Override the result of Article::isFileCacheable()(if true) & $article:article(object) being checked 'IsTrustedProxy':Override the result of IP::isTrustedProxy() & $ip:IP being check & $result:Change this value to override the result of IP::isTrustedProxy() 'IsUploadAllowedFromUrl':Override the result of UploadFromUrl::isAllowedUrl() $url:URL used to upload from & $allowed:Boolean indicating if uploading is allowed for given URL 'isValidEmailAddr':Override the result of Sanitizer::validateEmail(), for instance to return false if the domain name doesn 't match your organization. $addr:The e-mail address entered by the user & $result:Set this and return false to override the internal checks 'isValidPassword':Override the result of User::isValidPassword() $password:The password entered by the user & $result:Set this and return false to override the internal checks $user:User the password is being validated for 'Language::getMessagesFileName':$code:The language code or the language we 're looking for a messages file for & $file:The messages file path, you can override this to change the location. 'LanguageGetMagic':DEPRECATED! Use $magicWords in a file listed in $wgExtensionMessagesFiles instead. Use this to define synonyms of magic words depending of the language & $magicExtensions:associative array of magic words synonyms $lang:language code(string) 'LanguageGetNamespaces':Provide custom ordering for namespaces or remove namespaces. Do not use this hook to add namespaces. Use CanonicalNamespaces for that. & $namespaces:Array of namespaces indexed by their numbers 'LanguageGetSpecialPageAliases':DEPRECATED! Use $specialPageAliases in a file listed in $wgExtensionMessagesFiles instead. Use to define aliases of special pages names depending of the language & $specialPageAliases:associative array of magic words synonyms $lang:language code(string) 'LanguageGetTranslatedLanguageNames':Provide translated language names. & $names:array of language code=> language name $code:language of the preferred translations 'LanguageLinks':Manipulate a page 's language links. This is called in various places to allow extensions to define the effective language links for a page. $title:The page 's Title. & $links:Array with elements of the form "language:title" in the order that they will be output. & $linkFlags:Associative array mapping prefixed links to arrays of flags. Currently unused, but planned to provide support for marking individual language links in the UI, e.g. for featured articles. 'LanguageSelector':Hook to change the language selector available on a page. $out:The output page. $cssClassName:CSS class name of the language selector. 'LinkBegin':DEPRECATED! Use HtmlPageLinkRendererBegin instead. Used when generating internal and interwiki links in Linker::link(), before processing starts. Return false to skip default processing and return $ret. See documentation for Linker::link() for details on the expected meanings of parameters. $skin:the Skin object $target:the Title that the link is pointing to & $html:the contents that the< a > tag should have(raw HTML) $result
Definition: hooks.txt:1963
use
as see the revision history and available at free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:10
EventRelayerNull
No-op class for publishing messages into a PubSub system.
Definition: EventRelayerNull.php:24
WANObjectCache\makeMultiKeys
makeMultiKeys(array $entities, callable $keyFunc)
Definition: WANObjectCache.php:1342
WANObjectCache\getMultiWithSetCallback
getMultiWithSetCallback(ArrayIterator $keyedIds, $ttl, callable $callback, array $opts=[])
Method to fetch multiple cache keys at once with regeneration.
Definition: WANObjectCache.php:1107
$params
$params
Definition: styleTest.css.php:40
BagOStuff
interface is intended to be more or less compatible with the PHP memcached client.
Definition: BagOStuff.php:47
WANObjectCache\makeKey
makeKey()
Definition: WANObjectCache.php:1322
WANObjectCache\getMultiWithUnionSetCallback
getMultiWithUnionSetCallback(ArrayIterator $keyedIds, $ttl, callable $callback, array $opts=[])
Method to fetch/regenerate multiple cache keys at once.
Definition: WANObjectCache.php:1193
WANObjectCache\$processCaches
HashBagOStuff[] $processCaches
Map of group PHP instance caches.
Definition: WANObjectCache.php:84
$res
$res
Definition: database.txt:21
WANObjectCache\VFLD_VERSION
const VFLD_VERSION
Definition: WANObjectCache.php:168
cache
you have access to all of the normal MediaWiki so you can get a DB use the cache
Definition: maintenance.txt:52
WANObjectCache\TTL_LAGGED
const TTL_LAGGED
Max TTL to store keys when a data sourced is lagged.
Definition: WANObjectCache.php:132
BagOStuff\ERR_NONE
const ERR_NONE
Possible values for getLastError()
Definition: BagOStuff.php:77
WANObjectCache\reapCheckKey
reapCheckKey( $key, $purgeTimestamp, &$isStale=false)
Locally set a "check" key to expire soon if it is stale based on $purgeTimestamp.
Definition: WANObjectCache.php:1298
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:35
WANObjectCache\getCheckKeyTime
getCheckKeyTime( $key)
Fetch the value of a timestamp "check" key.
Definition: WANObjectCache.php:576
WANObjectCache\$logger
LoggerInterface $logger
Definition: WANObjectCache.php:90
WANObjectCache\VFLD_DATA
const VFLD_DATA
Definition: WANObjectCache.php:167
WANObjectCache\$purgeRelayer
EventRelayer $purgeRelayer
Bus that handles purge broadcasts.
Definition: WANObjectCache.php:88
WANObjectCache\$warmupKeyMisses
int $warmupKeyMisses
Key fetched.
Definition: WANObjectCache.php:100
WANObjectCache\newEmpty
static newEmpty()
Get an instance that wraps EmptyBagOStuff.
Definition: WANObjectCache.php:201
WANObjectCache\ERR_RELAY
const ERR_RELAY
Definition: WANObjectCache.php:158
WANObjectCache\TIME_KEY_PREFIX
const TIME_KEY_PREFIX
Definition: WANObjectCache.php:162
WANObjectCache\LOW_TTL
const LOW_TTL
Default remaining TTL at which to consider pre-emptive regeneration.
Definition: WANObjectCache.php:114
WANObjectCache\FLD_TIME
const FLD_TIME
Definition: WANObjectCache.php:147
IExpiringStore
Generic base class for storage interfaces.
Definition: IExpiringStore.php:31
WANObjectCache\clearProcessCache
clearProcessCache()
Clear the in-process caches; useful for testing.
Definition: WANObjectCache.php:1391
WANObjectCache\clearLastError
clearLastError()
Clear the "last error" registry.
Definition: WANObjectCache.php:1381
WANObjectCache\getWithSetCallback
getWithSetCallback( $key, $ttl, $callback, array $opts=[])
Method to fetch/regenerate cache keys.
Definition: WANObjectCache.php:857
WANObjectCache\prefixCacheKeys
static prefixCacheKeys(array $keys, $prefix)
Definition: WANObjectCache.php:1651
WANObjectCache\unwrap
unwrap( $wrapped, $now)
Do not use this method outside WANObjectCache.
Definition: WANObjectCache.php:1613
WANObjectCache\MIN_TIMESTAMP_NONE
const MIN_TIMESTAMP_NONE
Idiom for getWithSetCallback() for "no minimum required as-of timestamp".
Definition: WANObjectCache.php:136
WANObjectCache\getLastError
getLastError()
Get the "last error" registered; clearLastError() should be called manually.
Definition: WANObjectCache.php:1355
WANObjectCache\INTERIM_KEY_PREFIX
const INTERIM_KEY_PREFIX
Definition: WANObjectCache.php:161
WANObjectCache\__construct
__construct(array $params)
Definition: WANObjectCache.php:181
WANObjectCache\reap
reap( $key, $purgeTimestamp, &$isStale=false)
Locally set a key to expire soon if it is stale based on $purgeTimestamp.
Definition: WANObjectCache.php:1269
WANObjectCache\touchCheckKey
touchCheckKey( $key, $holdoff=self::HOLDOFF_TTL)
Purge a "check" key from all datacenters, invalidating keys that use it.
Definition: WANObjectCache.php:628
WANObjectCache\DEFAULT_PURGE_CHANNEL
const DEFAULT_PURGE_CHANNEL
Definition: WANObjectCache.php:172
WANObjectCache\ERR_NONE
const ERR_NONE
Definition: WANObjectCache.php:154
$time
see documentation in includes Linker php for Linker::makeImageLink & $time
Definition: hooks.txt:1778
WANObjectCache\adaptiveTTL
adaptiveTTL( $mtime, $maxTTL, $minTTL=30, $factor=0.2)
Get a TTL that is higher for objects that have not changed recently.
Definition: WANObjectCache.php:1427
WANObjectCache\relayPurge
relayPurge( $key, $ttl, $holdoff)
Do the actual async bus purge of a key.
Definition: WANObjectCache.php:1459
WANObjectCache\parsePurgeValue
static parsePurgeValue( $value)
Definition: WANObjectCache.php:1665
WANObjectCache\HOLDOFF_TTL
const HOLDOFF_TTL
Seconds to tombstone keys on delete()
Definition: WANObjectCache.php:107
string
This code would result in ircNotify being run twice when an article is and once for brion Hooks can return three possible true was required This is the default since MediaWiki *some string
Definition: hooks.txt:175
list
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Definition: deferred.txt:11
WANObjectCache\worthRefreshPopular
worthRefreshPopular( $asOf, $ageNew, $timeTillRefresh, $now)
Check if a key is due for randomized regeneration due to its popularity.
Definition: WANObjectCache.php:1548
WANObjectCache\ERR_NO_RESPONSE
const ERR_NO_RESPONSE
Definition: WANObjectCache.php:155
WANObjectCache\RAMPUP_TTL
const RAMPUP_TTL
Seconds to ramp up to the "popularity" refresh chance after a key is no longer new.
Definition: WANObjectCache.php:125
WANObjectCache\wrap
wrap( $value, $ttl, $now)
Do not use this method outside WANObjectCache.
Definition: WANObjectCache.php:1597
$value
$value
Definition: styleTest.css.php:45
WANObjectCache\MUTEX_KEY_PREFIX
const MUTEX_KEY_PREFIX
Definition: WANObjectCache.php:163
WANObjectCache\PC_PRIMARY
const PC_PRIMARY
Definition: WANObjectCache.php:170
WANObjectCache\worthRefreshExpiring
worthRefreshExpiring( $curTTL, $lowTTL)
Check if a key should be regenerated (using random probability)
Definition: WANObjectCache.php:1521
WANObjectCache
Multi-datacenter aware caching interface.
Definition: WANObjectCache.php:80
WANObjectCache\VERSION
const VERSION
Cache format version number.
Definition: WANObjectCache.php:142
WANObjectCache\getProcessCache
getProcessCache( $group)
Definition: WANObjectCache.php:1698
WANObjectCache\getRawKeysForWarmup
getRawKeysForWarmup(array $keys, array $checkKeys)
Definition: WANObjectCache.php:1732
WANObjectCache\getMulti
getMulti(array $keys, &$curTTLs=[], array $checkKeys=[], array &$asOfs=[])
Fetch the value of several keys from cache.
Definition: WANObjectCache.php:270
WANObjectCache\doGetWithSetCallback
doGetWithSetCallback( $key, $ttl, $callback, array $opts, &$asOf=null)
Do the actual I/O for getWithSetCallback() when needed.
Definition: WANObjectCache.php:939
WANObjectCache\resetCheckKey
resetCheckKey( $key)
Delete a "check" key from all datacenters, invalidating keys that use it.
Definition: WANObjectCache.php:663
WANObjectCache\TSE_NONE
const TSE_NONE
Idiom for getWithSetCallback() callbacks to 'lockTSE' logic.
Definition: WANObjectCache.php:130
WANObjectCache\HOT_TTR
const HOT_TTR
The time length of the "popularity" refresh window for hot keys.
Definition: WANObjectCache.php:121
WANObjectCache\LOCK_TTL
const LOCK_TTL
Seconds to keep lock keys around.
Definition: WANObjectCache.php:112
$code
this hook is for auditing only or null if authentication failed before getting that far or null if we can t even determine that probably a stub it is not rendered in wiki pages or galleries in category pages allow injecting custom HTML after the section Any uses of the hook need to handle escaping see BaseTemplate::getToolbox and BaseTemplate::makeListItem for details on the format of individual items inside of this array or by returning and letting standard HTTP rendering take place modifiable or by returning false and taking over the output modifiable & $code
Definition: hooks.txt:781
WANObjectCache\PURGE_VAL_PREFIX
const PURGE_VAL_PREFIX
Definition: WANObjectCache.php:165
WANObjectCache\LOCK_TSE
const LOCK_TSE
Default time-since-expiry on a miss that makes a key "hot".
Definition: WANObjectCache.php:116
WANObjectCache\getWarmupKeyMisses
getWarmupKeyMisses()
Definition: WANObjectCache.php:1445
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:9
IExpiringStore\TTL_YEAR
const TTL_YEAR
Definition: IExpiringStore.php:38
$keys
$keys
Definition: testCompression.php:65
WANObjectCache\$lastRelayError
int $lastRelayError
ERR_* constant for the "last error" registry.
Definition: WANObjectCache.php:93
WANObjectCache\HOLDOFF_NONE
const HOLDOFF_NONE
Idiom for delete() for "no hold-off".
Definition: WANObjectCache.php:134
WANObjectCache\$callbackDepth
int $callbackDepth
Callback stack depth for getWithSetCallback()
Definition: WANObjectCache.php:96
WANObjectCache\FLD_FLAGS
const FLD_FLAGS
Definition: WANObjectCache.php:148
WANObjectCache\AGE_NEW
const AGE_NEW
Never consider performing "popularity" refreshes until a key reaches this age.
Definition: WANObjectCache.php:119
WANObjectCache\setLogger
setLogger(LoggerInterface $logger)
Definition: WANObjectCache.php:192
WANObjectCache\TINY_NEGATIVE
const TINY_NEGATIVE
Tiny negative float to use when CTL comes up >= 0 due to clock skew.
Definition: WANObjectCache.php:139
WANObjectCache\CHECK_KEY_TTL
const CHECK_KEY_TTL
Seconds to keep dependency purge keys around.
Definition: WANObjectCache.php:110
EventRelayer
Base class for reliable event relays.
Definition: EventRelayer.php:27
WANObjectCache\FLD_HOLDOFF
const FLD_HOLDOFF
Definition: WANObjectCache.php:149
BagOStuff\ERR_NO_RESPONSE
const ERR_NO_RESPONSE
Definition: BagOStuff.php:78
WANObjectCache\ERR_UNEXPECTED
const ERR_UNEXPECTED
Definition: WANObjectCache.php:157
WANObjectCache\FLD_TTL
const FLD_TTL
Definition: WANObjectCache.php:146
WANObjectCache\HIT_RATE_HIGH
const HIT_RATE_HIGH
Hits/second for a refresh to be expected within the "popularity" window.
Definition: WANObjectCache.php:123
$flags
it s the revision text itself In either if gzip is the revision text is gzipped $flags
Definition: hooks.txt:2801
WANObjectCache\makeGlobalKey
makeGlobalKey()
Definition: WANObjectCache.php:1332
array
the array() calling protocol came about after MediaWiki 1.4rc1.
WANObjectCache\processCheckKeys
processCheckKeys(array $timeKeys, array $wrappedValues, $now)
Definition: WANObjectCache.php:361