Thứ Tư, 11 tháng 6, 2014

Knowing When to Cache [Caching]

It’s important to remember that caching is a trade-off. Caching large chunks of data will boost performance quite a bit,
but only incases where that specific chunk of data is needed a second or third time.  That’s why Drupal’s built-in full-page caching is used onlyfor anonymous visitors—registered users often require customized versions of pages,
and  the caching would be much less effective. Caching smaller chunks of data (e.g., the list of today’s popular articles)
means less dramatic performance gains but still helps tospeed up your site.

Caching works best  on data that doesn’t change rapidly. A list of the week’s top stories works well. Caching a list of the
last five comments posted on a busy forum is less helpful, because that information will become out of date  so quickly  that
few visitors will be able to use the cached list before it needs to be updated. In the worst  case, a bad cachingstrategy (e.g.,caching data that changes too often) will add overhead to a site rather than reduce it.

How Caching Works

Modules often have to make expensive database queries or calls to remote web services. Rather than using resources for
those operations every time  they occur, modules can store a cache of their data into one of the bins reserved for caching
within the Drupal database, where bins are tables in the database. Standard bins include the following:

cache: This is the generic cache storage bin. This bin is used to store variables, the theme registry, locale date, a list of
simple test, etc.
cache_block: This bin stores the content for various blocks. cache_bootstrap: This bin stores information used during
bootstrap. cache_field: This bin stores loaded fields for an entity object. cache_filter: This bin storesfiltered pieces of
content.
cache_form: This bin stores multi step forms.
cache_image: This bin stores information about in-progress image manipulations.
cache_menu: This bin stores the structure of visible navigation menus per page.

cache_page: This bin stores generated pages for anonymous users. This table is flushed often, whenever a page changes, at
least for every node and  comment submission. This is the only bin affected by the page cache settings on the
administrator panel.
cache_path: This bin stores the system paths that have an alias.

cache_update: This bin stores available releases.

Modules may also create their own table an store the data there. The next time  the data is needed, it can be quickly
retrieved with a single query. As you’ll see later in the chapter, Drupal’s caching back end is pluggable, so although we
refer to databasetables here, in reality  the back end  may be some other storage such as flat files or a memory-based cache.

The default table to which your module can write cached information is named cache. Using this table is the bes option
when storing only a couple rows of cached information. When  defining a new cache table for your module to use, it must bestructurally identical to the default cache table while having a different table name. It’s a good idea to prepend cache_ to
the table name for consistency. Let’s take a look at the database structure of the cache table see Table 16-1.

Table 16-1. cache Table Schema
Field*
Type
Null
Default
cid
varchar(255)
NO
data
longblob
YES
expire
int
NO
0
created
int
NO
0
serialized
smallint
NO
0
*Bold indicates a primary key; italics indicate an indexed field.

The cid column stores the primary cache ID for quick retrieval. Examples of cache IDs used within the Drupal core are theURL of the page for page caching (e.g., http://example.com/?q=node/1), a string and  a theme name for caching the
theme registry (e.g., theme_registry:garland), or even regular strings (e.g., the contents of the variables table are cached
with the primary cache ID set to variables). The important point is that the cache ID must be a unique identifier for the item being cached.

The data column stores the information you wish to cache. Complex data types  such as arrays oobjects need to be
serialized using PHP’s serialize() function to preserve their data structure within thdatabase (Drupal does this automatically).

The expire column takes one of the three following values:

     CACHE_PERMANENT: This value indicates that the item  should not be removed until cache_clear_all() has been
called  with the cache ID of the permanent item  to wipe.

     CACHE_TEMPORARY: This value indicates that the item  should be removed the next tim cache_clear_all() is called for a “general” wipe, with no minimum time enforcement imposed. Items marked CACHE_PERMANENT will nobe
removed from the cache.

     A Unix  timestamp: Indicates that the item  should be kept at least until  the time provided, after which it will behave like an item  marked CACHE_TEMPORARY and become eligible for deletion.

The created column is a Unix timestamp indicating the date  the cache entry was created. The serialized column indicates
whether the data in the data column is in serialized form. A indicates unserialized data while a 1 indicates serialized data. If
the data is serialized and  the value of thserialized column is 1, the cache system will unserialize thedata before returning it
to the caller. The cache system automatically serializes object and  array data and  sets the serialized column to 1 when this
type of data is cached.

How Caching Is Used Within Drupal Core

Drupal ships with ten cache tables by default: cache stores a copy of the variables table and  the database schema and themeregistry; cache_block stores cached copies of blocks; cache_bootstrap stores information that is used during the bootstrap
process; cache_field stores information about fields; cache_image stores information about images; cache_menu stores
cached copies of the navigational menus; cache_filter stores cached copies of each  node’s content after it has been parsed
by the filter system; cache_form is used by the form API to avoid form building when possible; cache_page stores cached
copies opages for anonymous users; cache_path stores cached URL aliases;  and  cache_update stores information related
to the current version of Drupal and  modules used on your site.It should be noted that the “Page cache” and “Block cache” settings at Configuration -> Performance affect only the page cache an block cache tables, not the other cache
component within Drupal. In other words, filters, menus, and  module settings are always cached.

Menu System

The menu system caches the router information that connects Drupal paths to callbacks. Any menu created by the menu
module is cached, regardless of whether Drupal’s page caching is enabled. So to clear the menu cache, use the “Clear
cached data” button on theConfiguration -> Performance page,  or call menu_cache_clear_all(). If you’ve made changes
to themenus that will affect blocks you might want to call the more aggressive menu_rebuild() function instead; the menu
cache is cleared when menus are rebuilt.Examples of menus include Drupal’s Main and  Secondary menus as well as the user navigation menu. Menus are cached on a per-user, per-locale basis. See Chapter 4 for more information on the menu system.

Caching Filtered Text

When  a node is created or edited, its content is run  through the various filters associated with its input format. For example,the HTML Filter format converts line breaks to HTML <p> and  <br /> tags, and  also strips out malicious HTML. It
would be anexpensive operation to do this for every single view of a node. Therefore, the filters are applied to the node
just after it has been created or edited, and  that content is cached to the cache_filter database table, regardless of whether  Drupal’s page caching is enabled. See Chapter 12 for more information on input formats.

Administration Variables and  Module Settings

Drupal stores most administrative settings in the variabletable, and  caches that data to speed the lookup of configuration
data. Examples of such variables include the name of your site, settings for comments and  users, and  the location of the
files directory.These  variables are cached to a single row in the cache_bootstrap table, so they can be quickly  retrieved,
rather than making a database query for each  variable value as it is needed. They are stored as a PHP array,  so the cache value is serialized to preserve itsstructure. Any variable that uses variable_set() and  variable_get() as its setter and  getter
functions will be stored and  cached in this manner.

We have been discussing the bits and  pieces that Drupal caches to optimize the more resource- heavy components of a site,but the biggest optimization Drupal makes is to cache an entire page view.For anonymous users, this is easily accomplished,since  all pages look the same to all anonymous users.
For logged-in users, however, every page is different and  customized to each of their profiles. A different caching strategy
is needed to cope  with this situation. For anonymous users, Drupal can retrieve the cached page content in a single query, although it takes a couple of other queries to load Drupal itself. Settings are found in the Drupal administration interface at
Configuration -> Performance. The interface is shown in Figure 16-1. Let’s look at each setting in the following sections.


Figure 16-1. The administrative interface for the control  of page-caching behavior

Disabling Caching

Unchecking the boxes for Cache pages and  Cache blocks  is useful when debugging a site, as it allows you to see your
changes without having to clear cache to reload elements that have changed. Generally, you will want  to enable caching.

Page Caching

Page caching offers a huge  performance boost over no caching at all, and  is one of the easiest ways to speed up a slow
Drupal site. Lets walk through the request life cycle when the page cache system is enabled.

To understand page caching, you need to first make sense of Drupals boot-strapping process. The bootstrapping process is
made up of small, isolated steps called  phases.  Drupal takes advantage of this phased bootstrapping system to load and
parse only the amount of code  necessary to serve a cached page,  and  to keep database queries to a minimumFigure
16-2 details the process of serving a cached page request to an anonymous user.


Figure 16-2. This chart shows the request life cycle of an anonymous user visiting a site and
the Drupal bootstrap process used to load the first page the visitor sees. Drupal attempts
to load the requested page from cache as the second step in thebootstrap process.

To begin, a request causes the web server  to execute index.php. A line of PHP code  inside index.php is to include
includes/bootstrap.inc, which contains the core functions for bootstrap loading. Next, index.php makes a call to drupal_
bootstrap().drupal_bootstrap() is in charge of executing each  bootstrap phase. For caching, we need to concern ourselves
only with the DRUPAL_BOOTSTRAP_PAGE_CACHE bootstrap phase. This phase attempts to load the page from the
cache_page bin.

Static Page Caching

By default, Drupal sends a "Vary: Cookie" HTTP header for anonymous page views. This tells a HTTP proxy that it may
return a page from its local cache without contacting the web server,  if the user sends the same Cookie header as the user who originally requested the cached page.  Without "Vary: Cookie", authenticated users would also be served the an on
mous page from the cache. If the site has mostly anonymous users except a few known editors/administrators, the Vary
header can be omitted. This allows for better caching in HTTP proxies (including reverse proxies), i.e., even if clients send
different cookies, they still get content served from the cache if aggressive caching is enabled and  the minimum cache time isnon-zero. However, authenticated users should accessthe site directly (i.e., not use an HTTP proxy, and  by pass the
reverse proxy if one is used) in order to avoid getting cached pages from the proxy. To enable the ability,  edit your
settings.php file and  uncomment the following line:

#$conf['omit_vary_cookie'] = TRUE;

Blocks

Depending on their content, blocks  may be cacheable. Drupal’s block caching can be enabled or disabled using  the administrative interface at Configuration -> Performance (see Figure  16-1).

Block caching is accomplished when a module that provides a block declares the cache ability of thablock when responding
to the list operation of hook_block_info(). For example, here  is part  of the hook_block_info() implementation of
modules/user/user.module:

/**
*  Implements hook_block_info().
*/
function user_block_info()  { global $user;
$blocks['login']['info'] = t('User login');
// Not worth caching.
$blocks['login']['cache'] = DRUPAL_NO_CACHE;
$blocks['new']['info'] = t('Who\'s new');
// Too dynamic to  cache.
$blocks['online']['info'] = t('Who\'s online');
$blocks['online']['cache'] = DRUPAL_NO_CACHE; return  $blocks;}

In the preceding example, all the blocks  provided by the user module declare that they should no be cached, with one
exception. The “Who’s new” block does not declare a cache preference, which means that if the administrator has enabled block caching and  then enables the “Who’s new” block, it will receive the default caching setting of DRUPAL_CACHE_
PER_ROLE. That means that a separate cached version of the block will be stored for each  role. To be more precise, a
separate cached version will bestored for each  combination of roles; the cache ID is created by concatenating the current
user’s role IDs (see _block_get_cache_id() in modules/block/block.module). The possible constants for caching are
shown in Table 16-2.



Table 16-2. Possible Constants for Caching
Constant
Value
Meaning
DRUPAL_CACHE_CUSTOM
2
The block is handling its own cache.
DRUPAL_NO_CACHE
1
Do not cache this block.
DRUPAL_CACHE_PER_ROLE
1
Each role sees a separate cached block.*
DRUPAL_CACHE_PER_USER
2
Each user sees a separate cached block.
DRUPAL_CACHE_PER_PAGE
4
Each page has its own cached block.
DRUPAL_CACHE_GLOBAL
8
Blocks are cached once for all users.
* Default for blocks that  do not declare a cache setting

All block that are cached are cached on a per-theme and  per-language basis.  This prevents users from seeing a block
that is themed by a theme other than the one the user  is viewing when multiple themes are enabled, and  it prevents blocks from showing up in the wrong language when multiple languages are enabled.

The block constants (like menu constants) can be used together using PHP bitwise operators. For example, the “Book
navigation” block provided by the book module’s implementation of hook_block_info() uses bothDRUPAL_CACHE_
PER_ROLE and  DRUPAL_CACHE_PER_PAGE:

/**
*   Implements hook_block_info().
*/
function  book_block_info() {
$block  = array();
$block['navigation']['info'] = t('Book navigation');
$block['navigation']['cache'] = DRUPAL_CACHE_PER_PAGE  | DRUPAL_CACHE_PER_ROLE;
return  $block;}
The DRUPAL_CACHE_PER_ROLE and  DRUPAL_CACHE_PER_USER constants should not be combined with the
bit wise OR operator (|), as the two caching modes are mutually exclusive.
Using the Cache  API
Module developers looking to take advantage of the cache API have two functions they need to know:
cache_set() and  cache_get().

Caching Data with cache_set()
cache_set() is used for writing data to the cache. The function signature follows:
cache_set($cid,  $data, $bin  = 'cache',  $expire = CACHE_PERMANENT)
And the function parameters are as follows:
     $cid: A unique cache ID string that acts as a key to the data. Colons are used to delimit the hierarchy of possibilities.
     $bin: The name of the cache bin to store the data in. Valid core values are 'cache_block', 'cache_bootstrap', 'cache_
field', 'cache_filter', 'cache_form''cache_menu', 'cache_page', 'cache_update', or 'cache' for the default cache.
     $data: The data to store in the cache. PHP objects and  arrays will be automatically serialized.
     $expire: The length of time  for which the cached data is valid. Possible values  are CACHE_PERMANENT, CACHE_TEMPORARY, or a Unix timestamp. If a Unix timestamp is given, the data will be treated as if it were markedCACHE_
TEMPORARY after the current time  exceeds the Unix time stamp.

A common iteration pattern for cache_set() can be seen in modules/filter/filter.module:
// Store  in  cache  with  a  minimum  expiration time  of  1  day.
if ($cache) {
cache_set($cid, $text, 'cache_filter',   REQUEST_TIME  + (60  *  60  *  24));}

Retrieving Cached Data with cache_get() and cache_get_multiple()

cache_get() is for retrieving the cached data. The function signature follows:
cache_get($cid, $bin  = 'cache')
And the function parameters are as follows:
     $cid: This is the cache ID of the data to retrieve.
     $bin: This is the name of the cache bin to store the data in. Valid core values are 'cache_block', 'cache_bootstrap',
'cache_field', 'cache_filter', 'cache_form''cache_menu', 'cache_page', 'cache_update', or 'cache' for the default cache.
A common pattern for cache_get() can be seen in modules/filter/filter.module.
// Check for  a  cached  version of  this  piece of  text.
if ($cached  = cache_get($cid, 'cache_filter')) { return  $cached->data;}
To return data from cache for a given array of cache IDs, use the cache_get_multiple() function. The function signature
follows. The only difference from cache_get is you are passing an array of cids.
cache_get_multiple(array &$cids,  $bin  = 'cache)

Checking to See If Cache Is Empty with cache_is_empty()

There may be instances where you want  to know whether a cache bin is empty. You can use the cache_is_empty
function to check  whether a specific bin has cached data in it. The function returns TRUE if the cache bin is empty. The
function signatureis as follows:
cache_is_empty($bin)
And the function parameters are
     $bin: This is the name of the cache bin to store the data in. Valid core values are 'cache_block', 'cache_bootstrap',
'cache_field', 'cache_filter', 'cache_form''cache_menu', 'cache_page', 'cache_update', or 'cache' for the default cache.
Clearing Cache with cache_clear_all()

If your module knows  best  when its data becomes stale, it should take responsibility for clearing caches at an appropriate
time.  Two guiding principles should be applied to cache clearing:

     Clear the most specific cache possible. Do not broadly wipe all Drupal’s caches just because a bit of module-specific data has changed! Its the equivalent of ripping out and  replacing all the carpeting in the house because the kitchen
floor needs sweeping.
     Use cached data as long as you can. Although the point of caching is to increase responsiveness by decreasing the amount of work that needs to be done, there is significant work involved in clearing cached data, especially if there is a lot of it.
The following subsections describe some ways of clearing cached data.
Using the $reset Parameter
Many Drupal functions that do internal caching with static variables have an optional reset that clears its internal cache.
For example, here’s  our old friend node_load().
node_load($nid = NULL,  $vid  = NULL,  $reset = FALSE)
The third parameter in the function call is whether to reset  the node_load_multiple cache.
Using cache_clear_all()

The main function for clearing cached data is cache_clear_all() in includes/cache.inc. The function signature is as follows:
function cache_clear_all($cid  = NULL,  $bin  = NULL,  $wildcard  = FALSE)  {...}
The $cid and  $bin parameters have the same meaning as they do for cache_set() and  cache_get(). The $wildcard parameter is used to indicate that the $cid being passed should be treated as a substring with any right-hand matches being cleared. Someexamples follow. Clear the specific entry foo:bar from the cache table:
$cid  = 'foo:bar'; cache_clear_all($cid, 'cache');
Clear any expirable entry in the cache table that was set by the foo module (and thus has a $cid that begins with the
foo: prefix):
$cid  = 'foo:'; // Will  match cache  keys  foo:bar, foo:baz, etc.cache_clear_all($cid, 'cache',  TRUE);
The actual database query that is run  in the preceding case is
db_delete($this->bin)->condition('cid',  db_like($cid) . '%',  'LIKE')->execute();

If the foo module keeps its data in its own cache table  named cache_foo, that table needs to be specified so cache_clear_
all() knows  which to clear:
$cid  = 'foo:bar'; cache_clear_all($cid, 'cache_foo');

If you want  to completely empty a cache table, pass  * as the $cid and  set the $wildcard parameter to TRUE. This
example clears the entire cache_foo table:
cache_clear_all('*',  'cache_foo', TRUE);
Clear any expirable entries from the page and  block caches (i.e., the cache_page and  cache_block tables):
cache_clear_all();
Using hook_flush_caches()
Drupal has a central function that flushes all the caches, including the JavaScript and  CSS caches. Here is the
drupal_flush_all_caches() function from includes/common.inc:
/**
*   Flush  all cached  data  on the  site.
*
*   Empties  cache  tables,  rebuilds the  menu  cache  and theme registries, and
*   invokes   a  hook so  that   other  modules'  cache  data  can  be  cleared as  well.
*/
function drupal_flush_all_caches()  {
// Change query-strings on css/js files to  enforce reload   for  all users.
_drupal_flush_css_js();
registry_rebuild(); drupal_clear_css_cache(); drupal_clear_js_cache();
// Rebuild  the  theme data. Note  that   the  module data  is rebuilt above,  as
// part  of  registry_rebuild().
system_rebuild_theme_data(); drupal_theme_rebuild();
menu_rebuild(); node_types_rebuild();
// Don't  clear cache_form  - in-progress form submissions may  break.
// Ordered so  clearing the  page  cache  will always  be  the  last action.
$core  = array('cache', 'cache_filter', 'cache_bootstrap',  'cache_page');
$cache_tables = array_merge(module_invoke_all('flush_caches'), $core); foreach   ($cache_tables as  $table) {
cache_clear_all('*', $table, TRUE);}}
If you are using your own cache tables, the hook_flush_caches() function gives your module a chance to clear its caches
when the Clear cached data button is clicke on the Configuration -> Performance page.  An implementation of
hook_flush_caches() is simple to write; your module should simply  return the names of any cache bins that should be
flushed. Here’s an example from the update status module:
/**
*   Implements hook_flush_caches().
*/
function  example module_flush_caches() { return  array('cache_example');
}

In the example, I am passing back the name of the cache bin used by a module named example module.
Summary
In this chapter, you learned about
     The various types  of caching Drupal provides: page,  block, menu, variable, and filter caching.
     How the page-caching systems work.
     The differences among Normal, Aggressive, and  fast path caching.
     How the block-caching system works.
     The cache API functions.

Không có nhận xét nào:

Đăng nhận xét