Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 66 |
|
0.00% |
0 / 9 |
CRAP | |
0.00% |
0 / 1 |
WinCacheBagOStuff | |
0.00% |
0 / 66 |
|
0.00% |
0 / 9 |
812 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 8 |
|
0.00% |
0 / 1 |
12 | |||
doGet | |
0.00% |
0 / 9 |
|
0.00% |
0 / 1 |
30 | |||
doCas | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
12 | |||
doSet | |
0.00% |
0 / 3 |
|
0.00% |
0 / 1 |
6 | |||
doAdd | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
12 | |||
doDelete | |
0.00% |
0 / 2 |
|
0.00% |
0 / 1 |
2 | |||
makeKeyInternal | |
0.00% |
0 / 13 |
|
0.00% |
0 / 1 |
20 | |||
requireConvertGenericKey | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
doIncrWithInit | |
0.00% |
0 / 12 |
|
0.00% |
0 / 1 |
42 |
1 | <?php |
2 | /** |
3 | * Object caching using WinCache. |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License as published by |
7 | * the Free Software Foundation; either version 2 of the License, or |
8 | * (at your option) any later version. |
9 | * |
10 | * This program is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | * GNU General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU General Public License along |
16 | * with this program; if not, write to the Free Software Foundation, Inc., |
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
18 | * http://www.gnu.org/copyleft/gpl.html |
19 | * |
20 | * @file |
21 | * @ingroup Cache |
22 | */ |
23 | |
24 | /** |
25 | * Wrapper for WinCache object caching functions; identical interface |
26 | * to the APC wrapper |
27 | * |
28 | * @ingroup Cache |
29 | */ |
30 | class WinCacheBagOStuff extends MediumSpecificBagOStuff { |
31 | public function __construct( array $params = [] ) { |
32 | $params['segmentationSize'] ??= INF; |
33 | parent::__construct( $params ); |
34 | |
35 | if ( PHP_SAPI === 'cli' ) { |
36 | $this->attrMap[self::ATTR_DURABILITY] = ini_get( 'wincache.enablecli' ) |
37 | ? self::QOS_DURABILITY_SCRIPT |
38 | : self::QOS_DURABILITY_NONE; |
39 | } else { |
40 | $this->attrMap[self::ATTR_DURABILITY] = self::QOS_DURABILITY_SERVICE; |
41 | } |
42 | } |
43 | |
44 | protected function doGet( $key, $flags = 0, &$casToken = null ) { |
45 | $getToken = ( $casToken === self::PASS_BY_REF ); |
46 | $casToken = null; |
47 | |
48 | $data = wincache_ucache_get( $key ); |
49 | if ( !is_string( $data ) && !is_int( $data ) ) { |
50 | return false; |
51 | } |
52 | |
53 | $value = $this->unserialize( $data ); |
54 | if ( $getToken && $value !== false ) { |
55 | $casToken = $data; |
56 | } |
57 | |
58 | return $value; |
59 | } |
60 | |
61 | protected function doCas( $casToken, $key, $value, $exptime = 0, $flags = 0 ) { |
62 | // optimize with FIFO lock |
63 | if ( !wincache_lock( $key ) ) { |
64 | return false; |
65 | } |
66 | |
67 | $curCasToken = self::PASS_BY_REF; |
68 | $this->doGet( $key, self::READ_LATEST, $curCasToken ); |
69 | if ( $casToken === $curCasToken ) { |
70 | $success = $this->set( $key, $value, $exptime, $flags ); |
71 | } else { |
72 | $this->logger->info( |
73 | __METHOD__ . ' failed due to race condition for {key}.', |
74 | [ 'key' => $key ] |
75 | ); |
76 | |
77 | // mismatched or failed |
78 | $success = false; |
79 | } |
80 | |
81 | wincache_unlock( $key ); |
82 | |
83 | return $success; |
84 | } |
85 | |
86 | protected function doSet( $key, $value, $exptime = 0, $flags = 0 ) { |
87 | $ttl = $this->getExpirationAsTTL( $exptime ); |
88 | $result = wincache_ucache_set( $key, $this->getSerialized( $value, $key ), $ttl ); |
89 | |
90 | // false positive, wincache_ucache_set returns an empty array |
91 | // in some circumstances. |
92 | // @phan-suppress-next-line PhanTypeComparisonToArray |
93 | return ( $result === [] || $result === true ); |
94 | } |
95 | |
96 | protected function doAdd( $key, $value, $exptime = 0, $flags = 0 ) { |
97 | if ( wincache_ucache_exists( $key ) ) { |
98 | // avoid warnings |
99 | return false; |
100 | } |
101 | |
102 | $ttl = $this->getExpirationAsTTL( $exptime ); |
103 | $result = wincache_ucache_add( $key, $this->getSerialized( $value, $key ), $ttl ); |
104 | |
105 | // false positive, wincache_ucache_add returns an empty array |
106 | // in some circumstances. |
107 | // @phan-suppress-next-line PhanTypeComparisonToArray |
108 | return ( $result === [] || $result === true ); |
109 | } |
110 | |
111 | protected function doDelete( $key, $flags = 0 ) { |
112 | wincache_ucache_delete( $key ); |
113 | |
114 | return true; |
115 | } |
116 | |
117 | protected function makeKeyInternal( $keyspace, $components ) { |
118 | // WinCache keys have a maximum length of 150 characters. From that, |
119 | // subtract the number of characters we need for the keyspace and for |
120 | // the separator character needed for each argument. To handle some |
121 | // custom prefixes used by thing like WANObjectCache, limit to 125. |
122 | // NOTE: Same as in memcached, except the max key length there is 255. |
123 | $charsLeft = 125 - strlen( $keyspace ) - count( $components ); |
124 | |
125 | $components = array_map( |
126 | static function ( $component ) use ( &$charsLeft ) { |
127 | // 33 = 32 characters for the MD5 + 1 for the '#' prefix. |
128 | if ( $charsLeft > 33 && strlen( $component ) > $charsLeft ) { |
129 | $component = '#' . md5( $component ); |
130 | } |
131 | |
132 | $charsLeft -= strlen( $component ); |
133 | return $component; |
134 | }, |
135 | $components |
136 | ); |
137 | |
138 | if ( $charsLeft < 0 ) { |
139 | return $keyspace . ':BagOStuff-long-key:##' . md5( implode( ':', $components ) ); |
140 | } |
141 | |
142 | return $keyspace . ':' . implode( ':', $components ); |
143 | } |
144 | |
145 | protected function requireConvertGenericKey(): bool { |
146 | return true; |
147 | } |
148 | |
149 | public function doIncrWithInit( $key, $exptime, $step, $init, $flags ) { |
150 | // optimize with FIFO lock |
151 | if ( !wincache_lock( $key ) ) { |
152 | return false; |
153 | } |
154 | |
155 | $curValue = $this->doGet( $key ); |
156 | if ( $curValue === false ) { |
157 | $newValue = $this->doSet( $key, $init, $exptime ) ? $init : false; |
158 | } elseif ( $this->isInteger( $curValue ) ) { |
159 | $sum = max( $curValue + $step, 0 ); |
160 | $oldTTL = wincache_ucache_info( false, $key )["ucache_entries"][1]["ttl_seconds"]; |
161 | $newValue = $this->doSet( $key, $sum, $oldTTL ) ? $sum : false; |
162 | } else { |
163 | $newValue = false; |
164 | } |
165 | |
166 | wincache_unlock( $key ); |
167 | |
168 | return $newValue; |
169 | } |
170 | } |