cvs diff: Diffing modules/update Index: modules/update/update.compare.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/update/update.compare.inc,v retrieving revision 1.8.2.2 diff -u -p -r1.8.2.2 update.compare.inc --- modules/update/update.compare.inc 28 Aug 2008 08:14:56 -0000 1.8.2.2 +++ modules/update/update.compare.inc 28 Apr 2009 19:35:40 -0000 @@ -30,7 +30,7 @@ function update_get_projects() { _update_process_info_list($projects, module_rebuild_cache(), 'module'); _update_process_info_list($projects, system_theme_data(), 'theme'); // Set the projects array into the cache table. - cache_set('update_project_projects', $projects, 'cache_update', time() + 3600); + _update_cache_set('update_project_projects', $projects, time() + 3600); } } return $projects; @@ -551,7 +551,7 @@ function update_calculate_project_data($ drupal_alter('update_status', $projects); // Set the projects array into the cache table. - cache_set('update_project_data', $projects, 'cache_update', time() + 3600); + _update_cache_set('update_project_data', $projects, time() + 3600); return $projects; } @@ -584,10 +584,10 @@ function update_project_cache($cid) { $q = $_GET['q']; $paths = array('admin/build/modules', 'admin/build/themes', 'admin/reports', 'admin/reports/updates', 'admin/reports/status', 'admin/reports/updates/check'); if (in_array($q, $paths)) { - cache_clear_all($cid, 'cache_update'); + update_invalidate_cache($cid); } else { - $cache = cache_get($cid, 'cache_update'); + $cache = _update_cache_get($cid); if (!empty($cache->data) && $cache->expire > time()) { $projects = $cache->data; } Index: modules/update/update.fetch.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/update/update.fetch.inc,v retrieving revision 1.7.2.2 diff -u -p -r1.7.2.2 update.fetch.inc --- modules/update/update.fetch.inc 14 Jan 2009 21:36:16 -0000 1.7.2.2 +++ modules/update/update.fetch.inc 28 Apr 2009 19:35:40 -0000 @@ -52,7 +52,7 @@ function _update_refresh() { } if (!empty($available) && is_array($available)) { $frequency = variable_get('update_check_frequency', 1); - cache_set('update_info', $available, 'cache_update', time() + (60 * 60 * 24 * $frequency)); + _update_cache_set('update_info', $available, time() + (60 * 60 * 24 * $frequency)); variable_set('update_last_check', time()); watchdog('update', 'Fetched information about all available new releases and updates.', array(), WATCHDOG_NOTICE, l(t('view'), 'admin/reports/updates')); } Index: modules/update/update.module =================================================================== RCS file: /cvs/drupal/drupal/modules/update/update.module,v retrieving revision 1.17.2.1 diff -u -p -r1.17.2.1 update.module --- modules/update/update.module 23 Sep 2008 10:19:02 -0000 1.17.2.1 +++ modules/update/update.module 28 Apr 2009 19:35:40 -0000 @@ -286,9 +286,9 @@ function _update_requirement_check($proj function update_cron() { $frequency = variable_get('update_check_frequency', 1); $interval = 60 * 60 * 24 * $frequency; - // Cron should check for updates if there is no update data cached or if the configured - // update interval has elapsed. - if (!cache_get('update_info', 'cache_update') || ((time() - variable_get('update_last_check', 0)) > $interval)) { + // Cron should check for updates if there is no update data cached or if the + // configured update interval has elapsed. + if (!_update_cache_get('update_info') || ((time() - variable_get('update_last_check', 0)) > $interval)) { update_refresh(); _update_cron_notify(); } @@ -353,8 +353,7 @@ function update_get_available($refresh = break; } } - if (!$needs_refresh && ($cache = cache_get('update_info', 'cache_update')) - && $cache->expire > time()) { + if (!$needs_refresh && ($cache = _update_cache_get('update_info')) && $cache->expire > time()) { $available = $cache->data; } elseif ($needs_refresh || $refresh) { @@ -378,13 +377,6 @@ function update_flush_caches() { } /** - * Invalidates any cached data relating to update status. - */ -function update_invalidate_cache() { - cache_clear_all('*', 'cache_update', TRUE); -} - -/** * Wrapper to load the include file and then refresh the release data. */ function update_refresh() { @@ -514,3 +506,92 @@ function _update_project_status_sort($a, $b_status = $b['status'] > 0 ? $b['status'] : (-10 * $b['status']); return $a_status - $b_status; } + +/** + * @defgroup update_status_cache Private update status cache system + * @{ + * + * We specifically do NOT use the core cache API for saving the fetched data + * about available updates. It is vitally important that this cache is only + * cleared when we're populating it after successfully fetching new available + * update data. When we relied on the core cache API, there were all sorts of + * potential problems that would result in attempting to fetch available + * update data all the time, including if a site sets a so-called "minimum + * cache lifetime" (which is both a minimum and a maximum), or if a site uses + * memcache. + * + * We continue to use the {cache_update} table, but instead of using + * cache_set(), cache_get(), and cache_clear_all(), there are private helper + * functions that implement these same basic tasks but ensure that the cache + * is not prematurely cleared, and that the data is always stored in the + * database, even if memcache is in use. + */ + +/** + * Store data in the private update status cache table. + * + * Note: this function completely ignores the {cache_update}.headers field + * since that is meaningless for the kinds of data we're caching. + * + * @param $cid + * The cache ID to save the data with. + * @param $data + * The data to store. + * @param $expire + * One of the following values: + * - CACHE_PERMANENT: Indicates that the item should never be removed unless + * explicitly told to using update_invalidate_cache(). + * - A Unix timestamp: Indicates that the item should be kept at least until + * the given time, after which it will be invalidated. + */ +function _update_cache_set($cid, $data, $expire) { + $serialized = 0; + if (is_object($data) || is_array($data)) { + $data = serialize($data); + $serialized = 1; + } + $created = time(); + db_query("UPDATE {cache_update} SET data = %b, created = %d, expire = %d, serialized = %d WHERE cid = '%s'", $data, $created, $expire, $serialized, $cid); + if (!db_affected_rows()) { + @db_query("INSERT INTO {cache_update} (cid, data, created, expire, serialized) VALUES ('%s', %b, %d, %d, %d)", $cid, $data, $created, $expire, $serialized); + } +} + +/** + * Retrieve data from the private update status cache table. + * + * @param $cid + * The cache ID to retrieve. + * @return + * The data for the given cache ID, or NULL if the ID was not found. + */ +function _update_cache_get($cid) { + $cache = db_fetch_object(db_query("SELECT data, created, expire, serialized FROM {cache_update} WHERE cid = '%s'", $cid)); + if (isset($cache->data)) { + $cache->data = db_decode_blob($cache->data); + if ($cache->serialized) { + $cache->data = unserialize($cache->data); + } + } + return $cache; +} + +/** + * Invalidates cached data relating to update status. + * + * @param $cid + * Optional cache ID of the record to clear from the private update module + * cache. If empty, all records will be cleared from the table. + */ +function update_invalidate_cache($cid = NULL) { + if (empty($cid)) { + db_query("DELETE FROM {cache_update}"); + } + else { + db_query("DELETE FROM {cache_update} WHERE cid = '%s'", $cid); + } +} + +/** + * @} End of "defgroup update_status_cache". + */