Make WordPress Core

Ticket #5570: no_persistent_cache.diff

File no_persistent_cache.diff, 9.9 KB (added by ryan, 17 years ago)
  • wp-includes/cache.php

     
    11<?php
    22function wp_cache_add($key, $data, $flag = '', $expire = 0) {
    33        global $wp_object_cache;
    4         $data = unserialize(serialize($data));
    54
    65        return $wp_object_cache->add($key, $data, $flag, $expire);
    76}
     
    3837
    3938function wp_cache_replace($key, $data, $flag = '', $expire = 0) {
    4039        global $wp_object_cache;
    41         $data = unserialize(serialize($data));
    4240
    4341        return $wp_object_cache->replace($key, $data, $flag, $expire);
    4442}
    4543
    4644function wp_cache_set($key, $data, $flag = '', $expire = 0) {
    4745        global $wp_object_cache;
    48         $data = unserialize(serialize($data));
    4946
    5047        return $wp_object_cache->set($key, $data, $flag, $expire);
    5148}
    5249
    53 define('CACHE_SERIAL_HEADER', "<?php\n/*");
    54 define('CACHE_SERIAL_FOOTER', "*/\n?".">");
    55 
    5650class WP_Object_Cache {
    57         var $cache_dir;
    58         var $cache_enabled = false;
    59         var $expiration_time = 900;
    60         var $flock_filename = 'wp_object_cache.lock';
    61         var $mutex;
    6251        var $cache = array ();
    63         var $dirty_objects = array ();
    6452        var $non_existant_objects = array ();
    6553        var $global_groups = array ('users', 'userlogins', 'usermeta');
    66         var $non_persistent_groups = array('comment');
    67         var $blog_id;
    68         var $cold_cache_hits = 0;
    69         var $warm_cache_hits = 0;
     54        var $cache_hits = 0;
    7055        var $cache_misses = 0;
    71         var $secret = '';
    7256
    73         function acquire_lock() {
    74                 // Acquire a write lock.
    75                 $this->mutex = @fopen($this->cache_dir.$this->flock_filename, 'w');
    76                 if ( false == $this->mutex)
    77                         return false;
    78                 flock($this->mutex, LOCK_EX);
    79                 return true;
    80         }
    81 
    8257        function add($id, $data, $group = 'default', $expire = '') {
    8358                if (empty ($group))
    8459                        $group = 'default';
     
    9873
    9974                unset ($this->cache[$group][$id]);
    10075                $this->non_existant_objects[$group][$id] = true;
    101                 $this->dirty_objects[$group][] = $id;
    10276                return true;
    10377        }
    10478
    10579        function flush() {
    106                 if ( !$this->cache_enabled )
    107                         return true;
    108 
    109                 if ( ! $this->acquire_lock() )
    110                         return false;
    111 
    112                 $this->rm_cache_dir();
    11380                $this->cache = array ();
    114                 $this->dirty_objects = array ();
    115                 $this->non_existant_objects = array ();
    11681
    117                 $this->release_lock();
    118 
    11982                return true;
    12083        }
    12184
    122         function get($id, $group = 'default', $count_hits = true) {
     85        function get($id, $group = 'default') {
    12386                if (empty ($group))
    12487                        $group = 'default';
    12588
    12689                if (isset ($this->cache[$group][$id])) {
    127                         if ($count_hits)
    128                                 $this->warm_cache_hits += 1;
     90                        $this->cache_hits += 1;
    12991                        return $this->cache[$group][$id];
    13092                }
    13193
    132                 if (isset ($this->non_existant_objects[$group][$id]))
     94                if ( isset ($this->non_existant_objects[$group][$id]) )
    13395                        return false;
    13496
    135                 //  If caching is not enabled, we have to fall back to pulling from the DB.
    136                 if (!$this->cache_enabled) {
    137                         if (!isset ($this->cache[$group]))
    138                                 $this->load_group_from_db($group);
    139 
    140                         if (isset ($this->cache[$group][$id])) {
    141                                 $this->cold_cache_hits += 1;
    142                                 return $this->cache[$group][$id];
    143                         }
    144 
    145                         $this->non_existant_objects[$group][$id] = true;
    146                         $this->cache_misses += 1;
    147                         return false;
    148                 }
    149 
    150                 $cache_file = $this->cache_dir.$this->get_group_dir($group)."/".$this->hash($id).'.php';
    151                 if (!file_exists($cache_file)) {
    152                         $this->non_existant_objects[$group][$id] = true;
    153                         $this->cache_misses += 1;
    154                         return false;
    155                 }
    156 
    157                 // If the object has expired, remove it from the cache and return false to force
    158                 // a refresh.
    159                 $now = time();
    160                 if ((filemtime($cache_file) + $this->expiration_time) <= $now) {
    161                         $this->cache_misses += 1;
    162                         $this->delete($id, $group, true);
    163                         return false;
    164                 }
    165 
    166                 $this->cache[$group][$id] = unserialize(base64_decode(substr(@ file_get_contents($cache_file), strlen(CACHE_SERIAL_HEADER), -strlen(CACHE_SERIAL_FOOTER))));
    167                 if (false === $this->cache[$group][$id])
    168                         $this->cache[$group][$id] = '';
    169 
    170                 $this->cold_cache_hits += 1;
    171                 return $this->cache[$group][$id];
     97                $this->non_existant_objects[$group][$id] = true;
     98                $this->cache_misses += 1;
     99                return false;
    172100        }
    173101
    174         function get_group_dir($group) {
    175                 if (false !== array_search($group, $this->global_groups))
    176                         return $group;
    177 
    178                 return "{$this->blog_id}/$group";
    179         }
    180 
    181         function hash($data) {
    182                 if ( function_exists('hash_hmac') ) {
    183                         return hash_hmac('md5', $data, $this->secret);
    184                 } else {
    185                         return md5($data . $this->secret);
    186                 }
    187         }
    188 
    189         function load_group_from_db($group) {
    190                 return;
    191         }
    192 
    193         function make_group_dir($group, $perms) {
    194                 $group_dir = $this->get_group_dir($group);
    195                 $make_dir = '';
    196                 foreach (split('/', $group_dir) as $subdir) {
    197                         $make_dir .= "$subdir/";
    198                         if (!file_exists($this->cache_dir.$make_dir)) {
    199                                 if (! @ mkdir($this->cache_dir.$make_dir))
    200                                         break;
    201                                 @ chmod($this->cache_dir.$make_dir, $perms);
    202                         }
    203 
    204                         if (!file_exists($this->cache_dir.$make_dir."index.php")) {
    205                                 $file_perms = $perms & 0000666;
    206                                 @ touch($this->cache_dir.$make_dir."index.php");
    207                                 @ chmod($this->cache_dir.$make_dir."index.php", $file_perms);
    208                         }
    209                 }
    210 
    211                 return $this->cache_dir."$group_dir/";
    212         }
    213 
    214         function rm_cache_dir() {
    215                 $dir = $this->cache_dir;
    216                 $dir = rtrim($dir, DIRECTORY_SEPARATOR);
    217                 $top_dir = $dir;
    218                 $stack = array($dir);
    219                 $index = 0;
    220 
    221                 while ($index < count($stack)) {
    222                         # Get indexed directory from stack
    223                         $dir = $stack[$index];
    224 
    225                         $dh = @ opendir($dir);
    226                         if (!$dh)
    227                                 return false;
    228 
    229                         while (($file = @ readdir($dh)) !== false) {
    230                                 if ($file == '.' or $file == '..')
    231                                         continue;
    232 
    233                                 if (@ is_dir($dir . DIRECTORY_SEPARATOR . $file))
    234                                         $stack[] = $dir . DIRECTORY_SEPARATOR . $file;
    235                                 else if (@ is_file($dir . DIRECTORY_SEPARATOR . $file))
    236                                         @ unlink($dir . DIRECTORY_SEPARATOR . $file);
    237                         }
    238 
    239                         $index++;
    240                 }
    241 
    242                 $stack = array_reverse($stack);  // Last added dirs are deepest
    243                 foreach($stack as $dir) {
    244                         if ( $dir != $top_dir)
    245                                 @ rmdir($dir);
    246                 }
    247 
    248         }
    249 
    250         function release_lock() {
    251                 // Release write lock.
    252                 flock($this->mutex, LOCK_UN);
    253                 fclose($this->mutex);
    254         }
    255 
    256102        function replace($id, $data, $group = 'default', $expire = '') {
    257103                if (empty ($group))
    258104                        $group = 'default';
     
    272118
    273119                $this->cache[$group][$id] = $data;
    274120                unset ($this->non_existant_objects[$group][$id]);
    275                 $this->dirty_objects[$group][] = $id;
    276121
    277122                return true;
    278123        }
    279124
    280         function save() {
    281                 //$this->stats();
    282 
    283                 if (!$this->cache_enabled)
    284                         return true;
    285 
    286                 if (empty ($this->dirty_objects))
    287                         return true;
    288 
    289                 // Give the new dirs the same perms as wp-content.
    290                 $stat = stat(ABSPATH.'wp-content');
    291                 $dir_perms = $stat['mode'] & 0007777; // Get the permission bits.
    292                 $file_perms = $dir_perms & 0000666; // Remove execute bits for files.
    293 
    294                 // Make the base cache dir.
    295                 if (!file_exists($this->cache_dir)) {
    296                         if (! @ mkdir($this->cache_dir))
    297                                 return false;
    298                         @ chmod($this->cache_dir, $dir_perms);
    299                 }
    300 
    301                 if (!file_exists($this->cache_dir."index.php")) {
    302                         @ touch($this->cache_dir."index.php");
    303                         @ chmod($this->cache_dir."index.php", $file_perms);
    304                 }
    305 
    306                 if ( ! $this->acquire_lock() )
    307                         return false;
    308 
    309                 // Loop over dirty objects and save them.
    310                 $errors = 0;
    311                 foreach ($this->dirty_objects as $group => $ids) {
    312                         if ( in_array($group, $this->non_persistent_groups) )
    313                                 continue;
    314 
    315                         $group_dir = $this->make_group_dir($group, $dir_perms);
    316 
    317                         $ids = array_unique($ids);
    318                         foreach ($ids as $id) {
    319                                 $cache_file = $group_dir.$this->hash($id).'.php';
    320 
    321                                 // Remove the cache file if the key is not set.
    322                                 if (!isset ($this->cache[$group][$id])) {
    323                                         if (file_exists($cache_file))
    324                                                 @ unlink($cache_file);
    325                                         continue;
    326                                 }
    327 
    328                                 $temp_file = tempnam($group_dir, 'tmp');
    329                                 $serial = CACHE_SERIAL_HEADER.base64_encode(serialize($this->cache[$group][$id])).CACHE_SERIAL_FOOTER;
    330                                 $fd = @fopen($temp_file, 'w');
    331                                 if ( false === $fd ) {
    332                                         $errors++;
    333                                         continue;
    334                                 }
    335                                 fputs($fd, $serial);
    336                                 fclose($fd);
    337                                 if (!@ rename($temp_file, $cache_file)) {
    338                                         if (!@ copy($temp_file, $cache_file))
    339                                                 $errors++;
    340                                         @ unlink($temp_file);
    341                                 }
    342                                 @ chmod($cache_file, $file_perms);
    343                         }
    344                 }
    345 
    346                 $this->dirty_objects = array();
    347 
    348                 $this->release_lock();
    349 
    350                 if ( $errors )
    351                         return false;
    352 
    353                 return true;
    354         }
    355 
    356125        function stats() {
    357126                echo "<p>";
    358                 echo "<strong>Cold Cache Hits:</strong> {$this->cold_cache_hits}<br />";
    359                 echo "<strong>Warm Cache Hits:</strong> {$this->warm_cache_hits}<br />";
     127                echo "<strong>Cache Hits:</strong> {$this->cache_hits}<br />";
    360128                echo "<strong>Cache Misses:</strong> {$this->cache_misses}<br />";
    361129                echo "</p>";
    362130
     
    367135                        echo "<pre>";
    368136                        print_r($cache);
    369137                        echo "</pre>";
    370                         if (isset ($this->dirty_objects[$group])) {
    371                                 echo "<strong>Dirty Objects:</strong>";
    372                                 echo "<pre>";
    373                                 print_r(array_unique($this->dirty_objects[$group]));
    374                                 echo "</pre>";
    375                                 echo "</p>";
    376                         }
    377138                }
    378139        }
    379140
     
    382143        }
    383144
    384145        function __construct() {
    385                 global $blog_id;
    386 
    387146                register_shutdown_function(array(&$this, "__destruct"));
    388 
    389                 if (defined('DISABLE_CACHE'))
    390                         return;
    391 
    392                 if ( ! defined('ENABLE_CACHE') )
    393                         return;
    394 
    395                 // Disable the persistent cache if safe_mode is on.
    396                 if ( ini_get('safe_mode') && ! defined('ENABLE_CACHE') )
    397                         return;
    398 
    399                 if (defined('CACHE_PATH'))
    400                         $this->cache_dir = CACHE_PATH;
    401                 else
    402                         // Using the correct separator eliminates some cache flush errors on Windows
    403                         $this->cache_dir = ABSPATH.'wp-content'.DIRECTORY_SEPARATOR.'cache'.DIRECTORY_SEPARATOR;
    404 
    405                 if (is_writable($this->cache_dir) && is_dir($this->cache_dir)) {
    406                                 $this->cache_enabled = true;
    407                 } else {
    408                         if (is_writable(ABSPATH.'wp-content')) {
    409                                 $this->cache_enabled = true;
    410                         }
    411                 }
    412 
    413                 if (defined('CACHE_EXPIRATION_TIME'))
    414                         $this->expiration_time = CACHE_EXPIRATION_TIME;
    415 
    416                 if ( defined('WP_SECRET') )
    417                         $this->secret = WP_SECRET;
    418                 else
    419                         $this->secret = DB_PASSWORD . DB_USER . DB_NAME . DB_HOST . ABSPATH;
    420 
    421                 $this->blog_id = $this->hash($blog_id);
    422147        }
    423148
    424149        function __destruct() {
    425                 $this->save();
    426150                return true;
    427151        }
    428152}