MediaWiki  master
APCUBagOStuff.php
Go to the documentation of this file.
1 <?php
42  private const KEY_SUFFIX = ':5';
43 
45  private static $CAS_MAX_ATTEMPTS = 100;
46 
47  public function __construct( array $params = [] ) {
48  // No use in segmenting values
49  $params['segmentationSize'] = INF;
50  parent::__construct( $params );
51  // Versions of apcu < 5.1.19 use apc.use_request_time=1 by default, causing new keys
52  // to be assigned timestamps based on the start of the PHP request/script. The longer
53  // the request has been running, the more likely that newly stored keys will instantly
54  // be seen as expired by other requests. Disable apc.use_request_time.
55  ini_set( 'apc.use_request_time', '0' );
56 
57  if ( PHP_SAPI === 'cli' ) {
58  $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'apc.enable_cli' )
61  } else {
63  }
64  }
65 
66  protected function doGet( $key, $flags = 0, &$casToken = null ) {
67  $getToken = ( $casToken === self::PASS_BY_REF );
68  $casToken = null;
69 
70  $value = apcu_fetch( $key . self::KEY_SUFFIX );
71  if ( $getToken && $value !== false ) {
72  // Note that if the driver handles serialization then this uses the PHP value
73  // as the token. This might require inspection or re-serialization in doCas().
74  $casToken = $value;
75  }
76 
77  return $value;
78  }
79 
80  protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
81  $ttl = $this->getExpirationAsTTL( $exptime );
82 
83  return apcu_store( $key . self::KEY_SUFFIX, $value, $ttl );
84  }
85 
86  protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
87  if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
88  // Avoid global write locks for high contention keys
89  return false;
90  }
91 
92  $ttl = $this->getExpirationAsTTL( $exptime );
93 
94  return apcu_add( $key . self::KEY_SUFFIX, $value, $ttl );
95  }
96 
97  protected function doDelete( $key, $flags = 0 ) {
98  apcu_delete( $key . self::KEY_SUFFIX );
99 
100  return true;
101  }
102 
103  public function incr( $key, $value = 1, $flags = 0 ) {
104  $result = false;
105  $value = (int)$value;
106 
107  // https://github.com/krakjoe/apcu/issues/166
108  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
109  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
110  if ( !is_int( $oldCount ) ) {
111  break;
112  }
113  $count = $oldCount + $value;
114  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
115  $result = $count;
116  break;
117  }
118  }
119 
120  return $result;
121  }
122 
123  public function decr( $key, $value = 1, $flags = 0 ) {
124  $result = false;
125  $value = (int)$value;
126 
127  // https://github.com/krakjoe/apcu/issues/166
128  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
129  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
130  if ( !is_int( $oldCount ) ) {
131  break;
132  }
133  $count = $oldCount - $value;
134  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
135  $result = $count;
136  break;
137  }
138  }
139 
140  return $result;
141  }
142 
143  protected function doIncrWithInit( $key, $exptime, $step, $init, $flags ) {
144  // Use apcu 5.1.12 $ttl argument if apcu_inc() will initialize to $init:
145  // https://www.php.net/manual/en/function.apcu-inc.php
146  if ( $step === $init ) {
148  $ttl = $this->getExpirationAsTTL( $exptime );
149  $result = apcu_inc( $key . self::KEY_SUFFIX, $step, $success, $ttl );
150  } else {
151  $result = false;
152  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
153  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
154  if ( $oldCount === false ) {
155  $count = $init;
156  $ttl = $this->getExpirationAsTTL( $exptime );
157  if ( apcu_add( $key . self::KEY_SUFFIX, $count, $ttl ) ) {
158  $result = $count;
159  break;
160  }
161  } elseif ( is_int( $oldCount ) ) {
162  $count = $oldCount + $step;
163  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
164  $result = $count;
165  break;
166  }
167  } else {
168  break;
169  }
170  }
171  }
172 
173  return $result;
174  }
175 
176  public function makeKeyInternal( $keyspace, $components ) {
177  return $this->genericKeyFromComponents( $keyspace, ...$components );
178  }
179 
180  protected function convertGenericKey( $key ) {
181  // short-circuit; already uses "generic" keys
182  return $key;
183  }
184 }
$success
This is a wrapper for APCu's shared memory functions.
doAdd( $key, $value, $exptime=0, $flags=0)
Insert an item if it does not already exist.
doIncrWithInit( $key, $exptime, $step, $init, $flags)
makeKeyInternal( $keyspace, $components)
Make a cache key for the given keyspace and components.
decr( $key, $value=1, $flags=0)
Decrease stored value of $key by $value while preserving its TTL.
doSet( $key, $value, $exptime=0, $flags=0)
Set an item.
doDelete( $key, $flags=0)
Delete an item.
convertGenericKey( $key)
Convert a "generic" reversible cache key into one for this cache.
__construct(array $params=[])
doGet( $key, $flags=0, &$casToken=null)
Get an item.
incr( $key, $value=1, $flags=0)
Increase stored value of $key by $value while preserving its TTL.
genericKeyFromComponents(... $components)
At a minimum, there must be a keyspace and collection name component.
Definition: BagOStuff.php:703
string $keyspace
Default keyspace; used by makeKey()
Definition: BagOStuff.php:101
Storage medium specific cache for storing items (e.g.
const PASS_BY_REF
Idiom for doGet() to return extra information by reference.
getExpirationAsTTL( $exptime)
Convert an optionally absolute expiry time to a relative time.
const QOS_DURABILITY_SERVICE
Data is lost once the service storing the data restarts.
const QOS_DURABILITY_SCRIPT
Data is lost at the end of the current web request or CLI script.
const QOS_DURABILITY_NONE
Data is never saved to begin with (blackhole store)
const ATTR_DURABILITY
Durability of writes; see QOS_DURABILITY_* (higher means stronger)