MediaWiki REL1_37
APCUBagOStuff.php
Go to the documentation of this file.
1<?php
41
47 private const KEY_SUFFIX = ':4';
48
50 private static $CAS_MAX_ATTEMPTS = 100;
51
52 public function __construct( array $params = [] ) {
53 $params['segmentationSize'] = $params['segmentationSize'] ?? INF;
54 parent::__construct( $params );
55 // The extension serializer is still buggy, unlike "php" and "igbinary"
56 $this->nativeSerialize = ( ini_get( 'apc.serializer' ) !== 'default' );
57 $this->useIncrTTLArg = version_compare( phpversion( 'apcu' ), '5.1.12', '>=' );
58 // Avoid back-dated values that expire too soon. In particular, regenerating a hot
59 // key before it expires should never have the end-result of purging that key. Using
60 // the web request time becomes increasingly problematic the longer the request lasts.
61 ini_set( 'apc.use_request_time', '0' );
62
63 if ( PHP_SAPI === 'cli' ) {
64 $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'apc.enable_cli' )
67 } else {
69 }
70 }
71
72 protected function doGet( $key, $flags = 0, &$casToken = null ) {
73 $getToken = ( $casToken === self::PASS_BY_REF );
74 $casToken = null;
75
76 $blob = apcu_fetch( $key . self::KEY_SUFFIX );
77 $value = $this->nativeSerialize ? $blob : $this->unserialize( $blob );
78 if ( $getToken && $value !== false ) {
79 $casToken = $blob; // don't bother hashing this
80 }
81
82 return $value;
83 }
84
85 protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
86 $blob = $this->nativeSerialize ? $value : $this->getSerialized( $value, $key );
87 $ttl = $this->getExpirationAsTTL( $exptime );
88 $success = apcu_store( $key . self::KEY_SUFFIX, $blob, $ttl );
89 return $success;
90 }
91
92 protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
93 $blob = $this->nativeSerialize ? $value : $this->getSerialized( $value, $key );
94 $ttl = $this->getExpirationAsTTL( $exptime );
95 $success = apcu_add( $key . self::KEY_SUFFIX, $blob, $ttl );
96 return $success;
97 }
98
99 protected function doDelete( $key, $flags = 0 ) {
100 apcu_delete( $key . self::KEY_SUFFIX );
101
102 return true;
103 }
104
105 public function incr( $key, $value = 1, $flags = 0 ) {
106 $result = false;
107
108 // https://github.com/krakjoe/apcu/issues/166
109 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
110 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
111 if ( !is_int( $oldCount ) ) {
112 break;
113 }
114 $count = $oldCount + (int)$value;
115 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
116 $result = $count;
117 break;
118 }
119 }
120
121 return $result;
122 }
123
124 public function decr( $key, $value = 1, $flags = 0 ) {
125 $result = false;
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 - (int)$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 public function incrWithInit( $key, $exptime, $value = 1, $init = null, $flags = 0 ) {
144 $init = is_int( $init ) ? $init : $value;
145 // Use apcu 5.1.12 $ttl argument if apcu_inc() will initialize to $init:
146 // https://www.php.net/manual/en/function.apcu-inc.php
147 if ( $value === $init && $this->useIncrTTLArg ) {
149 $ttl = $this->getExpirationAsTTL( $exptime );
150 $result = apcu_inc( $key . self::KEY_SUFFIX, $value, $success, $ttl );
151 } else {
152 $result = false;
153 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
154 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
155 if ( $oldCount === false ) {
156 $count = (int)$init;
157 $ttl = $this->getExpirationAsTTL( $exptime );
158 if ( apcu_add( $key . self::KEY_SUFFIX, $count, $ttl ) ) {
159 $result = $count;
160 break;
161 }
162 } elseif ( is_int( $oldCount ) ) {
163 $count = $oldCount + (int)$value;
164 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
165 $result = $count;
166 break;
167 }
168 } else {
169 break;
170 }
171 }
172 }
173
174 return $result;
175 }
176
177 public function makeKeyInternal( $keyspace, $components ) {
178 return $this->genericKeyFromComponents( $keyspace, ...$components );
179 }
180
181 protected function convertGenericKey( $key ) {
182 return $key; // short-circuit; already uses "generic" keys
183 }
184}
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.
incrWithInit( $key, $exptime, $value=1, $init=null, $flags=0)
Increase the value of the given key (no TTL change) if it exists or create it otherwise.
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.
string $keyspace
Default keyspace; used by makeKey()
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)