Drupal 7 Line by Line Part 6 - DRUPAL_BOOTSTRAP_VARIABLES

This is the 6th installment of the Drupal 7 Line by Line series of articles.

Up to this point in the series I've covered index.php, the basics of the drupal_bootstrap function and have been working through Drupal's bootstrap phases. (Links to earlier articles in the series can be found at the end of this article).

In the last article I covered the Drupal database bootstrap. In that article I mentioned the following:

[when I wrote about] page cache bootstrap process I noted that unless your site is configured in a specific way, both the DRUPAL_BOOTSTRAP_DATABASE (phase 3) and DRUPAL_BOOTSTRAP_VARIABLES (phase 4) bootstrapping phases will be completed before the page cache (phase2) bootstrap process can itself finish. As a result, I am technically covering the database bootstrapping process out of order and am not literally following the line by line code execution of Drupal exactly. I hope you can forgive me.

Keeping that in mind, today I will cover phase 4 in the bootstrap process: DRUPAL_BOOTSTRAP_VARIABLES.

Before I start, its worth talking about Drupal's 'variable' system. Drupal provides developers with a few handy functions to easily store persistent data required by their modules. Things a developer might want to persist (between page loads) include settings or configuration information. Those utility functions are variable_get(), variable_set() and variable_delete(). variable_set() writes the values of variables to the database. But, we've already seen that variable_get() does not read anything from the database. Instead it returns values from the global $conf array.

Filling up $conf with variables stored in the database is what this bootstrap phase is all about.

_drupal_bootstrap_variables()

The first thing that happens is that the global $conf variable is brought into scope. $conf is a global variable of type array that may have values added to it in settings.php.

Drupal's Locking Mechanism

Next Drupal attempts to "initialize the lock system". To understand what this is about I suggest reading: Implement a locking framework for long operations and the comments in the lock.inc file.

The short version is that in some cases Drupal executes long running operations like rebuilding the menu system and there is potential for race conditions and duplicated requests of the same operations to happen. A locking mechanism helps to keep solve these problems.

<?php
require_once DRUPAL_ROOT . '/' . variable_get('lock_inc', 'includes/lock.inc'); ?>

You'll notice that Drupal doesn't automatically include lock.inc. It may in fact load a different file to handle locking if one was defined in settings.php in $conf['lock_inc']. (Remember that variable_get is a wrapper around the $conf variable and, at this stage in page execution, the only values in $conf are those that were defined in settings.php)

With that file loaded Drupal calls lock_initialize(). By default all this function does is define a global variable called $lock and initialize it as an empty array.

Initializing Variables

<?php
 
// Load variables from the database, but do not overwrite variables set in settings.php.
 
$conf = variable_initialize(isset($conf) ? $conf : array());
?>

One note here, before I explain variable_initialize: the code comment here and the argument passed to the variable_initialize function are (as far as I can tell) unnecessary. $conf is most certainly initialized by this stage in the bootstrap and can only contain variables set in settings.php. I suspect this is legacy code that may have been required in earlier versions of Drupal.

<?php
/**
* Load the persistent variable table.
*
* The variable table is composed of values that have been saved in the table
* with variable_set() as well as those explicitly specified in the configuration
* file.
*/
function variable_initialize($conf = array()) {
 
// NOTE: caching the variables improves performance by 20% when serving
  // cached pages.
 
if ($cached = cache_get('variables', 'cache_bootstrap')) {
   
$variables = $cached->data;
  }
?>

Reading from Drupal Cache

Here I'll digress a little about the caching functions. In the earlier article about page caching bootstrap I talked about how the pluggable caching system (which is comprised of classes that implement the Drupal caching interface) is initialized. In the line above we actually see the first use of that system.

cache_get() takes two arguments. The first is what you want and the second is where you want to get it from. So, cache_get('variables', 'cache_bootstrap'); says get me the variables from the cache_bootstrap "bin".

How it works: Inside cache_get():

<?php
return _cache_get_object($bin)->get($cid);
?>

We see a call to _cache_get_object() which returns the appropriate object responsible for the type of storage or storage "bin" you are interested in. _cache_get_object does this by looking for settings in settings.php in the form $conf['cache_class_BINNAME'] = 'some_class_name' (where bin name is the name of the bin you are interested in - in this case 'cache_bootstrap'). If it finds a setting it instantiates that object otherwise it falls back to Drupal's default database cache. We also see that this line of code also calls the 'get' method of the cache object passing what we want as an argument (in this case 'variables').

How that 'get' method works is, as they say, an implementation detail. It all depends on how the object implements the method.

Back to Initializing Variables

If variables were found in cache they are assigned to a $variables variable. Otherwise:

<?php
 
else {
   
// Cache miss. Avoid a stampede.
   
$name = 'variable_init';
    if (!
lock_acquire($name, 1)) {
     
// Another request is building the variable cache.
      // Wait, then re-run this function.
     
lock_wait($name);
      return
variable_initialize($conf);
    }
    else {
     
// Proceed with variable rebuild.
     
$variables = array_map('unserialize', db_query('SELECT name, value FROM {variable}')->fetchAllKeyed());
     
cache_set('variables', $variables, 'cache_bootstrap');
     
lock_release($name);
    }
  }
?>

Which says: check to see if the 'variable_init' is in a locked state because something else is rebuilding the variable cache. When everything is clear, get all the variables from the table named 'variable' in the database and write them to cache.

The last thing that Drupal does before the function returns is a re-set of the variables that came from settings.php (via the $conf variable that was passed into this function).

<?php
 
foreach ($conf as $name => $value) {
   
$variables[$name] = $value;
  }
?>

This ensures variables in settings.php always trump variables in the database.

Module Loading

With variable_initialize complete, we go back to _drupal_bootstrap_variables() where all Drupal variables are assigned to the global $conf.

Drupal then includes the file module.inc and calls module_load_all(TRUE);

As you might guess, module.inc contains functions related to handling Drupal's flexible module system. To see all the wonderful things it can do read: http://api.drupal.org/api/drupal/includes--module.inc/7

The module_load_all() function loads all modules - except for when it doesn't!. e.g. like when it is called (as in this case) with the TRUE argument. By giving module_load_all this argument you are telling it that Drupal is in the midst of a bootstrap and only a subset of modules should be loaded (only those modules that might be required to display a cached page).

I won't step through each line of this process but I will highlight the functions that matter:
module_load_all calls module_list (but only asking for a list of bootstrap modules)
For each of the modules in that list drupal_load() is called.
drupal_load() includes the module's .module file with 'include_once'.

With a typical but minimal Drupal installation it appears as though 'dblog' and 'overlay' are the only modules loaded (assuming they are enabled) during this bootstrap phase.

And with that the variables bootstrap phase is complete.

Summary

I covered a lot of ground in this article, but the things to remember are:
Drupal has a locking framework.
If possible, variables are loaded from cache.
$conf is filled with variables from the database.
Variables set in settings.php will trump anything that is in the database.
A few (but certainly not all) modules may be loaded in this bootstrap phase.

Comments, questions and corrections are always welcome.

January 12th 2011 1PM
By: andre

 

Comments

There's some nice scripting

There's some nice scripting in this post man, nice job.

Before I start, its worth talking about Drupal's 'variable' system. Drupal provides developers with a few handy functions to easily store persistent data required by their modules. Things a developer might want to persist (between page loads) include settings or configuration information. Those utility functions are variable_get(), variable_set() and variable_delete(). variable_set() writes the values of variables to the database. But, we've already seen that variable_get() does not read anything from the database. Instead it returns values from the global $conf array.

manipulacna technika | catering | kabelky | osobni trener fitness

nice as generic viagra

nice as generic viagra

Nice piece

This is a nice post!and I think you should always maintain it, it gives a great help, like an I.T student like me.Thank you

Thanks for these articles,

Thanks for these articles, I've really enjoyed them. Hopefully they continue, it seems as if we are currently in the midst of a lull :)

Matt

First call to a hook?

I think that this is the first place where a hook can be effectively called, which is hook_boot(). It would be useful to point out where and when the hook system intersects with the core code so that readers can get a better understanding of the hook system.

So the take home point is: If you need to add some code to any page call no matter if is cached or not, use hook_boot().

I love what you are doing. Keep up the good work!