Krinkle has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/253656

Change subject: [WIP] Remove use of msg_resource table in favour of using 
MessageCache directly
......................................................................

[WIP] Remove use of msg_resource table in favour of using MessageCache directly

* Remove all interaction with the msg_resource table.

* MessageBlobStore: Make logger aware.

* MessageBlobStore: Log an error if json encoding fails.

* MessageBlobStore: Remove all caching. Reduce to a simple class that just
  json-encodes an array of messages. To be removed later. The MessageCache class
  behind wfMessage() already preload

* Refactor ResourceLoader to use a hash of the message blob instead of a 
timestamp.
  Timestamps are unreliable and roll over too frequently for message blob store
  because there is no authoritve source. The timestamps were inferred based on
  when a change is observed. Message overrides from the local wiki have an
  explicit update event when the page is edited. All other messages, such as
  from MediaWiki core and extensions using LocalisationCache, have a single
  timestamp for all messages which rolls over every time the cache is rebuilt.

  A hash is deterministic, and won't cause needless cache invalidation 
(T102578).

* ResourceLoader: Remove redundant pre-fetching in makeModuleResponse().
  This is already done by preloadModuleInfo() in respond(). Which also used
  a try/catch already.

This is patch is an alternative for I78bb09bc, which proposed to migrate
MessageBlobStore to WANCache instead.

Bug: T113092
Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
---
M includes/cache/MessageBlobStore.php
M includes/resourceloader/ResourceLoader.php
M includes/resourceloader/ResourceLoaderFileModule.php
M includes/resourceloader/ResourceLoaderModule.php
M maintenance/cleanupRemovedModules.php
M tests/phpunit/includes/OutputPageTest.php
M tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
7 files changed, 165 insertions(+), 406 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/56/253656/1

diff --git a/includes/cache/MessageBlobStore.php 
b/includes/cache/MessageBlobStore.php
index 624bbc9..6970405 100644
--- a/includes/cache/MessageBlobStore.php
+++ b/includes/cache/MessageBlobStore.php
@@ -22,212 +22,108 @@
  * @author Trevor Parscal
  */
 
+use Psr\Log\LoggerAwareInterface;
+use Psr\Log\LoggerInterface;
+use Psr\Log\NullLogger;
+
 /**
- * This class provides access to the message blobs used by ResourceLoader 
modules.
+ * This class generates message blobs for use by ResourceLoader modules.
  *
- * A message blob is a JSON object containing the interface messages for a
- * certain module in a certain language. These message blobs are cached
- * in the automatically invalidated when one of their constituent messages,
- * or the module definition, is changed.
+ * A message blob is a JSON object containing the interface messages for a 
certain module in
+ * a certain language. These blobs used to be cached in the database, but this 
class now
+ * uses MessageCache (via wfMessage) directly – see T113092.
  */
-class MessageBlobStore {
-       /**
-        * In-process cache for message blobs.
-        *
-        * Keyed by language code, then module name.
-        *
-        * @var array
-        */
-       protected $blobCache = array();
-
-       /* @var ResourceLoader */
-       protected $resourceloader;
+class MessageBlobStore implements LoggerAwareInterface {
 
        /**
-        * @param ResourceLoader $resourceloader
+        * @var LoggerInterface
         */
-       public function __construct( ResourceLoader $resourceloader = null ) {
-               $this->resourceloader = $resourceloader;
+       private $logger;
+
+       /**
+        * @param ResourceLoader $rl
+        * @param LoggerInterface $logger
+        */
+       public function __construct( ResourceLoader $unused = null, 
LoggerInterface $logger = null ) {
+               $this->logger = $logger ?: new NullLogger();
+       }
+
+       /**
+        * @since 1.27
+        * @param LoggerInterface $logger
+        */
+       public function setLogger( LoggerInterface $logger ) {
+               $this->logger = $logger;
+       }
+
+       /**
+        * Get the message blob for a module
+        *
+        * @since 1.27
+        * @param ResourceLoaderModule $module
+        * @param string $lang Language code
+        * @return string JSON
+        */
+       public function getBlob( ResourceLoaderModule $module, $lang ) {
+               return $this->generateMessageBlob( $module, $lang );
+       }
+
+       /**
+        * Generate message blobs for a set of modules
+        *
+        * @param array $modules Array of module objects keyed by name
+        * @param string $lang Language code
+        * @return array An array mapping module names to message blobs
+        */
+       public function getBlobs( $modules, $lang ) {
+               $blobs = array();
+               foreach ( $modules as $name => $module ) {
+                       $blobs[$name] = $this->generateMessageBlob( $module, 
$lang );
+               }
+               return $blobs;
        }
 
        /**
         * Get the message blobs for a set of modules
         *
-        * @param ResourceLoader $resourceLoader
-        * @param array $modules Array of module objects keyed by module name
-        * @param string $lang Language code
-        * @return array An array mapping module names to message blobs
+        * @deprecated since 1.27 Use getBlobs() instead
+        * @return array
         */
        public function get( ResourceLoader $resourceLoader, $modules, $lang ) {
-               if ( !count( $modules ) ) {
-                       return array();
-               }
-
-               $blobs = array();
-
-               // Try in-process cache
-               $missingFromCache = array();
-               foreach ( $modules as $name => $module ) {
-                       if ( isset( $this->blobCache[$lang][$name] ) ) {
-                               $blobs[$name] = $this->blobCache[$lang][$name];
-                       } else {
-                               $missingFromCache[$name] = $module;
-                       }
-               }
-
-               // Try DB cache
-               if ( $missingFromCache ) {
-                       $blobs += $this->getFromDB( $missingFromCache, $lang );
-               }
-
-               // Generate new blobs for any remaining modules and store in DB
-               $missingFromDb = array_diff( array_keys( $modules ), 
array_keys( $blobs ) );
-               foreach ( $missingFromDb as $name ) {
-                       $blob = $this->insertMessageBlob( $name, 
$modules[$name], $lang );
-                       if ( $blob ) {
-                               $blobs[$name] = $blob;
-                       }
-               }
-
-               // Update in-process cache
-               if ( isset( $this->blobCache[$lang] ) ) {
-                       $this->blobCache[$lang] += $blobs;
-               } else {
-                       $this->blobCache[$lang] = $blobs;
-               }
-
-               return $blobs;
+               return $this->getBlobs( $modules, $lang );
        }
 
        /**
-        * Generate and insert a new message blob. If the blob was already
-        * present, it is not regenerated; instead, the preexisting blob
-        * is fetched and returned.
+        * Previously used to populate a cache table in the database.
         *
-        * @param string $name Module name
-        * @param ResourceLoaderModule $module
-        * @param string $lang Language code
-        * @return string JSON blob
+        * @deprecated since 1.27 Obsolete
+        * @return bool
         */
        public function insertMessageBlob( $name, ResourceLoaderModule $module, 
$lang ) {
-               $blob = $this->generateMessageBlob( $module, $lang );
-
-               if ( !$blob ) {
-                       return false;
-               }
-
-               try {
-                       $dbw = wfGetDB( DB_MASTER );
-                       $success = $dbw->insert( 'msg_resource', array(
-                                       'mr_lang' => $lang,
-                                       'mr_resource' => $name,
-                                       'mr_blob' => $blob,
-                                       'mr_timestamp' => $dbw->timestamp()
-                               ),
-                               __METHOD__,
-                               array( 'IGNORE' )
-                       );
-
-                       if ( $success && $dbw->affectedRows() == 0 ) {
-                               // Blob was already present, fetch it
-                               $blob = $dbw->selectField( 'msg_resource', 
'mr_blob', array(
-                                               'mr_resource' => $name,
-                                               'mr_lang' => $lang,
-                                       ),
-                                       __METHOD__
-                               );
-                       }
-               } catch ( DBError $e ) {
-                       wfDebug( __METHOD__ . " failed to update DB: $e\n" );
-               }
-               return $blob;
+               return false;
        }
 
        /**
-        * Update the message blob for a given module in a given language
+        * Previously used to update a cache table in the database.
         *
-        * @param string $name Module name
-        * @param ResourceLoaderModule $module
-        * @param string $lang Language code
-        * @return string|null Regenerated message blob, or null if there was 
no blob for
-        *   the given module/language pair.
+        * @deprecated since 1.27 Obsolete
+        * @return null
         */
        public function updateModule( $name, ResourceLoaderModule $module, 
$lang ) {
-               $dbw = wfGetDB( DB_MASTER );
-               $row = $dbw->selectRow( 'msg_resource', 'mr_blob',
-                       array( 'mr_resource' => $name, 'mr_lang' => $lang ),
-                       __METHOD__
-               );
-               if ( !$row ) {
-                       return null;
-               }
-
-               $newBlob = $this->generateMessageBlob( $module, $lang );
-
-               try {
-                       $newRow = array(
-                               'mr_resource' => $name,
-                               'mr_lang' => $lang,
-                               'mr_blob' => $newBlob,
-                               'mr_timestamp' => $dbw->timestamp()
-                       );
-
-                       $dbw->replace( 'msg_resource',
-                               array( array( 'mr_resource', 'mr_lang' ) ),
-                               $newRow, __METHOD__
-                       );
-               } catch ( Exception $e ) {
-                       wfDebug( __METHOD__ . " failed to update DB: $e\n" );
-               }
-               return $newBlob;
+               return null;
        }
 
        /**
-        * Update a single message in all message blobs it occurs in.
+        * Previously used to purge rows from a cache table in the database.
         *
-        * @param string $key Message key
+        * @deprecated since 1.27 Obsolete
         */
        public function updateMessage( $key ) {
-               try {
-                       $dbw = wfGetDB( DB_MASTER );
-
-                       // Keep running until the updates queue is empty.
-                       // Due to update conflicts, the queue might not be 
emptied
-                       // in one iteration.
-                       $updates = null;
-                       do {
-                               $updates = $this->getUpdatesForMessage( $key, 
$updates );
-
-                               foreach ( $updates as $k => $update ) {
-                                       // Update the row on the condition that 
it
-                                       // didn't change since we fetched it by 
putting
-                                       // the timestamp in the WHERE clause.
-                                       $success = $dbw->update( 'msg_resource',
-                                               array(
-                                                       'mr_blob' => 
$update['newBlob'],
-                                                       'mr_timestamp' => 
$dbw->timestamp() ),
-                                               array(
-                                                       'mr_resource' => 
$update['resource'],
-                                                       'mr_lang' => 
$update['lang'],
-                                                       'mr_timestamp' => 
$update['timestamp'] ),
-                                               __METHOD__
-                                       );
-
-                                       // Only requeue conflicted updates.
-                                       // If update() returned false, don't 
retry, for
-                                       // fear of getting into an infinite loop
-                                       if ( !( $success && 
$dbw->affectedRows() == 0 ) ) {
-                                               // Not conflicted
-                                               unset( $updates[$k] );
-                                       }
-                               }
-                       } while ( count( $updates ) );
-
-               } catch ( Exception $e ) {
-                       wfDebug( __METHOD__ . " failed to update DB: $e\n" );
-               }
        }
 
+       /**
+        * @deprecated since 1.27 Obsolete
+        */
        public function clear() {
                try {
                        // Not using TRUNCATE, because that needs extra 
permissions,
@@ -240,75 +136,7 @@
        }
 
        /**
-        * @return ResourceLoader
-        */
-       protected function getResourceLoader() {
-               // For back-compat this class supports instantiation without 
passing ResourceLoader
-               // Lazy-initialise this property because most callers don't 
need it.
-               if ( $this->resourceloader === null ) {
-                       wfDebug( __CLASS__ . ' created without a ResourceLoader 
instance' );
-                       $this->resourceloader = new ResourceLoader();
-               }
-
-               return $this->resourceloader;
-       }
-
-       /**
-        * Create an update queue for updateMessage()
-        *
-        * @param string $key Message key
-        * @param array $prevUpdates Updates queue to refresh or null to build 
a fresh update queue
-        * @return array Updates queue
-        */
-       private function getUpdatesForMessage( $key, $prevUpdates = null ) {
-               $dbw = wfGetDB( DB_MASTER );
-
-               if ( is_null( $prevUpdates ) ) {
-                       $rl = $this->getResourceLoader();
-                       $moduleNames = $rl->getModulesByMessage( $key );
-                       // Fetch all blobs referencing $key
-                       $res = $dbw->select(
-                               array( 'msg_resource' ),
-                               array( 'mr_resource', 'mr_lang', 'mr_blob', 
'mr_timestamp' ),
-                               array(
-                                       'mr_resource' => $moduleNames,
-                               ),
-                               __METHOD__
-                       );
-               } else {
-                       // Refetch the blobs referenced by $prevUpdates
-
-                       // Reorganize the (resource, lang) pairs in the format
-                       // expected by makeWhereFrom2d()
-                       $twoD = array();
-
-                       foreach ( $prevUpdates as $update ) {
-                               $twoD[$update['resource']][$update['lang']] = 
true;
-                       }
-
-                       $res = $dbw->select( 'msg_resource',
-                               array( 'mr_resource', 'mr_lang', 'mr_blob', 
'mr_timestamp' ),
-                               $dbw->makeWhereFrom2d( $twoD, 'mr_resource', 
'mr_lang' ),
-                               __METHOD__
-                       );
-               }
-
-               // Build the new updates queue
-               $updates = array();
-
-               foreach ( $res as $row ) {
-                       $updates[] = array(
-                               'resource' => $row->mr_resource,
-                               'lang' => $row->mr_lang,
-                               'timestamp' => $row->mr_timestamp,
-                               'newBlob' => $this->reencodeBlob( 
$row->mr_blob, $key, $row->mr_lang )
-                       );
-               }
-
-               return $updates;
-       }
-
-       /**
+        * @since 1.27
         * @param string $key Message key
         * @param string $lang Language code
         * @return string
@@ -316,65 +144,12 @@
        private function fetchMessage( $key, $lang ) {
                $message = wfMessage( $key )->inLanguage( $lang );
                if ( !$message->exists() ) {
-                       wfDebugLog( 'resourceloader', __METHOD__ . " failed to 
find: '$key' ($lang)" );
+                       $this->logger->warning( __METHOD__ . " failed to find 
{message} ({lang})", array(
+                               'message' => $key,
+                               'lang' => $lang,
+                       ) );
                }
                return $message->plain();
-       }
-
-       /**
-        * Reencode a message blob with the updated value for a message
-        *
-        * @param string $blob Message blob (JSON object)
-        * @param string $key Message key
-        * @param string $lang Language code
-        * @return string Message blob with $key replaced with its new value
-        */
-       private function reencodeBlob( $blob, $key, $lang ) {
-               $decoded = FormatJson::decode( $blob, true );
-               $decoded[$key] = $this->fetchMessage( $key, $lang );
-               return FormatJson::encode( (object)$decoded );
-       }
-
-       /**
-        * Get the message blobs for a set of modules from the database.
-        * Modules whose blobs are not in the database are silently dropped.
-        *
-        * @param array $modules Array of module objects by name
-        * @param string $lang Language code
-        * @throws MWException
-        * @return array Array mapping module names to blobs
-        */
-       private function getFromDB( $modules, $lang ) {
-               if ( !count( $modules ) ) {
-                       return array();
-               }
-
-               $retval = array();
-               $dbr = wfGetDB( DB_SLAVE );
-               $res = $dbr->select( 'msg_resource',
-                       array( 'mr_blob', 'mr_resource', 'mr_timestamp' ),
-                       array( 'mr_resource' => array_keys( $modules ), 
'mr_lang' => $lang ),
-                       __METHOD__
-               );
-
-               foreach ( $res as $row ) {
-                       if ( !isset( $modules[ $row->mr_resource ] ) ) {
-                               // This shouldn't be possible
-                               throw new MWException( __METHOD__ . ' passed an 
invalid module name' );
-                       }
-                       $module = $modules[ $row->mr_resource ];
-
-                       // Update the module's blob if the list of messages 
changed
-                       $blobKeys = array_keys( FormatJson::decode( 
$row->mr_blob, true ) );
-                       $moduleMsgs = array_values( array_unique( 
$module->getMessages() ) );
-                       if ( $blobKeys !== $moduleMsgs ) {
-                               $retval[$row->mr_resource] = 
$this->updateModule( $row->mr_resource, $module, $lang );
-                       } else {
-                               $retval[$row->mr_resource] = $row->mr_blob;
-                       }
-               }
-
-               return $retval;
        }
 
        /**
@@ -386,11 +161,18 @@
         */
        private function generateMessageBlob( ResourceLoaderModule $module, 
$lang ) {
                $messages = array();
-
                foreach ( $module->getMessages() as $key ) {
                        $messages[$key] = $this->fetchMessage( $key, $lang );
                }
+               $json = FormatJson::encode( (object)$messages );
 
-               return FormatJson::encode( (object)$messages );
+               if ( $json === false ) {
+                       $this->logger->warning( 'Failed to encode message blob 
for {module} ({lang})', array(
+                               'module' => $module->getName(),
+                               'lang' => $lang,
+                       ) );
+                       $json = '{}';
+               }
+               return $json;
        }
 }
diff --git a/includes/resourceloader/ResourceLoader.php 
b/includes/resourceloader/ResourceLoader.php
index 6995642..b72d64e 100644
--- a/includes/resourceloader/ResourceLoader.php
+++ b/includes/resourceloader/ResourceLoader.php
@@ -101,11 +101,11 @@
         * requests its own information. This sacrifice of modularity yields a 
substantial
         * performance improvement.
         *
-        * @param array $modules List of module names to preload information for
+        * @param array $moduleNames List of module names to preload 
information for
         * @param ResourceLoaderContext $context Context to load the 
information within
         */
-       public function preloadModuleInfo( array $modules, 
ResourceLoaderContext $context ) {
-               if ( !count( $modules ) ) {
+       public function preloadModuleInfo( array $moduleNames, 
ResourceLoaderContext $context ) {
+               if ( !count( $moduleNames ) ) {
                        // Or else Database*::select() will explode, plus it's 
cheaper!
                        return;
                }
@@ -116,11 +116,12 @@
                // Batched version of ResourceLoaderModule::getFileDependencies
                $vary = "$skin|$lang";
                $res = $dbr->select( 'module_deps', array( 'md_module', 
'md_deps' ), array(
-                               'md_module' => $modules,
+                               'md_module' => $moduleNames,
                                'md_skin' => $vary,
                        ), __METHOD__
                );
-               // Prime in-object cache values for each module
+
+               // Prime in-object cache for file dependencies
                $modulesWithDeps = array();
                foreach ( $res as $row ) {
                        $module = $this->getModule( $row->md_module );
@@ -132,41 +133,25 @@
                        }
                }
                // Register the absence of a dependency row too
-               foreach ( array_diff( $modules, $modulesWithDeps ) as $name ) {
+               foreach ( array_diff( $moduleNames, $modulesWithDeps ) as $name 
) {
                        $module = $this->getModule( $name );
                        if ( $module ) {
                                $this->getModule( $name )->setFileDependencies( 
$context, array() );
                        }
                }
 
-               // Get message blob mtimes. Only do this for modules with 
messages
-               $modulesWithMessages = array();
-               foreach ( $modules as $name ) {
+               // Prime in-object cache for message blobs for modules with 
messages
+               $modules = array();
+               foreach ( $moduleNames as $name ) {
                        $module = $this->getModule( $name );
-                       if ( $module && count( $module->getMessages() ) ) {
-                               $modulesWithMessages[] = $name;
+                       if ( $module && $module->getMessages() ) {
+                               $modules[$name] = $module;
                        }
                }
-               $modulesWithoutMessages = array_flip( $modules ); // Will be 
trimmed down by the loop below
-               if ( count( $modulesWithMessages ) ) {
-                       $res = $dbr->select( 'msg_resource', array( 
'mr_resource', 'mr_timestamp' ), array(
-                                       'mr_resource' => $modulesWithMessages,
-                                       'mr_lang' => $lang
-                               ), __METHOD__
-                       );
-                       foreach ( $res as $row ) {
-                               $module = $this->getModule( $row->mr_resource );
-                               if ( $module ) {
-                                       $module->setMsgBlobMtime( $lang, 
wfTimestamp( TS_UNIX, $row->mr_timestamp ) );
-                                       unset( 
$modulesWithoutMessages[$row->mr_resource] );
-                               }
-                       }
-               }
-               foreach ( array_keys( $modulesWithoutMessages ) as $name ) {
-                       $module = $this->getModule( $name );
-                       if ( $module ) {
-                               $module->setMsgBlobMtime( $lang, 1 );
-                       }
+               $store = $this->getMessageBlobStore();
+               $blobs = $store->getBlobs( $modules, $lang );
+               foreach ( $blobs as $name => $blob ) {
+                       $modules[$name]->setMessageBlob( $blob, $lang );
                }
        }
 
@@ -246,10 +231,7 @@
        public function __construct( Config $config = null, LoggerInterface 
$logger = null ) {
                global $IP;
 
-               if ( !$logger ) {
-                       $logger = new NullLogger();
-               }
-               $this->setLogger( $logger );
+               $this->logger = $logger ?: new NullLogger();
 
                if ( !$config ) {
                        $this->logger->debug( __METHOD__ . ' was called without 
providing a Config instance' );
@@ -274,7 +256,7 @@
                        $this->registerTestModules();
                }
 
-               $this->setMessageBlobStore( new MessageBlobStore( $this ) );
+               $this->setMessageBlobStore( new MessageBlobStore( $this, 
$this->logger ) );
        }
 
        /**
@@ -284,6 +266,10 @@
                return $this->config;
        }
 
+       /**
+        * @since 1.26
+        * @param LoggerInterface $logger
+        */
        public function setLogger( LoggerInterface $logger ) {
                $this->logger = $logger;
        }
@@ -664,7 +650,7 @@
                }
 
                try {
-                       // Preload for getCombinedVersion()
+                       // Preload for getCombinedVersion() and for batch 
makeModuleResponse()
                        $this->preloadModuleInfo( array_keys( $modules ), 
$context );
                } catch ( Exception $e ) {
                        MWExceptionHandler::logException( $e );
@@ -962,19 +948,6 @@
                                $this->errors[] = 'Image generation failed';
                        }
                        return $data;
-               }
-
-               // Pre-fetch blobs
-               if ( $context->shouldIncludeMessages() ) {
-                       try {
-                               $this->blobStore->get( $this, $modules, 
$context->getLanguage() );
-                       } catch ( Exception $e ) {
-                               MWExceptionHandler::logException( $e );
-                               $this->logger->warning( 'Prefetching 
MessageBlobStore failed: {exception}', array(
-                                       'exception' => $e
-                               ) );
-                               $this->errors[] = 
self::formatExceptionNoComment( $e );
-                       }
                }
 
                foreach ( $missing as $name ) {
diff --git a/includes/resourceloader/ResourceLoaderFileModule.php 
b/includes/resourceloader/ResourceLoaderFileModule.php
index 1421b10..0f28bfe 100644
--- a/includes/resourceloader/ResourceLoaderFileModule.php
+++ b/includes/resourceloader/ResourceLoaderFileModule.php
@@ -583,7 +583,7 @@
                $summary[] = array(
                        'options' => $options,
                        'fileHashes' => $this->getFileHashes( $context ),
-                       'msgBlobMtime' => $this->getMsgBlobMtime( 
$context->getLanguage() ),
+                       'messageBlob' => $this->getMessageBlob( $context ),
                );
                return $summary;
        }
diff --git a/includes/resourceloader/ResourceLoaderModule.php 
b/includes/resourceloader/ResourceLoaderModule.php
index fcda87b..d4cb810 100644
--- a/includes/resourceloader/ResourceLoaderModule.php
+++ b/includes/resourceloader/ResourceLoaderModule.php
@@ -60,8 +60,8 @@
 
        // In-object cache for file dependencies
        protected $fileDeps = array();
-       // In-object cache for message blob mtime
-       protected $msgBlobMtime = array();
+       // In-object cache for message blob (keyed by language)
+       protected $msgBlobs = array();
        // In-object cache for version hash
        protected $versionHash = array();
        // In-object cache for module content
@@ -453,45 +453,37 @@
        }
 
        /**
-        * Get the last modification timestamp of the messages in this module 
for a given language.
-        * @param string $lang Language code
-        * @return int UNIX timestamp
+        * Get the hash of the message blob.
+        *
+        * @since 1.27
+        * @param ResourceLoaderContext $context
+        * @return string|null JSON blob or null if module has no messages
         */
-       public function getMsgBlobMtime( $lang ) {
-               if ( !isset( $this->msgBlobMtime[$lang] ) ) {
-                       if ( !count( $this->getMessages() ) ) {
-                               return 1;
-                       }
-
-                       $dbr = wfGetDB( DB_SLAVE );
-                       $msgBlobMtime = $dbr->selectField( 'msg_resource',
-                               'mr_timestamp',
-                               array(
-                                       'mr_resource' => $this->getName(),
-                                       'mr_lang' => $lang
-                               ),
-                               __METHOD__
-                       );
-                       // If no blob was found, but the module does have 
messages, that means we need
-                       // to regenerate it. Return NOW
-                       if ( $msgBlobMtime === false ) {
-                               $msgBlobMtime = wfTimestampNow();
-                       }
-                       $this->msgBlobMtime[$lang] = wfTimestamp( TS_UNIX, 
$msgBlobMtime );
+       protected function getMessageBlob( ResourceLoaderContext $context ) {
+               if ( !$this->getMessages() ) {
+                       // Don't bother consulting MessageBlobStore
+                       return null;
                }
-               return $this->msgBlobMtime[$lang];
+               // Message blobs may only vary language, not by context keys
+               $lang = $context->getLanguage();
+               if ( !isset( $lang, $this->msgBlobs ) ) {
+                       $store = 
$context->getResourceLoader()->getMessageBlobStore();
+                       $this->msgBlobs[$lang] = $store->getBlob( $this, $lang 
);
+               }
+               return $this->msgBlobs[$lang];
        }
 
        /**
-        * Set in-object cache for message blob time.
+        * Set in-object cache for message blobs..
         *
-        * This is used to retrieve data in batches. See 
ResourceLoader::preloadModuleInfo().
+        * Used to allow fetching of message blobs in batches. See 
ResourceLoader::preloadModuleInfo().
         *
+        * @since 1.27
+        * @param string|null $blob JSON blob or null
         * @param string $lang Language code
-        * @param int $mtime UNIX timestamp
         */
-       public function setMsgBlobMtime( $lang, $mtime ) {
-               $this->msgBlobMtime[$lang] = $mtime;
+       public function setMessageBlob( $lang, $blob ) {
+               $this->msgBlobs[$lang] = $blob;
        }
 
        /**
@@ -607,13 +599,9 @@
                }
 
                // Messages
-               $blobs = $rl->getMessageBlobStore()->get(
-                       $rl,
-                       array( $this->getName() => $this ),
-                       $context->getLanguage()
-               );
-               if ( isset( $blobs[$this->getName()] ) ) {
-                       $content['messagesBlob'] = $blobs[$this->getName()];
+               $blob = $this->getMessageBlob( $context );
+               if ( $blob ) {
+                       $content['messagesBlob'] = $blob;
                }
 
                $templates = $this->getTemplates();
@@ -746,7 +734,7 @@
         * A number of utility methods are available to help you gather data. 
These are not
         * called by default and must be included by the subclass' 
getDefinitionSummary().
         *
-        * - getMsgBlobMtime()
+        * - getMessageBlob()
         *
         * @since 1.23
         * @param ResourceLoaderContext $context
@@ -817,6 +805,32 @@
        }
 
        /**
+        * Get the last modification timestamp of the message blob for this 
module in a given language.
+        *
+        * @deprecated since 1.27 Superseded by getVersionHash()
+        * @param string $lang Language code
+        * @return int UNIX timestamp
+        */
+       public function getMsgBlobMtime( $lang ) {
+               if ( !$this->getMessages() ) {
+                       return 1;
+               }
+               // Dummy that is > 1
+               return 2;
+       }
+
+       /**
+        * Set in-object cache for message blob time. Obsolete.
+        *
+        * @deprecated since 1.27 Superseded by setMessageBlob()
+        * @param string $lang Language code
+        * @param int $mtime UNIX timestamp
+        */
+       public function setMsgBlobMtime( $lang, $mtime ) {
+               // No-op
+       }
+
+       /**
         * Check whether this module is known to be empty. If a child class
         * has an easy and cheap way to determine that this module is
         * definitely going to be empty, it should override this method to
diff --git a/maintenance/cleanupRemovedModules.php 
b/maintenance/cleanupRemovedModules.php
index ae05930..1181348 100644
--- a/maintenance/cleanupRemovedModules.php
+++ b/maintenance/cleanupRemovedModules.php
@@ -59,18 +59,9 @@
                } while ( $numRows > 0 );
                $this->output( "done\n" );
 
-               $this->output( "Cleaning up msg_resource table...\n" );
-               $i = 1;
-
-               $mrRes = $dbw->tableName( 'msg_resource' );
-               do {
-                       $where = $moduleList ? "mr_resource NOT IN 
($moduleList)" : '1=1';
-                       $dbw->query( "DELETE FROM $mrRes WHERE $where LIMIT 
$limit", __METHOD__ );
-                       $numRows = $dbw->affectedRows();
-                       $this->output( "Batch $i: $numRows rows\n" );
-                       $i++;
-                       wfWaitForSlaves();
-               } while ( $numRows > 0 );
+               $this->output( "Purging unused msg_resource table...\n" );
+               $blobStore = $rl->getMessageBlobStore();
+               $blobStore->clear();
                $this->output( "done\n" );
        }
 }
diff --git a/tests/phpunit/includes/OutputPageTest.php 
b/tests/phpunit/includes/OutputPageTest.php
index 5f21e07..f5ef016 100644
--- a/tests/phpunit/includes/OutputPageTest.php
+++ b/tests/phpunit/includes/OutputPageTest.php
@@ -375,7 +375,6 @@
        }
 
        public function updateModule( $name, ResourceLoaderModule $module, 
$lang ) {
-               return;
        }
 
        public function updateMessage( $key ) {
diff --git 
a/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php 
b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
index c552b80..9a36d18 100644
--- a/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
+++ b/tests/phpunit/includes/resourceloader/ResourceLoaderStartUpModuleTest.php
@@ -5,7 +5,7 @@
        // Version hash for a blank file module.
        // Result of ResourceLoader::makeHash(), ResourceLoaderTestModule
        // and ResourceLoaderFileModule::getDefinitionSummary().
-       protected static $blankVersion = 'wvTifjse';
+       protected static $blankVersion = 'GqV9IPpY';
 
        protected static function expandPlaceholders( $text ) {
                return strtr( $text, array(

-- 
To view, visit https://gerrit.wikimedia.org/r/253656
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Id8c26f41a82597e34013f95294cdc3971a4f52ae
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Krinkle <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to