Fix cache key used by SiteSQLStore.
authordaniel <daniel.kinzler@wikimedia.de>
Thu, 24 Jan 2013 11:15:54 +0000 (12:15 +0100)
committerdaniel <daniel.kinzler@wikimedia.de>
Thu, 24 Jan 2013 13:58:25 +0000 (14:58 +0100)
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
includes/site/SiteList.php
includes/site/SiteSQLStore.php

index b11f2b2..078bd26 100644 (file)
@@ -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
         *
index 35e11a1..97848b5 100644 (file)
@@ -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(
index 724f115..8745cb4 100644 (file)
@@ -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 );
        }
 
        /**