MediaWiki  master
APCUBagOStuff.php
Go to the documentation of this file.
1 <?php
40  private $useIncrTTLArg;
41 
47  private const KEY_SUFFIX = ':4';
48 
50  private static $CAS_MAX_ATTEMPTS = 100;
51 
52  public function __construct( array $params = [] ) {
53  // No use in segmenting values
54  $params['segmentationSize'] = INF;
55  parent::__construct( $params );
56  // The extension serializer is still buggy, unlike "php" and "igbinary"
57  $this->nativeSerialize = ( ini_get( 'apc.serializer' ) !== 'default' );
58  $this->useIncrTTLArg = version_compare( phpversion( 'apcu' ), '5.1.12', '>=' );
59  // Avoid back-dated values that expire too soon. In particular, regenerating a hot
60  // key before it expires should never have the end-result of purging that key. Using
61  // the web request time becomes increasingly problematic the longer the request lasts.
62  ini_set( 'apc.use_request_time', '0' );
63 
64  if ( PHP_SAPI === 'cli' ) {
65  $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'apc.enable_cli' )
68  } else {
70  }
71  }
72 
73  protected function doGet( $key, $flags = 0, &$casToken = null ) {
74  $getToken = ( $casToken === self::PASS_BY_REF );
75  $casToken = null;
76 
77  $blob = apcu_fetch( $key . self::KEY_SUFFIX );
78  $value = $this->nativeSerialize ? $blob : $this->unserialize( $blob );
79  if ( $getToken && $value !== false ) {
80  $casToken = $blob; // don't bother hashing this
81  }
82 
83  return $value;
84  }
85 
86  protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
87  $blob = $this->nativeSerialize ? $value : $this->getSerialized( $value, $key );
88  $ttl = $this->getExpirationAsTTL( $exptime );
89  $success = apcu_store( $key . self::KEY_SUFFIX, $blob, $ttl );
90  return $success;
91  }
92 
93  protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
94  $blob = $this->nativeSerialize ? $value : $this->getSerialized( $value, $key );
95  $ttl = $this->getExpirationAsTTL( $exptime );
96  $success = apcu_add( $key . self::KEY_SUFFIX, $blob, $ttl );
97  return $success;
98  }
99 
100  protected function doDelete( $key, $flags = 0 ) {
101  apcu_delete( $key . self::KEY_SUFFIX );
102 
103  return true;
104  }
105 
106  public function incr( $key, $value = 1, $flags = 0 ) {
107  $result = false;
108  $value = (int)$value;
109 
110  // https://github.com/krakjoe/apcu/issues/166
111  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
112  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
113  if ( !is_int( $oldCount ) ) {
114  break;
115  }
116  $count = $oldCount + $value;
117  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
118  $result = $count;
119  break;
120  }
121  }
122 
123  return $result;
124  }
125 
126  public function decr( $key, $value = 1, $flags = 0 ) {
127  $result = false;
128  $value = (int)$value;
129 
130  // https://github.com/krakjoe/apcu/issues/166
131  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
132  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
133  if ( !is_int( $oldCount ) ) {
134  break;
135  }
136  $count = $oldCount - $value;
137  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
138  $result = $count;
139  break;
140  }
141  }
142 
143  return $result;
144  }
145 
146  protected function doIncrWithInit( $key, $exptime, $step, $init, $flags ) {
147  // Use apcu 5.1.12 $ttl argument if apcu_inc() will initialize to $init:
148  // https://www.php.net/manual/en/function.apcu-inc.php
149  if ( $step === $init && $this->useIncrTTLArg ) {
151  $ttl = $this->getExpirationAsTTL( $exptime );
152  $result = apcu_inc( $key . self::KEY_SUFFIX, $step, $success, $ttl );
153  } else {
154  $result = false;
155  for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
156  $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
157  if ( $oldCount === false ) {
158  $count = $init;
159  $ttl = $this->getExpirationAsTTL( $exptime );
160  if ( apcu_add( $key . self::KEY_SUFFIX, $count, $ttl ) ) {
161  $result = $count;
162  break;
163  }
164  } elseif ( is_int( $oldCount ) ) {
165  $count = $oldCount + $step;
166  if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
167  $result = $count;
168  break;
169  }
170  } else {
171  break;
172  }
173  }
174  }
175 
176  return $result;
177  }
178 
179  public function makeKeyInternal( $keyspace, $components ) {
180  return $this->genericKeyFromComponents( $keyspace, ...$components );
181  }
182 
183  protected function convertGenericKey( $key ) {
184  return $key; // short-circuit; already uses "generic" keys
185  }
186 }
$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.
bool $nativeSerialize
Whether to trust the APC implementation to serialization.
convertGenericKey( $key)
Convert a "generic" reversible cache key into one for this cache.
static int $CAS_MAX_ATTEMPTS
Max attempts for implicit CAS operations.
__construct(array $params=[])
doGet( $key, $flags=0, &$casToken=null)
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:715
string $keyspace
Default keyspace; used by makeKey()
Definition: BagOStuff.php:104
Storage medium specific cache for storing items (e.g.
getSerialized( $value, $key)
Get the serialized form a value, using any applicable prepared value.
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)