Daniel Kinzler has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/71595


Change subject: (bug 50303) improve cache key for shared cache.
......................................................................

(bug 50303) improve cache key for shared cache.

This allows any object cache keys shared between clients
(and the repo) to be based on by a) a version ID
and b) the repo's name.

TODO: make the default value use the repo ID per default.

DEPLOYMENT NOTE:

This causes cached objects to NOT be shared between wikis per
default (see TODO)! When deploying on a wiki farm, make sure
to set the sharedCacheKeyPrefix option appropriately:
It should be based on the desired repo's database name and
a version ID indicating the version of the deployed code.
Suggested pattern: <repo>:deploy/<version>

Change-Id: I78009d3eb1aed2b42ee53acf6f7bc812e7ee836f
---
M client/config/WikibaseClient.example.php
M client/includes/WikibaseClient.php
M client/includes/parserhooks/PropertyParserFunction.php
M client/includes/store/ClientStore.php
M client/includes/store/sql/CachingSqlStore.php
M client/includes/store/sql/DirectSqlStore.php
M docs/options.wiki
M lib/config/WikibaseLib.default.php
M lib/includes/store/sql/WikiPageEntityLookup.php
M repo/config/Wikibase.example.php
M repo/includes/WikibaseRepo.php
M repo/includes/store/Store.php
M repo/includes/store/StoreFactory.php
M repo/includes/store/sql/SqlStore.php
M repo/tests/phpunit/includes/store/StoreTest.php
15 files changed, 222 insertions(+), 34 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase 
refs/changes/95/71595/1

diff --git a/client/config/WikibaseClient.example.php 
b/client/config/WikibaseClient.example.php
index 9654b3a..9009b53 100644
--- a/client/config/WikibaseClient.example.php
+++ b/client/config/WikibaseClient.example.php
@@ -65,6 +65,9 @@
 $wgWBClientSettings['injectRecentChanges'] = true;
 $wgWBClientSettings['showExternalRecentChanges'] = true;
 
+// Make sure we use the same keys on repo and clients, so we can share cached 
objects.
+$wgWBClientSettings['sharedCacheKeyPrefix'] = 
$wgWBClientSettings['repoDatabase'] . ':WBL/' . WBL_VERSION;
+
 $wgLBFactoryConf = array(
        // In order to seamlessly access a remote wiki, to fetch entity data,
        // LBFactory_Multi must be used.
diff --git a/client/includes/WikibaseClient.php 
b/client/includes/WikibaseClient.php
index a7767a2..ad4039b 100644
--- a/client/includes/WikibaseClient.php
+++ b/client/includes/WikibaseClient.php
@@ -242,9 +242,11 @@
                        return $this->storeInstances[$store];
                }
 
-               $instance = new $class(
-                       $this->getContentLanguage(),
-                       $repoDatabase
+               // Since we can't know what settings the ClientStore needs,
+               // delegate the instantiation to a factory method (poor man's 
builder).
+               $instance = $class::newFromSettings(
+                       $this->settings,
+                       $this->getContentLanguage()
                );
 
                assert( $instance instanceof ClientStore );
diff --git a/client/includes/parserhooks/PropertyParserFunction.php 
b/client/includes/parserhooks/PropertyParserFunction.php
index 4d09ab9..1301e70 100644
--- a/client/includes/parserhooks/PropertyParserFunction.php
+++ b/client/includes/parserhooks/PropertyParserFunction.php
@@ -182,7 +182,7 @@
                $targetLanguage = $parser->getTargetLanguage();
                $errorFormatter = new ParserErrorMessageFormatter( 
$targetLanguage );
 
-               $wikibaseClient = WikibaseClient::newInstance();
+               $wikibaseClient = WikibaseClient::getDefaultInstance();
 
                $entityLookup = $wikibaseClient->getStore()->getEntityLookup();
                $propertyLabelResolver = 
$wikibaseClient->getStore()->getPropertyLabelResolver();
diff --git a/client/includes/store/ClientStore.php 
b/client/includes/store/ClientStore.php
index 8ed355d..7be44f0 100644
--- a/client/includes/store/ClientStore.php
+++ b/client/includes/store/ClientStore.php
@@ -2,6 +2,8 @@
 
 namespace Wikibase;
 
+use Language;
+
 /**
  * Client store interface.
  *
@@ -22,8 +24,6 @@
  *
  * @since 0.1
  *
- * @todo: provide getXXX() methods for getting local pseudo-singletons (shared 
service objects).
- *
  * @file
  * @ingroup WikibaseClient
  *
@@ -34,6 +34,17 @@
 interface ClientStore {
 
        /**
+        * Creates a new ClientStore instance based on the given settings.
+        * Use by StoreFactory to instantiate stores of unknown type.
+        *
+        * @param SettingsArray $settings
+        * @param Language      $wikiLanguage
+        *
+        * @return ClientStore
+        */
+       public static function newFromSettings( SettingsArray $settings, 
Language $wikiLanguage );
+
+       /**
         * Returns a SiteLinkLookup for this store.
         *
         * @since 0.4
diff --git a/client/includes/store/sql/CachingSqlStore.php 
b/client/includes/store/sql/CachingSqlStore.php
index 919d006..c573e80 100644
--- a/client/includes/store/sql/CachingSqlStore.php
+++ b/client/includes/store/sql/CachingSqlStore.php
@@ -3,6 +3,7 @@
 namespace Wikibase;
 
 use Language;
+use ObjectCache;
 
 /**
  * Implementation of the client store interface using an SQL backend via 
MediaWiki's
@@ -52,10 +53,50 @@
        protected $language;
 
        /**
-        * @param Language $wikiLanguage
+        * @var string
         */
-       public function __construct( Language $wikiLanguage ) {
+       private $cachePrefix;
+
+       /**
+        * @var string
+        */
+       private $cacheType;
+
+       /**
+        * @var int
+        */
+       private $cacheDuration;
+
+       /**
+        * @param Language $wikiLanguage
+        * @param string   $cachePrefix
+        * @param          $cacheDuration
+        * @param          $cacheType
+        */
+       public function __construct( Language $wikiLanguage, $cachePrefix, 
$cacheDuration, $cacheType ) {
                $this->language = $wikiLanguage;
+               $this->cachePrefix = $cachePrefix;
+               $this->cacheDuration = $cacheDuration;
+               $this->cacheType = $cacheType;
+       }
+
+       /**
+        * This pseudo-constructor uses the following settings from $settings:
+        * - sharedCacheKeyPrefix
+        * - sharedCacheDuration
+        * - sharedCacheType
+        *
+        * @param SettingsArray $settings
+        * @param Language      $wikiLanguage
+        *
+        * @return CachingSqlStore
+        */
+       public static function newFromSettings( SettingsArray $settings, 
Language $wikiLanguage ) {
+               $cachePrefix = $settings->getSetting( 'sharedCacheKeyPrefix' );
+               $cacheDuration = $settings->getSetting( 'sharedCacheDuration' );
+               $cacheType = $settings->getSetting( 'sharedCacheType' );
+
+               return new self( $wikiLanguage, $cachePrefix, $cacheDuration, 
$cacheType );
        }
 
        /**
@@ -185,7 +226,7 @@
         * @return TermIndex
         */
        public function getTermIndex() {
-               throw new MWException( "Not Implemented, " . __CLASS__ . " is 
incomplete." );
+               throw new \MWException( "Not Implemented, " . __CLASS__ . " is 
incomplete." );
        }
 
        /**
@@ -194,10 +235,13 @@
         * @return PropertyLabelResolver
         */
        protected function newPropertyLabelResolver() {
+               $key = $this->cachePrefix . ':TermPropertyLabelResolver';
                return new TermPropertyLabelResolver(
                        $this->language->getCode(),
                        $this->getTermIndex(),
-                       wfGetMainCache()
+                       ObjectCache::getInstance( $this->cacheType ),
+                       $this->cacheDuration,
+                       $key
                );
        }
 
diff --git a/client/includes/store/sql/DirectSqlStore.php 
b/client/includes/store/sql/DirectSqlStore.php
index ffbd9e5..2b02062 100644
--- a/client/includes/store/sql/DirectSqlStore.php
+++ b/client/includes/store/sql/DirectSqlStore.php
@@ -3,6 +3,7 @@
 namespace Wikibase;
 
 use Language;
+use ObjectCache;
 
 /**
  * Implementation of the client store interface using direct access to the 
repository's
@@ -72,13 +73,56 @@
        private $entityUsageIndex = null;
 
        /**
-        * @param Language $wikiLanguage
-        * @param string    $repoWiki the symbolic database name of the repo 
wiki
+        * @var string
         */
-       public function __construct( Language $wikiLanguage, $repoWiki ) {
+       private $cachePrefix;
+
+       /**
+        * @var int
+        */
+       private $cacheType;
+
+       /**
+        * @var int
+        */
+       private $cacheDuration;
+
+       /**
+        * @param Language $wikiLanguage
+        * @param string   $repoWiki the symbolic database name of the repo wiki
+        * @param string   $cachePrefix
+        * @param int      $cacheDuration
+        * @param int      $cacheType
+        */
+       public function __construct( Language $wikiLanguage, $repoWiki, 
$cachePrefix, $cacheDuration, $cacheType ) {
                $this->repoWiki = $repoWiki;
+               $this->cachePrefix = $cachePrefix;
+               $this->cacheDuration = $cacheDuration;
+               $this->cacheType = $cacheType;
                $this->language = $wikiLanguage;
        }
+
+       /**
+        * This pseudo-constructor uses the following settings from $settings:
+        * - sharedCacheKeyPrefix
+        * - sharedCacheDuration
+        * - sharedCacheType
+        * - repoDatabase
+        *
+        * @param SettingsArray $settings
+        * @param Language      $wikiLanguage
+        *
+        * @return DirectSqlStore
+        */
+       public static function newFromSettings( SettingsArray $settings, 
Language $wikiLanguage ) {
+               $cachePrefix = $settings->getSetting( 'sharedCacheKeyPrefix' );
+               $cacheDuration = $settings->getSetting( 'sharedCacheDuration' );
+               $cacheType = $settings->getSetting( 'sharedCacheType' );
+               $repoWiki = $settings->getSetting( 'repoDatabase' );
+
+               return new self( $wikiLanguage, $repoWiki, $cachePrefix, 
$cacheDuration, $cacheType );
+       }
+
 
        /**
         * @see Store::getEntityUsageIndex
@@ -158,8 +202,11 @@
         * @return CachingEntityLoader
         */
        protected function newEntityLookup() {
-               //TODO: get config for persistent cache from config
-               $lookup = new WikiPageEntityLookup( $this->repoWiki ); // 
entities are stored in wiki pages
+               //NOTE: two layers of caching: persistent external cache in 
WikiPageEntityLookup;
+               //      transient local cache in CachingEntityLoader.
+               //NOTE: Keep in sync with SqlStore::newEntityLookup on the repo
+               $key = $this->cachePrefix . ':WikiPageEntityLookup';
+               $lookup = new WikiPageEntityLookup( $this->repoWiki, 
$this->cacheType, $this->cacheDuration, $key );
                return new CachingEntityLoader( $lookup );
        }
 
@@ -205,10 +252,13 @@
         * @return PropertyLabelResolver
         */
        protected function newPropertyLabelResolver() {
+               $key = $this->cachePrefix . ':TermPropertyLabelResolver';
                return new TermPropertyLabelResolver(
                        $this->language->getCode(),
                        $this->getTermIndex(),
-                       wfGetMainCache()
+                       ObjectCache::getInstance( $this->cacheType ),
+                       $this->cacheDuration,
+                       $key
                );
        }
 
diff --git a/docs/options.wiki b/docs/options.wiki
index 1dfd557..b3a85e3 100644
--- a/docs/options.wiki
+++ b/docs/options.wiki
@@ -14,6 +14,10 @@
 
 === Expert Settings ===
 
+;sharedCacheKeyPrefix:  Prefix to use for cache keys that should be shared 
among a wikibase repo and all its clients. The default is constructed from 
$wgDBname and WBL_VERSION. In order to share caches between clients (and the 
repo), set a prefix based on the repo's name and WBL_VERSION or a similar 
version ID.
+:* NOTE: The default may change in order to use the repo's database name 
automatically.
+;sharedCacheDuration: The default duration of entries in the shared object 
cache, in seconds. Default is 3600 seconds = 1 hour.
+;sharedCacheType: The type of cache to use for the shared object cache. 
Defaults to $wgMainCacheType. Use CACHE_XXX constants.
 ;entityPrefixes: ID prefixes to use for the different entity types, as an 
associative array mapping prefixes to entity type constants. Default:
 <poem>
           array(
diff --git a/lib/config/WikibaseLib.default.php 
b/lib/config/WikibaseLib.default.php
index 2c4d095..abd4443 100644
--- a/lib/config/WikibaseLib.default.php
+++ b/lib/config/WikibaseLib.default.php
@@ -59,6 +59,21 @@
                // may contain mappings from site-id to db-name.
                'localClientDatabases' => array(),
 
+               // Prefix to use for cache keys that should be shared among
+               // a wikibase repo and all its clients.
+               // The default includes WBL_VERSION and $wgDBname;
+               // In order to share caches between clients (and the repo),
+               // set a prefix based on the repo's name and WBL_VERSION
+               // or a similar version ID.
+               // @todo: generate the default programmatically, so it can 
automatically use the right repo ID.
+               'sharedCacheKeyPrefix' => $GLOBALS['wgDBname'] . ':WBL/' . 
WBL_VERSION,
+
+               // The duration of the object cache, in seconds.
+               'sharedCacheDuration' => 60 * 60,
+
+               // The type of object cache to use. Use CACHE_XXX constants.
+               'sharedCacheType' => $GLOBALS['wgMainCacheType'],
+
                'dispatchBatchChunkFactor' => 3,
                'dispatchBatchCacheFactor' => 3,
 
diff --git a/lib/includes/store/sql/WikiPageEntityLookup.php 
b/lib/includes/store/sql/WikiPageEntityLookup.php
index 51ade77..e33c291 100644
--- a/lib/includes/store/sql/WikiPageEntityLookup.php
+++ b/lib/includes/store/sql/WikiPageEntityLookup.php
@@ -53,7 +53,7 @@
        /**
         * @var int $cacheTimeout
         */
-       protected $cacheTimeout = 3600;
+       protected $cacheTimeout;
 
        /**
         * @param String|bool $wiki           The name of thw wiki database to 
use, in a form
@@ -66,20 +66,22 @@
         *                                    Note that the $wiki parameter 
determines the cache compartment,
         *                                    so multiple wikis loading 
entities from the same repository
         *                                    will share the cache.
+        * @param int          $cacheDuration Cache duration in seconds.
         * @param string      $cacheKeyPrefix The key prefix to use for 
constructing cache keys.
         *                                    Defaults to "wbentity". There 
should be no reason to change this.
         *
         * @return \Wikibase\WikiPageEntityLookup
         */
-       public function __construct( $wiki = false, $cacheType = null, 
$cacheKeyPrefix = "wbentity" ) {
+       public function __construct( $wiki = false, $cacheType = null, 
$cacheDuration = 3600, $cacheKeyPrefix = "wbentity" ) {
                parent::__construct( $wiki );
 
                if ( $cacheType === null ) {
                        $cacheType = $GLOBALS[ 'wgMainCacheType' ];
                }
 
-               $this->cacheType = $cacheType; //FIXME: take from Settings: 
defaultEntityCache
+               $this->cacheType = $cacheType;
                $this->cacheKeyPrefix = $cacheKeyPrefix;
+               $this->cacheTimeout = $cacheDuration;
        }
 
        /**
@@ -90,15 +92,10 @@
         * @return String
         */
        protected function getEntityCacheKey( EntityId $entityId ) {
-               global $wgCachePrefix;
+               $cacheKey = $this->cacheKeyPrefix
+                               . ':' . $entityId->getEntityType()
+                               . ':' . $entityId->getNumericId();
 
-               if ( $this->wiki === false ) {
-                       $keyDB = $wgCachePrefix === false ? wfWikiID() : 
$wgCachePrefix;
-               } else {
-                       $keyDB = $this->wiki;
-               }
-
-               $cacheKey = wfForeignMemcKey( $keyDB, $this->cacheKeyPrefix, 
$entityId->getPrefixedId() );
                return $cacheKey;
        }
 
diff --git a/repo/config/Wikibase.example.php b/repo/config/Wikibase.example.php
index 07598c8..a20438f 100644
--- a/repo/config/Wikibase.example.php
+++ b/repo/config/Wikibase.example.php
@@ -54,6 +54,9 @@
 $wgWBRepoSettings['entityNamespaces'][CONTENT_MODEL_WIKIBASE_ITEM] = 
WB_NS_ITEM;
 $wgWBRepoSettings['entityNamespaces'][CONTENT_MODEL_WIKIBASE_PROPERTY] = 
WB_NS_PROPERTY;
 
+// Make sure we use the same keys on repo and clients, so we can share cached 
objects.
+$wgWBRepoSettings['sharedCacheKeyPrefix'] = $wgDBname . ':WBL/' . WBL_VERSION;
+
 // NOTE: no need to set up $wgNamespaceContentModels, Wikibase will do that 
automatically based on $wgWBRepoSettings
 
 // Tell MediaWIki to search the item namespace
diff --git a/repo/includes/WikibaseRepo.php b/repo/includes/WikibaseRepo.php
index 3b87e11..334ad1b 100644
--- a/repo/includes/WikibaseRepo.php
+++ b/repo/includes/WikibaseRepo.php
@@ -263,8 +263,7 @@
         * @return Store
         */
        public function getStore() {
-               //TODO: inject this, get rid of global store instance(s)
-               return StoreFactory::getStore();
+               return $this->store;
        }
 
 }
diff --git a/repo/includes/store/Store.php b/repo/includes/store/Store.php
index b61037a..8c6c2c2 100644
--- a/repo/includes/store/Store.php
+++ b/repo/includes/store/Store.php
@@ -31,10 +31,21 @@
  *
  * @licence GNU GPL v2+
  * @author Jeroen De Dauw < jeroended...@gmail.com >
+ * @author Daniel Kinzler
  */
 interface Store {
 
        /**
+        * Creates a new Store instance based on the given settings.
+        * Use by StoreFactory to instantiate stores of unknown type.
+        *
+        * @param SettingsArray $settings
+        *
+        * @return Store
+        */
+       public static function newFromSettings( SettingsArray $settings );
+
+       /**
         * Returns a new SiteLinkCache for this store.
         *
         * @since 0.1
diff --git a/repo/includes/store/StoreFactory.php 
b/repo/includes/store/StoreFactory.php
index 88e776f..936429c 100644
--- a/repo/includes/store/StoreFactory.php
+++ b/repo/includes/store/StoreFactory.php
@@ -38,8 +38,12 @@
                        return $instances[$store];
                }
 
+               $settings = Settings::singleton();
                $class = $wgWBStores[$store];
-               $instance = new $class();
+
+               // Since we can't know what settings the Store needs,
+               // delegate the instantiation to a factory method (poor man's 
builder).
+               $instance = $class::newFromSettings( $settings );
 
                assert( $instance instanceof Store );
 
diff --git a/repo/includes/store/sql/SqlStore.php 
b/repo/includes/store/sql/SqlStore.php
index 8869547..99e75b6 100644
--- a/repo/includes/store/sql/SqlStore.php
+++ b/repo/includes/store/sql/SqlStore.php
@@ -28,6 +28,7 @@
  *
  * @licence GNU GPL v2+
  * @author Jeroen De Dauw < jeroended...@gmail.com >
+ * @author Daniel Kinzler
  */
 class SqlStore implements Store {
 
@@ -40,6 +41,50 @@
         * @var TermIndex
         */
        private $termIndex = null;
+
+       /**
+        * @var string
+        */
+       private $cachePrefix;
+
+       /**
+        * @var int
+        */
+       private $cacheType;
+
+       /**
+        * @var int
+        */
+       private $cacheDuration;
+
+       /**
+        * @param string $cachePrefix
+        * @param int    $cacheDuration
+        * @param int    $cacheType
+        */
+       public function __construct( $cachePrefix, $cacheDuration, $cacheType ) 
{
+               $this->cachePrefix = $cachePrefix;
+               $this->cacheDuration = $cacheDuration;
+               $this->cacheType = $cacheType;
+       }
+
+       /**
+        * This pseudo-constructor uses the following settings from $settings:
+        * - sharedCacheKeyPrefix
+        * - sharedCacheDuration
+        * - sharedCacheType
+        *
+        * @param SettingsArray
+        *
+        * @return \Wikibase\SqlStore
+        */
+       public static function newFromSettings( SettingsArray $settings ) {
+               $cachePrefix = $settings->getSetting( 'sharedCacheKeyPrefix' );
+               $cacheDuration = $settings->getSetting( 'sharedCacheDuration' );
+               $cacheType = $settings->getSetting( 'sharedCacheType' );
+
+               return new self( $cachePrefix, $cacheDuration, $cacheType );
+       }
 
        /**
         * @see Store::getTermIndex
@@ -236,11 +281,11 @@
         * @return CachingEntityLoader
         */
        protected function newEntityLookup() {
-               //TODO: get cache type etc from config
                //NOTE: two layers of caching: persistent external cache in 
WikiPageEntityLookup;
                //      transient local cache in CachingEntityLoader.
-               $lookup = new WikiPageEntityLookup( false );
+               //NOTE: Keep in sync with DirectSqlStore::newEntityLookup on 
the client
+               $key = $this->cachePrefix . ':WikiPageEntityLookup';
+               $lookup = new WikiPageEntityLookup( false, $this->cacheType, 
$this->cacheDuration, $key );
                return new CachingEntityLoader( $lookup );
        }
-
 }
diff --git a/repo/tests/phpunit/includes/store/StoreTest.php 
b/repo/tests/phpunit/includes/store/StoreTest.php
index 5bab52d..5b4acc1 100644
--- a/repo/tests/phpunit/includes/store/StoreTest.php
+++ b/repo/tests/phpunit/includes/store/StoreTest.php
@@ -42,7 +42,7 @@
 class StoreTest extends \MediaWikiTestCase {
 
        public function instanceProvider() {
-               $instances = array( new \Wikibase\SqlStore() );
+               $instances = array( new \Wikibase\SqlStore( 'testing', 1, 
CACHE_NONE ) );
 
                return $this->arrayWrap( $instances );
        }

-- 
To view, visit https://gerrit.wikimedia.org/r/71595
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I78009d3eb1aed2b42ee53acf6f7bc812e7ee836f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to