From: Tim Starling Date: Sat, 9 Apr 2005 10:30:45 +0000 (+0000) Subject: Smarter, more flexible cache type selection. Moved entire contents of ObjectCache... X-Git-Tag: 1.5.0alpha1~325 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/exercices/journal.php?a=commitdiff_plain;h=52a4214b2072705ee1c22c12fd10296ed6e72783;p=lhc%2Fweb%2Fwiklou.git Smarter, more flexible cache type selection. Moved entire contents of ObjectCache.php to BagOStuff.php, to make way for some more generic code. --- diff --git a/config/index.php b/config/index.php index 0c132576dc..328f34fb78 100644 --- a/config/index.php +++ b/config/index.php @@ -609,6 +609,8 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) { /* Write out the config file now that all is well */ print "

Creating LocalSettings.php...

\n\n"; $localSettings = "<" . "?php$endl$local$endl?" . ">"; + // Fix up a common line-ending problem (due to CVS on Windows) + $localSettings = str_replace( "\r\n", "\n", $localSettings ); if( version_compare( phpversion(), "4.3.2" ) >= 0 ) { $xt = "xt"; # Refuse to overwrite an existing file @@ -953,20 +955,17 @@ function writeLocalSettings( $conf ) { switch ( $conf->Shm ) { case 'memcached': - $memcached = 'true'; - $turck = '#'; + $cacheType = 'CACHE_MEMCACHED'; $mcservers = var_export( $conf->MCServerArray, true ); break; case 'turck': case 'eaccel': - $memcached = 'false'; + $cacheType = 'CACHE_ACCEL'; $mcservers = 'array()'; - $turck = ''; break; default: - $memcached = 'false'; + $cacheType = 'CACHE_NONE'; $mcservers = 'array()'; - $turck = '#'; } if ( $conf->Email == 'email_enabled' ) { @@ -1077,10 +1076,8 @@ if ( \$wgCommandLineMode ) { \$wgDBmysql4 = \$wgEnablePersistentLC = {$conf->DBmysql4}; ## Shared memory settings -\$wgUseMemCached = $memcached; +\$wgMainCacheType = $cacheType; \$wgMemCachedServers = $mcservers; -{$turck}\$wgUseTurckShm = function_exists( 'mmcache_get' ) && ( php_sapi_name() == 'apache' || php_sapi_name() == 'apache2handler' ); -{$turck}\$wgUseEAccelShm = function_exists( 'eaccelerator_get' ) && ( php_sapi_name() == 'apache' || php_sapi_name() == 'apache2handler' ); ## To enable image uploads, make sure the 'images' directory ## is writable, then uncomment this: diff --git a/includes/BagOStuff.php b/includes/BagOStuff.php new file mode 100644 index 0000000000..78ca5110b5 --- /dev/null +++ b/includes/BagOStuff.php @@ -0,0 +1,498 @@ + +# http://www.mediawiki.org/ +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# http://www.gnu.org/copyleft/gpl.html +/** + * + * @package MediaWiki + */ + +/** + * Simple generic object store + * + * interface is intended to be more or less compatible with + * the PHP memcached client. + * + * backends for local hash array and SQL table included: + * $bag = new HashBagOStuff(); + * $bag = new MysqlBagOStuff($tablename); # connect to db first + * + * @package MediaWiki + * @abstract + */ +class BagOStuff { + var $debugmode; + + function BagOStuff() { + $this->set_debug( false ); + } + + function set_debug($bool) { + $this->debugmode = $bool; + } + + /* *** THE GUTS OF THE OPERATION *** */ + /* Override these with functional things in subclasses */ + + function get($key) { + /* stub */ + return false; + } + + function set($key, $value, $exptime=0) { + /* stub */ + return false; + } + + function delete($key, $time=0) { + /* stub */ + return false; + } + + function lock($key, $timeout = 0) { + /* stub */ + return true; + } + + function unlock($key) { + /* stub */ + return true; + } + + /* *** Emulated functions *** */ + /* Better performance can likely be got with custom written versions */ + function get_multi($keys) { + $out = array(); + foreach($keys as $key) + $out[$key] = $this->get($key); + return $out; + } + + function set_multi($hash, $exptime=0) { + foreach($hash as $key => $value) + $this->set($key, $value, $exptime); + } + + function add($key, $value, $exptime=0) { + if( $this->get($key) == false ) { + $this->set($key, $value, $exptime); + return true; + } + } + + function add_multi($hash, $exptime=0) { + foreach($hash as $key => $value) + $this->add($key, $value, $exptime); + } + + function delete_multi($keys, $time=0) { + foreach($keys as $key) + $this->delete($key, $time); + } + + function replace($key, $value, $exptime=0) { + if( $this->get($key) !== false ) + $this->set($key, $value, $exptime); + } + + function incr($key, $value=1) { + if ( !$this->lock($key) ) { + return false; + } + $value = intval($value); + if($value < 0) $value = 0; + + $n = false; + if( ($n = $this->get($key)) !== false ) { + $n += $value; + $this->set($key, $n); // exptime? + } + $this->unlock($key); + return $n; + } + + function decr($key, $value=1) { + if ( !$this->lock($key) ) { + return false; + } + $value = intval($value); + if($value < 0) $value = 0; + + $m = false; + if( ($n = $this->get($key)) !== false ) { + $m = $n - $value; + if($m < 0) $m = 0; + $this->set($key, $m); // exptime? + } + $this->unlock($key); + return $m; + } + + function _debug($text) { + if($this->debugmode) + wfDebug("BagOStuff debug: $text\n"); + } +} + + +/** + * Functional versions! + * @todo document + * @package MediaWiki + */ +class HashBagOStuff extends BagOStuff { + /* + This is a test of the interface, mainly. It stores + things in an associative array, which is not going to + persist between program runs. + */ + var $bag; + + function HashBagOStuff() { + $this->bag = array(); + } + + function _expire($key) { + $et = $this->bag[$key][1]; + if(($et == 0) || ($et > time())) + return false; + $this->delete($key); + return true; + } + + function get($key) { + if(!$this->bag[$key]) + return false; + if($this->_expire($key)) + return false; + return $this->bag[$key][0]; + } + + function set($key,$value,$exptime=0) { + if(($exptime != 0) && ($exptime < 3600*24*30)) + $exptime = time() + $exptime; + $this->bag[$key] = array( $value, $exptime ); + } + + function delete($key,$time=0) { + if(!$this->bag[$key]) + return false; + unset($this->bag[$key]); + return true; + } +} + +/* +CREATE TABLE objectcache ( + keyname char(255) binary not null default '', + value mediumblob, + exptime datetime, + unique key (keyname), + key (exptime) +); +*/ + +/** + * @todo document + * @abstract + * @package MediaWiki + */ +class SqlBagOStuff extends BagOStuff { + var $table; + var $lastexpireall = 0; + + function SqlBagOStuff($tablename = 'objectcache') { + $this->table = $tablename; + } + + function get($key) { + /* expire old entries if any */ + $this->garbageCollect(); + + $res = $this->_query( + "SELECT value,exptime FROM $0 WHERE keyname='$1'", $key); + if(!$res) { + $this->_debug("get: ** error: " . $this->_dberror($res) . " **"); + return false; + } + if($row=$this->_fetchobject($res)) { + $this->_debug("get: retrieved data; exp time is " . $row->exptime); + return $this->_unserialize($row->value); + } else { + $this->_debug('get: no matching rows'); + } + return false; + } + + function set($key,$value,$exptime=0) { + $exptime = intval($exptime); + if($exptime < 0) $exptime = 0; + if($exptime == 0) { + $exp = $this->_maxdatetime(); + } else { + if($exptime < 3600*24*30) + $exptime += time(); + $exp = $this->_fromunixtime($exptime); + } + $this->delete( $key ); + $this->_query( + "INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2','$exp')", + $key, $this->_serialize($value)); + return true; /* ? */ + } + + function delete($key,$time=0) { + $this->_query( + "DELETE FROM $0 WHERE keyname='$1'", $key ); + return true; /* ? */ + } + + function getTableName() { + return $this->table; + } + + function _query($sql) { + $reps = func_get_args(); + $reps[0] = $this->getTableName(); + // ewwww + for($i=0;$i_strencode($reps[$i]), + $sql); + } + $res = $this->_doquery($sql); + if($res == false) { + $this->_debug('query failed: ' . $this->_dberror($res)); + } + return $res; + } + + function _strencode($str) { + /* Protect strings in SQL */ + return str_replace( "'", "''", $str ); + } + + function _doquery($sql) { + die( 'abstract function SqlBagOStuff::_doquery() must be defined' ); + } + + function _fetchrow($res) { + die( 'abstract function SqlBagOStuff::_fetchrow() must be defined' ); + } + + function _freeresult($result) { + /* stub */ + return false; + } + + function _dberror($result) { + /* stub */ + return 'unknown error'; + } + + function _maxdatetime() { + die( 'abstract function SqlBagOStuff::_maxdatetime() must be defined' ); + } + + function _fromunixtime() { + die( 'abstract function SqlBagOStuff::_fromunixtime() must be defined' ); + } + + function garbageCollect() { + /* Ignore 99% of requests */ + if ( !mt_rand( 0, 100 ) ) { + $nowtime = time(); + /* Avoid repeating the delete within a few seconds */ + if ( $nowtime > ($this->lastexpireall + 1) ) { + $this->lastexpireall = $nowtime; + $this->expireall(); + } + } + } + + function expireall() { + /* Remove any items that have expired */ + $now = $this->_fromunixtime( time() ); + $this->_query( "DELETE FROM $0 WHERE exptime<'$now'" ); + } + + function deleteall() { + /* Clear *all* items from cache table */ + $this->_query( "DELETE FROM $0" ); + } + + /** + * Serialize an object and, if possible, compress the representation. + * On typical message and page data, this can provide a 3X decrease + * in storage requirements. + * + * @param mixed $data + * @return string + */ + function _serialize( &$data ) { + $serial = serialize( $data ); + if( function_exists( 'gzdeflate' ) ) { + return gzdeflate( $serial ); + } else { + return $serial; + } + } + + /** + * Unserialize and, if necessary, decompress an object. + * @param string $serial + * @return mixed + */ + function &_unserialize( $serial ) { + if( function_exists( 'gzinflate' ) ) { + $decomp = @gzinflate( $serial ); + if( false !== $decomp ) { + $serial = $decomp; + } + } + return unserialize( $serial ); + } +} + +/** + * @todo document + * @package MediaWiki + */ +class MediaWikiBagOStuff extends SqlBagOStuff { + var $tableInitialised = false; + + function _doquery($sql) { + $dbw =& wfGetDB( DB_MASTER ); + return $dbw->query($sql, 'MediaWikiBagOStuff:_doquery'); + } + function _fetchobject($result) { + $dbw =& wfGetDB( DB_MASTER ); + return $dbw->fetchObject($result); + } + function _freeresult($result) { + $dbw =& wfGetDB( DB_MASTER ); + return $dbw->freeResult($result); + } + function _dberror($result) { + $dbw =& wfGetDB( DB_MASTER ); + return $dbw->lastError(); + } + function _maxdatetime() { + return '9999-12-31 12:59:59'; + } + function _fromunixtime($ts) { + return gmdate( 'Y-m-d H:i:s', $ts ); + } + function _strencode($s) { + $dbw =& wfGetDB( DB_MASTER ); + return $dbw->strencode($s); + } + function getTableName() { + if ( !$this->tableInitialised ) { + $dbw =& wfGetDB( DB_MASTER ); + $this->table = $dbw->tableName( $this->table ); + $this->tableInitialised = true; + } + return $this->table; + } +} + +/** + * This is a wrapper for Turck MMCache's shared memory functions. + * + * You can store objects with mmcache_put() and mmcache_get(), but Turck seems + * to use a weird custom serializer that randomly segfaults. So we wrap calls + * with serialize()/unserialize(). + * + * The thing I noticed about the Turck serialized data was that unlike ordinary + * serialize(), it contained the names of methods, and judging by the amount of + * binary data, perhaps even the bytecode of the methods themselves. It may be + * that Turck's serializer is faster, so a possible future extension would be + * to use it for arrays but not for objects. + * + * @package MediaWiki + */ +class TurckBagOStuff extends BagOStuff { + function get($key) { + $val = mmcache_get( $key ); + if ( is_string( $val ) ) { + $val = unserialize( $val ); + } + return $val; + } + + function set($key, $value, $exptime=0) { + mmcache_put( $key, serialize( $value ), $exptime ); + return true; + } + + function delete($key, $time=0) { + mmcache_rm( $key ); + return true; + } + + function lock($key, $waitTimeout = 0 ) { + mmcache_lock( $key ); + return true; + } + + function unlock($key) { + mmcache_unlock( $key ); + return true; + } +} + +/** + * This is a wrapper for eAccelerator's shared memory functions. + * + * This is basically identical to the Turck MMCache version, + * mostly because eAccelerator is based on Turck MMCache. + * + * @package MediaWiki + */ +class eAccelBagOStuff extends BagOStuff { + function get($key) { + $val = eaccelerator_get( $key ); + if ( is_string( $val ) ) { + $val = unserialize( $val ); + } + return $val; + } + + function set($key, $value, $exptime=0) { + eaccelerator_put( $key, serialize( $value ), $exptime ); + return true; + } + + function delete($key, $time=0) { + eaccelerator_rm( $key ); + return true; + } + + function lock($key, $waitTimeout = 0 ) { + eaccelerator_lock( $key ); + return true; + } + + function unlock($key) { + eaccelerator_unlock( $key ); + return true; + } +} +?> diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index 004cc5e105..fb08b23230 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -303,40 +303,25 @@ $wgSqlTimeout = 30; */ $wgLocalDatabases = array(); +/** + * Object cache settings + * See Defines.php for types + */ +$wgMainCacheType = CACHE_NONE; +$wgMessageCacheType = CACHE_ANYTHING; +$wgParserCacheType = CACHE_ANYTHING; -# Memcached settings -# See docs/memcached.doc -# -$wgMemCachedDebug = false; # Will be set to false in Setup.php, if the server isn't working -$wgUseMemCached = false; -$wgMemCachedServers = array( '127.0.0.1:11000' ); -$wgMemCachedDebug = false; $wgSessionsInMemcached = false; $wgLinkCacheMemcached = false; # Not fully tested /** - * Turck MMCache shared memory - * You can use this for persistent caching where your wiki runs on a single - * server. Enabled by default if Turck is installed. Mutually exclusive with - * memcached and eAccelerator, the preference order priorities being memcached first, - * Turck MMCache second, and eAccelerator third. - * - * @global bool $wgUseTurckShm Enable or disabled Turck MMCache + * Memcached-specific settings + * See docs/memcached.doc */ -$wgUseTurckShm = false; +$wgMemCachedDebug = false; # Will be set to false in Setup.php, if the server isn't working +$wgMemCachedServers = array( '127.0.0.1:11000' ); +$wgMemCachedDebug = false; -/** - * eAccelerator shared memory - * You can use this for persistent caching where your wiki runs on a single - * server. Enabled by default if eAccelerator is installed. Mutually exclusive with - * memcached and Turck MMCache, the preference order being memcached first, - * Turck MMCache second, and eAccelerator third. - * - * Most of the code to support this is directly copied from the Turck code. - * - * @global bool $wgUseEAccelShm Enable or disabled eAccelerator - */ -$wgUseEAccelShm = false; # Language settings diff --git a/includes/Defines.php b/includes/Defines.php index 9c35f22dae..c5e16a64a3 100644 --- a/includes/Defines.php +++ b/includes/Defines.php @@ -75,4 +75,13 @@ $wgAvailableRights = array('read', 'edit', 'move', 'delete', 'undelete', 'asksql', 'rollback', 'patrol', 'editinterface', 'siteadmin', 'bot', 'validate', 'import'); +/** + * Cache type + */ +define( 'CACHE_ANYTHING', -1 ); // Use anything, as long as it works +define( 'CACHE_NONE', 0 ); // Do not cache +define( 'CACHE_DB', 1 ); // Store cache objects in the DB +define( 'CACHE_MEMCACHED', 2 ); // MemCached, must specify servers in $wgMemCacheServers +define( 'CACHE_ACCEL', 3 ); // eAccelerator or Turck, whichever is available + ?> diff --git a/includes/ObjectCache.php b/includes/ObjectCache.php index 78ca5110b5..245bb38719 100644 --- a/includes/ObjectCache.php +++ b/includes/ObjectCache.php @@ -1,498 +1,111 @@ -# http://www.mediawiki.org/ -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# http://www.gnu.org/copyleft/gpl.html -/** - * - * @package MediaWiki - */ - -/** - * Simple generic object store - * - * interface is intended to be more or less compatible with - * the PHP memcached client. - * - * backends for local hash array and SQL table included: - * $bag = new HashBagOStuff(); - * $bag = new MysqlBagOStuff($tablename); # connect to db first - * - * @package MediaWiki - * @abstract - */ -class BagOStuff { - var $debugmode; - - function BagOStuff() { - $this->set_debug( false ); - } - - function set_debug($bool) { - $this->debugmode = $bool; - } - - /* *** THE GUTS OF THE OPERATION *** */ - /* Override these with functional things in subclasses */ - - function get($key) { - /* stub */ - return false; - } - - function set($key, $value, $exptime=0) { - /* stub */ - return false; - } - - function delete($key, $time=0) { - /* stub */ - return false; - } - - function lock($key, $timeout = 0) { - /* stub */ - return true; - } - function unlock($key) { - /* stub */ - return true; - } - - /* *** Emulated functions *** */ - /* Better performance can likely be got with custom written versions */ - function get_multi($keys) { - $out = array(); - foreach($keys as $key) - $out[$key] = $this->get($key); - return $out; - } - - function set_multi($hash, $exptime=0) { - foreach($hash as $key => $value) - $this->set($key, $value, $exptime); - } - - function add($key, $value, $exptime=0) { - if( $this->get($key) == false ) { - $this->set($key, $value, $exptime); - return true; - } - } - - function add_multi($hash, $exptime=0) { - foreach($hash as $key => $value) - $this->add($key, $value, $exptime); - } - - function delete_multi($keys, $time=0) { - foreach($keys as $key) - $this->delete($key, $time); - } - - function replace($key, $value, $exptime=0) { - if( $this->get($key) !== false ) - $this->set($key, $value, $exptime); - } - - function incr($key, $value=1) { - if ( !$this->lock($key) ) { - return false; - } - $value = intval($value); - if($value < 0) $value = 0; - - $n = false; - if( ($n = $this->get($key)) !== false ) { - $n += $value; - $this->set($key, $n); // exptime? - } - $this->unlock($key); - return $n; - } - - function decr($key, $value=1) { - if ( !$this->lock($key) ) { - return false; - } - $value = intval($value); - if($value < 0) $value = 0; - - $m = false; - if( ($n = $this->get($key)) !== false ) { - $m = $n - $value; - if($m < 0) $m = 0; - $this->set($key, $m); // exptime? - } - $this->unlock($key); - return $m; - } - - function _debug($text) { - if($this->debugmode) - wfDebug("BagOStuff debug: $text\n"); - } -} - - -/** - * Functional versions! - * @todo document - * @package MediaWiki - */ -class HashBagOStuff extends BagOStuff { - /* - This is a test of the interface, mainly. It stores - things in an associative array, which is not going to - persist between program runs. - */ - var $bag; - - function HashBagOStuff() { - $this->bag = array(); - } - - function _expire($key) { - $et = $this->bag[$key][1]; - if(($et == 0) || ($et > time())) - return false; - $this->delete($key); - return true; - } - - function get($key) { - if(!$this->bag[$key]) - return false; - if($this->_expire($key)) - return false; - return $this->bag[$key][0]; - } - - function set($key,$value,$exptime=0) { - if(($exptime != 0) && ($exptime < 3600*24*30)) - $exptime = time() + $exptime; - $this->bag[$key] = array( $value, $exptime ); - } - - function delete($key,$time=0) { - if(!$this->bag[$key]) - return false; - unset($this->bag[$key]); - return true; - } +if (!defined('MEDIAWIKI')) die( "Not a valid entry point"); + + +# FakeMemCachedClient imitates the API of memcached-client v. 0.1.2. +# It acts as a memcached server with no RAM, that is, all objects are +# cleared the moment they are set. All set operations succeed and all +# get operations return null. +class FakeMemCachedClient { + function add ($key, $val, $exp = 0) { return true; } + function decr ($key, $amt=1) { return null; } + function delete ($key, $time = 0) { return false; } + function disconnect_all () { } + function enable_compress ($enable) { } + function forget_dead_hosts () { } + function get ($key) { return null; } + function get_multi ($keys) { return array_pad(array(), count($keys), null); } + function incr ($key, $amt=1) { return null; } + function replace ($key, $value, $exp=0) { return false; } + function run_command ($sock, $cmd) { return null; } + function set ($key, $value, $exp=0){ return true; } + function set_compress_threshold ($thresh){ } + function set_debug ($dbg) { } + function set_servers ($list) { } } -/* -CREATE TABLE objectcache ( - keyname char(255) binary not null default '', - value mediumblob, - exptime datetime, - unique key (keyname), - key (exptime) -); -*/ +global $wgCaches; +$wgCaches = array(); -/** - * @todo document - * @abstract - * @package MediaWiki - */ -class SqlBagOStuff extends BagOStuff { - var $table; - var $lastexpireall = 0; +function &wfGetCache( $inputType ) { + global $wgCaches, $wgMemCachedServers, $wgMemCachedDebug; + $cache = false; - function SqlBagOStuff($tablename = 'objectcache') { - $this->table = $tablename; - } - - function get($key) { - /* expire old entries if any */ - $this->garbageCollect(); - - $res = $this->_query( - "SELECT value,exptime FROM $0 WHERE keyname='$1'", $key); - if(!$res) { - $this->_debug("get: ** error: " . $this->_dberror($res) . " **"); - return false; - } - if($row=$this->_fetchobject($res)) { - $this->_debug("get: retrieved data; exp time is " . $row->exptime); - return $this->_unserialize($row->value); - } else { - $this->_debug('get: no matching rows'); - } - return false; - } - - function set($key,$value,$exptime=0) { - $exptime = intval($exptime); - if($exptime < 0) $exptime = 0; - if($exptime == 0) { - $exp = $this->_maxdatetime(); - } else { - if($exptime < 3600*24*30) - $exptime += time(); - $exp = $this->_fromunixtime($exptime); - } - $this->delete( $key ); - $this->_query( - "INSERT INTO $0 (keyname,value,exptime) VALUES('$1','$2','$exp')", - $key, $this->_serialize($value)); - return true; /* ? */ - } - - function delete($key,$time=0) { - $this->_query( - "DELETE FROM $0 WHERE keyname='$1'", $key ); - return true; /* ? */ - } - - function getTableName() { - return $this->table; - } - - function _query($sql) { - $reps = func_get_args(); - $reps[0] = $this->getTableName(); - // ewwww - for($i=0;$i_strencode($reps[$i]), - $sql); + if ( $inputType == CACHE_ANYTHING ) { + reset( $wgCaches ); + $type = key( $wgCaches ); + if ( $type === false || $type === CACHE_NONE ) { + $type = CACHE_DB; } - $res = $this->_doquery($sql); - if($res == false) { - $this->_debug('query failed: ' . $this->_dberror($res)); - } - return $res; - } - - function _strencode($str) { - /* Protect strings in SQL */ - return str_replace( "'", "''", $str ); - } - - function _doquery($sql) { - die( 'abstract function SqlBagOStuff::_doquery() must be defined' ); - } - - function _fetchrow($res) { - die( 'abstract function SqlBagOStuff::_fetchrow() must be defined' ); - } - - function _freeresult($result) { - /* stub */ - return false; - } - - function _dberror($result) { - /* stub */ - return 'unknown error'; + } else { + $type = $inputType; } - - function _maxdatetime() { - die( 'abstract function SqlBagOStuff::_maxdatetime() must be defined' ); - } - - function _fromunixtime() { - die( 'abstract function SqlBagOStuff::_fromunixtime() must be defined' ); - } - - function garbageCollect() { - /* Ignore 99% of requests */ - if ( !mt_rand( 0, 100 ) ) { - $nowtime = time(); - /* Avoid repeating the delete within a few seconds */ - if ( $nowtime > ($this->lastexpireall + 1) ) { - $this->lastexpireall = $nowtime; - $this->expireall(); + + if ( $type == CACHE_MEMCACHED ) { + if ( !array_key_exists( CACHE_MEMCACHED, $wgCaches ) ){ + require_once( 'memcached-client.php' ); + + class MemCachedClientforWiki extends memcached { + function _debugprint( $text ) { + wfDebug( "memcached: $text\n" ); + } } - } - } - - function expireall() { - /* Remove any items that have expired */ - $now = $this->_fromunixtime( time() ); - $this->_query( "DELETE FROM $0 WHERE exptime<'$now'" ); - } - - function deleteall() { - /* Clear *all* items from cache table */ - $this->_query( "DELETE FROM $0" ); - } - - /** - * Serialize an object and, if possible, compress the representation. - * On typical message and page data, this can provide a 3X decrease - * in storage requirements. - * - * @param mixed $data - * @return string - */ - function _serialize( &$data ) { - $serial = serialize( $data ); - if( function_exists( 'gzdeflate' ) ) { - return gzdeflate( $serial ); - } else { - return $serial; - } - } - - /** - * Unserialize and, if necessary, decompress an object. - * @param string $serial - * @return mixed - */ - function &_unserialize( $serial ) { - if( function_exists( 'gzinflate' ) ) { - $decomp = @gzinflate( $serial ); - if( false !== $decomp ) { - $serial = $decomp; + + $wgCaches[CACHE_DB] = new MemCachedClientforWiki( + array('persistant' => true, 'compress_threshold' => 1500 ) ); + $cache =& $wgCaches[CACHE_DB]; + $cache->set_servers( $wgMemCachedServers ); + $cache->set_debug( $wgMemCachedDebug ); + } + } elseif ( $type == CACHE_ACCEL ) { + if ( !array_key_exists( CACHE_ACCEL, $wgCaches ) ) { + if ( function_exists( 'eaccelerator_get' ) ) { + require_once( 'BagOStuff.php' ); + $wgCaches[CACHE_ACCEL] = new eAccelBagOStuff; + } elseif ( function_exists( 'mmcache_get' ) ) { + require_once( 'BagOStuff.php' ); + $wgCaches[CACHE_ACCEL] = new TurckBagOStuff; + } else { + $wgCaches[CACHE_ACCEL] = false; } } - return unserialize( $serial ); - } -} - -/** - * @todo document - * @package MediaWiki - */ -class MediaWikiBagOStuff extends SqlBagOStuff { - var $tableInitialised = false; - - function _doquery($sql) { - $dbw =& wfGetDB( DB_MASTER ); - return $dbw->query($sql, 'MediaWikiBagOStuff:_doquery'); - } - function _fetchobject($result) { - $dbw =& wfGetDB( DB_MASTER ); - return $dbw->fetchObject($result); - } - function _freeresult($result) { - $dbw =& wfGetDB( DB_MASTER ); - return $dbw->freeResult($result); - } - function _dberror($result) { - $dbw =& wfGetDB( DB_MASTER ); - return $dbw->lastError(); - } - function _maxdatetime() { - return '9999-12-31 12:59:59'; - } - function _fromunixtime($ts) { - return gmdate( 'Y-m-d H:i:s', $ts ); - } - function _strencode($s) { - $dbw =& wfGetDB( DB_MASTER ); - return $dbw->strencode($s); - } - function getTableName() { - if ( !$this->tableInitialised ) { - $dbw =& wfGetDB( DB_MASTER ); - $this->table = $dbw->tableName( $this->table ); - $this->tableInitialised = true; + if ( $wgCaches[CACHE_ACCEL] !== false ) { + $cache =& $wgCaches[CACHE_ACCEL]; } - return $this->table; } -} -/** - * This is a wrapper for Turck MMCache's shared memory functions. - * - * You can store objects with mmcache_put() and mmcache_get(), but Turck seems - * to use a weird custom serializer that randomly segfaults. So we wrap calls - * with serialize()/unserialize(). - * - * The thing I noticed about the Turck serialized data was that unlike ordinary - * serialize(), it contained the names of methods, and judging by the amount of - * binary data, perhaps even the bytecode of the methods themselves. It may be - * that Turck's serializer is faster, so a possible future extension would be - * to use it for arrays but not for objects. - * - * @package MediaWiki - */ -class TurckBagOStuff extends BagOStuff { - function get($key) { - $val = mmcache_get( $key ); - if ( is_string( $val ) ) { - $val = unserialize( $val ); + if ( $type == CACHE_DB || ( $inputType == CACHE_ANYTHING && $cache === false ) ) { + if ( !array_key_exists( CACHE_DB, $wgCaches ) ) { + require_once( 'BagOStuff.php' ); + $wgCaches[CACHE_DB] = new MediaWikiBagOStuff('objectcache'); } - return $val; - } - - function set($key, $value, $exptime=0) { - mmcache_put( $key, serialize( $value ), $exptime ); - return true; + $cache =& $wgCaches[CACHE_DB]; } - function delete($key, $time=0) { - mmcache_rm( $key ); - return true; - } - - function lock($key, $waitTimeout = 0 ) { - mmcache_lock( $key ); - return true; + if ( $cache === false ) { + if ( !array_key_exists( CACHE_NONE, $wgCaches ) ) { + $wgCaches[CACHE_NONE] = new FakeMemCachedClient; + } + $cache =& $wgCaches[CACHE_NONE]; } - function unlock($key) { - mmcache_unlock( $key ); - return true; - } -} + return $cache; +} -/** - * This is a wrapper for eAccelerator's shared memory functions. - * - * This is basically identical to the Turck MMCache version, - * mostly because eAccelerator is based on Turck MMCache. - * - * @package MediaWiki - */ -class eAccelBagOStuff extends BagOStuff { - function get($key) { - $val = eaccelerator_get( $key ); - if ( is_string( $val ) ) { - $val = unserialize( $val ); - } - return $val; - } +function &wfGetMainCache() { + global $wgMainCacheType; + return wfGetCache( $wgMainCacheType ); +} - function set($key, $value, $exptime=0) { - eaccelerator_put( $key, serialize( $value ), $exptime ); - return true; - } - - function delete($key, $time=0) { - eaccelerator_rm( $key ); - return true; - } +function &wfGetMessageCacheStorage() { + global $wgMessageCacheType; + return wfGetCache( $wgMessageCacheType ); +} - function lock($key, $waitTimeout = 0 ) { - eaccelerator_lock( $key ); - return true; - } +function wfGetParserCacheStorage() { + global $wgParserCacheType; + return wfGetCache( $wgParserCacheType ); +} - function unlock($key) { - eaccelerator_unlock( $key ); - return true; - } -} ?> diff --git a/includes/Setup.php b/includes/Setup.php index 45fd9cd192..057181f831 100644 --- a/includes/Setup.php +++ b/includes/Setup.php @@ -16,7 +16,10 @@ if( defined( 'MEDIAWIKI' ) ) { # setting up a few globals. # -global $wgProfiling, $wgProfileSampleRate, $wgIP, $IP; +// Check to see if we are at the file scope +if ( !isset( $wgVersion ) ) { + die( "Error, Setup.php must be included from the file scope, after DefaultSettings.php\n" ); +} if( !isset( $wgProfiling ) ) $wgProfiling = false; @@ -43,9 +46,9 @@ if ( $wgProfiling and (0 == rand() % $wgProfileSampleRate ) ) { $fname = 'Setup.php'; wfProfileIn( $fname ); -global $wgUseDynamicDates; wfProfileIn( $fname.'-includes' ); + require_once( 'GlobalFunctions.php' ); require_once( 'Hooks.php' ); require_once( 'Namespace.php' ); @@ -67,21 +70,10 @@ require_once( 'WebRequest.php' ); require_once( 'LoadBalancer.php' ); require_once( 'HistoryBlob.php' ); require_once( 'ProxyTools.php' ); +require_once( 'ObjectCache.php' ); wfProfileOut( $fname.'-includes' ); wfProfileIn( $fname.'-misc1' ); -global $wgUser, $wgLang, $wgContLang, $wgOut, $wgTitle; -global $wgLangClass, $wgContLangClass; -global $wgArticle, $wgDeferredUpdateList, $wgLinkCache; -global $wgMemc, $wgMagicWords, $wgMwRedir, $wgDebugLogFile; -global $wgMessageCache, $wgUseMemCached, $wgUseDatabaseMessages; -global $wgMsgCacheExpiry, $wgCommandLineMode; -global $wgBlockCache, $wgParserCache, $wgParser, $wgMsgParserOptions; -global $wgLoadBalancer, $wgDBservers, $wgDebugDumpSql; -global $wgDBserver, $wgDBuser, $wgDBpassword, $wgDBname, $wgDBtype; -global $wgUseOldExistenceCheck, $wgEnablePersistentLC, $wgMasterWaitTimeout; - -global $wgFullyInitialised; $wgIP = wfGetIP(); $wgRequest = new WebRequest(); @@ -90,7 +82,7 @@ $wgRequest = new WebRequest(); if ( $wgCommandLineMode ) { # wfDebug( '"' . implode( '" "', $argv ) . '"' ); } elseif ( function_exists( 'getallheaders' ) ) { - wfDebug( "\nStart request\n" ); + wfDebug( "\n\nStart request\n" ); wfDebug( $_SERVER['REQUEST_METHOD'] . ' ' . $_SERVER['REQUEST_URI'] . "\n" ); $headers = getallheaders(); foreach ($headers as $name => $value) { @@ -109,72 +101,13 @@ if (!$wgUseOldExistenceCheck) { wfProfileOut( $fname.'-misc1' ); wfProfileIn( $fname.'-memcached' ); -# FakeMemCachedClient imitates the API of memcached-client v. 0.1.2. -# It acts as a memcached server with no RAM, that is, all objects are -# cleared the moment they are set. All set operations succeed and all -# get operations return null. - -if( $wgUseMemCached ) { - # Set up Memcached - # - require_once( 'memcached-client.php' ); - - /** - * - * @package MediaWiki - */ - class MemCachedClientforWiki extends memcached { - function _debugprint( $text ) { - wfDebug( "memcached: $text\n" ); - } - } +$wgMemc =& wfGetMainCache(); +$messageMemc =& wfGetMessageCacheStorage(); +$parserMemc =& wfGetParserCacheStorage(); - $wgMemc = new MemCachedClientforWiki( array('persistant' => true, 'compress_threshold' => 1500 ) ); - $wgMemc->set_servers( $wgMemCachedServers ); - $wgMemc->set_debug( $wgMemCachedDebug ); - - $messageMemc = &$wgMemc; -} elseif ( $wgUseTurckShm ) { - # Turck shared memory - # - require_once( 'ObjectCache.php' ); - $wgMemc = new TurckBagOStuff; - $messageMemc = &$wgMemc; -} elseif ( $wgUseEAccelShm ) { - # eAccelerator shared memory - # - require_once( 'ObjectCache.php' ); - $wgMemc = new eAccelBagOStuff; - $messageMemc = &$wgMemc; -} else { - /** - * No shared memory - * @package MediaWiki - */ - class FakeMemCachedClient { - function add ($key, $val, $exp = 0) { return true; } - function decr ($key, $amt=1) { return null; } - function delete ($key, $time = 0) { return false; } - function disconnect_all () { } - function enable_compress ($enable) { } - function forget_dead_hosts () { } - function get ($key) { return null; } - function get_multi ($keys) { return array_pad(array(), count($keys), null); } - function incr ($key, $amt=1) { return null; } - function replace ($key, $value, $exp=0) { return false; } - function run_command ($sock, $cmd) { return null; } - function set ($key, $value, $exp=0){ return true; } - function set_compress_threshold ($thresh){ } - function set_debug ($dbg) { } - function set_servers ($list) { } - } - $wgMemc = new FakeMemCachedClient(); - - # Give the message cache a separate cache in the DB. - # This is a speedup over separately querying every message used - require_once( 'ObjectCache.php' ); - $messageMemc = new MediaWikiBagOStuff('objectcache'); -} +wfDebug( 'Main cache: ' . get_class( $wgMemc ) . + "\nMessage cache: " . get_class( $messageMemc ) . + "\nParser cache: " . get_class( $parserMemc ) . "\n" ); wfProfileOut( $fname.'-memcached' ); wfProfileIn( $fname.'-SetupSession' ); @@ -296,7 +229,7 @@ wfProfileOut( $fname.'-language' ); wfProfileIn( $fname.'-MessageCache' ); $wgMessageCache = new MessageCache; -$wgMessageCache->initialise( $messageMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $wgDBname); +$wgMessageCache->initialise( $parserMemc, $wgUseDatabaseMessages, $wgMsgCacheExpiry, $wgDBname); wfProfileOut( $fname.'-MessageCache' ); @@ -325,14 +258,12 @@ wfProfileOut( $fname.'-MessageCache' ); wfProfileIn( $fname.'-OutputPage' ); $wgOut = new OutputPage(); -wfDebug( "\n\n" ); wfProfileOut( $fname.'-OutputPage' ); wfProfileIn( $fname.'-DateFormatter' ); if ( $wgUseDynamicDates ) { require_once( 'DateFormatter.php' ); - global $wgDateFormatter; $wgDateFormatter = new DateFormatter; } @@ -377,6 +308,7 @@ foreach ( $wgExtensionFunctions as $func ) { $func(); } +wfDebug( "\n" ); $wgFullyInitialised = true; wfProfileOut( $fname.'-extensions' ); wfProfileOut( $fname );