gallery: Fix phan annotation for ImageGalleryBase::getImages
[mediawiki.git] / includes / libs / objectcache / APCUBagOStuff.php
blobdbcf03295d34c16ae990ea251f5a07ed3636945d
1 <?php
2 /**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
18 * @file
20 namespace Wikimedia\ObjectCache;
22 /**
23 * Store data in the local server memory via APCu (php-apcu)
25 * Past issues of note:
26 * - Memory corruption when `apc.serializer=default` in INI:
27 * https://phabricator.wikimedia.org/T120267
28 * - We used to recommend `apc.serializer=php` as non-default setting, and if not set,
29 * applied serialize() manually to workaround bugs and to create values we can use
30 * as CAS tokens. Upstream defaults to serializer=php since php-apcu 5.1.15 (2018).
31 * https://gerrit.wikimedia.org/r/671634
33 * @see https://www.php.net/apcu
34 * @ingroup Cache
36 class APCUBagOStuff extends MediumSpecificBagOStuff {
37 /**
38 * @var string String to append to each APC key. This may be changed
39 * whenever the handling of values is changed, to prevent existing code
40 * from encountering older values which it cannot handle.
42 private const KEY_SUFFIX = ':5';
44 /** @var int Max attempts for implicit CAS operations */
45 private static $CAS_MAX_ATTEMPTS = 100;
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' );
57 if ( PHP_SAPI === 'cli' ) {
58 $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'apc.enable_cli' )
59 ? self::QOS_DURABILITY_SCRIPT
60 : self::QOS_DURABILITY_NONE;
61 } else {
62 $this->attrMap[self::ATTR_DURABILITY] = self::QOS_DURABILITY_SERVICE;
66 protected function doGet( $key, $flags = 0, &$casToken = null ) {
67 $getToken = ( $casToken === self::PASS_BY_REF );
68 $casToken = null;
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;
77 return $value;
80 protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) {
81 $ttl = $this->getExpirationAsTTL( $exptime );
83 return apcu_store( $key . self::KEY_SUFFIX, $value, $ttl );
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;
92 $ttl = $this->getExpirationAsTTL( $exptime );
94 return apcu_add( $key . self::KEY_SUFFIX, $value, $ttl );
97 protected function doDelete( $key, $flags = 0 ) {
98 apcu_delete( $key . self::KEY_SUFFIX );
100 return true;
103 protected function doIncrWithInit( $key, $exptime, $step, $init, $flags ) {
104 // Use apcu 5.1.12 $ttl argument if apcu_inc() will initialize to $init:
105 // https://www.php.net/manual/en/function.apcu-inc.php
106 if ( $step === $init ) {
107 /** @noinspection PhpMethodParametersCountMismatchInspection */
108 $ttl = $this->getExpirationAsTTL( $exptime );
109 $result = apcu_inc( $key . self::KEY_SUFFIX, $step, $success, $ttl );
110 } else {
111 $result = false;
112 for ( $i = 0; $i < self::$CAS_MAX_ATTEMPTS; ++$i ) {
113 $oldCount = apcu_fetch( $key . self::KEY_SUFFIX );
114 if ( $oldCount === false ) {
115 $count = $init;
116 $ttl = $this->getExpirationAsTTL( $exptime );
117 if ( apcu_add( $key . self::KEY_SUFFIX, $count, $ttl ) ) {
118 $result = $count;
119 break;
121 } elseif ( is_int( $oldCount ) ) {
122 $count = $oldCount + $step;
123 if ( apcu_cas( $key . self::KEY_SUFFIX, $oldCount, $count ) ) {
124 $result = $count;
125 break;
127 } else {
128 break;
133 return $result;
137 /** @deprecated class alias since 1.43 */
138 class_alias( APCUBagOStuff::class, 'APCUBagOStuff' );