diff -uprN modules/update_status/update_status.install modules/update_status_new/update_status.install
--- modules/update_status/update_status.install	2007-08-15 10:54:00.000000000 -0500
+++ modules/update_status_new/update_status.install	2009-05-10 15:47:55.351003037 -0500
@@ -2,6 +2,33 @@
 // $Id: update_status.install,v 1.1.2.6 2007/08/15 15:54:00 dww Exp $
 
 /**
+ * Implementation of hook_install().
+ */
+function update_status_install() {
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      db_query("CREATE TABLE {cache_update_status} (
+        cid varchar(255) NOT NULL default '',
+        data longblob,
+        expire int(11) NOT NULL default '0',
+        created int(11) NOT NULL default '0',
+        PRIMARY KEY (cid)
+      )");
+      break;
+    case 'pgsql':
+      db_query("CREATE TABLE {cache_update_status} (
+        cid varchar(255) NOT NULL default '',
+        data bytea,
+        expire int NOT NULL default '0',
+        created int NOT NULL default '0',
+        PRIMARY KEY (cid)
+      )");
+      break;
+  }
+}
+
+/**
  * Implementation of hook_uninstall().
  */
 function update_status_uninstall() {
@@ -16,6 +43,7 @@ function update_status_uninstall() {
   foreach ($variables as $variable) {
     variable_del($variable);
   }
+  db_query("DROP TABLE {cache_update}");
   cache_clear_all();
 }
 
@@ -62,3 +90,32 @@ function update_status_update_5202() {
   menu_rebuild();
   return $ret;
 }
+
+/**
+ * Backport cache functionality from 6.x (#155450.)
+ */
+function update_status_update_5205() {
+  $ret = array();
+  switch ($GLOBALS['db_type']) {
+    case 'mysql':
+    case 'mysqli':
+      $ret[] = update_sql("CREATE TABLE {cache_update_status} (
+        cid varchar(255) NOT NULL default '',
+        data longblob,
+        expire int(11) NOT NULL default '0',
+        created int(11) NOT NULL default '0',
+        PRIMARY KEY (cid)
+      )");
+      break;
+    case 'pgsql':
+      $ret[] = update_sql("CREATE TABLE {cache_update_status} (
+        cid varchar(255) NOT NULL default '',
+        data bytea,
+        expire int NOT NULL default '0',
+        created int NOT NULL default '0',
+        PRIMARY KEY (cid)
+      )");
+      break;
+  }
+  return $ret;
+}
diff -uprN modules/update_status/update_status.module modules/update_status_new/update_status.module
--- modules/update_status/update_status.module	2008-08-14 14:01:19.000000000 -0500
+++ modules/update_status_new/update_status.module	2009-05-10 16:25:33.097442821 -0500
@@ -390,7 +390,7 @@ function update_status_requirements($pha
  *
  * @param $project
  *  Array of information about the project we're testing as returned by
- *  update_calculate_project_data().
+ *  update_status_calculate_project_data().
  * @param $type
  *  What kind of project is this ('core' or 'contrib').
  *
@@ -460,7 +460,7 @@ function update_status_cron() {
  * Perform any notifications that should be done once cron fetches new data.
  *
  * This method checks the status of the site using the new data and depending
- * on the configuration of the site, notifys administrators via email if there
+ * on the configuration of the site, notifies administrators via email if there
  * are new releases or missing security updates.
  *
  * @see update_status_requirements()
@@ -514,9 +514,9 @@ function update_status_system_submit($fo
  * Helper function to return the appropriate message text when the site is out
  * of date or missing a security update.
  *
- * These error messages are shared by both update_requirements() for the
+ * These error messages are shared by both update_status_requirements() for the
  * site-wide status report at admin/logs/status and in the body of the
- * notification emails generated by update_cron().
+ * notification emails generated by update_status_cron().
  *
  * @param $msg_type
  *   String to indicate what kind of message to generate. Can be either
@@ -620,8 +620,18 @@ function _update_status_no_data() {
  * logic is only required when preparing the status report, not for 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_status} table using the
+ * 'update_status_project_projects' cache ID. 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.
+ *
  * @see update_status_process_project_info()
  * @see update_status_calculate_project_data()
+ * @see update_status_project_cache()
  *
  * @todo
  *   Extend this to include themes and theme engines when they get .info files.
@@ -706,7 +716,7 @@ function update_status_get_projects() {
     }
   }
   asort($projects);
-  cache_set('update_status_projects', 'cache', serialize($projects), time() + (60 * 60));
+  _update_status_cache_set('update_status_projects', serialize($projects), time() + (60 * 60));
   return $projects;
 }
 
@@ -838,12 +848,23 @@ function update_status_process_project_i
  * version (e.g. 5.x-1.5-beta1, 5.x-1.5-beta2, and 5.x-1.5). Development
  * snapshots for a given major version are always listed last.
  *
+ * The results of this function are expensive to compute, especially on sites
+ * with lots of modules, since it involves a lot of comparisons and
+ * other operations. Therefore, we cache the results into the {cache_update_status}
+ * table using the 'update_status_project_data' cache ID. 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.
+ *
  * @param $available
  *  Array of data about available project releases.
  *
  * @see update_status_get_available()
  * @see update_status_get_projects()
  * @see update_status_process_project_info()
+ * @see update_status_project_cache()
  */
 function update_status_calculate_project_data($available) {
 
@@ -1061,7 +1082,7 @@ function update_status_calculate_project
 
         // If we're running a dev snapshot and have a timestamp, stop
         // searching for security updates once we hit an official release
-        // older than what we've got.  Allow 100 seconds of leeway to handle
+        // older than what we've got. Allow 100 seconds of leeway to handle
         // differences between the datestamp in the .info file and the
         // timestamp of the tarball itself (which are usually off by 1 or 2
         // seconds) so that we don't flag that as a new release.
@@ -1186,7 +1207,7 @@ function update_status_calculate_project
       $projects[$project]['reason'] = t('No available releases found');
     }
   }
-  cache_set('update_status_data', 'cache', serialize($projects), time() + (60 * 60));
+  _update_status_cache_set('update_status_data', serialize($projects), time() + (60 * 60));
   return $projects;
 }
 
@@ -1384,11 +1405,14 @@ function update_status_refresh() {
   global $base_url;
 
   // Since we're fetching new available update data, we want to clear
-  // everything in our cache, to ensure we recompute the status. Note that
-  // this does not cause update_status_get_projects() to be recomputed twice
-  // in the same page load (e.g. when manually checking) since that function
-  // stashes its answer in a static array.
-  update_status_invalidate_cache();
+  // 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
+  // releases just yet, since that data (even if it's stale) can be useful
+  // during update_status_get_projects(); for example, to modules that implement
+  // hook_system_info_alter() such as cvs_deploy.
+  _update_status_cache_clear('update_status_project_projects');
+  _update_status_cache_clear('update_status_project_data');
+
 
   // If not in 'safe mode', increase the maximum execution time:
   if (!ini_get('safe_mode')) {
@@ -1397,10 +1421,14 @@ function update_status_refresh() {
 
   $available = array();
   $data = array();
-
   $site_key = md5($base_url . drupal_get_private_key());
-
   $projects = update_status_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
+  // to clear out the stale data at this point.
+  _update_status_cache_clear('update_status_available_releases');
+  
   foreach ($projects as $key => $project) {
     $url = _update_status_build_fetch_url($project, $site_key);
     $xml = drupal_http_request($url);
@@ -1412,7 +1440,7 @@ function update_status_refresh() {
   if ($data) {
     $parser = new update_status_xml_parser;
     $available = $parser->parse($data);
-    cache_set('update_status_info', 'cache', serialize($available), time() + (60 * 60 * 24));
+    _update_status_cache_set('update_status_info', serialize($available), time() + (60 * 60 * 24));
     variable_set('update_status_last', time());
     watchdog('update_status', t('Fetched information about all available new releases and updates.'), WATCHDOG_NOTICE, l(t('view'), 'admin/logs/updates'));
   }
@@ -1483,7 +1511,7 @@ function update_status_get_available($re
     }
   }
 
-  if (!$needs_refresh && ($cache = cache_get('update_status_info', 'cache'))
+  if (!$needs_refresh && ($cache = _update_status_cache_get('update_status_info'))
       && $cache->expire > time()) {
     $available = unserialize($cache->data);
   }
@@ -1494,13 +1522,6 @@ function update_status_get_available($re
 }
 
 /**
- * Invalidates any cached data relating to update status.
- */
-function update_status_invalidate_cache() {
-  cache_clear_all('update_status_', 'cache', TRUE);
-}
-
-/**
  * XML Parser object to read Drupal's project info files 
  * This uses PHP4's lame XML parsing, but it works. Mostly.
  */
@@ -1598,7 +1619,7 @@ class update_status_xml_parser {
 /**
  * Private sort function to order projects based on their status.
  *
- * @see update_requirements()
+ * @see update_status_requirements()
  * @see uasort()
  */
 function _update_status_project_status_sort($a, $b) {
@@ -1612,12 +1633,12 @@ function _update_status_project_status_s
 }
 
 /**
- * Retrieve data from {cache} or empty the cache when necessary.
+ * Retrieve data from {cache_update_status} or empty the cache when necessary.
  *
  * Two very expensive arrays computed by this module are the list of all
  * installed modules (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} table and used
+ * releases. These two arrays are cached in the {cache_update_status} table and used
  * whenever possible. The cache is cleared whenever the administrator visits
  * the status report, available updates report, or the module administration
  * pages, since we should always recompute the most current values on any of
@@ -1635,18 +1656,126 @@ function _update_status_project_status_s
 function update_status_project_cache($cid) {
   $projects = array();
 
-  // In some cases, we must clear the cache.  Rather than do so on a time
-  // basis, we check for specific paths.
+  // On certain paths, we should clear the cache and recompute the projects or
+  // update status of the site to avoid presenting stale information.
   $q = $_GET['q'];
   $paths = array('admin/build/modules', 'admin/logs', 'admin/logs/updates', 'admin/logs/status', 'admin/logs/updates/check');
   if (in_array($q, $paths)) {
-    cache_clear_all($cid, 'cache');
+    _update_status_cache_clear($cid);
   }
   else {
-    $cache = cache_get($cid, 'cache');
+    $cache = _update_status_cache_get($cid);
     if (!empty($cache->data) && $cache->expire > time()) {
       $projects = unserialize($cache->data);
     }
   }
   return $projects;
 }
+
+/**
+ * @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. 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
+ * plug-able cache system that assumes volatile caches.
+ *
+ * Update module uses the {cache_update_status} 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 or another cache backend is in use.
+ */
+
+/**
+ * Store 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:
+ *   - CACHE_PERMANENT: Indicates that the item should never be removed except
+ *     by explicitly using _update_status_cache_clear() or update_status_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_status_cache_set($cid, $data, $expire) {
+  $created = time();
+  db_query("UPDATE {cache_update_status} SET data = %b, created = %d, expire = %d WHERE cid = '%s'", $data, $created, $expire, $cid);
+  if (!db_affected_rows()) {
+    @db_query("INSERT INTO {cache_update_status} (cid, data, created, expire) VALUES ('%s', %b, %d, %d)", $cid, $data, $created, $expire);
+  }
+}
+
+/** 
+ * 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_status_cache_get($cid) {
+  $cache = db_fetch_object(db_query("SELECT data, created, expire FROM {cache_update_status} WHERE cid = '%s'", $cid));
+  if (isset($cache->data)) {
+    $cache->data = db_decode_blob($cache->data);
+  }
+  return $cache;
+}
+
+/**
+ * Invalidates specific 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_status_cache_clear($cid = NULL) {
+  if (empty($cid)) {
+    db_query("DELETE FROM {cache_update_status}");
+  }
+  else {
+    db_query("DELETE FROM {cache_update_status} WHERE cid = '%s'", $cid);
+  }
+}
+
+/**
+ * Implementation of hook_flush_caches().
+ *
+ * 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 database table ourselves at this point and return nothing, for example,
+ * on sites that use memcache where cache_clear_all() won't know how to purge
+ * this data.
+ *
+ * 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 the site is in MAINTENANCE_MODE == 'update' (which indicates
+ * update.php is running, not update module... alas for overloaded names).
+ */
+function update_status_flush_caches() {
+  if (defined('MAINTENANCE_MODE') && MAINTENANCE_MODE == 'update') {
+    _update_status_cache_clear();
+  }
+  return array();
+}
+
+/**
+ * Invalidates all cached data relating to update status.
+ */
+function update_status_invalidate_cache() {
+  _update_status_cache_clear();
+}
+
+/**
+ * @} End of "defgroup update_status_cache".
+ */
