Skip to content

Instantly share code, notes, and snippets.

@phizev
Last active April 7, 2022 17:35
Show Gist options
  • Save phizev/618ae544dca73abae492cbade8eae13b to your computer and use it in GitHub Desktop.
Save phizev/618ae544dca73abae492cbade8eae13b to your computer and use it in GitHub Desktop.
In short: Performance improvement, and a 50% reduction in cache_form, no negatives. Drupal database cache implementation using igbinary_(un)serialize().
Rationale:
igbinary does an excellent job at creating compact serialized data as opposed to
PHP's serializer. It's already used for serializing data stored in memcached,
Drupal's form cache can get notoriously large, can igbinary help?
https://github.com/igbinary/igbinary
Experimentation:
Drupal database cache implementation using igbinary_(un)serialize(). In my initial
experimentation, this reduced the size of cache_form by a factor of ~2.6. In one
to one comparisons of the results of serializing an extremely large form, this
difference began to top out at ~3.2. For very small forms, such as the login form,
I was seeing a factor of about 2:1. While igbinary can be slower than PHP's serialise,
I found the difference was far outstripped by the time saved in database queries,
especially over a network. Note: I had compact_strings enabled.
I have run some sites where this cache implementation is the only one in use.
<?php
/**
* @file
* Functions and interfaces for cache handling.
*/
/**
* Defines an igbinary databased backed cache implementation.
*
* This simply extends Drupal's default cache implementation, switching
* PHP's (un)serialize for igbinary_(un)serialize. It remains true to core
* in other manners.
*/
class IgbinaryDatabaseCache extends DrupalDatabaseCache {
/**
* Prepares a cached item.
*
* Checks that items are either permanent or did not expire, and unserializes
* data as appropriate.
*
* @param $cache
* An item loaded from cache_get() or cache_get_multiple().
*
* @return
* The item with data unserialized as appropriate or FALSE if there is no
* valid item to load.
*/
protected function prepareItem($cache) {
global $user;
if (!isset($cache->data)) {
return FALSE;
}
// If the cached data is temporary and subject to a per-user minimum
// lifetime, compare the cache entry timestamp with the user session
// cache_expiration timestamp. If the cache entry is too old, ignore it.
if ($cache->expire != CACHE_PERMANENT && variable_get('cache_lifetime', 0) && isset($_SESSION['cache_expiration'][$this->bin]) && $_SESSION['cache_expiration'][$this->bin] > $cache->created) {
// Ignore cache data that is too old and thus not valid for this user.
return FALSE;
}
// If the data is permanent or not subject to a minimum cache lifetime,
// unserialize and return the cached data.
if ($cache->serialized) {
$cache->data = igbinary_unserialize($cache->data);
}
return $cache;
}
/**
* Implements DrupalCacheInterface::set().
*/
function set($cid, $data, $expire = CACHE_PERMANENT) {
$fields = array(
'serialized' => 0,
'created' => REQUEST_TIME,
'expire' => $expire,
);
if (!is_string($data)) {
$fields['data'] = igbinary_serialize($data);
$fields['serialized'] = 1;
}
else {
$fields['data'] = $data;
$fields['serialized'] = 0;
}
try {
db_merge($this->bin)
->key(array('cid' => $cid))
->fields($fields)
->execute();
}
catch (Exception $e) {
// The database may not be available, so we'll ignore cache_set requests.
}
}
}
name = Igbinary DBcache
description = A copy of the Drupal core cache.inc, replacing (un)serialize() with the igbinary counterparts.
package = Performance and scalability
core = 7.x
<?php
/**
* Implements hook_requirements().
*/
function igbinary_dbcache_requirements($phase) {
$requirements = array();
$t = get_t();
if ($phase == 'install' || $phase == 'runtime') {
$requirements['igbinary_extension']['title'] = $t('Igbinary serializer');
if (extension_loaded('igbinary')) {
$requirements['igbinary_extension']['severity'] = REQUIREMENT_OK;
$requirements['igbinary_extension']['value'] = $t('Enabled');
}
else {
$requirements['igbinary_extension']['severity'] = REQUIREMENT_ERROR;
$requirements['igbinary_extension']['value'] = $t('The PHP igbinary extension is required to use the igbinary_dbcache backend.');
}
}
return $requirements;
}
<?php
/**
* @file
* Empty .module file so that the module can be enabled to check for igbinary.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment