X-Git-Url: http://git.heureux-cyclage.org/?a=blobdiff_plain;ds=sidebyside;f=includes%2FMessageCache.php;h=64336585a28df574220c73a48a58242769ec5bd4;hb=073ac49c1b2c1211b56956e2d993eff674b3c158;hp=a6f00f5f910e0a171cabec923985707d7f945336;hpb=b96b707efa42ebcbc78e50fedcc29ccaf8dd1467;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/MessageCache.php b/includes/MessageCache.php index a6f00f5f91..64336585a2 100755 --- a/includes/MessageCache.php +++ b/includes/MessageCache.php @@ -1,74 +1,113 @@ mUseCache = !is_null( $memCached ); $this->mMemc = &$memCached; $this->mDisable = !$useDB; $this->mExpiry = $expiry; $this->mDisableTransform = false; - $this->mMemcKey = "$memcPrefix:messages"; + $this->mMemcKey = $memcPrefix.':messages'; $this->mKeys = false; # initialised on demand $this->mInitialised = true; + + wfProfileIn( $fname.'-parseropt' ); $this->mParserOptions = ParserOptions::newFromUser( $u=NULL ); + wfProfileOut( $fname.'-parseropt' ); + wfProfileIn( $fname.'-parser' ); $this->mParser = new Parser; + wfProfileOut( $fname.'-parser' ); + + # When we first get asked for a message, + # then we'll fill up the cache. If we + # can return a cache hit, this saves + # some extra milliseconds + $this->mDeferred = true; - $this->load(); + wfProfileOut( $fname ); } - # Loads messages either from memcached or the database, if not disabled - # On error, quietly switches to a fallback mode - # Returns false for a reportable error, true otherwise + /** + * Loads messages either from memcached or the database, if not disabled + * On error, quietly switches to a fallback mode + * Returns false for a reportable error, true otherwise + */ function load() { global $wgAllMessagesEn; - + if ( $this->mDisable ) { wfDebug( "MessageCache::load(): disabled\n" ); return true; } - + $fname = 'MessageCache::load'; + wfProfileIn( $fname ); $success = true; - + if ( $this->mUseCache ) { + wfProfileIn( $fname.'-fromcache' ); $this->mCache = $this->mMemc->get( $this->mMemcKey ); - + wfProfileOut( $fname.'-fromcache' ); + # If there's nothing in memcached, load all the messages from the database if ( !$this->mCache ) { wfDebug( "MessageCache::load(): loading all messages\n" ); $this->lock(); # Other threads don't need to load the messages if another thread is doing it. - $this->mMemc->set( $this->mMemcKey, "loading", MSG_LOAD_TIMEOUT ); - $this->loadFromDB(); - # Save in memcached - # Keep trying if it fails, this is kind of important - for ( $i=0; $i<20 && !$this->mMemc->set( $this->mMemcKey, $this->mCache, $this->mExpiry ); $i++ ) { - usleep(mt_rand(500000,1500000)); - } - if ( $i == 20 ) { - $this->mMemc->set( $this->mMemcKey, "error", 86400 ); - wfDebug( "MemCached set error in MessageCache: restart memcached server!\n" ); + $success = $this->mMemc->add( $this->mMemcKey, "loading", MSG_LOAD_TIMEOUT ); + if ( $success ) { + wfProfileIn( $fname.'-load' ); + $this->loadFromDB(); + wfProfileOut( $fname.'-load' ); + # Save in memcached + # Keep trying if it fails, this is kind of important + wfProfileIn( $fname.'-save' ); + for ( $i=0; $i<20 && !$this->mMemc->set( $this->mMemcKey, $this->mCache, $this->mExpiry ); $i++ ) { + usleep(mt_rand(500000,1500000)); + } + wfProfileOut( $fname.'-save' ); + if ( $i == 20 ) { + $this->mMemc->set( $this->mMemcKey, 'error', 60*5 ); + wfDebug( "MemCached set error in MessageCache: restart memcached server!\n" ); + } } $this->unlock(); } - + if ( !is_array( $this->mCache ) ) { - wfMsg( "MessageCache::load(): individual message mode\n" ); + wfDebug( "MessageCache::load(): individual message mode\n" ); # If it is 'loading' or 'error', switch to individual message mode, otherwise disable - # Causing too much DB load, disabling -- TS + # Causing too much DB load, disabling -- TS $this->mDisable = true; /* if ( $this->mCache == "loading" ) { @@ -83,48 +122,77 @@ class MessageCache $this->mCache = false; } } + wfProfileOut( $fname ); + $this->mDeferred = false; return $success; } - # Loads all cacheable messages from the database - function loadFromDB() - { - $fname = "MessageCache::loadFromDB"; - $dbr =& wfGetDB( DB_READ ); - $res = $dbr->select( 'cur', - array( 'cur_title', 'cur_text' ), - array( 'cur_is_redirect' => 0, 'cur_namespace' => NS_MEDIAWIKI ), + /** + * Loads all or main part of cacheable messages from the database + */ + function loadFromDB() { + global $wgPartialMessageCache; + $fname = 'MessageCache::loadFromDB'; + $dbr =& wfGetDB( DB_SLAVE ); + $conditions = array( 'page_is_redirect' => 0, + 'page_namespace' => NS_MEDIAWIKI); + if ($wgPartialMessageCache) { + wfDebugDieBacktrace( "Confused about how this works." ); + if (is_array($wgPartialMessageCache)) { + $conditions['page_title']=$wgPartialMessageCache; + } else { + require_once("MessageCacheHints.php"); + $conditions['page_title']=MessageCacheHints::get(); + } + } + $res = $dbr->select( array( 'page', 'revision', 'text' ), + array( 'page_title', 'old_text', 'old_flags' ), + 'page_is_redirect=0 AND page_namespace='.NS_MEDIAWIKI.' AND page_latest=rev_id AND rev_text_id=old_id', $fname ); - + $this->mCache = array(); for ( $row = $dbr->fetchObject( $res ); $row; $row = $dbr->fetchObject( $res ) ) { - $this->mCache[$row->cur_title] = $row->cur_text; + $this->mCache[$row->page_title] = Revision::getRevisionText( $row ); } $dbr->freeResult( $res ); + /* + # FIXME: This is too slow currently. + # We need to bulk-fetch revisions, but in a portable way... + $resultSet = Revision::fetchFromConds( $dbr, array( + 'page_namespace' => NS_MEDIAWIKI, + 'page_is_redirect' => 0, + 'page_id=rev_page' ) ); + while( $row = $resultSet->fetchObject() ) { + $revision = new Revision( $row ); + $title = $revision->getTitle(); + $this->mCache[$title->getDBkey()] = $revision->getText(); + } + $resultSet->free(); + */ } - - # Not really needed anymore + + /** + * Not really needed anymore + */ function getKeys() { - global $wgAllMessagesEn, $wgLang; + global $wgAllMessagesEn, $wgContLang; if ( !$this->mKeys ) { $this->mKeys = array(); foreach ( $wgAllMessagesEn as $key => $value ) { - array_push( $this->mKeys, $wgLang->ucfirst( $key ) ); + $title = $wgContLang->ucfirst( $key ); + array_push( $this->mKeys, $title ); } } return $this->mKeys; } - - # Obsolete + + /** + * Obsolete + */ function isCacheable( $key ) { return true; - /* - global $wgAllMessagesEn, $wgLang; - return array_key_exists( $wgLang->lcfirst( $key ), $wgAllMessagesEn ) || - array_key_exists( $key, $wgAllMessagesEn ); - */ } function replace( $title, $text ) { @@ -137,96 +205,142 @@ class MessageCache $this->unlock(); } - # Returns success - # Represents a write lock on the messages key + /** + * Returns success + * Represents a write lock on the messages key + */ function lock() { if ( !$this->mUseCache ) { return true; } - $lockKey = $this->mMemcKey . "lock"; + $lockKey = $this->mMemcKey . 'lock'; for ($i=0; $i < MSG_WAIT_TIMEOUT && !$this->mMemc->add( $lockKey, 1, MSG_LOCK_TIMEOUT ); $i++ ) { sleep(1); } - + return $i >= MSG_WAIT_TIMEOUT; } - + function unlock() { if ( !$this->mUseCache ) { return; } - $lockKey = $this->mMemcKey . "lock"; + $lockKey = $this->mMemcKey . 'lock'; $this->mMemc->delete( $lockKey ); } - - function get( $key, $useDB ) { - global $wgLang, $wgLanguageCode; - + + function get( $key, $useDB, $forcontent=true, $isfullkey = false ) { + global $wgContLanguageCode; + if( $forcontent ) { + global $wgContLang; + $lang =& $wgContLang; + $langcode = $wgContLanguageCode; + } else { + global $wgLang, $wgLanguageCode; + $lang =& $wgLang; + $langcode = $wgLanguageCode; + } # If uninitialised, someone is trying to call this halfway through Setup.php - if ( !$this->mInitialised ) { + if( !$this->mInitialised ) { return "<$key>"; } - - $message = false; - if ( !$this->mDisable ) { - $title = $wgLang->ucfirst( $key ); - + # If cache initialization was deferred, start it now. + if( $this->mDeferred ) { + $this->load(); + } - # Try the cache - if ( $this->mUseCache && $this->mCache && array_key_exists( $title, $this->mCache ) ) { - $message = $this->mCache[$title]; - } - - # If it wasn't in the cache, load each message from the DB individually - if ( !$message && $useDB) { - $dbr =& wfGetDB( DB_READ ); - $result = $dbr->getArray( "cur", array("cur_text"), - array( "cur_namespace" => NS_MEDIAWIKI, "cur_title" => $title ), - "MessageCache::get" ); - if ( $result ) { - $message = $result->cur_text; - } + $message = false; + if( !$this->mDisable && $useDB ) { + $title = $lang->ucfirst( $key ); + if(!$isfullkey && ($langcode != $wgContLanguageCode) ) { + $title .= '/' . $langcode; } + $message = $this->getFromCache( $title ); } # Try the extension array - if ( !$message ) { + if( !$message ) { $message = @$this->mExtensionMessages[$key]; } - # Try the array in $wgLang - if ( !$message ) { - $message = $wgLang->getMessage( $key ); - } + # Try the array in the language object + if( !$message ) { + wfSuppressWarnings(); + $message = $lang->getMessage( $key ); + wfRestoreWarnings(); + } # Try the English array - if ( !$message && $wgLanguageCode != "en" ) { + if( !$message && $langcode != 'en' ) { + wfSuppressWarnings(); $message = Language::getMessage( $key ); + wfRestoreWarnings(); + } + + # Is this a custom message? Try the default language in the db... + if( !$message && + !$this->mDisable && $useDB && + !$isfullkey && ($langcode != $wgContLanguageCode) ) { + $message = $this->getFromCache( $lang->ucfirst( $key ) ); } # Final fallback - if ( !$message ) { + if( !$message ) { $message = "<$key>"; } - + # Replace brace tags $message = $this->transform( $message ); return $message; } + + function getFromCache( $title ) { + $message = false; + + # Try the cache + if( $this->mUseCache && is_array( $this->mCache ) && array_key_exists( $title, $this->mCache ) ) { + $message = $this->mCache[$title]; + } + + if ( !$message && $this->mUseCache ) { + $message = $this->mMemc->get( $this->mMemcKey . ':' . $title ); + if( $message ) { + $this->mCache[$title] = $message; + } + } + + # If it wasn't in the cache, load each message from the DB individually + if ( !$message ) { + $revision = Revision::newFromTitle( Title::makeTitle( NS_MEDIAWIKI, $title ) ); + if( $revision ) { + $message = $revision->getText(); + if ($this->mUseCache) { + $this->mCache[$title]=$message; + /* individual messages may be often + recached until proper purge code exists + */ + $this->mMemc->set( $this->mMemcKey . ':' . $title, $message, 300 ); + } + } + } + + return $message; + } function transform( $message ) { - if( !$this->mDisableTransform ) { - if ( strstr( $message, "{{" ) !== false ) { + if( !$this->mDisableTransform ) { + if( strpos( $message, '{{' ) !== false ) { $message = $this->mParser->transformMsg( $message, $this->mParserOptions ); } } return $message; } - + function disable() { $this->mDisable = true; } function enable() { $this->mDisable = false; } function disableTransform() { $this->mDisableTransform = true; } + function enableTransform() { $this->mDisableTransform = false; } function addMessage( $key, $value ) { $this->mExtensionMessages[$key] = $value; @@ -237,5 +351,14 @@ class MessageCache $this->mExtensionMessages[$key] = $value; } } + + /** + * Clear all stored messages. Mainly used after a mass rebuild. + */ + function clear() { + if( $this->mUseCache ) { + $this->mMemc->delete( $this->mMemcKey ); + } + } } ?>