Index: memcache.db.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache.db.inc,v retrieving revision 1.2.2.11 diff -u -p -r1.2.2.11 memcache.db.inc --- memcache.db.inc 12 Feb 2008 21:58:06 -0000 1.2.2.11 +++ memcache.db.inc 19 Oct 2008 19:39:22 -0000 @@ -6,32 +6,34 @@ require_once 'dmemcache.inc'; /** Implementation of cache.inc with memcache logic included **/ /** - * Return data from the persistent cache. + * Return data from the persistent cache. Data may be stored as either plain text or as serialized data. + * cache_get will automatically return unserialized objects and arrays. * - * @param $key + * @param $cid * The cache ID of the data to retrieve. * @param $table * The table $table to store the data in. Valid core values are 'cache_filter', * 'cache_menu', 'cache_page', or 'cache' for the default cache. */ -function cache_get($key, $table = 'cache') { +function cache_get($cid, $table = 'cache') { global $user; // Garbage collection necessary when enforcing a minimum cache lifetime $cache_flush = variable_get('cache_flush', 0); if ($cache_flush && ($cache_flush + variable_get('cache_lifetime', 0) <= time())) { + // Reset the variable immediately to prevent a meltdown in heavy load situations. + variable_set('cache_flush', 0); // Time to flush old cache data db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire <= %d", CACHE_PERMANENT, $cache_flush); - variable_set('cache_flush', 0); } // If we have a memcache hit for this, return it. - if ($cache = dmemcache_get($key, $table)) { + if ($cache = dmemcache_get($cid, $table)) { return $cache; } // Look for a database cache hit. - if ($cache = db_fetch_object(db_query("SELECT data, created, headers, expire, serialized FROM {". $table ."} WHERE cid = '%s'", $key))) { + if ($cache = db_fetch_object(db_query("SELECT data, created, headers, expire, serialized FROM {". $table ."} WHERE cid = '%s'", $cid))) { if (isset($cache->data)) { // If the data is permanent or we're not enforcing a minimum cache lifetime // always return the cached data. @@ -62,7 +64,7 @@ function cache_get($key, $table = 'cache // By calling cache_set with an extra paramater to signify no db storage, // we can lazy instantiate memcache that just comes online. - cache_set($key, $table, $cache->data, $cache->expire, $cache->headers, FALSE); + cache_set($cid, $cache->data, $table, $cache->expire, $cache->headers, FALSE); return $cache; } return 0; @@ -95,11 +97,13 @@ function cache_get($key, $table = 'cache * * @param $cid * The cache ID of the data to store. + * @param $data + * The data to store in the cache. Complex data types will be automatically + * serialized before insertion. Strings will be stored as plain text and + * not serialized. * @param $table * The table $table to store the data in. Valid core values are 'cache_filter', * 'cache_menu', 'cache_page', or 'cache'. - * @param $data - * The data to store in the cache. Complex data types must be serialized first. * @param $expire * One of the following values: * - CACHE_PERMANENT: Indicates that the item should never be removed unless @@ -115,14 +119,14 @@ function cache_get($key, $table = 'cache * It allows us to do a cache_set and not write to the database, but only * to memcache. */ -function cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $headers = NULL, $db_storage = TRUE) { - $time = time(); +function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL, $db_storage = TRUE) { + $created = time(); // Create new cache object. $cache = new stdClass; $cache->cid = $cid; $cache->data = is_object($data) ? memcache_clone($data) : $data; - $cache->created = $time; + $cache->created = $created; $cache->expire = $expire; $cache->headers = $headers; @@ -135,11 +139,12 @@ function cache_set($cid, $table = 'cache // Save to the database db_query("DELETE FROM {%s} WHERE cid = '%s'", $table, $cid); - db_query("INSERT INTO {%s} (data, created, expire, headers, serialized, cid) VALUES (%b, %d, %d, '%s', %d, '%s')", $table, $data, time(), $expire, $headers, $serialized, $cid); + db_query("INSERT INTO {%s} (cid, data, expire, created, headers, serialized) VALUES ('%s', %b, %d, %d, '%s', '%s')", $table, $cid, $data, $expire, $created, $headers, $serialized); } // Save to memcache if ($expire == CACHE_TEMPORARY) { + // 2591199 seconds = about 1 month $expire = variable_get('cache_lifetime', 2591999); } dmemcache_set($cid, $cache, $expire, $table); @@ -166,28 +171,14 @@ function cache_set($cid, $table = 'cache function cache_clear_all($cid = NULL, $table = NULL, $wildcard = FALSE) { global $user; - $bin = empty($table) ? 'cache_page' : $table; - // Memcache logic is simpler because memcache doesn't have a minimum cache - // lifetime consideration (it handles it internally), and doesn't support - // wildcards. - if (empty($cid) || ($cid == '*' && $wildcard !== TRUE)) { - # don't do anything if cid is unset. this matches the default drupal behavior... - if ($wildcard && $cid != '*') { - if (variable_get('memcache_debug', FALSE)) { - // call watchdog, since you probably didn't want to flush the entire bin. - watchdog('memcache', "illegal wildcard in cache_clear_all - not flushing entire bin. table: $table. cid: $cid", WATCHDOG_WARNING); - } - } - } - else if ($cid == '*' || $wildcard === TRUE) { - dmemcache_flush($table); - } - else { - dmemcache_delete($cid, $table); - } - + // Default behavior for when cache_clear_all() is called without parameters + // is to clear all of the expirable entries in the block and page caches. if (!isset($cid) && !isset($table)) { - cache_clear_all('*', 'cache_page', TRUE); + // Clear the block cache first, so stale data will + // not end up in the page cache. + cache_clear_all(NULL, 'cache_block'); + cache_clear_all(NULL, 'cache_page'); + return; } @@ -209,16 +200,25 @@ function cache_clear_all($cid = NULL, $t // passed since the first request to clear the cache. db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); variable_set('cache_flush', 0); + // Note there is no memcache flush here. + // Items are cached in memcache with an expiry equal to cache_lifetime + // and memcache will expire these automatically. } } else { // No minimum cache lifetime, flush all temporary cache entries now. + // Note, however, that memcache does not have the ability to discern + // between CACHE_PERMANENT and CACHE_TEMPORARY items. So having no + // minimum cache lifetime means that all CACHE_PERMANENT items are + // lost here, too. To avoid that, set a minimum cache lifetime. + dmemcache_flush($table); db_query("DELETE FROM {". $table ."} WHERE expire != %d AND expire < %d", CACHE_PERMANENT, time()); } } else { if ($wildcard) { if ($cid == '*') { + dmemcache_flush($table); db_query("DELETE FROM {". $table ."}"); } else { @@ -226,6 +226,7 @@ function cache_clear_all($cid = NULL, $t } } else { + dmemcache_delete($cid, $table); db_query("DELETE FROM {". $table ."} WHERE cid = '%s'", $cid); } } Index: memcache.inc =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache.inc,v retrieving revision 1.15.2.8 diff -u -p -r1.15.2.8 memcache.inc --- memcache.inc 12 Feb 2008 21:58:06 -0000 1.15.2.8 +++ memcache.inc 19 Oct 2008 19:39:22 -0000 @@ -7,15 +7,18 @@ require_once 'dmemcache.inc'; /** * Return data from the persistent cache. + * + * Data may be stored as either plain text or as serialized data. + * cache_get() will automatically return unserialized objects and arrays. * - * @param $key + * @param $cid * The cache ID of the data to retrieve. * @param $table * The table $table to store the data in. Valid core values are 'cache_filter', * 'cache_menu', 'cache_page', or 'cache' for the default cache. */ -function cache_get($key, $table = 'cache') { - return dmemcache_get($key, $table); +function cache_get($cid, $table = 'cache') { + return dmemcache_get($cid, $table); } /** @@ -23,11 +26,13 @@ function cache_get($key, $table = 'cache * * @param $cid * The cache ID of the data to store. + * @param $data + * The data to store in the cache. Complex data types will be automatically + * serialized before insertion. Strings will be stored as plain text and + * not serialized. * @param $table * The table $table to store the data in. Valid core values are 'cache_filter', * 'cache_menu', 'cache_page', or 'cache'. - * @param $data - * The data to store in the cache. Complex data types must be serialized first. * @param $expire * One of the following values: * - CACHE_PERMANENT: Indicates that the item should never be removed unless @@ -38,19 +43,15 @@ function cache_get($key, $table = 'cache * the given time, after which it behaves like CACHE_TEMPORARY. * @param $headers * A string containing HTTP header information for cached pages. - * @param $db_storage - * This boolean is unique to the memcache.inc implementation of cache set. - * It allows us to do a cache_set and not write to the database, but only - * to memcache. */ -function cache_set($cid, $table = 'cache', $data, $expire = CACHE_PERMANENT, $headers = NULL) { - $time = time(); +function cache_set($cid, $data, $table = 'cache', $expire = CACHE_PERMANENT, $headers = NULL) { + $created = time(); // Create new cache object. $cache = new stdClass; $cache->cid = $cid; $cache->data = is_object($data) ? memcache_clone($data) : $data; - $cache->created = $time; + $cache->created = $created; $cache->expire = $expire; $cache->headers = $headers; @@ -64,7 +65,7 @@ function cache_set($cid, $table = 'cache /** * * Expire data from the cache. If called without arguments, expirable - * entries will be cleared from the cache_page table. + * entries will be cleared from the cache_page and cache_block tables. * * @param $cid * If set, the cache ID to delete. Otherwise, all cache entries that can Index: memcache_admin/memcache_admin.info =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache_admin/memcache_admin.info,v retrieving revision 1.1.2.5 diff -u -p -r1.1.2.5 memcache_admin.info --- memcache_admin/memcache_admin.info 31 Jul 2007 14:51:36 -0000 1.1.2.5 +++ memcache_admin/memcache_admin.info 19 Oct 2008 19:39:22 -0000 @@ -1,5 +1,5 @@ -; $Id: memcache_admin.info,v 1.1.2.5 2007/07/31 14:51:36 robertDouglass Exp $ -name = Memcache Admin -description = Adds a User Interface to monitor the Memcache for this site. -package = Caching -dependencies = memcache +; $Id: memcache_admin.info,v 1.1.2.5 2007/07/31 14:51:36 robertDouglass Exp $ +name = Memcache Admin +description = Adds a User Interface to monitor the Memcache for this site. +package = Caching +core = 6.x Index: memcache_admin/memcache_admin.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/memcache/memcache_admin/memcache_admin.module,v retrieving revision 1.3.2.10 diff -u -p -r1.3.2.10 memcache_admin.module --- memcache_admin/memcache_admin.module 1 Aug 2008 10:24:33 -0000 1.3.2.10 +++ memcache_admin/memcache_admin.module 19 Oct 2008 19:39:22 -0000 @@ -1,251 +1,249 @@ - part of the HTML - * document. - */ -function memcache_admin_init() { - global $user; - if (($user->uid == 0) || strstr($_SERVER['PHP_SELF'], 'update.php') || strstr($_GET['q'], 'autocomplete')) { - // update.php relies on standard error handler - } - else { - if ($user->uid) { - drupal_add_js(drupal_get_path('module', 'memcache_admin'). '/memcache.js'); - } - register_shutdown_function('memcache_admin_shutdown'); - } -} - -/** - * Implementation of hook_perm - */ -function memcache_admin_perm() { - return array('access memcache statistics'); -} - -/** - * Implementation of hook_menu - */ -function memcache_admin_menu($may_cache) { - $items = array(); - - if ($may_cache) { - $items[] = array( - 'path' => 'admin/settings/memcache', - 'title' => t('Memcache'), - 'callback' => 'drupal_get_form', - 'callback arguments' => array('memcache_admin_admin_settings'), - 'access' => user_access('administer site configuration'), - 'type' => MENU_NORMAL_ITEM - ); - $items[] = array( - 'path' => 'admin/logs/memcache', - 'callback' => 'memcache_admin_stats', - 'title' => t('Memcache status'), - 'access' => user_access('access memcache statistics'), - 'description' => t("View the statistics for this site's memcache and generate new settings."), - 'weight' => 1, - ); - } - - else if (arg(0) == 'admin' && arg(1) == 'logs' && arg(2) == 'memcache') { - $memache_servers = variable_get('memcache_servers', array()); - $clusters = array(); - foreach($memache_servers as $server => $cluster) { - $clusters[$cluster]['servers'][] = $server; - $clusters[$cluster]['bin'] = _memcache_admin_get_bin_for_cluster($cluster); - } - - $count = 0; - foreach ($clusters as $cluster => $cluster_info) { - if ($cluster_info['bin']) { - if (empty($current_cluster)) { - $current_cluster = arg(3); - if (empty($current_cluster)) { - $current_cluster = $cluster; - } - } - - $items[] = array( - 'path' => 'admin/logs/memcache/' . $cluster, - 'type' => $count == 0 ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, - 'callback' => 'memcache_admin_stats', - 'callback arguments' => array($cluster), - 'title' => $cluster, - 'access' => user_access('access memcache statistics'), - 'weight' => $count, - ); - - $count++; - - if ($cluster == $current_cluster) { - $sub_count = 0; - foreach(array('default', 'reset', 'malloc', 'maps', 'slabs', 'items', 'sizes') as $type) { - $items[] = array( - 'path' => 'admin/logs/memcache/' . $cluster . '/' . $type, - 'type' => $type == 'default' ? MENU_DEFAULT_LOCAL_TASK : MENU_LOCAL_TASK, - 'callback' => 'memcache_admin_stats', - 'callback arguments' => array($cluster, $type), - 'title' => $type, - 'access' => user_access('access memcache statistics'), - 'weight' => $sub_count, - ); - $sub_count++; - } - } - } - } - } - - return $items; -} - -/** - * Settings form - */ -function memcache_admin_admin_settings() { - $form['show_memcache_statistics'] = array('#type' => 'checkbox', - '#title' => t('Show memcache statistics at the bottom of each page'), - '#default_value' => variable_get('show_memcache_statistics', 1), - '#description' => t("These statistics will be visible to users with the 'access memcache statistics' permission."), - ); - return system_settings_form($form); -} - -/** - * Memcahe Stats page - * - * @param string $cluster - which cluster to view? - * @param string $type - which type of stat, eg: default, reset, malloc, maps, cachedump, slabs, items or sizes - * @return string - */ -function memcache_admin_stats($cluster = 'default', $type = 'default') { - $bin = _memcache_admin_get_bin_for_cluster($cluster); - - if ($bin) { - $stats = dmemcache_stats($bin, $type); - - if (is_array($stats) && count($stats)) { - $output = ""; - - foreach ($stats as $server => $values) { - if (is_array($values)) { - //Do some custome value tweaks for specific stat page types. - switch ($type) { - case 'default' : - $values['uptime'] = format_interval($values['uptime']); - $values['time'] = format_date($values['time']); - $values['bytes'] = format_size($values['bytes']); - $values['bytes_read'] = format_size($values['bytes_read']); - $values['bytes_written'] = format_size($values['bytes_written']); - $values['limit_maxbytes'] = format_size($values['limit_maxbytes']); - - //Custom Entries - $values['hit_percentage'] = ($values['cmd_get'] > 0) - ? number_format(100.0 * $values['get_hits'] / $values['cmd_get'], 2) . '%' - : '0'; - - $mem_used = intval($values['bytes']) / (intval($values['limit_maxbytes']) * 1024); - $values['mem_used'] = number_format(100.0 * $mem_used, 2) . '%'; - break; - } - - $output .= theme('memcache_admin_stats_table', $server, $values); - } - else { - drupal_set_message(t('Unable to connect to server: %server', array('%server' => $server))); - } - } - } - - else { - $output = ''; - drupal_set_message(t('No available statistics for this bin.')); - } - } - - return $output; -} - - -/** - * Theme function for rendering the output from memcache_admin_stats - * - * @param string $server - Server name:port for caption for the table - * @param array $stats - array of key/value string pairs for the table results - * @return string - */ -function theme_memcache_admin_stats_table($server, $stats) { - $rows = array(); - - foreach ($stats as $key => $value) { - if (is_array($value)) { - $rs = array(); - foreach ($value as $k => $v) { - $rs[] = array($k, $v); - } - $rows[] = array($key, theme('table', array(), $rs)); - } - else { - $rows[] = array($key, $value); - } - } - - return theme('table', array(t('Property'), t('Value')), $rows, array(), $server); -} - - -/** - * Retrieve the cluster for any given bin - * - * @param string $cluster - Cluster ID - * @return string - */ -function _memcache_admin_get_bin_for_cluster($cluster) { - static $cluster_map = array(); - - if (!isset($cluster_map[$cluster])) { - $memache_bins = variable_get('memcache_bins', array()); - if ($mapping = array_search($cluster, $memache_bins)) { - $cluster_map[$cluster] = $mapping; - } - else { - $cluster_map[$cluster] = 'default'; - } - } - - return $cluster_map[$cluster]; -} - -/** - * See memcache_admin_init() which registers this function as a shutdown function. - * Displays memcache stats in the footer. - */ -function memcache_admin_shutdown() { - global $_memcache_statistics; - - // Try not to break non html pages. - if (function_exists('drupal_get_headers')) { - $headers = drupal_get_headers(); - if(strstr($headers, 'xml') || strstr($headers, 'javascript') || strstr($headers, 'plain')) { - return; - } - } - - if (variable_get('show_memcache_statistics', TRUE) && function_exists('user_access') && user_access('access memcache statistics')) { - $stats = array(); - - foreach ($_memcache_statistics as $stat => $val) { - $stats[] = "$stat: ". theme('item_list', $val); - } - if (!empty($stats)) { - $output = theme('item_list', $stats); - - // this makes sure all of the HTML is within the
even though this