MessageCache: Restore 'loadedLanguages' tracking for load()
authorTimo Tijhof <krinklemail@gmail.com>
Mon, 29 Jul 2019 18:22:10 +0000 (19:22 +0100)
committerTimo Tijhof <krinklemail@gmail.com>
Mon, 29 Jul 2019 18:22:10 +0000 (19:22 +0100)
This was removed in 97e86d934b3 in 2018 in favour of using
`$this->cache->has($code)`. This is a problem because there
are cases where only a narrow subset of that structure is
populated (by MessageCache->replace) without things like
$this->overridable (or anything else that MessageCache->load does)
having ocurred yet.

The assumption that keys are only added to $this->cache by
MessageCache->load (or after that method has been called) was
actually true at some point. But, this changed in 2017 when
commit c962b480568e optimised MessageCache->replace to not call
MessageCache->load.

Bug: T208897
Change-Id: Ie8bb4a4793675e5f1454e65c427f3100035c8b4d

includes/cache/MessageCache.php

index a8bcfc6..5745451 100644 (file)
@@ -98,6 +98,12 @@ class MessageCache {
        /** @var Language */
        protected $contLang;
 
+       /**
+        * Track which languages have been loaded by load().
+        * @var array
+        */
+       private $loadedLanguages = [];
+
        /**
         * Singleton instance
         *
@@ -264,23 +270,12 @@ class MessageCache {
                }
 
                # Don't do double loading...
-               if ( $this->cache->has( $code ) && $mode != self::FOR_UPDATE ) {
+               if ( isset( $this->loadedLanguages[$code] ) && $mode != self::FOR_UPDATE ) {
                        return true;
                }
 
                $this->overridable = array_flip( Language::getMessageKeysFor( $code ) );
 
-               // T208897 array_flip can fail and return null
-               if ( is_null( $this->overridable ) ) {
-                       LoggerFactory::getInstance( 'MessageCache' )->error(
-                               __METHOD__ . ': $this->overridable is null',
-                               [
-                                       'message_keys' => Language::getMessageKeysFor( $code ),
-                                       'code' => $code
-                               ]
-                       );
-               }
-
                # 8 lines of code just to say (once) that message cache is disabled
                if ( $this->mDisable ) {
                        static $shownDisabled = false;
@@ -396,6 +391,9 @@ class MessageCache {
                        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 {
+                       # All good, just record the success
+                       $this->loadedLanguages[$code] = true;
                }
 
                if ( !$this->cache->has( $code ) ) { // sanity
@@ -1300,6 +1298,7 @@ class MessageCache {
                        $this->wanCache->touchCheckKey( $this->getCheckKey( $code ) );
                }
                $this->cache->clear();
+               $this->loadedLanguages = [];
        }
 
        /**