From f556c7f2ae3dc09aa55801d42b8002946b768f92 Mon Sep 17 00:00:00 2001 From: daniel Date: Thu, 24 Jan 2013 12:15:54 +0100 Subject: [PATCH] Fix cache key used by SiteSQLStore. This makes sure that SiteSQLStore uses a cache key that includes information about the serialization structure as well as where the list of sites was loaded from. This avoids problems with loading "old" serialized versions from the cache after an upgrade. It also avoids cache conflicts with site lists loaded from different places. Change-Id: I7ad5b8ae63dc24598d41b2f150df7c14105d9f62 --- includes/site/Site.php | 10 +++++++++ includes/site/SiteList.php | 25 ++++++++++++++++++++++ includes/site/SiteSQLStore.php | 38 ++++++++++++++++++++++++++++++++-- 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/includes/site/Site.php b/includes/site/Site.php index b11f2b2180..078bd26c76 100644 --- a/includes/site/Site.php +++ b/includes/site/Site.php @@ -40,6 +40,16 @@ class Site { const PATH_LINK = 'link'; + + /** + * A version ID that identifies the serialization structure used by getSerializationData() + * and unserialize(). This is useful for constructing cache keys in cases where the cache relies + * on serialization for storing the SiteList. + * + * @var string A string uniquely identifying the version of the serialization structure. + */ + const SERIAL_VERSION_ID = '2013-01-23'; + /** * @since 1.21 * diff --git a/includes/site/SiteList.php b/includes/site/SiteList.php index 35e11a151f..97848b5d57 100644 --- a/includes/site/SiteList.php +++ b/includes/site/SiteList.php @@ -232,6 +232,29 @@ class SiteList extends GenericArrayObject { return $group; } + /** + * A version ID that identifies the serialization structure used by getSerializationData() + * and unserialize(). This is useful for constructing cache keys in cases where the cache relies + * on serialization for storing the SiteList. + * + * @var string A string uniquely identifying the version of the serialization structure, + * not including any sub-structures. + */ + const SERIAL_VERSION_ID = '2013-01-23'; + + /** + * Returns the version ID that identifies the serialization structure used by + * getSerializationData() and unserialize(), including the structure of any nested structures. + * This is useful for constructing cache keys in cases where the cache relies + * on serialization for storing the SiteList. + * + * @return string A string uniquely identifying the version of the serialization structure, + * including any sub-structures. + */ + public static function getSerialVersionId() { + return self::SERIAL_VERSION_ID . '+Site:' . Site::SERIAL_VERSION_ID; + } + /** * @see GenericArrayObject::getSerializationData * @@ -240,6 +263,8 @@ class SiteList extends GenericArrayObject { * @return array */ protected function getSerializationData() { + //NOTE: When changing the structure, either implement unserialize() to handle the + // old structure too, or update SERIAL_VERSION_ID to kill any caches. return array_merge( parent::getSerializationData(), array( diff --git a/includes/site/SiteSQLStore.php b/includes/site/SiteSQLStore.php index 724f115768..8745cb4f76 100644 --- a/includes/site/SiteSQLStore.php +++ b/includes/site/SiteSQLStore.php @@ -42,6 +42,11 @@ class SiteSQLStore implements SiteStore { */ protected $sitesTable; + /** + * @var string|null + */ + private $cacheKey = null; + /** * @since 1.21 * @@ -68,6 +73,35 @@ class SiteSQLStore implements SiteStore { $this->sitesTable = $sitesTable; } + /** + * Constructs a cache key to use for caching the list of sites. + * + * This includes the concrete class name of the site list as well as a version identifier + * for the list's serialization, to avoid problems when unserializing site lists serialized + * by an older version, e.g. when reading from a cache. + * + * The cache key also includes information about where the sites were loaded from, e.g. + * the name of a database table. + * + * @see SiteList::getSerialVersionId + * + * @return String The cache key. + */ + protected function getCacheKey() { + if ( $this->cacheKey === null ) { + $type = 'SiteList#' . SiteList::getSerialVersionId(); + $source = $this->sitesTable->getName(); + + if ( $this->sitesTable->getTargetWiki() !== false ) { + $source = $this->sitesTable->getTargetWiki() . '.' . $source; + } + + $this->cacheKey = wfMemcKey( "$source/$type" ); + } + + return $this->cacheKey; + } + /** * @see SiteStore::getSites * @@ -81,7 +115,7 @@ class SiteSQLStore implements SiteStore { if ( $source === 'cache' ) { if ( $this->sites === null ) { $cache = wfGetMainCache(); - $sites = $cache->get( wfMemcKey( 'SiteList' ) ); + $sites = $cache->get( $this->getCacheKey() ); if ( is_object( $sites ) ) { $this->sites = $sites; @@ -171,7 +205,7 @@ class SiteSQLStore implements SiteStore { } $cache = wfGetMainCache(); - $cache->set( wfMemcKey( 'SiteList' ), $this->sites ); + $cache->set( $this->getCacheKey(), $this->sites ); } /** -- 2.20.1