From: Aaron Schulz Date: Tue, 2 Oct 2018 17:59:28 +0000 (-0700) Subject: messagecache: avoid caching message pages that do not override X-Git-Tag: 1.34.0-rc.0~3814^2 X-Git-Url: https://git.cyclocoop.org/%7B%24admin_url%7Dmembres/supprimer.php?a=commitdiff_plain;h=a3d6c1411dad3e057b6558416d3deb86d8e75282;p=lhc%2Fweb%2Fwiklou.git messagecache: avoid caching message pages that do not override Clean up individual message cache handling when the master key is volatile. The goal is not to treat the message as gone but to re-fetch it when accessed rather than cache the value in the main/process cache. Bug: T193271 Change-Id: I4bcaf10c1516e7c96c2d0963722affeaf80272e0 --- diff --git a/includes/cache/MessageCache.php b/includes/cache/MessageCache.php index bf2ed2e430..69cdf04214 100644 --- a/includes/cache/MessageCache.php +++ b/includes/cache/MessageCache.php @@ -464,13 +464,7 @@ class MessageCache { $cache = []; - # Common conditions - $conds = [ - 'page_is_redirect' => 0, - 'page_namespace' => NS_MEDIAWIKI, - ]; - - $mostused = []; + $mostused = []; // list of "/" if ( $wgAdaptiveMessageCache && $code !== $wgLanguageCode ) { if ( !$this->cache->has( $wgLanguageCode ) ) { $this->load( $wgLanguageCode ); @@ -481,6 +475,14 @@ class MessageCache { } } + // Get the list of software-defined messages in core/extensions + $overridable = array_flip( Language::getMessageKeysFor( $wgLanguageCode ) ); + + // Common conditions + $conds = [ + 'page_is_redirect' => 0, + 'page_namespace' => NS_MEDIAWIKI, + ]; if ( count( $mostused ) ) { $conds['page_title'] = $mostused; } elseif ( $code !== $wgLanguageCode ) { @@ -492,31 +494,28 @@ class MessageCache { $dbr->buildLike( $dbr->anyString(), '/', $dbr->anyString() ); } - # Conditions to fetch oversized pages to ignore them - $bigConds = $conds; - $bigConds[] = 'page_len > ' . intval( $wgMaxMsgCacheEntrySize ); - - # Load titles for all oversized pages in the MediaWiki namespace + // Set the stubs for oversized software-defined messages in the main cache map $res = $dbr->select( 'page', [ 'page_title', 'page_latest' ], - $bigConds, + array_merge( $conds, [ 'page_len > ' . intval( $wgMaxMsgCacheEntrySize ) ] ), __METHOD__ . "($code)-big" ); foreach ( $res as $row ) { - $cache[$row->page_title] = '!TOO BIG'; + $name = $this->contLang->lcfirst( $row->page_title ); + // Include entries/stubs for all keys in $mostused in adaptive mode + if ( $wgAdaptiveMessageCache || isset( $overridable[$name] ) ) { + $cache[$row->page_title] = '!TOO BIG'; + } // At least include revision ID so page changes are reflected in the hash $cache['EXCESSIVE'][$row->page_title] = $row->page_latest; } - # Conditions to load the remaining pages with their contents - $smallConds = $conds; - $smallConds[] = 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize ); - + // Set the text for small software-defined messages in the main cache map $res = $dbr->select( [ 'page', 'revision', 'text' ], - [ 'page_title', 'old_id', 'old_text', 'old_flags' ], - $smallConds, + [ 'page_title', 'page_latest', 'old_id', 'old_text', 'old_flags' ], + array_merge( $conds, [ 'page_len <= ' . intval( $wgMaxMsgCacheEntrySize ) ] ), __METHOD__ . "($code)-small", [], [ @@ -524,23 +523,30 @@ class MessageCache { 'text' => [ 'JOIN', 'rev_text_id=old_id' ], ] ); - foreach ( $res as $row ) { - $text = Revision::getRevisionText( $row ); - if ( $text === false ) { - // Failed to fetch data; possible ES errors? - // Store a marker to fetch on-demand as a workaround... - // TODO Use a differnt marker - $entry = '!TOO BIG'; - wfDebugLog( - 'MessageCache', - __METHOD__ - . ": failed to load message page text for {$row->page_title} ($code)" - ); + $name = $this->contLang->lcfirst( $row->page_title ); + // Include entries/stubs for all keys in $mostused in adaptive mode + if ( $wgAdaptiveMessageCache || isset( $overridable[$name] ) ) { + $text = Revision::getRevisionText( $row ); + if ( $text === false ) { + // Failed to fetch data; possible ES errors? + // Store a marker to fetch on-demand as a workaround... + // TODO Use a differnt marker + $entry = '!TOO BIG'; + wfDebugLog( + 'MessageCache', + __METHOD__ + . ": failed to load message page text for {$row->page_title} ($code)" + ); + } else { + $entry = ' ' . $text; + } + $cache[$row->page_title] = $entry; } else { - $entry = ' ' . $text; + // T193271: cache object gets too big and slow to generate. + // At least include revision ID so page changes are reflected in the hash. + $cache['EXCESSIVE'][$row->page_title] = $row->page_latest; } - $cache[$row->page_title] = $entry; } $cache['VERSION'] = MSG_CACHE_VERSION; @@ -799,9 +805,8 @@ class MessageCache { Hooks::run( 'MessageCache::get', [ &$lckey ] ); // Loop through each language in the fallback list until we find something useful - $lang = wfGetLangObj( $langcode ); $message = $this->getMessageFromFallbackChain( - $lang, + wfGetLangObj( $langcode ), $lckey, !$this->mDisable && $useDB ); @@ -893,7 +898,6 @@ class MessageCache { $this->getMessagePageName( $langcode, $uckey ), $langcode ); - if ( $message !== false ) { return $message; } @@ -968,44 +972,54 @@ class MessageCache { $this->load( $code ); $entry = $this->cache->getField( $code, $title ); + if ( $entry !== null ) { + // Message page exists as an override of a software messages if ( substr( $entry, 0, 1 ) === ' ' ) { // The message exists and is not '!TOO BIG' return (string)substr( $entry, 1 ); } elseif ( $entry === '!NONEXISTENT' ) { + // The text might be '-' or missing due to some data loss return false; } - // Fall through and try invididual message cache below - } else { - // Message does not have a MediaWiki page definition - $message = false; - Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] ); - if ( $message !== false ) { - $this->cache->setField( $code, $title, ' ' . $message ); - } else { - $this->cache->setField( $code, $title, '!NONEXISTENT' ); - } - - return $message; - } - - if ( $this->cacheVolatile[$code] ) { - $entry = false; - // Make sure that individual keys respect the WAN cache holdoff period too - LoggerFactory::getInstance( 'MessageCache' )->debug( - __METHOD__ . ': loading volatile key \'{titleKey}\'', - [ 'titleKey' => $title, 'code' => $code ] ); + // Load the message page, utilizing the individual message cache. + // If the page does not exist, there will be no hook handler fallbacks. + $entry = $this->loadCachedMessagePageEntry( + $title, + $code, + $this->cache->getField( $code, 'HASH' ) + ); } else { - // Try the individual message cache + // Message page does not exist or does not override a software message. + // Load the message page, utilizing the individual message cache. $entry = $this->loadCachedMessagePageEntry( $title, $code, $this->cache->getField( $code, 'HASH' ) ); + if ( substr( $entry, 0, 1 ) !== ' ' ) { + // Message does not have a MediaWiki page definition; try hook handlers + $message = false; + Hooks::run( 'MessagesPreLoad', [ $title, &$message, $code ] ); + if ( $message !== false ) { + $this->cache->setField( $code, $title, ' ' . $message ); + } else { + $this->cache->setField( $code, $title, '!NONEXISTENT' ); + } + + return $message; + } } if ( $entry !== false && substr( $entry, 0, 1 ) === ' ' ) { - $this->cache->setField( $code, $title, $entry ); + if ( $this->cacheVolatile[$code] ) { + // Make sure that individual keys respect the WAN cache holdoff period too + LoggerFactory::getInstance( 'MessageCache' )->debug( + __METHOD__ . ': loading volatile key \'{titleKey}\'', + [ 'titleKey' => $title, 'code' => $code ] ); + } else { + $this->cache->setField( $code, $title, $entry ); + } // The message exists, so make sure a string is returned return (string)substr( $entry, 1 ); }