[wp-hackers] Caching as part of the core

Jeff Waugh jdub at bethesignal.org
Sun Jul 29 00:00:49 UTC 2012


On Sun, Jul 29, 2012 at 7:42 AM, Mike Schinkel <mike at newclarity.net> wrote:

> Now that statement generates the height of frustration for me. Much of
> this thread has been me saying we need access to Transients in
> advanced-cache.php.  Please do me the courtesy of reading this entire
> thread before your next reply.


I have read the entire thread. Your replies continue to suggest that you
don't understand what advanced-cache.php is for, or how it's used.

There are two things you'd do in an implementation of advanced-cache.php
(excluding dirty, dirty hacks):

1) Determine whether a request can be fulfilled by your cache*, at which
point you serve content from the cache and die() before the rest of the
WordPress code is loaded and executed. advanced-cache.php is included early
so you can get in and out as fast as possible. Ideally, you wouldn't even
hit PHP or WordPress to serve items out of the cache (cf. wp-super-cache's
"mod_rewrite" method, i.e. writing out files the web server can serve
directly instead).

2) Determine whether the request is cacheable, at which point you set up an
output buffer handler to save the entire page into your cache once the rest
of the WordPress code is loaded and executed.

I hope this makes it obvious why transients (and similar higher level
caching mechanisms) simply aren't relevant when it comes to page caching.
You either want the entire WordPress process to run, giving you a complete
page to cache, or none at all, because you've serviced the request from
your cache.

If you want an advanced-cache.php implementation that allows you to choose
the storage backend, then you can choose wp-super-cache with its
experimental support for storage using a given object-cache.php
implementation (i.e. APC or memcache) or W3TC which can store in files,
APC, memcache, etc.

* A caching mechanism defined entirely by your advanced-cache.php
implementation, which might back on to files (ew!), the database (ew!), a
key/value store (such as APC or memcache), etc.

...

That said, what would change if we *had* to have transients before
advanced-cache.php?

We'd load WPINC/functions.php (or WPINC/option.php, which is loaded at the
top of functions.php anyway) ahead of advanced-cache.php. We can leave
WPINC/compat.php for later, because neither functions.php or option.php
require it in WordPress 3.4.1. Let's stick to option.php for the time being.

https://raw.github.com/gist/28bad92a34f291f411da/1971ae139bb458812c2373d44a87264fbc9fc3f3/wp-settings.php.01.diff

To be tidy, we'd remove the same include from the top of functions.php.

Now we can call get_transient from advanced-cache.php, right? Not so fast:
get_transient calls apply_filters, which is defined in WPINC/plugin.php,
which is loaded a bit later in wp-settings.php. Alrighty, let's load it
earlier:

https://raw.github.com/gist/28bad92a34f291f411da/715e7eb7833fde1296e22dd7ce6d931480c25cc7/wp-settings.php.02.diff

Uh oh, get_transient calls wp_load_alloptions, which calls wp_cache_get,
which is not defined until wp-settings.php calls wp_start_object_cache().
Let's do that early too!

https://gist.github.com/raw/28bad92a34f291f411da/682916187c5e5f06aa0d502824e3db19f98421b8/wp-settings.php.03.diff

By the way, here's my cheesy advanced-cache.php implementation, to make
sure we can at least run get/set_transient (otherwise, all this malarkey is
massively untested):

https://gist.github.com/raw/28bad92a34f291f411da/05b8be30505b228883fe2d3a5ecc164f36f1eca2/advanced-cache.php

So what do we get for our efforts? Note that only two (okay, at least
three) of these functions are tested:

$ grep ^function wp-includes/option.php
function get_option( $option, $default = false ) {
function wp_protect_special_option( $option ) {
function form_option( $option ) {
function wp_load_alloptions() {
function wp_load_core_site_options( $site_id = null ) {
function update_option( $option, $newvalue ) {
function add_option( $option, $value = '', $deprecated = '', $autoload =
'yes' ) {
function delete_option( $option ) {
function delete_transient( $transient ) {
function get_transient( $transient ) {
function set_transient( $transient, $value, $expiration = 0 ) {
function wp_user_settings() {
function get_user_setting( $name, $default = false ) {
function set_user_setting( $name, $value ) {
function delete_user_setting( $names ) {
function get_all_user_settings() {
function wp_set_all_user_settings($all) {
function delete_all_user_settings() {
function get_site_option( $option, $default = false, $use_cache = true ) {
function add_site_option( $option, $value ) {
function delete_site_option( $option ) {
function update_site_option( $option, $value ) {
function delete_site_transient( $transient ) {
function get_site_transient( $transient ) {
function set_site_transient( $transient, $value, $expiration = 0 ) {

Some of those might be useful to caching logic. Maybe.

And what did we spend?

Luckily, the additional files we loaded early did not also load more code
themselves:

https://gist.github.com/raw/28bad92a34f291f411da/ad2f1ea51772fcdcbfe9cb0a08e9f0a97bb0421d/no-further-includes.txt

However, that's at least an additional 2000 lines of code (we only include
one of the cache implementations, one of which is non-persistent and
therefore pretty useless) before we hit advanced-cache.php, which is more
PHP work to be done before advanced-cache.php has an opportunity to spit
out something from its cache and die().

$ wc -l wp-includes/option.php wp-includes/plugin.php wp-includes/cache.php
wp-content/object-cache.php
  1046 wp-includes/option.php
  784 wp-includes/plugin.php
  566 wp-includes/cache.php
  358 wp-content/object-cache.php
 2754 total

By comparison, here's what wp-super-cache loads:

https://gist.github.com/raw/28bad92a34f291f411da/9aca81eaf36c99e51c2f4af26706d9e808acda69/wp-super-cache-includes.txt

Practically nothing from core. All of that code is 100% focused on the task
at hand.

...

So, I guess I have to ask the question again: For what purpose do you think
you're going to use transients in the context of advanced-cache.php?

The correct answer has two parts:

1) To make the decision whether or not you have a cached page, or can serve
it for the current request, transients are unlikely to be useful. Certainly
not any more useful than directly using whatever persistent object cache
implementation you've got to hand (as wp-super-cache does, experimentally).

2) If you haven't serviced the request from the cache, then you're going to
load all of WordPress anyway, so loading transients support early was a
complete waste of time (not to mention the semi-invasive changes to core).

There you go. Evidence. Data. *jazzhands*


More information about the wp-hackers mailing list