diff --git a/Bugzilla.class.php b/Bugzilla.class.php index 9cd18bd..8aa041b 100644 --- a/Bugzilla.class.php +++ b/Bugzilla.class.php @@ -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 @@ public static function create($config=array(), $opts=array(), $title='') { 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(); - } } diff --git a/Bugzilla.php b/Bugzilla.php index b37b3ef..649773e 100755 --- a/Bugzilla.php +++ b/Bugzilla.php @@ -51,33 +51,15 @@ $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 @@ function BugzillaRender($input, array $args, Parser $parser, $frame=null ) { // 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) diff --git a/BugzillaOutput.class.php b/BugzillaOutput.class.php index 867346b..cb89129 100644 --- a/BugzillaOutput.class.php +++ b/BugzillaOutput.class.php @@ -3,7 +3,6 @@ abstract class BugzillaOutput { public $response; - public $cache; public function __construct($config, $options, $title='') { $this->title = $title; @@ -58,15 +57,6 @@ public function render() { } - protected function _getCache() - { - if (!$this->cache) { - $this->cache = Bugzilla::getCache(); - } - - return $this->cache; - } - abstract protected function setup_template_data(); } @@ -146,15 +136,22 @@ public function setup_template_data() { include_once 'pchart/class/pData.class.php'; global $wgBugzillaChartUrl; - - $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'; + global $wgBugzillaCacheTimeOut; + global $wgMainCacheType; + + $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 @@ public function generate_chart($chart_name) $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 @@ public function generate_chart($chart_name) $pImage->drawBarChart(); $pImage->render($wgBugzillaChartStorage . '/' . $chart_name . '.png'); - $cache = $this->_getCache(); - $cache->set($chart_name, $chart_name . '.png'); + return $chart_name; } } - diff --git a/BugzillaQuery.class.php b/BugzillaQuery.class.php index 05f1f6d..aea2c22 100644 --- a/BugzillaQuery.class.php +++ b/BugzillaQuery.class.php @@ -31,19 +31,10 @@ public function __construct($type, $options, $title) { $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 @@ public function rebased_options() 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; } - - $cache = $this->_getCache(); - $row = $cache->get($this->id()); + if ($this->error) { return; } - // If the cache entry is older than this we need to invalidate it - $expiry = strtotime("-$wgBugzillaCacheMins minutes"); + $key = implode(':', ['mediawiki', 'bugzilla', 'bugs', sha1(serialize($this->id()))]); + $cache = wfGetCache($wgMainCacheType); + $row = $cache->get($key); - if( !$row ) { - // No cache entry - $this->cached = false; + if ($row === false) { + $this->cached = false; - // Does the Bugzilla query in the background and updates the cache - $this->_fetch_by_options(); - $this->_update_cache(); + $this->_fetch_by_options(); + $cache->set($key, base64_encode(serialize($this->data)), $wgBugzillaCacheTimeOut * 60); - 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)); } } diff --git a/README.md b/README.md index b4a39c5..f8102d0 100644 --- a/README.md +++ b/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 ================================ diff --git a/cache/BugzillaCacheApc.class.php b/cache/BugzillaCacheApc.class.php deleted file mode 100644 index 6c949da..0000000 --- a/cache/BugzillaCacheApc.class.php +++ /dev/null @@ -1,23 +0,0 @@ -_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; - } -} \ No newline at end of file diff --git a/cache/BugzillaCacheSql.class.php b/cache/BugzillaCacheSql.class.php deleted file mode 100644 index ba50bb8..0000000 --- a/cache/BugzillaCacheSql.class.php +++ /dev/null @@ -1,123 +0,0 @@ -_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)); - } - } -} diff --git a/cache/sql/mysql.sql b/cache/sql/mysql.sql deleted file mode 100644 index 5502938..0000000 --- a/cache/sql/mysql.sql +++ /dev/null @@ -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*/; diff --git a/cache/sql/postgresql.sql b/cache/sql/postgresql.sql deleted file mode 100644 index 7879eee..0000000 --- a/cache/sql/postgresql.sql +++ /dev/null @@ -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 -); \ No newline at end of file diff --git a/cache/sql/sqlite.sql b/cache/sql/sqlite.sql deleted file mode 100644 index 06b8f8e..0000000 --- a/cache/sql/sqlite.sql +++ /dev/null @@ -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`); -