MediaWiki REL1_39
APCUBagOStuff.php
Go to the documentation of this file.
1<?php
38 private $nativeSerialize;
39
45 private const KEY_SUFFIX = ':4';
46
48 private static $CAS_MAX_ATTEMPTS = 100;
49
50 public function __construct( array $params = [] ) {
51 // No use in segmenting values
52 $params['segmentationSize'] = INF;
53 parent::__construct( $params );
54 // The extension serializer is still buggy, unlike "php" and "igbinary"
55 $this->nativeSerialize = ( ini_get( 'apc.serializer' ) !== 'default' );
56 // Avoid back-dated values that expire too soon. In particular, regenerating a hot
57 // key before it expires should never have the end-result of purging that key. Using
58 // the web request time becomes increasingly problematic the longer the request lasts.
59 ini_set( 'apc.use_request_time', '0' );
60
61 if ( PHP_SAPI === 'cli' ) {
62 $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'apc.enable_cli' )
63 ? self::QOS_DURABILITY_SCRIPT
64 : self::QOS_DURABILITY_NONE;
65 } else {
66 $this->attrMap[self::ATTR_DURABILITY] = self::QOS_DURABILITY_SERVICE;
67 }
68 }
69
70 protected function doGet( $key, $flags = 0, &$casToken = null ) {
71 $getToken = ( $casToken === self::PASS_BY_REF );
72 $casToken = null;
73
74 $blob = apcu_fetch( $key . self::KEY_SUFFIX );
75 $value = $this->nativeSerialize ? $blob : $this->unserialize( $blob );
76 if ( $getToken && $value !== false ) {
77 // Note that if the driver handles serialization then this uses the PHP value
78 // as the token. This might require inspection or re-serialization in doCas().
79 $casToken = $blob;
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 return apcu_store( $key . self::KEY_SUFFIX, $blob, $ttl );
89 }
90
91 protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) {
92 if ( apcu_exists( $key . self::KEY_SUFFIX ) ) {
93 return false;
94 }
95
96 $blob = $this->nativeSerialize ? $value : $this->getSerialized( $value, $key );
97 $ttl = $this->getExpirationAsTTL( $exptime );
98 return apcu_add( $key . self::KEY_SUFFIX, $blob, $ttl );
99 }
100
101 protected function doDelete( $key, $flags = 0 ) {
102 apcu_delete( $key . self::KEY_SUFFIX );
103
104 return true;
105 }
106
107 public function incr( $key, $value = 1, $flags = 0 ) {
108 $result = false;
109 $value = (int)$value;
110
111 // https://github.com/krakjoe/apcu/issues/166
112 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
113 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
114 if ( !is_int( $oldCount ) ) {
115 break;
116 }
117 $count = $oldCount + $value;
118 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
119 $result = $count;
120 break;
121 }
122 }
123
124 return $result;
125 }
126
127 public function decr( $key, $value = 1, $flags = 0 ) {
128 $result = false;
129 $value = (int)$value;
130
131 // https://github.com/krakjoe/apcu/issues/166
132 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
133 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
134 if ( !is_int( $oldCount ) ) {
135 break;
136 }
137 $count = $oldCount - $value;
138 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
139 $result = $count;
140 break;
141 }
142 }
143
144 return $result;
145 }
146
147 protected function doIncrWithInit( $key, $exptime, $step, $init, $flags ) {
148 // Use apcu 5.1.12 $ttl argument if apcu_inc() will initialize to $init:
149 // https://www.php.net/manual/en/function.apcu-inc.php
150 if ( $step === $init ) {
152 $ttl = $this->getExpirationAsTTL( $exptime );
153 $result = apcu_inc( $key . self::KEY_SUFFIX, $step, $success, $ttl );
154 } else {
155 $result = false;
156 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
157 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
158 if ( $oldCount === false ) {
159 $count = $init;
160 $ttl = $this->getExpirationAsTTL( $exptime );
161 if ( apcu_add( $key . self::KEY_SUFFIX, $count, $ttl ) ) {
162 $result = $count;
163 break;
164 }
165 } elseif ( is_int( $oldCount ) ) {
166 $count = $oldCount + $step;
167 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
168 $result = $count;
169 break;
170 }
171 } else {
172 break;
173 }
174 }
175 }
176
177 return $result;
178 }
179
180 public function setNewPreparedValues( array $valueByKey ) {
181 // Do not bother staging serialized values if the PECL driver does the serializing
182 return $this->nativeSerialize
183 ? $this->guessSerialSizeOfValues( $valueByKey )
184 : parent::setNewPreparedValues( $valueByKey );
185 }
186
187 public function makeKeyInternal( $keyspace, $components ) {
188 return $this->genericKeyFromComponents( $keyspace, ...$components );
189 }
190
191 protected function convertGenericKey( $key ) {
192 // short-circuit; already uses "generic" keys
193 return $key;
194 }
195}
unserialize( $serialized)
This is a wrapper for APCu's shared memory functions.
setNewPreparedValues(array $valueByKey)
Stage a set of new key values for storage and estimate the amount of bytes needed.
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.
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.
guessSerialSizeOfValues(array $values)
Estimate the size of a each variable once serialized.