View source
<?php
define('MEMCACHE_STORAGE_MINIMUM_MEMCACHE_VERSION', '2.2.1');
define('MEMCACHE_STORAGE_MINIMUM_MEMCACHED_VERSION', '2.0.1');
function memcache_storage_menu() {
$items['admin/config/development/memcache_storage'] = array(
'title' => 'Memcache storage',
'description' => t('Manage Memcache Storage settings'),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'memcache_storage_settings_form',
),
'access arguments' => array(
'administer memcache storage',
),
'file' => 'memcache_storage.admin.inc',
);
$items['memcache_storage/delete/%/%/%'] = array(
'page callback' => 'memcache_storage_clear_cache_ajax_callback',
'page arguments' => array(
2,
3,
4,
5,
),
'access arguments' => array(
'view memcache storage debug',
),
'theme callback' => 'ajax_base_page_theme',
'type' => MENU_CALLBACK,
'file' => 'memcache_storage.pages.inc',
);
return $items;
}
function memcache_storage_permission() {
return array(
'administer memcache storage' => array(
'title' => t('Administer Memcache storage'),
'description' => t('Manage Memcache storage module settings.'),
),
'view memcache storage debug' => array(
'title' => t('View Memcache Storage debug output'),
'description' => t('Allow user to see memcache I/O operations at the bottom of the page.'),
),
);
}
function memcache_storage_admin_menu_cache_info() {
$caches['memcache_storage'] = array(
'title' => t('Memcache data'),
'callback' => 'memcache_storage_flush_all_cache',
);
return $caches;
}
function memcache_storage_flush_all_cache() {
$cache_bins = _memcache_storage_memcached_cache_bins();
foreach ($cache_bins as $cache_bin) {
cache_clear_all('*', $cache_bin, TRUE);
}
drupal_set_message(t('Memcached cache bins were successfully flushed.'));
}
function memcache_storage_init() {
$last_wildcards_flush = variable_get('memcache_storage_last_wildcards_flush');
$wildcards_flush_interval = variable_get('memcache_storage_wildcards_flush_interval', 3600);
if (REQUEST_TIME >= $last_wildcards_flush + $wildcards_flush_interval) {
drupal_register_shutdown_function('memcache_storage_wildcard_flush');
}
if (!variable_get('memcache_storage_debug', FALSE)) {
return;
}
if (!user_access('view memcache storage debug')) {
return;
}
if (!strstr($_SERVER['PHP_SELF'], 'index.php') || strstr($_GET['q'], 'upload/js') || strstr($_GET['q'], 'admin/content/node-settings/rebuild') || strstr($_GET['q'], 'system') || strstr($_GET['q'], 'batch') || strstr($_GET['q'], 'ckeditor/xss') || strstr($_GET['q'], 'autocomplete')) {
return;
}
else {
drupal_add_library('system', 'drupal.ajax');
drupal_add_css(drupal_get_path('module', 'memcache_storage') . '/css/memcache_storage.css');
drupal_register_shutdown_function('memcache_storage_debug_shutdown');
drupal_page_is_cacheable(FALSE);
drupal_add_http_header('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
}
}
function memcache_storage_wildcard_flush() {
$cache_bins = _memcache_storage_memcached_cache_bins();
foreach ($cache_bins as $bin) {
$object = _cache_get_object($bin);
if (!$object instanceof MemcacheStorage) {
continue;
}
$wildcards = $object
->getWildcards();
if (empty($wildcards)) {
continue;
}
$cache_ids = $object
->getCacheIDs();
$delete_ids = array();
foreach ($wildcards as $wildcard => $flush_timestamp) {
foreach ($cache_ids as $cache_id => $cache_created) {
if ($cache_created <= $flush_timestamp) {
if (strpos($cache_id, $wildcard) === 0) {
$delete_ids[] = $cache_id;
}
}
}
}
if (!empty($delete_ids)) {
$object
->clear($delete_ids);
}
$object
->clear('memcache_storage_wildcards');
}
variable_set('memcache_storage_last_wildcards_flush', REQUEST_TIME);
}
function memcache_storage_debug_shutdown() {
if (!function_exists('theme_get_registry') || !theme_get_registry()) {
return;
}
if (function_exists('drupal_get_http_header') && !strstr(drupal_get_http_header('Content-Type'), 'html')) {
return;
}
$debug_output = drupal_static('memcache_storage_debug_output');
if (empty($debug_output)) {
return;
}
$common_stats = array();
foreach ($debug_output as $key => &$row) {
$action = $row['action'];
if (empty($common_stats[$action])) {
$common_stats[$action]['action'] = $action;
$common_stats[$action]['time'] = 0;
$common_stats[$action]['mem'] = 0;
$common_stats[$action]['HIT'] = 0;
$common_stats[$action]['MISS'] = 0;
}
$common_stats[$action][$row['result']]++;
if (!empty($row['clear_link'])) {
$row['clear_link']['#text'] = t('Delete');
$row['clear_link']['#options']['query'] = array(
'token' => drupal_get_token($row['token']),
);
}
unset($row['token']);
$debug_output[$key]['clear_link'] = render($row['clear_link']);
if (isset($debug_output[$key - 1]) && $debug_output[$key - 1]['timer'] == $row['timer'] && $debug_output[$key - 1]['memory'] == $row['memory']) {
continue;
}
$common_stats[$action]['time'] += $row['timer'];
$common_stats[$action]['mem'] += $row['memory'];
}
foreach ($common_stats as &$stats) {
$stats['mem'] = number_format($stats['mem'] / 1024, 2);
$stats['HIT'] = $stats['HIT'] . ' / ' . number_format($stats['HIT'] / ($stats['HIT'] + $stats['MISS']) * 100, 1) . '%';
$stats['MISS'] = $stats['MISS'] . ' / ' . number_format($stats['MISS'] / ($stats['HIT'] + $stats['MISS']) * 100, 1) . '%';
}
$detailed_debug = array();
foreach ($debug_output as $row) {
$detailed_debug[] = array(
'data' => $row,
'class' => array(
$row['result'] == 'MISS' ? 'miss' : 'hit',
),
);
}
$stats_table = array(
'#theme' => 'table',
'#header' => array(
t('Action'),
t('Total time, ms'),
t('Total memory used, MB'),
t('Total hits / %'),
t('Total misses / %'),
),
'#rows' => $common_stats,
'#attributes' => array(
'class' => array(
'memcache-storage-common-debug',
),
),
);
$debug_table = array(
'#theme' => 'table',
'#header' => array(
t('Action'),
t('Time, ms'),
t('Used memory, KB'),
t('Result'),
t('Cache bin'),
t('Cache ID'),
t('Memcache key'),
t('Cache action'),
),
'#rows' => $detailed_debug,
'#attributes' => array(
'class' => array(
'memcache-storage-detailed-debug',
),
),
);
print '<h2>' . t('Memcache Storage debug output') . '</h2>';
print t('Request URL: !url', array(
'!url' => '<strong>' . url($_GET['q'], array(
'absolute' => TRUE,
)) . '</strong>',
));
print render($stats_table) . render($debug_table);
}
function _memcache_storage_memcached_cache_bins() {
$available_bins = array();
$schema = drupal_get_complete_schema();
foreach ($schema as $table_name => $table_data) {
if (strpos($table_name, 'cache') === 0) {
$cache_class = variable_get('cache_class_' . $table_name);
if (!isset($cache_class)) {
$cache_class = variable_get('cache_default_class', 'DrupalDatabaseCache');
}
if ($cache_class == 'MemcacheStorage') {
$available_bins[$table_name] = $table_name;
}
}
}
ksort($available_bins);
unset($available_bins['cache_form']);
unset($available_bins['cache_update']);
$external_page_cache = variable_get('memcache_storage_external_page_cache', FALSE);
if ($external_page_cache) {
unset($available_bins['cache_page']);
}
return $available_bins;
}