WordPress.org

Make WordPress Core

Ticket #20499: object-cache.-2.0.1-patch.php

File object-cache.-2.0.1-patch.php, 9.2 KB (added by toddlahman, 2 years ago)
Line 
1<?php
2
3/*
4Plugin Name: Memcached
5Description: Memcached backend for the WP Object Cache.
6Version: 2.0.1
7Plugin URI: http://wordpress.org/extend/plugins/memcached/
8Author: Ryan Boren, Denis de Bernardy, Matt Martz
9
10Install this file to wp-content/object-cache.php
11*/
12
13function wp_cache_add($key, $data, $flag = '', $expire = 0) {
14        global $wp_object_cache;
15
16        return $wp_object_cache->add($key, $data, $flag, $expire);
17}
18
19function wp_cache_incr($key, $n = 1, $flag = '') {
20        global $wp_object_cache;
21
22        return $wp_object_cache->incr($key, $n, $flag);
23}
24
25function wp_cache_decr($key, $n = 1, $flag = '') {
26        global $wp_object_cache;
27
28        return $wp_object_cache->decr($key, $n, $flag);
29}
30
31function wp_cache_close() {
32        global $wp_object_cache;
33
34        return $wp_object_cache->close();
35}
36
37function wp_cache_delete($id, $flag = '') {
38        global $wp_object_cache;
39
40        return $wp_object_cache->delete($id, $flag);
41}
42
43function wp_cache_flush() {
44        global $wp_object_cache;
45
46        return $wp_object_cache->flush();
47}
48
49function wp_cache_get($id, $flag = '') {
50        global $wp_object_cache;
51
52        return $wp_object_cache->get($id, $flag);
53}
54
55function wp_cache_init() {
56        global $wp_object_cache;
57
58        $wp_object_cache = new WP_Object_Cache();
59}
60
61function wp_cache_replace($key, $data, $flag = '', $expire = 0) {
62        global $wp_object_cache;
63
64        return $wp_object_cache->replace($key, $data, $flag, $expire);
65}
66
67function wp_cache_set($key, $data, $flag = '', $expire = 0) {
68        global $wp_object_cache;
69
70        if ( defined('WP_INSTALLING') == false )
71                return $wp_object_cache->set($key, $data, $flag, $expire);
72        else
73                return $wp_object_cache->delete($key, $flag);
74}
75
76function wp_cache_add_global_groups( $groups ) {
77        global $wp_object_cache;
78
79        $wp_object_cache->add_global_groups($groups);
80}
81
82function wp_cache_add_non_persistent_groups( $groups ) {
83        global $wp_object_cache;
84
85        $wp_object_cache->add_non_persistent_groups($groups);
86}
87
88class WP_Object_Cache {
89        var $global_groups = array ('users', 'userlogins', 'usermeta', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss');
90
91        var $no_mc_groups = array( 'comment', 'counts' );
92
93        var $autoload_groups = array ('options');
94
95        var $cache = array();
96        var $mc = array();
97        var $stats = array();
98        var $group_ops = array();
99
100        var $cache_enabled = true;
101        var $default_expiration = 0;
102
103        function add($id, $data, $group = 'default', $expire = 0) {
104                $key = $this->key($id, $group);
105
106                if ( in_array($group, $this->no_mc_groups) ) {
107                        $this->cache[$key] = $data;
108                        return true;
109                } elseif ( isset($this->cache[$key]) && $this->cache[$key] !== false ) {
110                        return false;
111                }
112
113                $mc =& $this->get_mc($group);
114                $expire = ($expire == 0) ? $this->default_expiration : $expire;
115                $result = $mc->add($key, $data, false, $expire);
116
117                if ( false !== $result ) {
118                        @ ++$this->stats['add'];
119                        $this->group_ops[$group][] = "add $id";
120                        $this->cache[$key] = $data;
121                }
122
123                return $result;
124        }
125
126        function add_global_groups($groups) {
127                if ( ! is_array($groups) )
128                        $groups = (array) $groups;
129
130                $this->global_groups = array_merge($this->global_groups, $groups);
131                $this->global_groups = array_unique($this->global_groups);
132        }
133
134        function add_non_persistent_groups($groups) {
135                if ( ! is_array($groups) )
136                        $groups = (array) $groups;
137
138                $this->no_mc_groups = array_merge($this->no_mc_groups, $groups);
139                $this->no_mc_groups = array_unique($this->no_mc_groups);
140        }
141
142        function incr($id, $n, $group) {
143                $key = $this->key($id, $group);
144                $mc =& $this->get_mc($group);
145
146                return $mc->increment($key, $n);
147        }
148
149        function decr($id, $n, $group) {
150                $key = $this->key($id, $group);
151                $mc =& $this->get_mc($group);
152
153                return $mc->decrement($key, $n);
154        }
155
156        function close() {
157
158                foreach ( $this->mc as $bucket => $mc )
159                        $mc->close();
160        }
161
162        function delete($id, $group = 'default') {
163                $key = $this->key($id, $group);
164
165                if ( in_array($group, $this->no_mc_groups) ) {
166                        unset($this->cache[$key]);
167                        return true;
168                }
169
170                $mc =& $this->get_mc($group);
171
172                $result = $mc->delete($key);
173
174                @ ++$this->stats['delete'];
175                $this->group_ops[$group][] = "delete $id";
176
177                if ( false !== $result )
178                        unset($this->cache[$key]);
179
180                return $result; 
181        }
182
183        function flush() {
184                // Don't flush if multi-blog.
185                if ( function_exists('is_site_admin') || defined('CUSTOM_USER_TABLE') && defined('CUSTOM_USER_META_TABLE') )
186                        return true;
187
188                $ret = true;
189                foreach ( array_keys($this->mc) as $group )
190                        $ret &= $this->mc[$group]->flush();
191                return $ret;
192        }
193
194        function get($id, $group = 'default') {
195                $key = $this->key($id, $group);
196                $mc =& $this->get_mc($group);
197
198                if ( isset($this->cache[$key]) )
199                        $value = $this->cache[$key];
200                else if ( in_array($group, $this->no_mc_groups) )
201                        $value = false;
202                else
203                        $value = $mc->get($key);
204
205                @ ++$this->stats['get'];
206                $this->group_ops[$group][] = "get $id";
207
208                if ( NULL === $value )
209                        $value = false;
210                       
211                $this->cache[$key] = $value;
212
213                if ( 'checkthedatabaseplease' == $value )
214                        $value = false;
215
216                return $value;
217        }
218
219        function get_multi( $groups ) {
220                /*
221                format: $get['group-name'] = array( 'key1', 'key2' );
222                */
223                $return = array();
224                foreach ( $groups as $group => $ids ) {
225                        $mc =& $this->get_mc($group);
226                        foreach ( $ids as $id ) {
227                                $key = $this->key($id, $group);
228                                if ( isset($this->cache[$key]) ) {
229                                        $return[$key] = $this->cache[$key];
230                                        continue;
231                                } else if ( in_array($group, $this->no_mc_groups) ) {
232                                        $return[$key] = false;
233                                        continue;
234                                } else {
235                                        $return[$key] = $mc->get($key);
236                                }
237                        }
238                        if ( $to_get ) {
239                                $vals = $mc->get_multi( $to_get );
240                                $return = array_merge( $return, $vals );
241                        }
242                }
243                @ ++$this->stats['get_multi'];
244                $this->group_ops[$group][] = "get_multi $id";
245                $this->cache = array_merge( $this->cache, $return );
246                return $return;
247        }
248
249        function key($key, $group) {   
250                if ( empty($group) )
251                        $group = 'default';
252
253                if ( false !== array_search($group, $this->global_groups) )
254                        $prefix = $this->global_prefix;
255                else
256                        $prefix = $this->blog_prefix;
257
258                return preg_replace('/\s+/', '', "$prefix$group:$key");
259        }
260
261        function replace($id, $data, $group = 'default', $expire = 0) {
262                $key = $this->key($id, $group);
263                $expire = ($expire == 0) ? $this->default_expiration : $expire;
264                $mc =& $this->get_mc($group);
265                $result = $mc->replace($key, $data, false, $expire);
266                if ( false !== $result )
267                        $this->cache[$key] = $data;
268                return $result;
269        }
270
271        function set($id, $data, $group = 'default', $expire = 0) {
272                $key = $this->key($id, $group);
273                if ( isset($this->cache[$key]) && ('checkthedatabaseplease' == $this->cache[$key]) )
274                        return false;
275                $this->cache[$key] = $data;
276
277                if ( in_array($group, $this->no_mc_groups) )
278                        return true;
279
280                $expire = ($expire == 0) ? $this->default_expiration : $expire;
281                $mc =& $this->get_mc($group);
282                $result = $mc->set($key, $data, false, $expire);
283
284                return $result;
285        }
286
287        function colorize_debug_line($line) {
288                $colors = array(
289                        'get' => 'green',
290                        'set' => 'purple',
291                        'add' => 'blue',
292                        'delete' => 'red');
293
294                $cmd = substr($line, 0, strpos($line, ' '));
295
296                $cmd2 = "<span style='color:{$colors[$cmd]}'>$cmd</span>";
297
298                return $cmd2 . substr($line, strlen($cmd)) . "\n";
299        }
300
301        function stats() {
302                echo "<p>\n";
303                foreach ( $this->stats as $stat => $n ) {
304                        echo "<strong>$stat</strong> $n";
305                        echo "<br/>\n";
306                }
307                echo "</p>\n";
308                echo "<h3>Memcached:</h3>";
309                foreach ( $this->group_ops as $group => $ops ) {
310                        if ( !isset($_GET['debug_queries']) && 500 < count($ops) ) { 
311                                $ops = array_slice( $ops, 0, 500 ); 
312                                echo "<big>Too many to show! <a href='" . add_query_arg( 'debug_queries', 'true' ) . "'>Show them anyway</a>.</big>\n";
313                        } 
314                        echo "<h4>$group commands</h4>";
315                        echo "<pre>\n";
316                        $lines = array();
317                        foreach ( $ops as $op ) {
318                                $lines[] = $this->colorize_debug_line($op); 
319                        }
320                        print_r($lines);
321                        echo "</pre>\n";
322                }
323
324                if ( $this->debug )
325                        var_dump($this->memcache_debug);
326        }
327
328        function &get_mc($group) {
329                if ( isset($this->mc[$group]) )
330                        return $this->mc[$group];
331                return $this->mc['default'];
332        }
333
334        function failure_callback($host, $port) {
335                //error_log("Connection failure for $host:$port\n", 3, '/tmp/memcached.txt');
336        }
337
338        function WP_Object_Cache() {
339                global $memcached_servers;
340
341                if ( isset($memcached_servers) )
342                        $buckets = $memcached_servers;
343                else
344                        $buckets = array('127.0.0.1');
345
346                reset($buckets);
347                if ( is_int(key($buckets)) )
348                        $buckets = array('default' => $buckets);
349
350                foreach ( $buckets as $bucket => $servers) {
351                        $this->mc[$bucket] = new Memcache();
352                        foreach ( $servers as $server  ) {
353                                list ( $node, $port ) = explode(':', $server);
354                                if ( !$port )
355                                        $port = ini_get('memcache.default_port');
356                                $port = intval($port);
357                                if ( !$port )
358                                        $port = 11211;
359                                $this->mc[$bucket]->addServer($node, $port, true, 1, 1, 15, true, array($this, 'failure_callback'));
360                                $this->mc[$bucket]->setCompressThreshold(20000, 0.2);
361                        }
362                }
363
364                global $blog_id, $table_prefix;
365                $this->global_prefix = '';
366                $this->blog_prefix = '';
367                if ( function_exists( 'is_multisite' ) && is_multisite() ) {
368                        $this->global_prefix = ( is_multisite() || defined('CUSTOM_USER_TABLE') && defined('CUSTOM_USER_META_TABLE') ) ? '' : $table_prefix;
369                        $this->blog_prefix = ( is_multisite() ? $blog_id : $table_prefix ) . ':';
370                } else {
371                        $this->global_prefix = $table_prefix;
372                        $this->blog_prefix = $blog_id;
373                }
374
375                $this->cache_hits =& $this->stats['get'];
376                $this->cache_misses =& $this->stats['add'];
377        }
378}
379?>