X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2Fcache%2FMessageCache.php;h=e871855a32b617f082c9e31e11d88b8d69b60bde;hb=30f4b3c103997bd9154b247cda8282eb8bd0ba66;hp=b26dc8da2f6f91622acd97150b375e70c26e5d1b;hpb=7f91193ef37d534949950c980416b5a921cd5d79;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php index b26dc8da2f..e871855a32 100644 --- a/includes/cache/MessageCache.php +++ b/includes/cache/MessageCache.php @@ -51,7 +51,7 @@ class MessageCache { protected $mCache; /** - * Should mean that database cannot be used, but check + * Should mean that database cannot be used, but check * @var bool $mDisable */ protected $mDisable; @@ -302,7 +302,7 @@ class MessageCache { $where[] = 'global cache is expired'; $staleCache = $cache; } elseif ( $hashVolatile ) { - # DB results are slave lag prone until the holdoff TTL passes. + # DB results are replica DB lag prone until the holdoff TTL passes. # By then, updates should be reflected in loadFromDBWithLock(). # One thread renerates the cache while others use old values. $where[] = 'global cache is expired/volatile'; @@ -355,6 +355,7 @@ class MessageCache { $where[] = 'loading FAILED - cache is disabled'; $this->mDisable = true; $this->mCache = false; + wfDebugLog( 'MessageCacheError', __METHOD__ . ": Failed to load $code\n" ); # This used to throw an exception, but that led to nasty side effects like # the whole wiki being instantly down if the memcached server died } else { @@ -441,7 +442,7 @@ class MessageCache { function loadFromDB( $code, $mode = null ) { global $wgMaxMsgCacheEntrySize, $wgLanguageCode, $wgAdaptiveMessageCache; - $dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_SLAVE ); + $dbr = wfGetDB( ( $mode == self::FOR_UPDATE ) ? DB_MASTER : DB_REPLICA ); $cache = []; @@ -563,7 +564,7 @@ class MessageCache { } // Mark this cache as definitely "latest" (non-volatile) so - // load() calls do try to refresh the cache with slave data + // load() calls do try to refresh the cache with replica DB data $this->mCache[$code]['LATEST'] = time(); // Update caches if the lock was acquired @@ -818,84 +819,96 @@ class MessageCache { * @return string|bool The message, or false if not found */ protected function getMessageFromFallbackChain( $lang, $lckey, $useDB ) { - global $wgLanguageCode, $wgContLang; - - $uckey = $wgContLang->ucfirst( $lckey ); - $langcode = $lang->getCode(); - $message = false; + global $wgContLang; - // First try the requested language. - if ( $useDB ) { - if ( $langcode === $wgLanguageCode ) { - // Messages created in the content language will not have the /lang extension - $message = $this->getMsgFromNamespace( $uckey, $langcode ); - } else { - $message = $this->getMsgFromNamespace( "$uckey/$langcode", $langcode ); - } - } + $alreadyTried = []; + // First try the requested language. + $message = $this->getMessageForLang( $lang, $lckey, $useDB, $alreadyTried ); if ( $message !== false ) { return $message; } - // Check the CDB cache - $message = $lang->getMessage( $lckey ); - if ( $message !== null ) { - return $message; - } + // Now try checking the site language. + $message = $this->getMessageForLang( $wgContLang, $lckey, $useDB, $alreadyTried ); + return $message; + } - list( $fallbackChain, $siteFallbackChain ) = - Language::getFallbacksIncludingSiteLanguage( $langcode ); + /** + * Given a language, try and fetch messages from that language and its fallbacks. + * + * @see MessageCache::get + * @param Language|StubObject $lang Preferred language + * @param string $lckey Lowercase key for the message (as for localisation cache) + * @param bool $useDB Whether to include messages from the wiki database + * @param bool[] $alreadyTried Contains true for each language that has been tried already + * @return string|bool The message, or false if not found + */ + private function getMessageForLang( $lang, $lckey, $useDB, &$alreadyTried ) { + global $wgContLang; + $langcode = $lang->getCode(); - // Next try checking the database for all of the fallback languages of the requested language. + // Try checking the database for the requested language if ( $useDB ) { - foreach ( $fallbackChain as $code ) { - if ( $code === $wgLanguageCode ) { - // Messages created in the content language will not have the /lang extension - $message = $this->getMsgFromNamespace( $uckey, $code ); - } else { - $message = $this->getMsgFromNamespace( "$uckey/$code", $code ); - } + $uckey = $wgContLang->ucfirst( $lckey ); + + if ( !isset( $alreadyTried[ $langcode ] ) ) { + $message = $this->getMsgFromNamespace( + $this->getMessagePageName( $langcode, $uckey ), + $langcode + ); if ( $message !== false ) { - // Found the message. return $message; } + $alreadyTried[ $langcode ] = true; } } - // Now try checking the site language. - if ( $useDB ) { - $message = $this->getMsgFromNamespace( $uckey, $wgLanguageCode ); - if ( $message !== false ) { - return $message; - } - } - - $message = $wgContLang->getMessage( $lckey ); + // Check the CDB cache + $message = $lang->getMessage( $lckey ); if ( $message !== null ) { return $message; } - // Finally try the DB for the site language's fallbacks. + // Try checking the database for all of the fallback languages if ( $useDB ) { - foreach ( $siteFallbackChain as $code ) { - $message = $this->getMsgFromNamespace( "$uckey/$code", $code ); - if ( $message === false && $code === $wgLanguageCode ) { - // Messages created in the content language will not have the /lang extension - $message = $this->getMsgFromNamespace( $uckey, $code ); + $fallbackChain = Language::getFallbacksFor( $langcode ); + + foreach ( $fallbackChain as $code ) { + if ( isset( $alreadyTried[ $code ] ) ) { + continue; } + $message = $this->getMsgFromNamespace( $this->getMessagePageName( $code, $uckey ), $code ); + if ( $message !== false ) { - // Found the message. return $message; } + $alreadyTried[ $code ] = true; } } return false; } + /** + * Get the message page name for a given language + * + * @param string $langcode + * @param string $uckey Uppercase key for the message + * @return string The page name + */ + private function getMessagePageName( $langcode, $uckey ) { + global $wgLanguageCode; + if ( $langcode === $wgLanguageCode ) { + // Messages created in the content language will not have the /lang extension + return $uckey; + } else { + return "$uckey/$langcode"; + } + } + /** * Get a message from the MediaWiki namespace, with caching. The key must * first be converted to two-part lang/msg form if necessary. @@ -1076,7 +1089,7 @@ class MessageCache { if ( !$title || !$title instanceof Title ) { global $wgTitle; wfDebugLog( 'GlobalTitleFail', __METHOD__ . ' called by ' . - wfGetAllCallers( 5 ) . ' with no title set.' ); + wfGetAllCallers( 6 ) . ' with no title set.' ); $title = $wgTitle; } // Sometimes $wgTitle isn't set either... @@ -1101,6 +1114,22 @@ class MessageCache { $this->mDisable = false; } + /** + * Whether DB/cache usage is disabled for determining messages + * + * If so, this typically indicates either: + * - a) load() failed to find a cached copy nor query the DB + * - b) we are in a special context or error mode that cannot use the DB + * If the DB is ignored, any derived HTML output or cached objects may be wrong. + * To avoid long-term cache pollution, TTLs can be adjusted accordingly. + * + * @return bool + * @since 1.27 + */ + public function isDisabled() { + return $this->mDisable; + } + /** * Clear all stored messages. Mainly used after a mass rebuild. */