Use MediaWiki cache strategy and code
This removes all BugzillaCache* classes and code that used it, replaces it with MediaWiki `wfGetCache($wgMainCacheType)`, which provides sensibly the same set of options. Doing so also simplifies a first install, by removing specific configuration for this extension.
This commit is contained in:
Родитель
59c74e67be
Коммит
eaa6d855c3
|
@ -5,11 +5,6 @@
|
|||
|
||||
$dir = dirname(__FILE__);
|
||||
require_once ($dir . '/BugzillaOutput.class.php');
|
||||
require_once ($dir . '/cache/BugzillaCacheI.class.php');
|
||||
require_once ($dir . '/cache/BugzillaCacheDummy.class.php');
|
||||
require_once ($dir . '/cache/BugzillaCacheApc.class.php');
|
||||
require_once ($dir . '/cache/BugzillaCacheMemcache.class.php');
|
||||
require_once ($dir . '/cache/BugzillaCacheSql.class.php');
|
||||
|
||||
// Factory
|
||||
class Bugzilla {
|
||||
|
@ -45,38 +40,4 @@ class Bugzilla {
|
|||
|
||||
return new $class($theconfig, $opts, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the BugzillaCacheI extended class in charge
|
||||
* for the cache backend in use.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCacheClass( $type ) {
|
||||
|
||||
$suffix = 'dummy';
|
||||
|
||||
if ( in_array( $type, array( 'mysql', 'postgresql', 'sqlite' ) ) ) {
|
||||
$suffix = 'sql';
|
||||
} elseif ( in_array( $type, array( 'apc', 'memcache' ) ) ) {
|
||||
$suffix = $type;
|
||||
}
|
||||
|
||||
return 'BugzillaCache' . ucwords( $suffix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Build and return a working cache, depending on config.
|
||||
*
|
||||
* @return BugzillaCacheI object
|
||||
*/
|
||||
public static function getCache() {
|
||||
global $wgBugzillaCacheType;
|
||||
|
||||
$object = self::getCacheClass( $wgBugzillaCacheType );
|
||||
|
||||
return new $object();
|
||||
}
|
||||
}
|
||||
|
|
27
Bugzilla.php
27
Bugzilla.php
|
@ -51,33 +51,15 @@ $wgExtensionMessagesFiles['Bugzilla'] = "$cwd/Bugzilla.i18n.php";
|
|||
$wgAutoloadClasses['Bugzilla'] = $cwd . '/Bugzilla.class.php';
|
||||
$wgAutoloadClasses['BugzillaQuery'] = $cwd . '/BugzillaQuery.class.php';
|
||||
$wgAutoloadClasses['BugzillaOutput'] = $cwd . '/BugzillaOutput.class.php';
|
||||
$wgAutoloadClasses['BugzillaCacheI'] = $cwd . '/cache/BugzillaCacheI.class.php';
|
||||
$wgAutoloadClasses['BugzillaCacheDummy'] = $cwd . '/cache/BugzillaCacheDummy.class.php';
|
||||
$wgAutoloadClasses['BugzillaCacheApc'] = $cwd . '/cache/BugzillaCacheApc.class.php';
|
||||
$wgAutoloadClasses['BugzillaCacheMemcache'] = $cwd . '/cache/BugzillaCacheMemcache.class.php';
|
||||
$wgAutoloadClasses['BugzillaCacheSql'] = $cwd . '/cache/BugzillaCacheSql.class.php';
|
||||
|
||||
/**
|
||||
* These hooks are used by mediawiki to properly display the plugin information
|
||||
* and properly interpret the tags used.
|
||||
*/
|
||||
|
||||
$wgHooks['LoadExtensionSchemaUpdates'][] = 'BugzillaCreateCache';
|
||||
$wgHooks['BeforePageDisplay'][] = 'BugzillaIncludeHTML';
|
||||
$wgHooks['ParserFirstCallInit'][] = 'BugzillaParserInit';
|
||||
|
||||
// Schema updates for the database cache
|
||||
function BugzillaCreateCache($updater) {
|
||||
|
||||
global $wgBugzillaCacheType;
|
||||
|
||||
$class = Bugzilla::getCacheClass($wgBugzillaCacheType);
|
||||
$class::setup($updater);
|
||||
|
||||
// Let the other hooks keep processing
|
||||
return true;
|
||||
}
|
||||
|
||||
// Add content to page HTML
|
||||
function BugzillaIncludeHTML( &$out, &$sk ) {
|
||||
|
||||
|
@ -185,10 +167,11 @@ $wgBugzillaMethod = 'REST'; // XML-RPC and JSON-RPC may be supported later
|
|||
|
||||
// Cache
|
||||
// NOTE: $wgBugzillaUseCache has been removed. Use $wgBugzillaCacheType below only:
|
||||
// - any valid value for using it
|
||||
// - equivalent to previous $wgBugzillaUseCache = false; is $wgBugzillaCacheType = 'dummy';
|
||||
$wgBugzillaCacheType = 'mysql'; // valid values are: memcache, apc, mysql, postgresql, sqlite, dummy.
|
||||
$wgBugzillaCacheMins = 5; // Minutes to cache results (default: 5)
|
||||
// NOTE: $wgBugzillaUseCache has been removed. $wgBugzillaCacheType has been removed as well.
|
||||
// NOTE: This extension now relies on what cache is available through MediaWiki directly;
|
||||
// NOTE: see $wgMainCacheType in LocalSettings.php
|
||||
|
||||
$wgBugzillaCacheTimeOut = 5; // Minutes to cache results (default: 5)
|
||||
|
||||
$wgBugzillaJqueryTable = true; // Use a jQuery table for display (default: true)
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
abstract class BugzillaOutput {
|
||||
|
||||
public $response;
|
||||
public $cache;
|
||||
|
||||
public function __construct($config, $options, $title='') {
|
||||
$this->title = $title;
|
||||
|
@ -58,15 +57,6 @@ abstract class BugzillaOutput {
|
|||
|
||||
}
|
||||
|
||||
protected function _getCache()
|
||||
{
|
||||
if (!$this->cache) {
|
||||
$this->cache = Bugzilla::getCache();
|
||||
}
|
||||
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
abstract protected function setup_template_data();
|
||||
}
|
||||
|
||||
|
@ -146,15 +136,22 @@ abstract class BugzillaGraph extends BugzillaOutput {
|
|||
include_once 'pchart/class/pData.class.php';
|
||||
|
||||
global $wgBugzillaChartUrl;
|
||||
global $wgBugzillaCacheTimeOut;
|
||||
global $wgMainCacheType;
|
||||
|
||||
$key = md5($this->query->id . $this->_get_size() . get_class($this));
|
||||
$cache = $this->_getCache();
|
||||
if($result = $cache->get($key)) {
|
||||
$image = $result;
|
||||
$this->response->image = $wgBugzillaChartUrl . '/' . $image;
|
||||
} else {
|
||||
$this->response->image = $wgBugzillaChartUrl . '/' . $this->generate_chart($key) . '.png';
|
||||
$fileName = sha1(serialize([$this->query->id, $this->_get_size(), get_class($this)]));
|
||||
$key = implode(':', ['mediawiki', 'bugzilla', 'chart', $fileName]);
|
||||
$cache = wfGetCache($wgMainCacheType);
|
||||
|
||||
// We use the cache only to invalidate/recompute the charts:
|
||||
// the key is its own value. Only the TTL is useful here.
|
||||
if ($cache->get($key) === false) {
|
||||
if ($this->generate_chart($fileName)) {
|
||||
$cache->set($key, $fileName);
|
||||
}
|
||||
}
|
||||
|
||||
$this->response->image = $wgBugzillaChartUrl.'/'.$fileName.'.png';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -227,8 +224,7 @@ class BugzillaPieGraph extends BugzillaGraph {
|
|||
$pPieChart->drawPieLegend(2*$radius + 2*$padding, $padding, array("Alpha"=>20));
|
||||
|
||||
$pImage->render($wgBugzillaChartStorage . '/' . $chart_name . '.png');
|
||||
$cache = $this->_getCache();
|
||||
$cache->set($chart_name, $chart_name . '.png');
|
||||
|
||||
return $chart_name;
|
||||
}
|
||||
}
|
||||
|
@ -252,10 +248,8 @@ class BugzillaBarGraph extends BugzillaGraph {
|
|||
|
||||
$pImage->drawBarChart();
|
||||
$pImage->render($wgBugzillaChartStorage . '/' . $chart_name . '.png');
|
||||
$cache = $this->_getCache();
|
||||
$cache->set($chart_name, $chart_name . '.png');
|
||||
|
||||
return $chart_name;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -31,19 +31,10 @@ abstract class BugzillaBaseQuery {
|
|||
$this->error = FALSE;
|
||||
$this->data = array();
|
||||
$this->synthetic_fields = array();
|
||||
$this->cache = FALSE;
|
||||
$this->cached = FALSE;
|
||||
$this->options = $this->prepare_options($options, $wgBugzillaDefaultFields);
|
||||
}
|
||||
|
||||
protected function _getCache()
|
||||
{
|
||||
if (!$this->cache) {
|
||||
$this->cache = Bugzilla::getCache();
|
||||
}
|
||||
|
||||
return $this->cache;
|
||||
}
|
||||
|
||||
public function id() {
|
||||
if (!$this->id) {
|
||||
$this->id = $this->_generate_id($this->options);
|
||||
|
@ -112,33 +103,35 @@ abstract class BugzillaBaseQuery {
|
|||
return $options;
|
||||
}
|
||||
|
||||
// Connect and fetch the data
|
||||
/**
|
||||
* Wrap around sub-classes actual fetch action, with caching.
|
||||
* Uses MediaWiki main cache strategy.
|
||||
*
|
||||
* TODO: use ObjectCache::getLocalServerInstance() once MW >= 1.27
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function fetch() {
|
||||
|
||||
global $wgBugzillaCacheMins;
|
||||
global $wgMainCacheType;
|
||||
global $wgBugzillaCacheTimeOut;
|
||||
|
||||
// Don't do anything if we already had an error
|
||||
if( $this->error ) { return; }
|
||||
if ($this->error) { return; }
|
||||
|
||||
$cache = $this->_getCache();
|
||||
$row = $cache->get($this->id());
|
||||
$key = implode(':', ['mediawiki', 'bugzilla', 'bugs', sha1(serialize($this->id()))]);
|
||||
$cache = wfGetCache($wgMainCacheType);
|
||||
$row = $cache->get($key);
|
||||
|
||||
// If the cache entry is older than this we need to invalidate it
|
||||
$expiry = strtotime("-$wgBugzillaCacheMins minutes");
|
||||
if ($row === false) {
|
||||
$this->cached = false;
|
||||
|
||||
if( !$row ) {
|
||||
// No cache entry
|
||||
$this->cached = false;
|
||||
$this->_fetch_by_options();
|
||||
$cache->set($key, base64_encode(serialize($this->data)), $wgBugzillaCacheTimeOut * 60);
|
||||
|
||||
// Does the Bugzilla query in the background and updates the cache
|
||||
$this->_fetch_by_options();
|
||||
$this->_update_cache();
|
||||
|
||||
return $this->data;
|
||||
return $this->data;
|
||||
} else {
|
||||
// Cache is good, use it
|
||||
$this->cached = true;
|
||||
$this->data = unserialize(base64_decode($row));
|
||||
$this->cached = true;
|
||||
return $this->data = unserialize(base64_decode($row));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
15
README.md
15
README.md
|
@ -19,16 +19,11 @@ Installation
|
|||
Please substitute your installation path if it is different*
|
||||
|
||||
1. Install the requirements above
|
||||
2. Check the project out into `/var/lib/mediawiki/extensions/Bugzilla`
|
||||
3. Edit `/etc/mediawiki/LocalSettings.php` and add
|
||||
`require_once("/var/lib/mediawiki/extensions/Bugzilla/Bugzilla.php");`
|
||||
4. Edit `/etc/mediawiki/LocalSettings.php` and change/override any
|
||||
configuration variables. Current configuration variables and their defaults
|
||||
can be found at the end of `Bugzilla.php`
|
||||
5. Run the MediaWiki update script to create the cache database table
|
||||
`php /var/lib/mediawiki/maintenance/update.php`. __Note that you may need to
|
||||
add `$wgDBadminuser` and `$wgDBadminpassword` to
|
||||
`/etc/mediawiki/LocalSettings.php` depending on your MediaWiki version__
|
||||
2. Check the project out into `/path/to/your/mediawiki/extensions/Bugzilla`
|
||||
3. Edit `/path/to/your/mediawiki/LocalSettings.php` and add
|
||||
`require_once("$IP/extensions/Bugzilla/Bugzilla.php");`
|
||||
and change/override any configuration variables.
|
||||
Current configuration variables and their defaults can be found at the end of `Bugzilla.php`
|
||||
|
||||
Usage
|
||||
================================
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<?php
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
class BugzillaCacheApc implements BugzillaCacheI
|
||||
{
|
||||
|
||||
public function set($key, $value, $ttl = 300) {
|
||||
return apc_store($key, $value, $ttl);
|
||||
}
|
||||
|
||||
public function get($key) {
|
||||
return apc_fetch($key);
|
||||
}
|
||||
|
||||
public function expire($key) {
|
||||
return apc_delete($key);
|
||||
}
|
||||
|
||||
public static function setup($updater) {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
/**
|
||||
* Dummy cache for those times you want to test the functionality WITHOUT the
|
||||
* cache.
|
||||
*/
|
||||
class BugzillaCacheDummy implements BugzillaCacheI
|
||||
{
|
||||
|
||||
public function set($key, $value, $ttl = 300)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
public function expire($key)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function setup($updater)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
<?php
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
interface BugzillaCacheI
|
||||
{
|
||||
public function set($key, $value, $ttl = 300);
|
||||
|
||||
public function get($key);
|
||||
|
||||
public function expire($key);
|
||||
|
||||
public static function setup($updater);
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
class BugzillaCacheMemcache implements BugzillaCacheI
|
||||
{
|
||||
|
||||
protected $_memcache;
|
||||
|
||||
public function __construct() {
|
||||
// As much as I detest using a global here, it is necessary to avoid
|
||||
// needing to inject the $wgMemc object, thus breaking the usefulness
|
||||
// of the interface. Using the $wgMemc object is important for the
|
||||
// consistency of the code.
|
||||
global $wgMemc;
|
||||
$this->_memcache = $wgMemc;
|
||||
}
|
||||
|
||||
public function set($key, $value, $ttl = 300) {
|
||||
// Get the wikimedia key style expected
|
||||
$key = wfMemcKey($key);
|
||||
return $this->_memcache->set($key, $value, $ttl);
|
||||
}
|
||||
|
||||
public function get($key) {
|
||||
// Get the wikimedia key style expected
|
||||
$key = wfMemcKey($key);
|
||||
return $this->_memcache->get($key);
|
||||
}
|
||||
|
||||
public function expire($key) {
|
||||
// Get the wikimedia key style expected
|
||||
$key = wfMemcKey($key);
|
||||
return $this->_memcache->delete($key);
|
||||
}
|
||||
|
||||
public static function setup($updater) {
|
||||
return;
|
||||
}
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
<?php
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
/**
|
||||
*/
|
||||
class BugzillaCacheSql implements BugzillaCacheI
|
||||
{
|
||||
protected function _getDatabase($type = DB_MASTER) {
|
||||
return wfGetDB($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
* @param string $value
|
||||
* @param integer $ttl
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function set($key, $value, $ttl = 300)
|
||||
{
|
||||
$master = $this->_getDatabase();
|
||||
|
||||
$now = time(); // Using time() because it's a PHP built-in.
|
||||
$expires = $now + $ttl;
|
||||
|
||||
if (null === $this->get($key)) {
|
||||
$res = $master->insert(
|
||||
'bugzilla_cache',
|
||||
array(
|
||||
$master->addIdentifierQuotes( 'key' ) => $key,
|
||||
'data' => $value,
|
||||
'expires' => $expires
|
||||
),
|
||||
__METHOD__
|
||||
);
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function get($key)
|
||||
{
|
||||
$slave = $this->_getDatabase(DB_SLAVE);
|
||||
|
||||
$res = $slave->select(
|
||||
'bugzilla_cache',
|
||||
array( 'id', 'data', 'expires' ),
|
||||
array( $slave->addIdentifierQuotes( 'key' ) => $key ),
|
||||
__METHOD__,
|
||||
array( 'LIMIT' => 1 )
|
||||
);
|
||||
|
||||
if( !$res ) {
|
||||
$this->expire($key);
|
||||
return null;
|
||||
}
|
||||
$row = $res->fetchRow();
|
||||
|
||||
if (!$row || ($row['expires'] < time())) {
|
||||
$this->expire($key); // This won't hurt us if the first condition is true.
|
||||
return null;
|
||||
}
|
||||
|
||||
return $row['data'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $key
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function expire($key)
|
||||
{
|
||||
$master = $this->_getDatabase();
|
||||
global $wgBugzillaCacheType;
|
||||
|
||||
if ($wgBugzillaCacheType == 'mysql') {
|
||||
return $master->delete(
|
||||
'bugzilla_cache',
|
||||
array('`key`="' . $key . '"')
|
||||
);
|
||||
} else {
|
||||
return $master->delete(
|
||||
'bugzilla_cache',
|
||||
array('key' => $key)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $updater DatabaseUpdater
|
||||
*/
|
||||
final public static function setup($updater)
|
||||
{
|
||||
global $wgBugzillaCacheType;
|
||||
|
||||
$sqlFile = sprintf('%s/sql/%s.sql',
|
||||
dirname(__FILE__),
|
||||
$wgBugzillaCacheType);
|
||||
|
||||
if ($updater === null) {
|
||||
// <= 1.16 support
|
||||
global $wgExtNewTables;
|
||||
global $wgExtModifiedFields;
|
||||
$wgExtNewTables[] = array(
|
||||
'bugzilla_cache',
|
||||
$sqlFile,
|
||||
);
|
||||
} else {
|
||||
// >= 1.17 support
|
||||
$updater->addExtensionUpdate(array('addTable',
|
||||
'bugzilla_cache',
|
||||
$sqlFile,
|
||||
TRUE));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
CREATE TABLE IF NOT EXISTS /*$wgDBprefix*/bugzilla_cache (
|
||||
`id` integer(40) NOT NULL AUTO_INCREMENT,
|
||||
`key` varchar(255) NOT NULL DEFAULT '',
|
||||
`data` longtext,
|
||||
`expires` integer(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE INDEX /*i*/uniq_bugzilla_cache_key (`key`)
|
||||
) /*$wgDBTableOptions*/;
|
|
@ -1,6 +0,0 @@
|
|||
CREATE TABLE bugzilla_cache (
|
||||
id SERIAL PRIMARY KEY,
|
||||
key VARCHAR(255) UNIQUE NOT NULL DEFAULT '',
|
||||
data TEXT,
|
||||
expires INTEGER NOT NULL DEFAULT 0
|
||||
);
|
|
@ -1,8 +0,0 @@
|
|||
CREATE TABLE `bugzilla_cache` (
|
||||
`id` integer primary key AUTOINCREMENT,
|
||||
`key` TEXT NOT NULL DEFAULT '',
|
||||
`data` TEXT,
|
||||
`expires` integer(11) NOT NULL DEFAULT 0
|
||||
);
|
||||
CREATE UNIQUE INDEX uniq_bugzilla_cache_key ON `bugzilla_cache` (`key`);
|
||||
|
Загрузка…
Ссылка в новой задаче