diff options
Diffstat (limited to 'includes/cache')
-rw-r--r-- | includes/cache/CacheDependency.php | 23 | ||||
-rw-r--r-- | includes/cache/FileCacheBase.php | 35 | ||||
-rw-r--r-- | includes/cache/GenderCache.php | 93 | ||||
-rw-r--r-- | includes/cache/HTMLCacheUpdate.php | 21 | ||||
-rw-r--r-- | includes/cache/HTMLFileCache.php | 33 | ||||
-rw-r--r-- | includes/cache/LinkBatch.php | 28 | ||||
-rw-r--r-- | includes/cache/LinkCache.php | 22 | ||||
-rw-r--r-- | includes/cache/MemcachedSessions.php | 98 | ||||
-rw-r--r-- | includes/cache/MessageCache.php | 40 | ||||
-rw-r--r-- | includes/cache/ObjectFileCache.php | 24 | ||||
-rw-r--r-- | includes/cache/ProcessCacheLRU.php | 120 | ||||
-rw-r--r-- | includes/cache/ResourceFileCache.php | 24 | ||||
-rw-r--r-- | includes/cache/SquidUpdate.php | 64 | ||||
-rw-r--r-- | includes/cache/UserCache.php | 134 |
14 files changed, 609 insertions, 150 deletions
diff --git a/includes/cache/CacheDependency.php b/includes/cache/CacheDependency.php index 0df0cd89..a3c2b52a 100644 --- a/includes/cache/CacheDependency.php +++ b/includes/cache/CacheDependency.php @@ -1,11 +1,32 @@ <?php /** + * Data caching with dependencies. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ + +/** * This class stores an arbitrary value along with its dependencies. * Users should typically only use DependencyWrapper::getValueFromCache(), * rather than instantiating one of these objects directly. * @ingroup Cache */ - class DependencyWrapper { var $value; var $deps; diff --git a/includes/cache/FileCacheBase.php b/includes/cache/FileCacheBase.php index 37401655..c0c5609c 100644 --- a/includes/cache/FileCacheBase.php +++ b/includes/cache/FileCacheBase.php @@ -1,9 +1,31 @@ <?php /** - * Contain the FileCacheBase class + * Data storage in the file system. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ + +/** + * Base class for data storage in the file system. + * + * @ingroup Cache + */ abstract class FileCacheBase { protected $mKey; protected $mType = 'object'; @@ -74,7 +96,7 @@ abstract class FileCacheBase { /** * Get the last-modified timestamp of the cache file - * @return string|false TS_MW timestamp + * @return string|bool TS_MW timestamp */ public function cacheTimestamp() { $timestamp = filemtime( $this->cachePath() ); @@ -116,9 +138,12 @@ abstract class FileCacheBase { * @return string */ public function fetchText() { - // gzopen can transparently read from gziped or plain text - $fh = gzopen( $this->cachePath(), 'rb' ); - return stream_get_contents( $fh ); + if( $this->useGzip() ) { + $fh = gzopen( $this->cachePath(), 'rb' ); + return stream_get_contents( $fh ); + } else { + return file_get_contents( $this->cachePath() ); + } } /** diff --git a/includes/cache/GenderCache.php b/includes/cache/GenderCache.php index 342f8dba..2a169bb3 100644 --- a/includes/cache/GenderCache.php +++ b/includes/cache/GenderCache.php @@ -1,8 +1,30 @@ <?php - /** * Caches user genders when needed to use correct namespace aliases. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file * @author Niklas Laxström + * @ingroup Cache + */ + +/** + * Caches user genders when needed to use correct namespace aliases. + * * @since 1.18 */ class GenderCache { @@ -37,14 +59,18 @@ class GenderCache { /** * Returns the gender for given username. - * @param $username String: username + * @param $username String or User: username * @param $caller String: the calling method * @return String */ public function getGenderOf( $username, $caller = '' ) { global $wgUser; - $username = strtr( $username, '_', ' ' ); + if( $username instanceof User ) { + $username = $username->getName(); + } + + $username = self::normalizeUsername( $username ); if ( !isset( $this->cache[$username] ) ) { if ( $this->misses >= $this->missLimit && $wgUser->getName() !== $username ) { @@ -56,11 +82,7 @@ class GenderCache { } else { $this->misses++; - if ( !User::isValidUserName( $username ) ) { - $this->cache[$username] = $this->getDefault(); - } else { - $this->doQuery( $username, $caller ); - } + $this->doQuery( $username, $caller ); } } @@ -82,7 +104,6 @@ class GenderCache { foreach ( $data as $ns => $pagenames ) { if ( !MWNamespace::hasGenderDistinction( $ns ) ) continue; foreach ( array_keys( $pagenames ) as $username ) { - if ( isset( $this->cache[$username] ) ) continue; $users[$username] = true; } } @@ -91,6 +112,29 @@ class GenderCache { } /** + * Wrapper for doQuery that processes a title or string array. + * + * @since 1.20 + * @param $titles List: array of Title objects or strings + * @param $caller String: the calling method + */ + public function doTitlesArray( $titles, $caller = '' ) { + $users = array(); + foreach ( $titles as $title ) { + $titleObj = is_string( $title ) ? Title::newFromText( $title ) : $title; + if ( !$titleObj ) { + continue; + } + if ( !MWNamespace::hasGenderDistinction( $titleObj->getNamespace() ) ) { + continue; + } + $users[] = $titleObj->getText(); + } + + $this->doQuery( $users, $caller ); + } + + /** * Preloads genders for given list of users. * @param $users List|String: usernames * @param $caller String: the calling method @@ -98,26 +142,28 @@ class GenderCache { public function doQuery( $users, $caller = '' ) { $default = $this->getDefault(); - foreach ( (array) $users as $index => $value ) { - $name = strtr( $value, '_', ' ' ); - if ( isset( $this->cache[$name] ) ) { - // Skip users whose gender setting we already know - unset( $users[$index] ); - } else { - $users[$index] = $name; + $usersToCheck = array(); + foreach ( (array) $users as $value ) { + $name = self::normalizeUsername( $value ); + // Skip users whose gender setting we already know + if ( !isset( $this->cache[$name] ) ) { // For existing users, this value will be overwritten by the correct value $this->cache[$name] = $default; + // query only for valid names, which can be in the database + if( User::isValidUserName( $name ) ) { + $usersToCheck[] = $name; + } } } - if ( count( $users ) === 0 ) { + if ( count( $usersToCheck ) === 0 ) { return; } $dbr = wfGetDB( DB_SLAVE ); $table = array( 'user', 'user_properties' ); $fields = array( 'user_name', 'up_value' ); - $conds = array( 'user_name' => $users ); + $conds = array( 'user_name' => $usersToCheck ); $joins = array( 'user_properties' => array( 'LEFT JOIN', array( 'user_id = up_user', 'up_property' => 'gender' ) ) ); @@ -125,11 +171,20 @@ class GenderCache { if ( strval( $caller ) !== '' ) { $comment .= "/$caller"; } - $res = $dbr->select( $table, $fields, $conds, $comment, $joins, $joins ); + $res = $dbr->select( $table, $fields, $conds, $comment, array(), $joins ); foreach ( $res as $row ) { $this->cache[$row->user_name] = $row->up_value ? $row->up_value : $default; } } + private static function normalizeUsername( $username ) { + // Strip off subpages + $indexSlash = strpos( $username, '/' ); + if ( $indexSlash !== false ) { + $username = substr( $username, 0, $indexSlash ); + } + // normalize underscore/spaces + return strtr( $username, '_', ' ' ); + } } diff --git a/includes/cache/HTMLCacheUpdate.php b/includes/cache/HTMLCacheUpdate.php index 11e2ae74..0a3c0023 100644 --- a/includes/cache/HTMLCacheUpdate.php +++ b/includes/cache/HTMLCacheUpdate.php @@ -1,4 +1,25 @@ <?php +/** + * HTML cache invalidation of all pages linking to a given title. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ /** * Class to invalidate the HTML cache of all the pages linking to a given title. diff --git a/includes/cache/HTMLFileCache.php b/includes/cache/HTMLFileCache.php index 92130f69..6bfeed32 100644 --- a/includes/cache/HTMLFileCache.php +++ b/includes/cache/HTMLFileCache.php @@ -1,9 +1,33 @@ <?php /** - * Contain the HTMLFileCache class + * Page view caching in the file system. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ + +/** + * Page view caching in the file system. + * The only cacheable actions are "view" and "history". Also special pages + * will not be cached. + * + * @ingroup Cache + */ class HTMLFileCache extends FileCacheBase { /** * Construct an ObjectFileCache from a Title and an action @@ -105,19 +129,22 @@ class HTMLFileCache extends FileCacheBase { wfDebug( __METHOD__ . "()\n"); $filename = $this->cachePath(); + $context->getOutput()->sendCacheControl(); header( "Content-Type: $wgMimeType; charset=UTF-8" ); header( "Content-Language: $wgLanguageCode" ); if ( $this->useGzip() ) { if ( wfClientAcceptsGzip() ) { header( 'Content-Encoding: gzip' ); + readfile( $filename ); } else { /* Send uncompressed */ + wfDebug( __METHOD__ . " uncompressing cache file and sending it\n" ); readgzfile( $filename ); - return; } + } else { + readfile( $filename ); } - readfile( $filename ); $context->getOutput()->disable(); // tell $wgOut that output is taken care of } diff --git a/includes/cache/LinkBatch.php b/includes/cache/LinkBatch.php index 17e8739b..372f983b 100644 --- a/includes/cache/LinkBatch.php +++ b/includes/cache/LinkBatch.php @@ -1,4 +1,25 @@ <?php +/** + * Batch query to determine page existence. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ /** * Class representing a list of titles @@ -45,6 +66,11 @@ class LinkBatch { } } + /** + * @param $ns int + * @param $dbkey string + * @return mixed + */ public function add( $ns, $dbkey ) { if ( $ns < 0 ) { return; @@ -190,7 +216,7 @@ class LinkBatch { } $genderCache = GenderCache::singleton(); - $genderCache->dolinkBatch( $this->data, $this->caller ); + $genderCache->doLinkBatch( $this->data, $this->caller ); return true; } diff --git a/includes/cache/LinkCache.php b/includes/cache/LinkCache.php index a73eaaa4..f759c020 100644 --- a/includes/cache/LinkCache.php +++ b/includes/cache/LinkCache.php @@ -1,5 +1,27 @@ <?php /** + * Page existence cache. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ + +/** * Cache for article titles (prefixed DB keys) and ids linked from one source * * @ingroup Cache diff --git a/includes/cache/MemcachedSessions.php b/includes/cache/MemcachedSessions.php deleted file mode 100644 index 36733595..00000000 --- a/includes/cache/MemcachedSessions.php +++ /dev/null @@ -1,98 +0,0 @@ -<?php -/** - * This file gets included if $wgSessionsInMemcache is set in the config. - * It redirects session handling functions to store their data in memcached - * instead of the local filesystem. Depending on circumstances, it may also - * be necessary to change the cookie settings to work across hostnames. - * See: http://www.php.net/manual/en/function.session-set-save-handler.php - * - * @file - * @ingroup Cache - */ - -/** - * Get a cache key for the given session id. - * - * @param $id String: session id - * @return String: cache key - */ -function memsess_key( $id ) { - return wfMemcKey( 'session', $id ); -} - -/** - * Callback when opening a session. - * NOP: $wgMemc should be set up already. - * - * @param $save_path String: path used to store session files, unused - * @param $session_name String: session name - * @return Boolean: success - */ -function memsess_open( $save_path, $session_name ) { - return true; -} - -/** - * Callback when closing a session. - * NOP. - * - * @return Boolean: success - */ -function memsess_close() { - return true; -} - -/** - * Callback when reading session data. - * - * @param $id String: session id - * @return Mixed: session data - */ -function memsess_read( $id ) { - global $wgMemc; - $data = $wgMemc->get( memsess_key( $id ) ); - if( ! $data ) return ''; - return $data; -} - -/** - * Callback when writing session data. - * - * @param $id String: session id - * @param $data Mixed: session data - * @return Boolean: success - */ -function memsess_write( $id, $data ) { - global $wgMemc; - $wgMemc->set( memsess_key( $id ), $data, 3600 ); - return true; -} - -/** - * Callback to destroy a session when calling session_destroy(). - * - * @param $id String: session id - * @return Boolean: success - */ -function memsess_destroy( $id ) { - global $wgMemc; - - $wgMemc->delete( memsess_key( $id ) ); - return true; -} - -/** - * Callback to execute garbage collection. - * NOP: Memcached performs garbage collection. - * - * @param $maxlifetime Integer: maximum session life time - * @return Boolean: success - */ -function memsess_gc( $maxlifetime ) { - return true; -} - -function memsess_write_close() { - session_write_close(); -} - diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php index 146edd28..b854a2ec 100644 --- a/includes/cache/MessageCache.php +++ b/includes/cache/MessageCache.php @@ -1,5 +1,22 @@ <?php /** + * Localisation messages cache. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ @@ -115,6 +132,7 @@ class MessageCache { function getParserOptions() { if ( !$this->mParserOptions ) { $this->mParserOptions = new ParserOptions; + $this->mParserOptions->setEditSection( false ); } return $this->mParserOptions; } @@ -126,7 +144,7 @@ class MessageCache { * * @param $hash String: the hash of contents, to check validity. * @param $code Mixed: Optional language code, see documenation of load(). - * @return false on failure. + * @return bool on failure. */ function loadFromLocal( $hash, $code ) { global $wgCacheDirectory, $wgLocalMessageCacheSerialized; @@ -260,6 +278,7 @@ class MessageCache { * is disabled. * * @param $code String: language to which load messages + * @return bool */ function load( $code = false ) { global $wgUseLocalMessageCache; @@ -496,7 +515,7 @@ class MessageCache { if ( $code === 'en' ) { // Delete all sidebars, like for example on action=purge on the // sidebar messages - $codes = array_keys( Language::getLanguageNames() ); + $codes = array_keys( Language::fetchLanguageNames() ); } global $wgMemc; @@ -520,7 +539,7 @@ class MessageCache { * @param $cache Array: cached messages with a version. * @param $memc Bool: Wether to update or not memcache. * @param $code String: Language code. - * @return False on somekind of error. + * @return bool on somekind of error. */ protected function saveToCaches( $cache, $memc = true, $code = false ) { wfProfileIn( __METHOD__ ); @@ -588,7 +607,7 @@ class MessageCache { * @param $isFullKey Boolean: specifies whether $key is a two part key * "msg/lang". * - * @return string|false + * @return string|bool */ function get( $key, $useDB = true, $langcode = true, $isFullKey = false ) { global $wgLanguageCode, $wgContLang; @@ -696,7 +715,7 @@ class MessageCache { * @param $title String: Message cache key with initial uppercase letter. * @param $code String: code denoting the language to try. * - * @return string|false + * @return string|bool False on failure */ function getMsgFromNamespace( $title, $code ) { global $wgAdaptiveMessageCache; @@ -747,12 +766,14 @@ class MessageCache { } # Try loading it from the database - $revision = Revision::newFromTitle( Title::makeTitle( NS_MEDIAWIKI, $title ) ); + $revision = Revision::newFromTitle( + Title::makeTitle( NS_MEDIAWIKI, $title ), false, Revision::READ_LATEST + ); if ( $revision ) { $message = $revision->getText(); if ($message === false) { // A possibly temporary loading failure. - wfDebugLog( 'MessageCache', __METHOD__ . ": failed to load message page text for {$title->getDbKey()} ($code)" ); + wfDebugLog( 'MessageCache', __METHOD__ . ": failed to load message page text for {$title} ($code)" ); } else { $this->mCache[$code][$title] = ' ' . $message; $this->mMemc->set( $titleKey, ' ' . $message, $this->mExpiry ); @@ -868,7 +889,7 @@ class MessageCache { * Clear all stored messages. Mainly used after a mass rebuild. */ function clear() { - $langs = Language::getLanguageNames( false ); + $langs = Language::fetchLanguageNames( null, 'mw' ); foreach ( array_keys($langs) as $code ) { # Global cache $this->mMemc->delete( wfMemcKey( 'messages', $code ) ); @@ -890,8 +911,7 @@ class MessageCache { } $lang = array_pop( $pieces ); - $validCodes = Language::getLanguageNames(); - if( !array_key_exists( $lang, $validCodes ) ) { + if( !Language::fetchLanguageName( $lang, null, 'mw' ) ) { return array( $key, $wgLanguageCode ); } diff --git a/includes/cache/ObjectFileCache.php b/includes/cache/ObjectFileCache.php index 3356f1fc..ed1e49a6 100644 --- a/includes/cache/ObjectFileCache.php +++ b/includes/cache/ObjectFileCache.php @@ -1,9 +1,31 @@ <?php /** - * Contain the ObjectFileCache class + * Object cache in the file system. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ + +/** + * Object cache in the file system. + * + * @ingroup Cache + */ class ObjectFileCache extends FileCacheBase { /** * Construct an ObjectFileCache from a key and a type diff --git a/includes/cache/ProcessCacheLRU.php b/includes/cache/ProcessCacheLRU.php new file mode 100644 index 00000000..f215ebd8 --- /dev/null +++ b/includes/cache/ProcessCacheLRU.php @@ -0,0 +1,120 @@ +<?php +/** + * Per-process memory cache for storing items. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ + +/** + * Handles per process caching of items + * @ingroup Cache + */ +class ProcessCacheLRU { + /** @var Array */ + protected $cache = array(); // (key => prop => value) + + protected $maxCacheKeys; // integer; max entries + + /** + * @param $maxKeys integer Maximum number of entries allowed (min 1). + * @throws MWException When $maxCacheKeys is not an int or =< 0. + */ + public function __construct( $maxKeys ) { + if ( !is_int( $maxKeys ) || $maxKeys < 1 ) { + throw new MWException( __METHOD__ . " must be given an integer and >= 1" ); + } + $this->maxCacheKeys = $maxKeys; + } + + /** + * Set a property field for a cache entry. + * This will prune the cache if it gets too large. + * If the item is already set, it will be pushed to the top of the cache. + * + * @param $key string + * @param $prop string + * @param $value mixed + * @return void + */ + public function set( $key, $prop, $value ) { + if ( isset( $this->cache[$key] ) ) { + $this->ping( $key ); // push to top + } elseif ( count( $this->cache ) >= $this->maxCacheKeys ) { + reset( $this->cache ); + unset( $this->cache[key( $this->cache )] ); + } + $this->cache[$key][$prop] = $value; + } + + /** + * Check if a property field exists for a cache entry. + * + * @param $key string + * @param $prop string + * @return bool + */ + public function has( $key, $prop ) { + return isset( $this->cache[$key][$prop] ); + } + + /** + * Get a property field for a cache entry. + * This returns null if the property is not set. + * If the item is already set, it will be pushed to the top of the cache. + * + * @param $key string + * @param $prop string + * @return mixed + */ + public function get( $key, $prop ) { + if ( isset( $this->cache[$key][$prop] ) ) { + $this->ping( $key ); // push to top + return $this->cache[$key][$prop]; + } else { + return null; + } + } + + /** + * Clear one or several cache entries, or all cache entries + * + * @param $keys string|Array + * @return void + */ + public function clear( $keys = null ) { + if ( $keys === null ) { + $this->cache = array(); + } else { + foreach ( (array)$keys as $key ) { + unset( $this->cache[$key] ); + } + } + } + + /** + * Push an entry to the top of the cache + * + * @param $key string + */ + protected function ping( $key ) { + $item = $this->cache[$key]; + unset( $this->cache[$key] ); + $this->cache[$key] = $item; + } +} diff --git a/includes/cache/ResourceFileCache.php b/includes/cache/ResourceFileCache.php index e73fc2d7..61f1e8c3 100644 --- a/includes/cache/ResourceFileCache.php +++ b/includes/cache/ResourceFileCache.php @@ -1,9 +1,31 @@ <?php /** - * Contain the ResourceFileCache class + * Resource loader request result caching in the file system. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ + +/** + * Resource loader request result caching in the file system. + * + * @ingroup Cache + */ class ResourceFileCache extends FileCacheBase { protected $mCacheWorthy; diff --git a/includes/cache/SquidUpdate.php b/includes/cache/SquidUpdate.php index d47b5b5e..423e3884 100644 --- a/includes/cache/SquidUpdate.php +++ b/includes/cache/SquidUpdate.php @@ -1,6 +1,22 @@ <?php /** - * See deferred.txt + * Squid cache purging. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * * @file * @ingroup Cache */ @@ -12,13 +28,18 @@ class SquidUpdate { var $urlArr, $mMaxTitles; - function __construct( $urlArr = Array(), $maxTitles = false ) { + /** + * @param $urlArr array + * @param $maxTitles bool|int + */ + function __construct( $urlArr = array(), $maxTitles = false ) { global $wgMaxSquidPurgeTitles; if ( $maxTitles === false ) { $this->mMaxTitles = $wgMaxSquidPurgeTitles; } else { $this->mMaxTitles = $maxTitles; } + $urlArr = array_unique( $urlArr ); // Remove duplicates if ( count( $urlArr ) > $this->mMaxTitles ) { $urlArr = array_slice( $urlArr, 0, $this->mMaxTitles ); } @@ -102,23 +123,19 @@ class SquidUpdate { * @return void */ static function purge( $urlArr ) { - global $wgSquidServers, $wgHTCPMulticastAddress, $wgHTCPPort; - - /*if ( (@$wgSquidServers[0]) == 'echo' ) { - echo implode("<br />\n", $urlArr) . "<br />\n"; - return; - }*/ + global $wgSquidServers, $wgHTCPMulticastRouting; if( !$urlArr ) { return; } - if ( $wgHTCPMulticastAddress && $wgHTCPPort ) { + if ( $wgHTCPMulticastRouting ) { SquidUpdate::HTCPPurge( $urlArr ); } wfProfileIn( __METHOD__ ); + $urlArr = array_unique( $urlArr ); // Remove duplicates $maxSocketsPerSquid = 8; // socket cap per Squid $urlsPerSocket = 400; // 400 seems to be a good tradeoff, opening a socket takes a while $socketsPerSquid = ceil( count( $urlArr ) / $urlsPerSocket ); @@ -147,7 +164,7 @@ class SquidUpdate { * @param $urlArr array */ static function HTCPPurge( $urlArr ) { - global $wgHTCPMulticastAddress, $wgHTCPMulticastTTL, $wgHTCPPort; + global $wgHTCPMulticastRouting, $wgHTCPMulticastTTL; wfProfileIn( __METHOD__ ); $htcpOpCLR = 4; // HTCP CLR @@ -168,11 +185,20 @@ class SquidUpdate { socket_set_option( $conn, IPPROTO_IP, IP_MULTICAST_TTL, $wgHTCPMulticastTTL ); + $urlArr = array_unique( $urlArr ); // Remove duplicates foreach ( $urlArr as $url ) { if( !is_string( $url ) ) { throw new MWException( 'Bad purge URL' ); } $url = SquidUpdate::expand( $url ); + $conf = self::getRuleForURL( $url, $wgHTCPMulticastRouting ); + if ( !$conf ) { + wfDebug( "No HTCP rule configured for URL $url , skipping\n" ); + continue; + } + if ( !isset( $conf['host'] ) || !isset( $conf['port'] ) ) { + throw new MWException( "Invalid HTCP rule for URL $url\n" ); + } // Construct a minimal HTCP request diagram // as per RFC 2756 @@ -196,7 +222,7 @@ class SquidUpdate { // Send out wfDebug( "Purging URL $url via HTCP\n" ); socket_sendto( $conn, $htcpPacket, $htcpLen, 0, - $wgHTCPMulticastAddress, $wgHTCPPort ); + $conf['host'], $conf['port'] ); } } else { $errstr = socket_strerror( socket_last_error() ); @@ -223,4 +249,20 @@ class SquidUpdate { static function expand( $url ) { return wfExpandUrl( $url, PROTO_INTERNAL ); } + + /** + * Find the HTCP routing rule to use for a given URL. + * @param $url string URL to match + * @param $rules array Array of rules, see $wgHTCPMulticastRouting for format and behavior + * @return mixed Element of $rules that matched, or false if nothing matched + */ + static function getRuleForURL( $url, $rules ) { + foreach ( $rules as $regex => $routing ) { + if ( $regex === '' || preg_match( $regex, $url ) ) { + return $routing; + } + } + return false; + } + } diff --git a/includes/cache/UserCache.php b/includes/cache/UserCache.php new file mode 100644 index 00000000..6ec23669 --- /dev/null +++ b/includes/cache/UserCache.php @@ -0,0 +1,134 @@ +<?php +/** + * Caches current user names and other info based on user IDs. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * http://www.gnu.org/copyleft/gpl.html + * + * @file + * @ingroup Cache + */ + +/** + * @since 1.20 + */ +class UserCache { + protected $cache = array(); // (uid => property => value) + protected $typesCached = array(); // (uid => cache type => 1) + + /** + * @return UserCache + */ + public static function singleton() { + static $instance = null; + if ( $instance === null ) { + $instance = new self(); + } + return $instance; + } + + protected function __construct() {} + + /** + * Get a property of a user based on their user ID + * + * @param $userId integer User ID + * @param $prop string User property + * @return mixed The property or false if the user does not exist + */ + public function getProp( $userId, $prop ) { + if ( !isset( $this->cache[$userId][$prop] ) ) { + wfDebug( __METHOD__ . ": querying DB for prop '$prop' for user ID '$userId'.\n" ); + $this->doQuery( array( $userId ) ); // cache miss + } + return isset( $this->cache[$userId][$prop] ) + ? $this->cache[$userId][$prop] + : false; // user does not exist? + } + + /** + * Preloads user names for given list of users. + * @param $userIds Array List of user IDs + * @param $options Array Option flags; include 'userpage' and 'usertalk' + * @param $caller String: the calling method + */ + public function doQuery( array $userIds, $options = array(), $caller = '' ) { + wfProfileIn( __METHOD__ ); + + $usersToCheck = array(); + $usersToQuery = array(); + + foreach ( $userIds as $userId ) { + $userId = (int)$userId; + if ( $userId <= 0 ) { + continue; // skip anons + } + if ( isset( $this->cache[$userId]['name'] ) ) { + $usersToCheck[$userId] = $this->cache[$userId]['name']; // already have name + } else { + $usersToQuery[] = $userId; // we need to get the name + } + } + + // Lookup basic info for users not yet loaded... + if ( count( $usersToQuery ) ) { + $dbr = wfGetDB( DB_SLAVE ); + $table = array( 'user' ); + $conds = array( 'user_id' => $usersToQuery ); + $fields = array( 'user_name', 'user_real_name', 'user_registration', 'user_id' ); + + $comment = __METHOD__; + if ( strval( $caller ) !== '' ) { + $comment .= "/$caller"; + } + + $res = $dbr->select( $table, $fields, $conds, $comment ); + foreach ( $res as $row ) { // load each user into cache + $userId = (int)$row->user_id; + $this->cache[$userId]['name'] = $row->user_name; + $this->cache[$userId]['real_name'] = $row->user_real_name; + $this->cache[$userId]['registration'] = $row->user_registration; + $usersToCheck[$userId] = $row->user_name; + } + } + + $lb = new LinkBatch(); + foreach ( $usersToCheck as $userId => $name ) { + if ( $this->queryNeeded( $userId, 'userpage', $options ) ) { + $lb->add( NS_USER, str_replace( ' ', '_', $row->user_name ) ); + $this->typesCached[$userId]['userpage'] = 1; + } + if ( $this->queryNeeded( $userId, 'usertalk', $options ) ) { + $lb->add( NS_USER_TALK, str_replace( ' ', '_', $row->user_name ) ); + $this->typesCached[$userId]['usertalk'] = 1; + } + } + $lb->execute(); + + wfProfileOut( __METHOD__ ); + } + + /** + * Check if a cache type is in $options and was not loaded for this user + * + * @param $uid integer user ID + * @param $type string Cache type + * @param $options Array Requested cache types + * @return bool + */ + protected function queryNeeded( $uid, $type, array $options ) { + return ( in_array( $type, $options ) && !isset( $this->typesCached[$uid][$type] ) ); + } +} |