Smarter, more flexible cache type selection. Moved entire contents of ObjectCache...
authorTim Starling <tstarling@users.mediawiki.org>
Sat, 9 Apr 2005 10:30:45 +0000 (10:30 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Sat, 9 Apr 2005 10:30:45 +0000 (10:30 +0000)
config/index.php
includes/BagOStuff.php [new file with mode: 0644]
includes/DefaultSettings.php
includes/Defines.php
includes/ObjectCache.php
includes/Setup.php

index 0c13257..328f34f 100644 (file)
@@ -609,6 +609,8 @@ if( $conf->posted && ( 0 == count( $errs ) ) ) {
                /* Write out the config file now that all is well */
                print "<p>Creating LocalSettings.php...</p>\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 (file)
index 0000000..78ca511
--- /dev/null
@@ -0,0 +1,498 @@
+<?php
+#
+# Copyright (C) 2003-2004 Brion Vibber <brion@pobox.com>
+# 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<count($reps);$i++) {
+                       $sql = str_replace(
+                               '$' . $i,
+                               $this->_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;
+       }
+}      
+?>
index 004cc5e..fb08b23 100644 (file)
@@ -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
index 9c35f22..c5e16a6 100644 (file)
@@ -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
+
 ?>
index 78ca511..245bb38 100644 (file)
 <?php
-#
-# Copyright (C) 2003-2004 Brion Vibber <brion@pobox.com>
-# 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<count($reps);$i++) {
-                       $sql = str_replace(
-                               '$' . $i,
-                               $this->_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;
-       }
-}      
 ?>
index 45fd9cd..057181f 100644 (file)
@@ -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 );