PluginProbe
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score / 1.1
Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score v1.1
trunk 1.0 1.0.1 1.1 1.1.1 1.1.2 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.1 2.1.1 2.1.2 2.2 2.2.1 All 69 releases
powered-cache / includes / dropins / memcached-object-cache.php

memcached-object-cache.php in Powered Cache – Caching and Optimization for WordPress – Easily Improve PageSpeed & Web Vitals Score 1.1, at includes/dropins/memcached-object-cache.php

469 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Memcached Redux
3
4 if ( !defined( 'WP_CACHE_KEY_SALT' ) ) {
5 define( 'WP_CACHE_KEY_SALT', '' );
6 }
7
8 if ( class_exists( 'Memcached' ) ):
9
10 function wp_cache_add( $key, $data, $group = '', $expire = 0 ) {
11 global $wp_object_cache;
12
13 return $wp_object_cache->add( $key, $data, $group, $expire );
14 }
15
16 function wp_cache_incr( $key, $n = 1, $group = '' ) {
17 global $wp_object_cache;
18
19 return $wp_object_cache->incr( $key, $n, $group );
20 }
21
22 function wp_cache_decr( $key, $n = 1, $group = '' ) {
23 global $wp_object_cache;
24
25 return $wp_object_cache->decr( $key, $n, $group );
26 }
27
28 function wp_cache_close() {
29 global $wp_object_cache;
30
31 return $wp_object_cache->close();
32 }
33
34 function wp_cache_delete( $key, $group = '' ) {
35 global $wp_object_cache;
36
37 return $wp_object_cache->delete( $key, $group );
38 }
39
40 function wp_cache_flush() {
41 global $wp_object_cache;
42
43 return $wp_object_cache->flush();
44 }
45
46 function wp_cache_get( $key, $group = '', $force = false, &$found = null ) {
47 global $wp_object_cache;
48
49 return $wp_object_cache->get( $key, $group, $force, $found );
50 }
51
52 /**
53 * $keys_and_groups = array(
54 * array( 'key', 'group' ),
55 * array( 'key', '' ),
56 * array( 'key', 'group' ),
57 * array( 'key' )
58 * );
59 *
60 */
61 function wp_cache_get_multi( $key_and_groups, $bucket = 'default' ) {
62 global $wp_object_cache;
63
64 return $wp_object_cache->get_multi( $key_and_groups, $bucket );
65 }
66
67 /**
68 * $items = array(
69 * array( 'key', 'data', 'group' ),
70 * array( 'key', 'data' )
71 * );
72 *
73 */
74 function wp_cache_set_multi( $items, $expire = 0, $group = 'default' ) {
75 global $wp_object_cache;
76
77 return $wp_object_cache->set_multi( $items, $expire = 0, $group = 'default' );
78 }
79
80 function wp_cache_init() {
81 global $wp_object_cache;
82
83 $wp_object_cache = new WP_Object_Cache();
84 }
85
86 function wp_cache_replace( $key, $data, $group = '', $expire = 0 ) {
87 global $wp_object_cache;
88
89 return $wp_object_cache->replace( $key, $data, $group, $expire );
90 }
91
92 function wp_cache_set( $key, $data, $group = '', $expire = 0 ) {
93 global $wp_object_cache;
94
95 if ( defined( 'WP_INSTALLING' ) == false )
96 return $wp_object_cache->set( $key, $data, $group, $expire );
97 else
98 return $wp_object_cache->delete( $key, $group );
99 }
100
101 function wp_cache_add_global_groups( $groups ) {
102 global $wp_object_cache;
103
104 $wp_object_cache->add_global_groups( $groups );
105 }
106
107 function wp_cache_add_non_persistent_groups( $groups ) {
108 global $wp_object_cache;
109
110 $wp_object_cache->add_non_persistent_groups( $groups );
111 }
112
113 class WP_Object_Cache {
114 var $global_groups = array();
115
116 var $no_mc_groups = array();
117
118 var $cache = array();
119 var $mc = array();
120 var $stats = array();
121 var $group_ops = array();
122
123 var $cache_enabled = true;
124 var $default_expiration = 0;
125
126 function add( $id, $data, $group = 'default', $expire = 0 ) {
127 $key = $this->key( $id, $group );
128
129 if ( is_object( $data ) )
130 $data = clone $data;
131
132 if ( in_array( $group, $this->no_mc_groups ) ) {
133 $this->cache[$key] = $data;
134 return true;
135 } elseif ( isset( $this->cache[$key] ) && $this->cache[$key] !== false ) {
136 return false;
137 }
138
139 $mc =& $this->get_mc( $group );
140 $expire = ( $expire == 0) ? $this->default_expiration : $expire;
141 $result = $mc->add( $key, $data, $expire );
142
143 if ( false !== $result ) {
144 @ ++$this->stats['add'];
145 $this->group_ops[$group][] = "add $id";
146 $this->cache[$key] = $data;
147 }
148
149 return $result;
150 }
151
152 function add_global_groups( $groups ) {
153 if ( ! is_array( $groups ) )
154 $groups = (array) $groups;
155
156 $this->global_groups = array_merge( $this->global_groups, $groups );
157 $this->global_groups = array_unique( $this->global_groups );
158 }
159
160 function add_non_persistent_groups( $groups ) {
161 if ( ! is_array( $groups ) )
162 $groups = (array) $groups;
163
164 $this->no_mc_groups = array_merge( $this->no_mc_groups, $groups );
165 $this->no_mc_groups = array_unique( $this->no_mc_groups );
166 }
167
168 function incr( $id, $n = 1, $group = 'default' ) {
169 $key = $this->key( $id, $group );
170 $mc =& $this->get_mc( $group );
171 $this->cache[ $key ] = $mc->increment( $key, $n );
172 return $this->cache[ $key ];
173 }
174
175 function decr( $id, $n = 1, $group = 'default' ) {
176 $key = $this->key( $id, $group );
177 $mc =& $this->get_mc( $group );
178 $this->cache[ $key ] = $mc->decrement( $key, $n );
179 return $this->cache[ $key ];
180 }
181
182 function close() {
183 // Silence is Golden.
184 }
185
186 function delete( $id, $group = 'default' ) {
187 $key = $this->key( $id, $group );
188
189 if ( in_array( $group, $this->no_mc_groups ) ) {
190 unset( $this->cache[$key] );
191 return true;
192 }
193
194 $mc =& $this->get_mc( $group );
195
196 $result = $mc->delete( $key );
197
198 @ ++$this->stats['delete'];
199 $this->group_ops[$group][] = "delete $id";
200
201 if ( false !== $result )
202 unset( $this->cache[$key] );
203
204 return $result;
205 }
206
207 function flush() {
208 // Don't flush if multi-blog.
209 if ( function_exists( 'is_site_admin' ) || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) )
210 return true;
211
212 $ret = true;
213 foreach ( array_keys( $this->mc ) as $group )
214 $ret &= $this->mc[$group]->flush();
215 return $ret;
216 }
217
218 function get( $id, $group = 'default', $force = false, &$found = null ) {
219 $key = $this->key( $id, $group );
220 $mc =& $this->get_mc( $group );
221 $found = false;
222
223 if ( isset( $this->cache[$key] ) && ( !$force || in_array( $group, $this->no_mc_groups ) ) ) {
224 $found = true;
225 if ( is_object( $this->cache[$key] ) )
226 $value = clone $this->cache[$key];
227 else
228 $value = $this->cache[$key];
229 } else if ( in_array( $group, $this->no_mc_groups ) ) {
230 $this->cache[$key] = $value = false;
231 } else {
232 $value = $mc->get( $key );
233 if ( empty( $value ) || ( is_integer( $value ) && -1 == $value ) ){
234 $value = false;
235 $found = $mc->getResultCode() !== Memcached::RES_NOTFOUND;
236 } else {
237 $found = true;
238 }
239 $this->cache[$key] = $value;
240 }
241
242 @ ++$this->stats['get'];
243 $this->group_ops[$group][] = "get $id";
244
245 if ( 'checkthedatabaseplease' === $value ) {
246 unset( $this->cache[$key] );
247 $value = false;
248 }
249
250 return $value;
251 }
252
253 function get_multi( $keys, $group = 'default' ) {
254 $return = array();
255 $gets = array();
256 foreach ( $keys as $i => $values ) {
257 $mc =& $this->get_mc( $group );
258 $values = (array) $values;
259 if ( empty( $values[1] ) )
260 $values[1] = 'default';
261
262 list( $id, $group ) = (array) $values;
263 $key = $this->key( $id, $group );
264
265 if ( isset( $this->cache[$key] ) ) {
266
267 if ( is_object( $this->cache[$key] ) )
268 $return[$key] = clone $this->cache[$key];
269 else
270 $return[$key] = $this->cache[$key];
271
272 } else if ( in_array( $group, $this->no_mc_groups ) ) {
273 $return[$key] = false;
274
275 } else {
276 $gets[$key] = $key;
277 }
278 }
279
280 if ( !empty( $gets ) ) {
281 $results = $mc->getMulti( $gets, $null, Memcached::GET_PRESERVE_ORDER );
282 $joined = array_combine( array_keys( $gets ), array_values( $results ) );
283 $return = array_merge( $return, $joined );
284 }
285
286 @ ++$this->stats['get_multi'];
287 $this->group_ops[$group][] = "get_multi $id";
288 $this->cache = array_merge( $this->cache, $return );
289 return array_values( $return );
290 }
291
292 function key( $key, $group ) {
293 if ( empty( $group ) )
294 $group = 'default';
295
296 if ( false !== array_search( $group, $this->global_groups ) )
297 $prefix = $this->global_prefix;
298 else
299 $prefix = $this->blog_prefix;
300
301 return preg_replace( '/\s+/', '', WP_CACHE_KEY_SALT . "$prefix$group:$key" );
302 }
303
304 function replace( $id, $data, $group = 'default', $expire = 0 ) {
305 $key = $this->key( $id, $group );
306 $expire = ( $expire == 0) ? $this->default_expiration : $expire;
307 $mc =& $this->get_mc( $group );
308
309 if ( is_object( $data ) )
310 $data = clone $data;
311
312 $result = $mc->replace( $key, $data, $expire );
313 if ( false !== $result )
314 $this->cache[$key] = $data;
315 return $result;
316 }
317
318 function set( $id, $data, $group = 'default', $expire = 0 ) {
319 $key = $this->key( $id, $group );
320 if ( isset( $this->cache[$key] ) && ( 'checkthedatabaseplease' === $this->cache[$key] ) )
321 return false;
322
323 if ( is_object( $data) )
324 $data = clone $data;
325
326 $this->cache[$key] = $data;
327
328 if ( in_array( $group, $this->no_mc_groups ) )
329 return true;
330
331 $expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
332 $mc =& $this->get_mc( $group );
333 $result = $mc->set( $key, $data, $expire );
334
335 return $result;
336 }
337
338 function set_multi( $items, $expire = 0, $group = 'default' ) {
339 $sets = array();
340 $mc =& $this->get_mc( $group );
341 $expire = ( $expire == 0 ) ? $this->default_expiration : $expire;
342
343 foreach ( $items as $i => $item ) {
344 if ( empty( $item[2] ) )
345 $item[2] = 'default';
346
347 list( $id, $data, $group ) = $item;
348
349 $key = $this->key( $id, $group );
350 if ( isset( $this->cache[$key] ) && ( 'checkthedatabaseplease' === $this->cache[$key] ) )
351 continue;
352
353 if ( is_object( $data) )
354 $data = clone $data;
355
356 $this->cache[$key] = $data;
357
358 if ( in_array( $group, $this->no_mc_groups ) )
359 continue;
360
361 $sets[$key] = $data;
362 }
363
364 if ( !empty( $sets ) )
365 $mc->setMulti( $sets, $expire );
366 }
367
368 function colorize_debug_line( $line ) {
369 $colors = array(
370 'get' => 'green',
371 'set' => 'purple',
372 'add' => 'blue',
373 'delete'=> 'red'
374 );
375
376 $cmd = substr( $line, 0, strpos( $line, ' ' ) );
377
378 $cmd2 = "<span style='color:{$colors[$cmd]}'>$cmd</span>";
379
380 return $cmd2 . substr( $line, strlen( $cmd ) ) . "\n";
381 }
382
383 function stats() {
384 echo "<p>\n";
385 foreach ( $this->stats as $stat => $n ) {
386 echo "<strong>$stat</strong> $n";
387 echo "<br/>\n";
388 }
389 echo "</p>\n";
390 echo "<h3>Memcached:</h3>";
391 foreach ( $this->group_ops as $group => $ops ) {
392 if ( !isset( $_GET['debug_queries'] ) && 500 < count( $ops ) ) {
393 $ops = array_slice( $ops, 0, 500 );
394 echo "<big>Too many to show! <a href='" . add_query_arg( 'debug_queries', 'true' ) . "'>Show them anyway</a>.</big>\n";
395 }
396 echo "<h4>$group commands</h4>";
397 echo "<pre>\n";
398 $lines = array();
399 foreach ( $ops as $op ) {
400 $lines[] = $this->colorize_debug_line( $op );
401 }
402 print_r( $lines );
403 echo "</pre>\n";
404 }
405
406 if ( !empty( $this->debug ) && $this->debug )
407 var_dump( $this->memcache_debug );
408 }
409
410 function &get_mc( $group ) {
411 if ( isset( $this->mc[$group] ) )
412 return $this->mc[$group];
413 return $this->mc['default'];
414 }
415
416 function WP_Object_Cache() {
417 global $memcached_servers;
418
419 if ( isset( $memcached_servers ) )
420 $buckets = $memcached_servers;
421 else
422 $buckets = array( '127.0.0.1' );
423
424 reset( $buckets );
425 if ( is_int( key( $buckets ) ) )
426 $buckets = array( 'default' => $buckets );
427
428 foreach ( $buckets as $bucket => $servers ) {
429 $this->mc[$bucket] = new Memcached();
430
431 $instances = array();
432 foreach ( $servers as $server ) {
433 @list( $node, $port ) = explode( ':', $server );
434 if ( empty( $port ) )
435 $port = ini_get( 'memcache.default_port' );
436 $port = intval( $port );
437 if ( !$port )
438 $port = 11211;
439
440 $instances[] = array( $node, $port, 1 );
441 }
442 $this->mc[$bucket]->addServers( $instances );
443 }
444
445 global $blog_id, $table_prefix;
446 $this->global_prefix = '';
447 $this->blog_prefix = '';
448 if ( function_exists( 'is_multisite' ) ) {
449 $this->global_prefix = ( is_multisite() || defined( 'CUSTOM_USER_TABLE' ) && defined( 'CUSTOM_USER_META_TABLE' ) ) ? '' : $table_prefix;
450 $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ) . ':';
451 }
452
453 $this->cache_hits =& $this->stats['get'];
454 $this->cache_misses =& $this->stats['add'];
455 }
456 }
457 else: // No Memcached
458
459 // In 3.7+, we can handle this smoothly
460 if ( function_exists( 'wp_using_ext_object_cache' ) ) {
461 wp_using_ext_object_cache( false );
462
463 // In earlier versions, there isn't a clean bail-out method.
464 } else {
465 wp_die( 'Memcached class not available.' );
466 }
467
468 endif;
469