.../Drupal/Core/KeyValueStore/DatabaseStorage.php | 7 + .../Core/KeyValueStore/KeyValueStoreInterface.php | 5 + .../Drupal/Core/KeyValueStore/MemoryStorage.php | 6 + core/modules/system/theme.api.php | 2 +- .../lib/Drupal/update/Tests/UpdateCoreTest.php | 4 +- core/modules/update/update.authorize.inc | 28 +-- core/modules/update/update.compare.inc | 74 ++++--- core/modules/update/update.fetch.inc | 66 +++--- core/modules/update/update.install | 16 +- core/modules/update/update.module | 211 ++++---------------- core/modules/update/update.settings.inc | 6 +- 11 files changed, 135 insertions(+), 290 deletions(-) diff --git a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php index d36fd30..3cc1303 100644 --- a/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php +++ b/core/lib/Drupal/Core/KeyValueStore/DatabaseStorage.php @@ -123,4 +123,11 @@ class DatabaseStorage extends StorageBase { while (count($keys)); } + /** + * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteAll(). + */ + public function deleteAll() { + db_delete($this->table) + ->execute(); + } } diff --git a/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php index 0b653b5..1a6c467 100644 --- a/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php +++ b/core/lib/Drupal/Core/KeyValueStore/KeyValueStoreInterface.php @@ -109,4 +109,9 @@ interface KeyValueStoreInterface { */ public function deleteMultiple(array $keys); + /** + * Deletes all items from the key/value store. + */ + public function deleteAll(); + } diff --git a/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php b/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php index a025dbc..6f6aca5 100644 --- a/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php +++ b/core/lib/Drupal/Core/KeyValueStore/MemoryStorage.php @@ -98,4 +98,10 @@ class MemoryStorage implements KeyValueStoreInterface { } } + /** + * Implements Drupal\Core\KeyValueStore\KeyValueStoreInterface::deleteAll(). + */ + public function deleteAll() { + $this->data = array(); + } } diff --git a/core/modules/system/theme.api.php b/core/modules/system/theme.api.php index 0001cba..a697eef 100644 --- a/core/modules/system/theme.api.php +++ b/core/modules/system/theme.api.php @@ -234,5 +234,5 @@ function hook_themes_enabled($theme_list) { */ function hook_themes_disabled($theme_list) { // Clear all update module caches. - _update_cache_clear(); + update_storage_clear(); } diff --git a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreTest.php b/core/modules/update/lib/Drupal/update/Tests/UpdateCoreTest.php index 5dc09fd..dd9626b 100644 --- a/core/modules/update/lib/Drupal/update/Tests/UpdateCoreTest.php +++ b/core/modules/update/lib/Drupal/update/Tests/UpdateCoreTest.php @@ -210,8 +210,8 @@ class UpdateCoreTest extends UpdateTestBase { update_create_fetch_task($projecta); $this->assertEqual($queue->numberOfItems(), 2, 'Queue still contains two items'); - // Clear cache and try again. - _update_cache_clear(); + // Clear storage and try again. + update_storage_clear(); drupal_static_reset('_update_create_fetch_task'); update_create_fetch_task($projecta); $this->assertEqual($queue->numberOfItems(), 2, 'Queue contains two items'); diff --git a/core/modules/update/update.authorize.inc b/core/modules/update/update.authorize.inc index d22f235..396fa75 100644 --- a/core/modules/update/update.authorize.inc +++ b/core/modules/update/update.authorize.inc @@ -177,7 +177,7 @@ function update_authorize_batch_copy_project($project, $updater_name, $local_url * * This processes the results and stashes them into SESSION such that * authorize.php will render a report. Also responsible for putting the site - * back online and clearing the update status cache after a successful update. + * back online and clearing the update status storage after a successful update. * * @param $success * TRUE if the batch operation was successful; FALSE if there were errors. @@ -192,8 +192,8 @@ function update_authorize_update_batch_finished($success, $results) { } $offline = config('system.maintenance')->get('enabled'); if ($success) { - // Now that the update completed, we need to clear the cache of available - // update data and recompute our status, so prevent show bogus results. + // Now that the update completed, we need to clear the available update data + // and recompute our status, so prevent show bogus results. _update_authorize_clear_update_status(); // Take the site out of maintenance mode if it was previously that way. @@ -314,25 +314,19 @@ function _update_batch_create_message(&$project_results, $message, $success = TR } /** - * Clears cached available update status data. + * Clears available update status data. * * Since this function is run at such a low bootstrap level, the Update Manager - * module is not loaded. So, we can't just call _update_cache_clear(). However, - * the database is bootstrapped, so we can do a query ourselves to clear out - * what we want to clear. + * module is not loaded. So, we can't just call update_storage_clear(). However, + * the key-value backend is available, so we just call that. * - * Note that we do not want to just truncate the table, since that would remove - * items related to currently pending fetch attempts. + * Note that we do not want to delete items related to currently pending fetch + * attempts. * * @see update_authorize_update_batch_finished() - * @see _update_cache_clear() + * @see update_storage_clear() */ function _update_authorize_clear_update_status() { - $query = db_delete('cache_update'); - $query->condition( - db_or() - ->condition('cid', 'update_project_%', 'LIKE') - ->condition('cid', 'available_releases::%', 'LIKE') - ); - $query->execute(); + DatabaseStorageExpirable('update', array('connection' => Database::getConnection()))->deleteAll(); + DatabaseStorageExpirable('update_available_releases', array('connection' => Database::getConnection()))->deleteAll(); } diff --git a/core/modules/update/update.compare.inc b/core/modules/update/update.compare.inc index 2262404..9d0aa4b 100644 --- a/core/modules/update/update.compare.inc +++ b/core/modules/update/update.compare.inc @@ -16,13 +16,12 @@ * fetching the available release data. * * This array is fairly expensive to construct, since it involves a lot of disk - * I/O, so we cache the results into the {cache_update} table using the - * 'update_project_projects' cache ID. However, since this is not the data about + * I/O, so we store the results. However, since this is not the data about * available updates fetched from the network, it is acceptable to invalidate it * somewhat quickly. If we keep this data for very long, site administrators are * more likely to see incorrect results if they upgrade to a newer version of a * module or theme but do not visit certain pages that automatically clear this - * cache. + * data. * * @return * An associative array of currently enabled projects keyed by the @@ -51,15 +50,15 @@ * * @see update_process_project_info() * @see update_calculate_project_data() - * @see update_project_cache() + * @see update_project_storage() */ function update_get_projects() { $projects = &drupal_static(__FUNCTION__, array()); if (empty($projects)) { - // Retrieve the projects from cache, if present. - $projects = update_project_cache('update_project_projects'); + // Retrieve the projects from storage, if present. + $projects = update_project_storage('update_project_projects'); if (empty($projects)) { - // Still empty, so we have to rebuild the cache. + // Still empty, so we have to rebuild. $module_data = system_rebuild_module_data(); $theme_data = system_rebuild_theme_data(); update_process_info_list($projects, $module_data, 'module', TRUE); @@ -70,8 +69,8 @@ function update_get_projects() { } // Allow other modules to alter projects before fetching and comparing. drupal_alter('update_projects', $projects); - // Cache the site's project data for at most 1 hour. - _update_cache_set('update_project_projects', $projects, REQUEST_TIME + 3600); + // Store the site's project data for at most 1 hour. + update_storage()->setWithExpire('update_project_projects', $projects, 3600); } } return $projects; @@ -89,7 +88,7 @@ function update_get_projects() { * enabled code. Modules and themes set as hidden are always ignored. This * function also records the latest change time on the .info files for each * module or theme, which is important data which is used when deciding if the - * cached available update data should be invalidated. + * available update data should be invalidated. * * @param $projects * Reference to the array of project data of what's installed on this site. @@ -316,13 +315,12 @@ function update_process_project_info(&$projects) { * * The results of this function are expensive to compute, especially on sites * with lots of modules or themes, since it involves a lot of comparisons and - * other operations. Therefore, we cache the results into the {cache_update} - * table using the 'update_project_data' cache ID. However, since this is not + * other operations. Therefore, we store the results. However, since this is not * the data about available updates fetched from the network, it is ok to * invalidate it somewhat quickly. If we keep this data for very long, site * administrators are more likely to see incorrect results if they upgrade to a * newer version of a module or theme but do not visit certain pages that - * automatically clear this cache. + * automatically clear this. * * @param array $available * Data about available project releases. @@ -333,13 +331,13 @@ function update_process_project_info(&$projects) { * @see update_get_available() * @see update_get_projects() * @see update_process_project_info() - * @see update_project_cache() + * @see update_project_storage() */ function update_calculate_project_data($available) { - // Retrieve the projects from cache, if present. - $projects = update_project_cache('update_project_data'); - // If $projects is empty, then the cache must be rebuilt. - // Otherwise, return the cached data and skip the rest of the function. + // Retrieve the projects from storage, if present. + $projects = update_project_storage('update_project_data'); + // If $projects is empty, then the data must be rebuilt. + // Otherwise, return the data and skip the rest of the function. if (!empty($projects)) { return $projects; } @@ -359,8 +357,8 @@ function update_calculate_project_data($available) { // projects or releases). drupal_alter('update_status', $projects); - // Cache the site's update status for at most 1 hour. - _update_cache_set('update_project_data', $projects, REQUEST_TIME + 3600); + // Store the site's update status for at most 1 hour. + update_storage()->setWithExpire('update_project_data', $projects, 3600); return $projects; } @@ -750,37 +748,36 @@ function update_calculate_project_update_status(&$project_data, $available) { } /** - * Retrieves data from {cache_update} or empties the cache when necessary. + * Retrieves update storage data or empties it. * * Two very expensive arrays computed by this module are the list of all * installed modules and themes (and .info data, project associations, etc), and * the current status of the site relative to the currently available releases. - * These two arrays are cached in the {cache_update} table and used whenever - * possible. The cache is cleared whenever the administrator visits the status - * report, available updates report, or the module or theme administration - * pages, since we should always recompute the most current values on any of - * those pages. + * These two arrays are stored and used whenever possible. The data is cleared + * whenever the administrator visits the status report, available updates + * report, or the module or theme administration pages, since we should always + * recompute the most current values on any of those pages. * * Note: while both of these arrays are expensive to compute (in terms of disk * I/O and some fairly heavy CPU processing), neither of these is the actual * data about available updates that we have to fetch over the network from - * updates.drupal.org. That information is stored with the - * 'update_available_releases' cache ID -- it needs to persist longer than 1 + * updates.drupal.org. That information is stored in the + * 'update_available_releases' collection -- it needs to persist longer than 1 * hour and never get invalidated just by visiting a page on the site. * - * @param $cid - * The cache ID of data to return from the cache. Valid options are - * 'update_project_data' and 'update_project_projects'. + * @param $key + * The key of data to return. Valid options are 'update_project_data' and + * 'update_project_projects'. * * @return - * The cached value of the $projects array generated by + * The stored value of the $projects array generated by * update_calculate_project_data() or update_get_projects(), or an empty array - * when the cache is cleared. + * when the storage is cleared. */ -function update_project_cache($cid) { +function update_project_storage($key) { $projects = array(); - // On certain paths, we should clear the cache and recompute the projects for + // On certain paths, we should clear the data and recompute the projects for // update status of the site to avoid presenting stale information. $paths = array( 'admin/modules', @@ -794,13 +791,10 @@ function update_project_cache($cid) { 'admin/reports/updates/check', ); if (in_array(current_path(), $paths)) { - _update_cache_clear($cid); + update_storage()->delete($key); } else { - $cache = _update_cache_get($cid); - if (!empty($cache->data) && $cache->expire > REQUEST_TIME) { - $projects = $cache->data; - } + $projects = update_storage()->get($key); } return $projects; } diff --git a/core/modules/update/update.fetch.inc b/core/modules/update/update.fetch.inc index a4d1bd7..3157547 100644 --- a/core/modules/update/update.fetch.inc +++ b/core/modules/update/update.fetch.inc @@ -117,8 +117,8 @@ function _update_fetch_data() { /** * Processes a task to fetch available update data for a single project. * - * Once the release history XML data is downloaded, it is parsed and saved into - * the {cache_update} table in an entry just for that project. + * Once the release history XML data is downloaded, it is parsed and saved in an + * entry just for that project. * * @param $project * Associative array of information about the project to fetch data for. @@ -132,13 +132,11 @@ function _update_process_fetch_task($project) { $fail = &drupal_static(__FUNCTION__, array()); // This can be in the middle of a long-running batch, so REQUEST_TIME won't // necessarily be valid. - $now = time(); + $request_time_difference = time() - REQUEST_TIME; if (empty($fail)) { // If we have valid data about release history XML servers that we have - // failed to fetch from on previous attempts, load that from the cache. - if (($cache = _update_cache_get('fetch_failures')) && ($cache->expire > $now)) { - $fail = $cache->data; - } + // failed to fetch from on previous attempts, load that. + $fail = update_storage()->get('fetch_failures'); } $max_fetch_attempts = $update_config->get('fetch.max_attempts'); @@ -179,43 +177,42 @@ function _update_process_fetch_task($project) { } $frequency = $update_config->get('check.interval_days'); - $cid = 'available_releases::' . $project_name; - _update_cache_set($cid, $available, $now + (60 * 60 * 24 * $frequency)); + update_storage('update_available_releases')->setWithExpire($project_name, $available, $request_time_difference + (60 * 60 * 24 * $frequency)); // Stash the $fail data back in the DB for the next 5 minutes. - _update_cache_set('fetch_failures', $fail, $now + (60 * 5)); + update_storage()->setWithExpire('fetch_failures', $fail, $request_time_difference + (60 * 5)); // Whether this worked or not, we did just (try to) check for updates. - variable_set('update_last_check', $now); + variable_set('update_last_check', REQUEST_TIME + $request_time_difference); // Now that we processed the fetch task for this project, clear out the - // record in {cache_update} for this task so we're willing to fetch again. - _update_cache_clear('fetch_task::' . $project_name); + // record for this task so we're willing to fetch again. + update_storage('update_fetch_task')->delete($project_name); return $success; } /** - * Clears out all the cached available update data and initiates re-fetching. + * Clears out all the available update data and initiates re-fetching. */ function _update_refresh() { module_load_include('inc', 'update', 'update.compare'); // Since we're fetching new available update data, we want to clear - // our cache of both the projects we care about, and the current update - // status of the site. We do *not* want to clear the cache of available + // both the projects we care about, and the current update + // status of the site. We do *not* want to clear the data of available // releases just yet, since that data (even if it's stale) can be useful // during update_get_projects(); for example, to modules that implement // hook_system_info_alter() such as cvs_deploy. - _update_cache_clear('update_project_projects'); - _update_cache_clear('update_project_data'); + update_storage()->delete('update_project_projects'); + update_storage()->delete('update_project_data'); $projects = update_get_projects(); - // Now that we have the list of projects, we should also clear our cache of - // available release data, since even if we fail to fetch new data, we need + // Now that we have the list of projects, we should also clear the available + // release data, since even if we fail to fetch new data, we need // to clear out the stale data at this point. - _update_cache_clear('available_releases::', TRUE); + update_storage('available_releases')->deleteAll(); foreach ($projects as $key => $project) { update_create_fetch_task($project); @@ -226,8 +223,7 @@ function _update_refresh() { * Adds a task to the queue for fetching release history data for a project. * * We only create a new fetch task if there's no task already in the queue for - * this particular project (based on 'fetch_task::' entries in the - * {cache_update} table). + * this particular project (based on 'update_fetch_task' key-value collection). * * @param $project * Associative array of information about a project as created by @@ -243,29 +239,13 @@ function _update_refresh() { function _update_create_fetch_task($project) { $fetch_tasks = &drupal_static(__FUNCTION__, array()); if (empty($fetch_tasks)) { - $fetch_tasks = _update_get_cache_multiple('fetch_task'); + $fetch_tasks = update_storage('update_fetch_task')->getAll(); } - $cid = 'fetch_task::' . $project['name']; - if (empty($fetch_tasks[$cid])) { + if (empty($fetch_tasks[$project['name']])) { $queue = queue('update_fetch_tasks'); $queue->createItem($project); - // Due to race conditions, it is possible that another process already - // inserted a row into the {cache_update} table and the following query will - // throw an exception. - // @todo: Remove the need for the manual check by relying on a queue that - // enforces unique items. - try { - db_insert('cache_update') - ->fields(array( - 'cid' => $cid, - 'created' => REQUEST_TIME, - )) - ->execute(); - } - catch (Exception $e) { - // The exception can be ignored safely. - } - $fetch_tasks[$cid] = REQUEST_TIME; + update_storage('update_fetch_task')->set($project['name'], $project); + $fetch_tasks[$project['name']] = REQUEST_TIME; } } diff --git a/core/modules/update/update.install b/core/modules/update/update.install index 14efc3a..8eedda1 100644 --- a/core/modules/update/update.install +++ b/core/modules/update/update.install @@ -57,15 +57,6 @@ function update_requirements($phase) { } /** - * Implements hook_schema(). - */ -function update_schema() { - $schema['cache_update'] = drupal_get_schema_unprocessed('system', 'cache'); - $schema['cache_update']['description'] = 'Cache table for the Update module to store information about available releases, fetched from central server.'; - return $schema; -} - -/** * Implements hook_install(). */ function update_install() { @@ -162,3 +153,10 @@ function update_update_8000() { 'update_notification_threshold' => 'notification.threshold', )); } + +/** + * Delete the {cache_update} table. + */ +function update_update_8001() { + db_delete('cache_update'); +} diff --git a/core/modules/update/update.module b/core/modules/update/update.module index 51e77e6..b4551a3 100644 --- a/core/modules/update/update.module +++ b/core/modules/update/update.module @@ -1,5 +1,8 @@ $interval) { // If the configured update interval has elapsed, we want to invalidate - // the cached data for all projects, attempt to re-fetch, and trigger any + // the data for all projects, attempt to re-fetch, and trigger any // configured notifications about the new status. update_refresh(); update_fetch_data(); @@ -311,33 +314,33 @@ function update_cron() { /** * Implements hook_themes_enabled(). * - * If themes are enabled, we invalidate the cache of available updates. + * If themes are enabled, we invalidate the information of available updates. */ function update_themes_enabled($themes) { - // Clear all update module caches. - _update_cache_clear(); + // Clear all update module data. + update_storage_clear(); } /** * Implements hook_themes_disabled(). * - * If themes are disabled, we invalidate the cache of available updates. + * If themes are disabled, we invalidate the information of available updates. */ function update_themes_disabled($themes) { - // Clear all update module caches. - _update_cache_clear(); + // Clear all update module data. + update_storage_clear(); } /** * Implements hook_form_FORM_ID_alter() for system_modules(). * * Adds a form submission handler to the system modules form, so that if a site - * admin saves the form, we invalidate the cache of available updates. + * admin saves the form, we invalidate the information of available updates. * * @see _update_cache_clear() */ function update_form_system_modules_alter(&$form, $form_state) { - $form['#submit'][] = 'update_cache_clear_submit'; + $form['#submit'][] = 'update_storage_clear_submit'; } /** @@ -345,9 +348,9 @@ function update_form_system_modules_alter(&$form, $form_state) { * * @see update_form_system_modules_alter() */ -function update_cache_clear_submit($form, &$form_state) { - // Clear all update module caches. - _update_cache_clear(); +function update_storage_clear_submit($form, &$form_state) { + // Clear all update module data. + update_storage_clear(); } /** @@ -362,9 +365,9 @@ function _update_no_data() { } /** - * Tries to get update information from cache and refreshes it when necessary. + * Tries to get update information and refreshes it when necessary. * - * In addition to checking the cache lifetime, this function also ensures that + * In addition to checking the lifetime, this function also ensures that * there are no .info files for enabled modules or themes that have a newer * modification timestamp than the last time we checked for available update * data. If any .info file was modified, it almost certainly means a new version @@ -373,8 +376,8 @@ function _update_no_data() { * results. * * @param $refresh - * (optional) Boolean to indicate if this method should refresh the cache - * automatically if there's no data. Defaults to FALSE. + * (optional) Boolean to indicate if this method should refresh automatically + * if there's no data. Defaults to FALSE. * * @return * Array of data about available releases, keyed by project shortname. @@ -386,9 +389,8 @@ function update_get_available($refresh = FALSE) { module_load_include('inc', 'update', 'update.compare'); $needs_refresh = FALSE; - // Grab whatever data we currently have cached in the DB. - $available = _update_get_cached_available_releases(); - $num_avail = count($available); + // Grab whatever data we currently have. + $available = update_storage('update_available_releases')->getAll(); $projects = update_get_projects(); foreach ($projects as $key => $project) { @@ -426,8 +428,8 @@ function update_get_available($refresh = FALSE) { // Attempt to drain the queue of fetch tasks. update_fetch_data(); // After processing the queue, we've (hopefully) got better data, so pull - // the latest from the cache again and use that directly. - $available = _update_get_cached_available_releases(); + // the latest data again and use that directly. + $available = update_storage('update_available_releases')->getAll(); } return $available; @@ -468,29 +470,6 @@ function update_fetch_data() { } /** - * Returns all currently cached data about available releases for all projects. - * - * @return - * Array of data about available releases, keyed by project shortname. - */ -function _update_get_cached_available_releases() { - $data = array(); - $cache_items = _update_get_cache_multiple('available_releases'); - foreach ($cache_items as $cid => $cache) { - $cache->data['last_fetch'] = $cache->created; - if ($cache->expire < REQUEST_TIME) { - $cache->data['fetch_status'] = UPDATE_FETCH_PENDING; - } - // The project shortname is embedded in the cache ID, even if there's no - // data for this project in the DB at all, so use that for the indexes in - // the array. - $parts = explode('::', $cid, 2); - $data[$parts[1]] = $cache->data; - } - return $data; -} - -/** * Implements hook_mail(). * * Constructs the e-mail notification message when the site is out of date. @@ -725,137 +704,23 @@ function update_verify_update_archive($project, $archive_file, $directory) { } /** - * @defgroup update_status_cache Private update status cache system - * @{ - * Functions to manage the update status cache. - * - * 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. Usage of the core cache API results in all sorts of potential - * problems that would result in attempting to fetch available update data all - * the time, including if a site has a "minimum cache lifetime" (which is both a - * minimum and a maximum) defined, or if a site uses memcache or another - * pluggable cache system that assumes volatile caches. - * - * The Update Manager module still uses the {cache_update} table, but instead of - * using the cache API, 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 or another - * cache backend is in use. - */ - -/** - * Stores data in the private update status cache table. - * - * @param $cid - * The cache ID to save the data with. - * @param $data - * The data to store. - * @param $expire - * One of the following values: - * - CacheBackendInterface::CACHE_PERMANENT: Indicates that the item should - * never be removed except by explicitly using _update_cache_clear(). - * - A Unix timestamp: Indicates that the item should be kept at least until - * the given time, after which it will be invalidated. - * - * @see _update_cache_get() - */ -function _update_cache_set($cid, $data, $expire) { - $fields = array( - 'created' => REQUEST_TIME, - 'expire' => $expire, - ); - if (!is_string($data)) { - $fields['data'] = serialize($data); - $fields['serialized'] = 1; - } - else { - $fields['data'] = $data; - $fields['serialized'] = 0; - } - db_merge('cache_update') - ->key(array('cid' => $cid)) - ->fields($fields) - ->execute(); -} - -/** - * Retrieves data from the private update status cache table. - * - * @param $cid - * The cache ID to retrieve. - * - * @return - * An array of data for the given cache ID, or NULL if the ID was not found. * - * @see _update_cache_set() + * @return Drupal\Core\KeyValueStore\KeyValueStoreExpirableInterface */ -function _update_cache_get($cid) { - $cache = db_query("SELECT data, created, expire, serialized FROM {cache_update} WHERE cid = :cid", array(':cid' => $cid))->fetchObject(); - if (isset($cache->data)) { - if ($cache->serialized) { - $cache->data = unserialize($cache->data); - } - } - return $cache; -} - -/** - * Returns an array of cache items with a given cache ID prefix. - * - * @param string $cid_prefix - * The cache ID prefix. - * - * @return - * Associative array of cache items, keyed by cache ID. - */ -function _update_get_cache_multiple($cid_prefix) { - $data = array(); - $result = db_select('cache_update') - ->fields('cache_update', array('cid', 'data', 'created', 'expire', 'serialized')) - ->condition('cache_update.cid', $cid_prefix . '::%', 'LIKE') - ->execute(); - foreach ($result as $cache) { - if ($cache) { - if ($cache->serialized) { - $cache->data = unserialize($cache->data); - } - $data[$cache->cid] = $cache; - } +function update_storage($collection = 'update') { + $storage = &drupal_static(__FUNCTION__); + if (!isset($storage[$collection])) { + $storage[$collection] = new DatabaseStorageExpirable($collection, array('connection' => Database::getConnection())); } - return $data; + return $storage[$collection]; } /** - * 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 except fetch - * tasks. Defaults to NULL. - * @param $wildcard - * (optional) If TRUE, cache IDs starting with $cid are deleted in addition to - * the exact cache ID specified by $cid. Defaults to FALSE. + * Invalidates stored data relating to update status. */ -function _update_cache_clear($cid = NULL, $wildcard = FALSE) { - if (empty($cid)) { - db_delete('cache_update') - // Clear everything except fetch task information because these are used - // to ensure that the fetch task queue items are not added multiple times. - ->condition('cid', 'fetch_task::%', 'NOT LIKE') - ->execute(); - } - else { - $query = db_delete('cache_update'); - if ($wildcard) { - $query->condition('cid', $cid . '%', 'LIKE'); - } - else { - $query->condition('cid', $cid); - } - $query->execute(); - } +function update_storage_clear() { + update_storage()->deleteAll(); + update_storage('update_available_release')->deleteAll(); } /** @@ -864,8 +729,8 @@ function _update_cache_clear($cid = NULL, $wildcard = FALSE) { * Called from update.php (among others) to flush the caches. Since we're * running update.php, we are likely to install a new version of something, in * which case, we want to check for available update data again. However, - * because we have our own caching system, we need to directly clear the - * the database table ourselves at this point and return nothing. + * because we use the key value storage system, we need to clear directly at + * this point and return nothing. * * However, we only want to do this from update.php, since otherwise, we'd lose * all the available update data on every cron run. So, we specifically check if @@ -874,16 +739,12 @@ function _update_cache_clear($cid = NULL, $wildcard = FALSE) { */ function update_cache_flush() { if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') { - _update_cache_clear(); + update_storage_clear(); } return array(); } /** - * @} End of "defgroup update_status_cache". - */ - -/** * Returns a short unique identifier for this Drupal installation. * * @return diff --git a/core/modules/update/update.settings.inc b/core/modules/update/update.settings.inc index 0a5e337..442510b 100644 --- a/core/modules/update/update.settings.inc +++ b/core/modules/update/update.settings.inc @@ -92,7 +92,7 @@ function update_settings_validate($form, &$form_state) { /** * Form submission handler for update_settings(). * - * Also invalidates the cache of available updates if the "Check for updates of + * Also invalidates the data of available updates if the "Check for updates of * disabled modules and themes" setting is being changed. The available updates * report needs to refetch available update data after this setting changes or * it would show misleading things (e.g., listing the disabled projects on the @@ -104,9 +104,9 @@ function update_settings_submit($form, $form_state) { $config = config('update.settings'); // See if the update_check_disabled setting is being changed, and if so, - // invalidate all cached update status data. + // invalidate all update status data. if ($form_state['values']['update_check_disabled'] != $config->get('check.disabled_extensions')) { - _update_cache_clear(); + update_storage_clear(); } $config