Skip to content

Commit

Permalink
[FEATURE] Detach render cache clear from cache flushes
Browse files Browse the repository at this point in the history
Render caches are robust enough to not depend on TTLs or other time
based processes.
  • Loading branch information
Mateu Aguiló Bosch committed Dec 17, 2015
1 parent 2cdf7aa commit c5886a3
Show file tree
Hide file tree
Showing 7 changed files with 118 additions and 44 deletions.
32 changes: 0 additions & 32 deletions restful.admin.inc
Original file line number Diff line number Diff line change
Expand Up @@ -73,38 +73,6 @@ function restful_admin_settings($form_state) {
'#default_value' => variable_get('restful_allowed_origin', ''),
);

$form['restful_cache'] = array(
'#type' => 'fieldset',
'#title' => t('Cache'),
'#description' => t('Cache options for the different layers of RESTful.'),
'#collapsible' => FALSE,
);

$form['restful_cache']['restful_page_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Page cache'),
'#description' => t('RESTful can leverage page cache, this will boost your performace for anonymous traffic. !link to start caching responses. Status: <strong>@status</strong>. <strong>CAUTION:</strong> If your resources are using authentication providers other than cookie, you will want to turn this off. Otherwise you may get cached anonymous values for your authenticated GET requests.', array(
'!link' => l(t('Enable page cache'), 'admin/config/development/performance'),
'@status' => variable_get('cache', FALSE) ? t('Enabled') : t('Disabled'),
)),
'#disabled' => !variable_get('cache', FALSE),
'#default_value' => variable_get('restful_page_cache', FALSE) && variable_get('cache', FALSE),
);

$form['restful_cache']['restful_render_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Cache results'),
'#description' => t('When enabled any resource that has not explicitly disabled the caching will be cached. Note that the first hit may result with slower response, although the next ones would be significantly faster. This is different from the page cache in the sense that it acts at the row level (a single entity, a single database row, ...), therefore allowing you to assemble non cached pages with the cached bits faster.'),
'#default_value' => variable_get('restful_render_cache', FALSE),
);

$form['restful_cache']['restful_fast_cache_clear'] = array(
'#type' => 'checkbox',
'#title' => t('Fast cache clear'),
'#description' => t('A lot of cache fragment entries may be created by default. This may cause your cache clears to be slow. By checking this checkbox the cache fragments are deleted from the database in a fast manner. As a trade-in, no hook_entity_delete will be fired for the cache fragment entities. This is OK in the vast majority of the cases. You can mitigate the number of generated fragments by overriding the "getCacheContext" method in your data provider.'),
'#default_value' => variable_get('restful_fast_cache_clear', TRUE),
);

$form['advanced'] = array(
'#type' => 'fieldset',
'#title' => t('Advanced'),
Expand Down
79 changes: 79 additions & 0 deletions restful.cache.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php

/**
* @file
* Procedural implementations for cache related features.
*/
use Drupal\restful\RenderCache\RenderCache;

/**
* Clears all caches and associated fragments.
*/
function restful_clear_caches() {
/* @var \Drupal\restful\RenderCache\Entity\CacheFragmentController $controller */
$controller = entity_get_controller('cache_fragment');
$controller->wipe();
cache_clear_all('*', RenderCache::CACHE_BIN, TRUE);
drupal_set_message(t('RESTful caches were successfully cleared.'));
}

/**
* Implements hook_flush_caches().
*/
function restful_flush_caches() {
if (!variable_get('restful_clear_on_cc_all', FALSE)) {
return array();
}
// Delete all the cache fragments.
/* @var \Drupal\restful\RenderCache\Entity\CacheFragmentController $controller */
$controller = entity_get_controller('cache_fragment');
$controller->wipe();
return array(RenderCache::CACHE_BIN);
}

/**
* Menu callback; Admin settings form.
*/
function restful_admin_cache_settings($form_state) {
$form = array();
$form['restful_page_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Page cache'),
'#description' => t('RESTful can leverage page cache, this will boost your performace for anonymous traffic. !link to start caching responses. Status: <strong>@status</strong>. <strong>CAUTION:</strong> If your resources are using authentication providers other than cookie, you will want to turn this off. Otherwise you may get cached anonymous values for your authenticated GET requests.', array(
'!link' => l(t('Enable page cache'), 'admin/config/development/performance'),
'@status' => variable_get('cache', FALSE) ? t('Enabled') : t('Disabled'),
)),
'#disabled' => !variable_get('cache', FALSE),
'#default_value' => variable_get('restful_page_cache', FALSE) && variable_get('cache', FALSE),
);

$form['restful_render_cache'] = array(
'#type' => 'checkbox',
'#title' => t('Cache results'),
'#description' => t('When enabled any resource that has not explicitly disabled the caching will be cached. Note that the first hit may result with slower response, although the next ones would be significantly faster. This is different from the page cache in the sense that it acts at the row level (a single entity, a single database row, ...), therefore allowing you to assemble non cached pages with the cached bits faster.'),
'#default_value' => variable_get('restful_render_cache', FALSE),
);

$form['clear_restful'] = array(
'#submit' => array('restful_clear_caches'),
'#type' => 'submit',
'#value' => t('Clear render caches'),
'#disabled' => !variable_get('restful_render_cache', FALSE) && user_access('restful clear render caches'),
);

$form['restful_clear_on_cc_all'] = array(
'#type' => 'checkbox',
'#title' => t('Clear on global flush'),
'#description' => t("Check this box to clear the render caches when clearing Drupal's caches. In general the render caches are more robust than the TTL based caches. The recommended value is unchecked."),
'#default_value' => variable_get('restful_clear_on_cc_all', FALSE),
);

$form['restful_fast_cache_clear'] = array(
'#type' => 'checkbox',
'#title' => t('Fast cache clear'),
'#description' => t('A lot of cache fragment entries may be created by default. This may cause your cache clears to be slow. By checking this checkbox the cache fragments are deleted from the database in a fast manner. As a trade-in, no hook_entity_delete will be fired for the cache fragment entities. This is OK in the vast majority of the cases. You can mitigate the number of generated fragments by overriding the "getCacheContext" method in your data provider.'),
'#default_value' => variable_get('restful_fast_cache_clear', TRUE),
);

return system_settings_form($form);
}
9 changes: 9 additions & 0 deletions restful.install
Original file line number Diff line number Diff line change
Expand Up @@ -142,3 +142,12 @@ function restful_update_7200() {
$table_schema = drupal_get_schema('restful_cache_fragment', TRUE);
db_create_table('restful_cache_fragment', $table_schema);
}

/**
* Clear RESTful cache on cache flush.
*/
function restful_update_7201() {
// Even if the recommended value is FALSE, there might be some deploy
// workflows that assume cache clearing.
variable_set('restful_clear_on_cc_all', TRUE);
}
31 changes: 21 additions & 10 deletions restful.module
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

include_once __DIR__ . '/restful.entity.inc';
include_once __DIR__ . '/restful.cache.inc';

use Drupal\Component\Plugin\Exception\PluginNotFoundException;
use Drupal\Component\Plugin\PluginBase;
Expand Down Expand Up @@ -88,6 +89,17 @@ function restful_menu() {
);
$items['admin/config/services/restful/restful'] = $items['admin/config/services/restful'];
$items['admin/config/services/restful/restful']['type'] = MENU_DEFAULT_LOCAL_TASK;
// Add cache administration page.
$items['admin/config/services/restful/cache'] = array(
'title' => 'Cache',
'description' => 'Administer the RESTful module cache system.',
'page callback' => 'drupal_get_form',
'page arguments' => array('restful_admin_cache_settings'),
'access arguments' => array('administer restful'),
'file' => 'restful.cache.inc',
'type' => MENU_LOCAL_TASK,
'weight' => 2,
);

return $items;
}
Expand All @@ -105,6 +117,10 @@ function restful_permission() {
'title' => t('Administer the resources'),
'description' => t('Perform operations on the resources.'),
),
'restful clear render caches' => array(
'title' => t('Clear RESTful render caches'),
'description' => t('Clear the render caches and their correspoding cache fragments.'),
),
);
}

Expand All @@ -119,6 +135,11 @@ function restful_help($path, $arg) {
'!link' => l(t('Docs'), 'https://github.com/RESTful-Drupal/restful/tree/7.x-2.x/docs'),
));
return '<p>' . $message . '</p>';

case 'admin/config/services/restful/cache':
$message = t('The RESTful module contains several layers of caching for enhanced performance: (1) page cache (aka URL level caching) for anonymous users. This cache is extremely fast, but not very flexible. (2) The render cache can be configured for each resource and allows you to serve cached versions of your records (even to authenticated users!). The render cache also contains smart invalidation, which means that you do not need to have a TTL based cache system. Instead the caches are evicted when automatically when necessary.');
return '<p>' . $message . '</p>';

}
}

Expand Down Expand Up @@ -551,13 +572,3 @@ function restful_restful_resource_alter(ResourceInterface &$resource) {
$resource->disable();
}
}

/**
* Implements hook_flush_caches().
*/
function restful_flush_caches() {
// Delete all the cache fragments.
$controller = entity_get_controller('cache_fragment');
$controller->wipe();
return array('cache_restful');
}
3 changes: 2 additions & 1 deletion src/Plugin/resource/Decorators/CacheDecoratedResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
use Drupal\restful\Plugin\resource\DataProvider\DataProviderInterface;
use Drupal\restful\Plugin\resource\ResourceInterface;
use Drupal\restful\RenderCache\Entity\CacheFragmentController;
use Drupal\restful\RenderCache\RenderCache;
use Drupal\restful\Resource\ResourceManager;

class CacheDecoratedResource extends ResourceDecoratorBase implements CacheDecoratedResourceInterface {
Expand Down Expand Up @@ -239,7 +240,7 @@ protected function defaultCacheInfo() {
$cache_info += array(
'render' => variable_get('restful_render_cache', FALSE),
'class' => NULL,
'bin' => 'cache_restful',
'bin' => RenderCache::CACHE_BIN,
'expire' => CACHE_PERMANENT,
'simpleInvalidate' => TRUE,
'granularity' => DRUPAL_CACHE_PER_USER,
Expand Down
5 changes: 5 additions & 0 deletions src/RenderCache/RenderCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
use Doctrine\Common\Collections\ArrayCollection;
use Drupal\restful\RenderCache\Entity\CacheFragmentController;

/**
* Class RenderCache.
*
* @package Drupal\restful\RenderCache
*/
class RenderCache implements RenderCacheInterface {

/**
Expand Down
3 changes: 2 additions & 1 deletion src/RestfulManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use Drupal\restful\Http\Response;
use Drupal\restful\Http\ResponseInterface;
use Drupal\restful\Plugin\resource\DataInterpreter\DataInterpreterInterface;
use Drupal\restful\RenderCache\RenderCache;
use Drupal\restful\Resource\ResourceManager;
use Drupal\restful\Resource\ResourceManagerInterface;
use Drupal\restful\Util\PersistableCache;
Expand Down Expand Up @@ -179,7 +180,7 @@ public static function createFromGlobals() {
$response = Response::create();
$resource_manager = new ResourceManager($request);
$formatter_manager = new FormatterManager();
$persistable_cache = new PersistableCache('cache_restful');
$persistable_cache = new PersistableCache(RenderCache::CACHE_BIN);

return new static($request, $response, $resource_manager, $formatter_manager, $persistable_cache);
}
Expand Down

0 comments on commit c5886a3

Please sign in to comment.