* Rewrote ObjectCache.php to conform to the modern coding style, and to be less convo...
authorTim Starling <tstarling@users.mediawiki.org>
Thu, 3 Mar 2011 09:37:37 +0000 (09:37 +0000)
committerTim Starling <tstarling@users.mediawiki.org>
Thu, 3 Mar 2011 09:37:37 +0000 (09:37 +0000)
* Moved the global functions to GlobalFunctions.php, where they are now just convenience wrappers. Made them return non-references. Updated callers (none found in extensions).
* Added an advanced configuration method, $wgObjectCaches, which allows a lot more detail in the object cache configuration than $wgMainCacheType.
* Made all object cache classes derive from BagOStuff.
* Split the MWMemcached class into a generic client class and a MediaWiki-specific wrapper class. The wrapper class presents a simple BagOStuff interface to calling code, hiding memcached client internals, and will simplify the task of supporting the PECL extension.
* Added some extra constructor parameters to MWMemcached, configurable via $wgObjectCaches.
* Removed the *_multi() methods from BagOStuff, my grepping indicates that they are not used.
* Rewrote FakeMemCachedClient as a BagOStuff subclass, called EmptyBagOStuff.
* Added an optional "server" parameter to SQLBagOStuff. This allows the server holding the objectcache table to be different from the server holding the core DB.
* Added MultiWriteBagOStuff: a cache class which writes to multiple locations, and reads from them in a defined fallback sequence. This can be used to extend the cache space by adding disk-backed storage to existing in-memory caches.
* Made MWMemcached::get() return false on failure instead of null, to match the BagOStuff documentation and the other BagOStuff subclasses. Anything that was relying on it returning null would have already been broken with SqlBagOStuff.
* Fixed a bug in the memcached client causing keys with spaces or line breaks in them to break the memcached protocol, injecting arbitrary commands or parameters. Since the PECL client apparently also has this flaw, I implemented the fix in the wrapper class.
* Renamed BagOStuff::set_debug() to setDebug(), since we aren't emulating the memcached client anymore
* Fixed spelling error in MWMemcached: persistant -> persistent

14 files changed:
includes/AutoLoader.php
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/Setup.php
includes/objectcache/BagOStuff.php
includes/objectcache/EmptyBagOStuff.php [new file with mode: 0644]
includes/objectcache/MemcachedClient.php
includes/objectcache/MemcachedPhpBagOStuff.php [new file with mode: 0644]
includes/objectcache/MultiWriteBagOStuff.php [new file with mode: 0644]
includes/objectcache/ObjectCache.php
includes/objectcache/SqlBagOStuff.php
maintenance/mcc.php
tests/phpunit/includes/parser/NewParserTest.php
tests/phpunit/suites/UploadFromUrlTestSuite.php

index 705d7e8..961f180 100644 (file)
@@ -505,11 +505,15 @@ $wgAutoloadLocalClasses = array(
        'BagOStuff' => 'includes/objectcache/BagOStuff.php',
        'DBABagOStuff' => 'includes/objectcache/DBABagOStuff.php',
        'eAccelBagOStuff' => 'includes/objectcache/eAccelBagOStuff.php',
-       'FakeMemCachedClient' => 'includes/objectcache/ObjectCache.php',
+       'EmptyBagOStuff' => 'includes/objectcache/EmptyBagOStuff.php',
+       'FakeMemCachedClient' => 'includes/objectcache/EmptyBagOStuff.php',
        'HashBagOStuff' => 'includes/objectcache/HashBagOStuff.php',
        'MWMemcached' => 'includes/objectcache/MemcachedClient.php',
        'MediaWikiBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
        'MemCachedClientforWiki' => 'includes/objectcache/MemcachedClient.php',
+       'MemcachedPhpBagOStuff' => 'includes/objectcache/MemcachedPhpBagOStuff.php',
+       'MultiWriteBagOStuff' => 'includes/objectcache/MultiWriteBagOStuff.php',
+       'ObjectCache' => 'includes/objectcache/ObjectCache.php',
        'SqlBagOStuff' => 'includes/objectcache/SqlBagOStuff.php',
        'WinCacheBagOStuff' => 'includes/objectcache/WinCacheBagOStuff.php',
        'XCacheBagOStuff' => 'includes/objectcache/XCacheBagOStuff.php',
index 3c73d55..37c64cf 100644 (file)
@@ -1481,6 +1481,8 @@ $wgCacheDirectory = false;
  *   - CACHE_DBA:        Use PHP's DBA extension to store in a DBM-style
  *                       database. This is slow, and is not recommended for
  *                       anything other than debugging.
+ *   - (other):          A string may be used which identifies a cache 
+ *                       configuration in $wgObjectCaches.
  *
  * @see $wgMessageCacheType, $wgParserCacheType
  */
@@ -1502,6 +1504,36 @@ $wgMessageCacheType = CACHE_ANYTHING;
  */
 $wgParserCacheType = CACHE_ANYTHING;
 
+/**
+ * Advanced object cache configuration.
+ *
+ * Use this to define the class names and constructor parameters which are used 
+ * for the various cache types. Custom cache types may be defined here and 
+ * referenced from $wgMainCacheType, $wgMessageCacheType or $wgParserCacheType.
+ *
+ * The format is an associative array where the key is a cache identifier, and 
+ * the value is an associative array of parameters. The "class" parameter is the
+ * class name which will be used. Alternatively, a "factory" parameter may be 
+ * given, giving a callable function which will generate a suitable cache object.
+ *
+ * The other parameters are dependent on the class used.
+ */
+$wgObjectCaches = array(
+       CACHE_NONE => array( 'class' => 'FakeMemCachedClient' ),
+       CACHE_DB => array( 'class' => 'SqlBagOStuff', 'table' => 'objectcache' ),
+       CACHE_DBA => array( 'class' => 'DBABagOStuff' ),
+
+       CACHE_ANYTHING => array( 'factory' => 'ObjectCache::newAnything' ),
+       CACHE_ACCEL => array( 'factory' => 'ObjectCache::newAccelerator' ),
+       CACHE_MEMCACHED => array( 'factory' => 'ObjectCache::newMemcached' ),
+
+       'eaccelerator' => array( 'class' => 'eAccelBagOStuff' ),
+       'apc' => array( 'class' => 'APCBagOStuff' ),
+       'xcache' => array( 'class' => 'XCacheBagOStuff' ),
+       'wincache' => array( 'class' => 'WinCacheBagOStuff' ),
+       'memcached-php' => array( 'class' => 'MemcachedPhpBagOStuff' ),
+);
+
 /**
  * The expiry time for the parser cache, in seconds. The default is 86.4k
  * seconds, otherwise known as a day.
index e925c4b..d906255 100644 (file)
@@ -3357,3 +3357,33 @@ function wfArrayMap( $function, $input ) {
        }
        return $ret;
 }
+
+
+/**
+ * Get a cache object.
+ * @param $inputType Cache type, one the the CACHE_* constants.
+ *
+ * @return BagOStuff
+ */
+function wfGetCache( $inputType ) {
+       return ObjectCache::getInstance( $inputType );
+}
+
+/** Get the main cache object */
+function wfGetMainCache() {
+       global $wgMainCacheType;
+       return ObjectCache::getInstance( $wgMainCacheType );
+}
+
+/** Get the cache object used by the message cache */
+function wfGetMessageCacheStorage() {
+       global $wgMessageCacheType;
+       return ObjectCache::getInstance( $wgMessageCacheType );
+}
+
+/** Get the cache object used by the parser cache */
+function wfGetParserCacheStorage() {
+       global $wgParserCacheType;
+       return ObjectCache::getInstance( $wgParserCacheType );
+}
+
index f331dc4..7dfe94b 100644 (file)
@@ -283,7 +283,6 @@ require_once( "$IP/includes/GlobalFunctions.php" );
 require_once( "$IP/includes/Hooks.php" );
 require_once( "$IP/includes/Namespace.php" );
 require_once( "$IP/includes/ProxyTools.php" );
-require_once( "$IP/includes/objectcache/ObjectCache.php" );
 require_once( "$IP/includes/ImageFunctions.php" );
 wfProfileOut( $fname . '-includes' );
 wfProfileIn( $fname . '-misc1' );
@@ -323,9 +322,9 @@ if ( $wgCommandLineMode ) {
 wfProfileOut( $fname . '-misc1' );
 wfProfileIn( $fname . '-memcached' );
 
-$wgMemc =& wfGetMainCache();
-$messageMemc =& wfGetMessageCacheStorage();
-$parserMemc =& wfGetParserCacheStorage();
+$wgMemc = wfGetMainCache();
+$messageMemc = wfGetMessageCacheStorage();
+$parserMemc = wfGetParserCacheStorage();
 
 wfDebug( 'CACHES: ' . get_class( $wgMemc ) . '[main] ' .
        get_class( $messageMemc ) . '[message] ' .
index f85722b..adb6abc 100644 (file)
@@ -43,7 +43,7 @@
 abstract class BagOStuff {
        var $debugMode = false;
 
-       public function set_debug( $bool ) {
+       public function setDebug( $bool ) {
                $this->debugMode = $bool;
        }
 
@@ -87,22 +87,6 @@ abstract class BagOStuff {
        }
 
        /* *** Emulated functions *** */
-       /* Better performance can likely be got with custom written versions */
-       public function get_multi( $keys ) {
-               $out = array();
-
-               foreach ( $keys as $key ) {
-                       $out[$key] = $this->get( $key );
-               }
-
-               return $out;
-       }
-
-       public function set_multi( $hash, $exptime = 0 ) {
-               foreach ( $hash as $key => $value ) {
-                       $this->set( $key, $value, $exptime );
-               }
-       }
 
        public function add( $key, $value, $exptime = 0 ) {
                if ( !$this->get( $key ) ) {
@@ -112,18 +96,6 @@ abstract class BagOStuff {
                }
        }
 
-       public function add_multi( $hash, $exptime = 0 ) {
-               foreach ( $hash as $key => $value ) {
-                       $this->add( $key, $value, $exptime );
-               }
-       }
-
-       public function delete_multi( $keys, $time = 0 ) {
-               foreach ( $keys as $key ) {
-                       $this->delete( $key, $time );
-               }
-       }
-
        public function replace( $key, $value, $exptime = 0 ) {
                if ( $this->get( $key ) !== false ) {
                        $this->set( $key, $value, $exptime );
diff --git a/includes/objectcache/EmptyBagOStuff.php b/includes/objectcache/EmptyBagOStuff.php
new file mode 100644 (file)
index 0000000..f811352
--- /dev/null
@@ -0,0 +1,27 @@
+<?php
+
+/**
+ * A BagOStuff object with no objects in it. Used to provide a no-op object to calling code.
+ *
+ * @ingroup Cache
+ */
+class EmptyBagOStuff extends BagOStuff {
+       function get( $key ) {
+               return false;
+       }
+
+       function set( $key, $value, $exp = 0 ) {
+               return true;
+       }
+
+       function delete( $key, $time = 0 ) {
+               return true;
+       }
+}
+
+/** 
+ * Backwards compatibility alias for EmptyBagOStuff
+ * @deprecated
+ */
+class FakeMemCachedClient extends EmptyBagOStuff {
+}
index 53f0324..824e6fa 100644 (file)
@@ -51,7 +51,7 @@
  *                                 '127.0.0.1:10020'),
  *              'debug'   => false,
  *              'compress_threshold' => 10240,
- *              'persistant' => true));
+ *              'persistent' => true));
  *
  * $mc->add('key', array('some', 'array'));
  * $mc->replace('key', 'some random string');
@@ -158,12 +158,12 @@ class MWMemcached {
        var $_compress_threshold;
 
        /**
-        * Are we using persistant links?
+        * Are we using persistent links?
         *
         * @var     boolean
         * @access  private
         */
-       var $_persistant;
+       var $_persistent;
 
        /**
         * If only using one server; contains ip:port to connect to
@@ -245,12 +245,11 @@ class MWMemcached {
         * @return  mixed
         */
        public function __construct( $args ) {
-               global $wgMemCachedTimeout;
                $this->set_servers( isset( $args['servers'] ) ? $args['servers'] : array() );
                $this->_debug = isset( $args['debug'] ) ? $args['debug'] : false;
                $this->stats = array();
                $this->_compress_threshold = isset( $args['compress_threshold'] ) ? $args['compress_threshold'] : 0;
-               $this->_persistant = isset( $args['persistant'] ) ? $args['persistant'] : false;
+               $this->_persistent = isset( $args['persistent'] ) ? $args['persistent'] : false;
                $this->_compress_enable = true;
                $this->_have_zlib = function_exists( 'gzcompress' );
 
@@ -258,9 +257,9 @@ class MWMemcached {
                $this->_host_dead = array();
 
                $this->_timeout_seconds = 0;
-               $this->_timeout_microseconds = $wgMemCachedTimeout;
+               $this->_timeout_microseconds = isset( $args['timeout'] ) ? $args['timeout'] : 100000;
 
-               $this->_connect_timeout = 0.01;
+               $this->_connect_timeout = isset( $args['connect_timeout'] ) ? $args['connect_timeout'] : 0.1;
                $this->_connect_attempts = 2;
        }
 
@@ -433,7 +432,11 @@ class MWMemcached {
                }
 
                wfProfileOut( __METHOD__ );
-               return @$val[$key];
+               if ( isset( $val[$key] ) ) {
+                       return $val[$key];
+               } else {
+                       return false;
+               }
        }
 
        // }}}
@@ -695,7 +698,7 @@ class MWMemcached {
                $errno = $errstr = null;
                for( $i = 0; !$sock && $i < $this->_connect_attempts; $i++ ) {
                        wfSuppressWarnings();
-                       if ( $this->_persistant == 1 ) {
+                       if ( $this->_persistent == 1 ) {
                                $sock = pfsockopen( $ip, $port, $errno, $errstr, $timeout );
                        } else {
                                $sock = fsockopen( $ip, $port, $errno, $errstr, $timeout );
diff --git a/includes/objectcache/MemcachedPhpBagOStuff.php b/includes/objectcache/MemcachedPhpBagOStuff.php
new file mode 100644 (file)
index 0000000..4538bb0
--- /dev/null
@@ -0,0 +1,116 @@
+<?php
+
+/**
+ * A wrapper class for the pure-PHP memcached client, exposing a BagOStuff interface.
+ */
+class MemcachedPhpBagOStuff extends BagOStuff {
+       /**
+        * Constructor.
+        *
+        * Available parameters are:
+        *   - servers:             The list of IP:port combinations holding the memcached servers.
+        *   - debug:               Whether to set the debug flag in the underlying client.
+        *   - persistent:          Whether to use a persistent connection
+        *   - compress_threshold:  The minimum size an object must be before it is compressed
+        *   - timeout:             The read timeout in microseconds
+        *   - connect_timeout:     The connect timeout in seconds
+        */
+       function __construct( $params ) {
+               if ( !isset( $params['servers'] ) ) {
+                       $params['servers'] = $GLOBALS['wgMemCachedServers'];
+               }
+               if ( !isset( $params['debug'] ) ) {
+                       $params['debug'] = $GLOBALS['wgMemCachedDebug'];
+               }
+               if ( !isset( $params['persistent'] ) ) {
+                       $params['persistent'] = $GLOBALS['wgMemCachedPersistent'];
+               }
+               if  ( !isset( $params['compress_threshold'] ) ) {
+                       $params['compress_threshold'] = 1500;
+               }
+               if ( !isset( $params['timeout'] ) ) {
+                       $params['timeout'] = $GLOBALS['wgMemCachedTimeout'];
+               }
+               if ( !isset( $params['connect_timeout'] ) ) {
+                       $params['connect_timeout'] = 0.1;
+               }
+
+               $this->client = new MemCachedClientforWiki( $params );
+               $this->client->set_servers( $params['servers'] );
+               $this->client->set_debug( $params['debug'] );
+       }
+
+       public function setDebug( $debug ) {
+               $this->client->set_debug( $debug );
+       }
+
+       public function get( $key ) {
+               return $this->client->get( $this->encodeKey( $key ) );
+       }
+       
+       public function set( $key, $value, $exptime = 0 ) {
+               return $this->client->set( $this->encodeKey( $key ), $value, $exptime );
+       }
+
+       public function delete( $key, $time = 0 ) {
+               return $this->client->delete( $this->encodeKey( $key ), $time );
+       }
+
+       public function lock( $key, $timeout = 0 ) {
+               return $this->client->lock( $this->encodeKey( $key ), $timeout );
+       }
+
+       public function unlock( $key ) {
+               return $this->client->unlock( $this->encodeKey( $key ) );
+       }
+
+       public function add( $key, $value, $exptime = 0 ) {
+               return $this->client->add( $this->encodeKey( $key ), $value, $exptime );
+       }
+
+       public function replace( $key, $value, $exptime = 0 ) {
+               return $this->client->replace( $this->encodeKey( $key ), $value, $exptime );
+       }
+
+       public function incr( $key, $value = 1 ) {
+               return $this->client->incr( $this->encodeKey( $key ), $value );
+       }
+
+       public function decr( $key, $value = 1 ) {
+               return $this->client->decr( $this->encodeKey( $key ), $value );
+       }
+
+       /**
+        * Get the underlying client object. This is provided for debugging 
+        * purposes.
+        */
+       public function getClient() {
+               return $this->client;
+       }
+
+       /**
+        * Encode a key for use on the wire inside the memcached protocol.
+        *
+        * We encode spaces and line breaks to avoid protocol errors. We encode 
+        * the other control characters for compatibility with libmemcached 
+        * verify_key. We leave other punctuation alone, to maximise backwards
+        * compatibility.
+        */
+       public function encodeKey( $key ) {
+               return preg_replace_callback( '/[\x00-\x20\x25\x7f]+/', 
+                       array( $this, 'encodeKeyCallback' ), $key );
+       }
+
+       protected function encodeKeyCallback( $m ) {
+               return urlencode( $m[0] );
+       }
+
+       /**
+        * Decode a key encoded with encodeKey(). This is provided as a convenience 
+        * function for debugging.
+        */
+       public function decodeKey( $key ) {
+               return urldecode( $key );
+       }
+}
+
diff --git a/includes/objectcache/MultiWriteBagOStuff.php b/includes/objectcache/MultiWriteBagOStuff.php
new file mode 100644 (file)
index 0000000..0cb47c9
--- /dev/null
@@ -0,0 +1,95 @@
+<?php
+
+/**
+ * A cache class that replicates all writes to multiple child caches. Reads 
+ * are implemented by reading from the caches in the order they are given in 
+ * the configuration until a cache gives a positive result.
+ */
+class MultiWriteBagOStuff extends BagOStuff {
+       var $caches;
+
+       /**
+        * Constructor. Parameters are:
+        *
+        *   - caches:   This should have a numbered array of cache parameter 
+        *               structures, in the style required by $wgObjectCaches. See
+        *               the documentation of $wgObjectCaches for more detail.
+        */
+       public function __construct( $params ) {
+               if ( !isset( $params['caches'] ) ) {
+                       throw new MWException( __METHOD__.': the caches parameter is required' );
+               }
+
+               $this->caches = array();
+               foreach ( $params['caches'] as $cacheInfo ) {
+                       $this->caches[] = ObjectCache::newFromParams( $cacheInfo );
+               }
+       }
+
+       public function setDebug( $debug ) {
+               $this->doWrite( 'setDebug', $debug );
+       }
+
+       public function get( $key ) {
+               foreach ( $this->caches as $cache ) {
+                       $value = $cache->get( $key );
+                       if ( $value !== false ) {
+                               return $value;
+                       }
+               }
+               return false;
+       }
+
+       public function set( $key, $value, $exptime = 0 ) {
+               return $this->doWrite( 'set', $key, $value, $exptime );
+       }
+
+       public function delete( $key, $time = 0 ) {
+               return $this->doWrite( 'delete', $key, $time );
+       }
+
+       public function add( $key, $value, $exptime = 0 ) {
+               return $this->doWrite( 'add', $key, $value, $exptime );
+       }
+
+       public function replace( $key, $value, $exptime = 0 ) {
+               return $this->doWrite( 'replace', $key, $value, $exptime );
+       }
+
+       public function incr( $key, $value = 1 ) {
+               return $this->doWrite( 'incr', $key, $value );
+       }
+
+       public function decr( $key, $value = 1 ) {
+               return $this->doWrite( 'decr', $key, $value );
+       }       
+
+       public function lock( $key, $timeout = 0 ) {
+               // Lock only the first cache, to avoid deadlocks
+               if ( isset( $this->caches[0] ) ) {
+                       return $this->caches[0]->lock( $key, $timeout );
+               } else {
+                       return true;
+               }
+       }
+
+       public function unlock( $key ) {
+               if ( isset( $this->caches[0] ) ) {
+                       return $this->caches[0]->unlock( $key );
+               } else {
+                       return true;
+               }
+       }
+
+       protected function doWrite( $method /*, ... */ ) {
+               $ret = true;
+               $args = func_get_args();
+               array_shift( $args );
+
+               foreach ( $this->caches as $cache ) {
+                       $ret = $ret && call_user_func_array( array( $cache, $method ), $args );
+               }
+               return $ret;
+       }
+
+}
index 74b7dcd..96dd4cf 100644 (file)
@@ -5,96 +5,90 @@
  * @file
  * @ingroup Cache
  */
+class ObjectCache {
+       static $instances = array();
 
-global $wgCaches;
-$wgCaches = array();
+       /**
+        * Get a cached instance of the specified type of cache object.
+        */
+       static function getInstance( $id ) {
+               if ( isset( self::$instances[$id] ) ) {
+                       return self::$instances[$id];
+               }
 
-/**
- * Get a cache object.
- * @param $inputType Integer: cache type, one the the CACHE_* constants.
- *
- * @return BagOStuff
- */
-function &wfGetCache( $inputType ) {
-       global $wgCaches, $wgMemCachedServers, $wgMemCachedDebug, $wgMemCachedPersistent;
-       $cache = false;
+               $object = self::newFromId( $id );
+               self::$instances[$id] = $object;
+               return $object;
+       }
 
-       if ( $inputType == CACHE_ANYTHING ) {
-               reset( $wgCaches );
-               $type = key( $wgCaches );
-               if ( $type === false || $type === CACHE_NONE ) {
-                       $type = CACHE_DB;
+       /**
+        * Create a new cache object of the specified type.
+        */
+       static function newFromId( $id ) {
+               global $wgObjectCaches;
+
+               if ( !isset( $wgObjectCaches[$id] ) ) {
+                       throw new MWException( "Invalid object cache type \"$id\" requested. " . 
+                               "It is not present in \$wgObjectCaches." );
                }
-       } else {
-               $type = $inputType;
+
+               return self::newFromParams( $wgObjectCaches[$id] );
        }
 
-       if ( $type == CACHE_MEMCACHED ) {
-               if ( !array_key_exists( CACHE_MEMCACHED, $wgCaches ) ) {
-                       $wgCaches[CACHE_MEMCACHED] = new MemCachedClientforWiki(
-                               array('persistant' => $wgMemCachedPersistent, 'compress_threshold' => 1500 ) );
-                       $wgCaches[CACHE_MEMCACHED]->set_servers( $wgMemCachedServers );
-                       $wgCaches[CACHE_MEMCACHED]->set_debug( $wgMemCachedDebug );
-               }
-               $cache =& $wgCaches[CACHE_MEMCACHED];
-       } elseif ( $type == CACHE_ACCEL ) {
-               if ( !array_key_exists( CACHE_ACCEL, $wgCaches ) ) {
-                       if ( function_exists( 'eaccelerator_get' ) ) {
-                               $wgCaches[CACHE_ACCEL] = new eAccelBagOStuff;
-                       } elseif ( function_exists( 'apc_fetch') ) {
-                               $wgCaches[CACHE_ACCEL] = new APCBagOStuff;
-                       } elseif( function_exists( 'xcache_get' ) ) {
-                               $wgCaches[CACHE_ACCEL] = new XCacheBagOStuff();
-                       } elseif( function_exists( 'wincache_ucache_get' ) ) {
-                               $wgCaches[CACHE_ACCEL] = new WinCacheBagOStuff();
-                       } else {
-                               $wgCaches[CACHE_ACCEL] = false;
-                       }
-               }
-               if ( $wgCaches[CACHE_ACCEL] !== false ) {
-                       $cache =& $wgCaches[CACHE_ACCEL];
+       /**
+        * Create a new cache object from parameters
+        */
+       static function newFromParams( $params ) {
+               if ( isset( $params['factory'] ) ) {
+                       return call_user_func( $params['factory'], $params );
+               } elseif ( isset( $params['class'] ) ) {
+                       $class = $params['class'];
+                       return new $class( $params );
+               } else {
+                       throw new MWException( "The definition of cache type \"$id\" lacks both " . 
+                               "factory and class parameters." );
                }
-       } elseif ( $type == CACHE_DBA ) {
-               if ( !array_key_exists( CACHE_DBA, $wgCaches ) ) {
-                       $wgCaches[CACHE_DBA] = new DBABagOStuff;
-               }
-               $cache =& $wgCaches[CACHE_DBA];
        }
 
-       if ( $type == CACHE_DB || ( $inputType == CACHE_ANYTHING && $cache === false ) ) {
-               if ( !array_key_exists( CACHE_DB, $wgCaches ) ) {
-                       $wgCaches[CACHE_DB] = new SqlBagOStuff('objectcache');
+       /**
+        * Factory function referenced from DefaultSettings.php for CACHE_ANYTHING
+        */
+       static function newAnything( $params ) {
+               global $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType;
+               $candidates = array( $wgMainCacheType, $wgMessageCacheType, $wgParserCacheType );
+               foreach ( $candidates as $candidate ) {
+                       if ( $candidate !== CACHE_NONE && $candidate !== CACHE_ANYTHING ) {
+                               return self::newFromId( $candidate );
+                       }
                }
-               $cache =& $wgCaches[CACHE_DB];
+               return self::newFromId( CACHE_DB );
        }
 
-       if ( $cache === false ) {
-               if ( !array_key_exists( CACHE_NONE, $wgCaches ) ) {
-                       $wgCaches[CACHE_NONE] = new FakeMemCachedClient;
+       /**
+        * Factory function referenced from DefaultSettings.php for CACHE_ACCEL.
+        */
+       static function newAccelerator( $params ) {
+               if ( function_exists( 'eaccelerator_get' ) ) {
+                       $id = 'eaccelerator';
+               } elseif ( function_exists( 'apc_fetch') ) {
+                       $id = 'apc';
+               } elseif( function_exists( 'xcache_get' ) ) {
+                       $id = 'xcache';
+               } elseif( function_exists( 'wincache_ucache_get' ) ) {
+                       $id = 'wincache';
+               } else {
+                       throw new MWException( "CACHE_ACCEL requested but no suitable object " .
+                               "cache is present. You may want to install APC." );
                }
-               $cache =& $wgCaches[CACHE_NONE];
+               return self::newFromId( $id );
        }
 
-       return $cache;
-}
-
-/** Get the main cache object */
-function &wfGetMainCache() {
-       global $wgMainCacheType;
-       $ret =& wfGetCache( $wgMainCacheType );
-       return $ret;
-}
-
-/** Get the cache object used by the message cache */
-function &wfGetMessageCacheStorage() {
-       global $wgMessageCacheType;
-       $ret =& wfGetCache( $wgMessageCacheType );
-       return $ret;
-}
-
-/** Get the cache object used by the parser cache */
-function &wfGetParserCacheStorage() {
-       global $wgParserCacheType;
-       $ret =& wfGetCache( $wgParserCacheType );
-       return $ret;
+       /**
+        * Factory function that creates a memcached client object.
+        * The idea of this is that it might eventually detect and automatically 
+        * support the PECL extension, assuming someone can get it to compile.
+        */
+       static function newMemcached( $params ) {
+               return new MemcachedPhpBagOStuff( $params );
+       }
 }
index e58ab51..bed2e12 100644 (file)
@@ -6,21 +6,40 @@
  * @ingroup Cache
  */
 class SqlBagOStuff extends BagOStuff {
-       var $lb, $db;
+       var $lb, $db, $serverInfo;
        var $lastExpireAll = 0;
 
+       /**
+        * Constructor. Parameters are:
+        *   - server:   A server info structure in the format required by each 
+        *               element in $wgDBServers.
+        */
+       public function __construct( $params ) {
+               if ( isset( $params['server'] ) ) {
+                       $this->serverInfo = $params['server'];
+                       $this->serverInfo['load'] = 1;
+               }
+       }
+
        protected function getDB() {
                if ( !isset( $this->db ) ) {
-                       /* We must keep a separate connection to MySQL in order to avoid deadlocks
-                        * However, SQLite has an opposite behaviour.
-                        * @todo Investigate behaviour for other databases
-                        */
-                       if ( wfGetDB( DB_MASTER )->getType() == 'sqlite' ) {
-                               $this->db = wfGetDB( DB_MASTER );
-                       } else {
-                               $this->lb = wfGetLBFactory()->newMainLB();
+                       # If server connection info was given, use that
+                       if ( $this->serverInfo ) {
+                               $this->lb = new LoadBalancer( array(
+                                       'servers' => array( $this->serverInfo ) ) );
                                $this->db = $this->lb->getConnection( DB_MASTER );
                                $this->db->clearFlag( DBO_TRX );
+                       } else {
+                               # We must keep a separate connection to MySQL in order to avoid deadlocks
+                               # However, SQLite has an opposite behaviour.
+                               # @todo Investigate behaviour for other databases
+                               if ( wfGetDB( DB_MASTER )->getType() == 'sqlite' ) {
+                                       $this->db = wfGetDB( DB_MASTER );
+                               } else {
+                                       $this->lb = wfGetLBFactory()->newMainLB();
+                                       $this->db = $this->lb->getConnection( DB_MASTER );
+                                       $this->db->clearFlag( DBO_TRX );
+                               }
                        }
                }
 
index 13d0d6b..0244527 100644 (file)
@@ -25,7 +25,7 @@
 /** */
 require_once( dirname( __FILE__ ) . '/commandLine.inc' );
 
-$mcc = new MWMemcached( array( 'persistant' => true/*, 'debug' => true*/ ) );
+$mcc = new MWMemcached( array( 'persistent' => true/*, 'debug' => true*/ ) );
 $mcc->set_servers( $wgMemCachedServers );
 # $mcc->set_debug( true );
 
index 391e925..35b7540 100644 (file)
@@ -70,9 +70,9 @@ class NewParserTest extends MediaWikiTestCase {
                $tmpGlobals['wgEnableParserCache'] = false;
                $tmpGlobals['wgHooks'] = $wgHooks;
                $tmpGlobals['wgDeferredUpdateList'] = array();
-               $tmpGlobals['wgMemc'] = &wfGetMainCache();
-               $tmpGlobals['messageMemc'] = &wfGetMessageCacheStorage();
-               $tmpGlobals['parserMemc'] = &wfGetParserCacheStorage();
+               $tmpGlobals['wgMemc'] = wfGetMainCache();
+               $tmpGlobals['messageMemc'] = wfGetMessageCacheStorage();
+               $tmpGlobals['parserMemc'] = wfGetParserCacheStorage();
 
                // $tmpGlobals['wgContLang'] = new StubContLang;
                $tmpGlobals['wgUser'] = new User;
index cfa7cf5..db8efce 100644 (file)
@@ -42,9 +42,9 @@ class UploadFromUrlTestSuite extends PHPUnit_Framework_TestSuite {
 
                $wgEnableParserCache = false;
                $wgDeferredUpdateList = array();
-               $wgMemc = &wfGetMainCache();
-               $messageMemc = &wfGetMessageCacheStorage();
-               $parserMemc = &wfGetParserCacheStorage();
+               $wgMemc = wfGetMainCache();
+               $messageMemc = wfGetMessageCacheStorage();
+               $parserMemc = wfGetParserCacheStorage();
 
                // $wgContLang = new StubContLang;
                $wgUser = new User;