Make LocalFile check early if the revision store is available
authorAaron Schulz <aschulz@wikimedia.org>
Thu, 22 Feb 2018 08:48:42 +0000 (00:48 -0800)
committerChad <chadh@wikimedia.org>
Thu, 22 Feb 2018 22:07:30 +0000 (22:07 +0000)
This reduces the odds of having files without corresponding
wiki pages, given that the later is done in a deferred update.

Also made some documentation cleanups.

Bug: T187942
Change-Id: Iff516669f535713d37e0011e2d7ed285c667f1c5

includes/Storage/BlobStore.php
includes/Storage/RevisionStore.php
includes/Storage/SqlBlobStore.php
includes/externalstore/ExternalStore.php
includes/externalstore/ExternalStoreMedium.php
includes/filerepo/file/LocalFile.php

index 28caf3a..8b1112b 100644 (file)
@@ -110,4 +110,10 @@ interface BlobStore {
         */
        public function storeBlob( $data, $hints = [] );
 
+       /**
+        * Check if the blob metadata or backing blob data store is read-only
+        *
+        * @return bool
+        */
+       public function isReadOnly();
 }
index 2992211..db06afe 100644 (file)
@@ -132,6 +132,13 @@ class RevisionStore
                $this->logger = $logger;
        }
 
+       /**
+        * @return bool Whether the store is read-only
+        */
+       public function isReadOnly() {
+               return $this->blobStore->isReadOnly();
+       }
+
        /**
         * @return bool
         */
index b890e5a..0ff7c13 100644 (file)
@@ -590,4 +590,11 @@ class SqlBlobStore implements IDBAccessObject, BlobStore {
                return [ $schema, $id, $parameters ];
        }
 
+       public function isReadOnly() {
+               if ( $this->useExternalStore && ExternalStore::defaultStoresAreReadOnly() ) {
+                       return true;
+               }
+
+               return ( $this->getDBLoadBalancer()->getReadOnlyReason() !== false );
+       }
 }
index 2ac6f7e..de7d1a4 100644 (file)
@@ -158,7 +158,7 @@ class ExternalStore {
         * provided by $wgDefaultExternalStore.
         *
         * @param string $data
-        * @param array $params Associative array of ExternalStoreMedium parameters
+        * @param array $params Map of ExternalStoreMedium::__construct context parameters
         * @return string|bool The URL of the stored data item, or false on error
         * @throws MWException
         */
@@ -176,7 +176,7 @@ class ExternalStore {
         *
         * @param array $tryStores Refer to $wgDefaultExternalStore
         * @param string $data
-        * @param array $params Associative array of ExternalStoreMedium parameters
+        * @param array $params Map of ExternalStoreMedium::__construct context parameters
         * @return string|bool The URL of the stored data item, or false on error
         * @throws MWException
         */
@@ -219,6 +219,29 @@ class ExternalStore {
                }
        }
 
+       /**
+        * @return bool Whether all the default insertion stores are marked as read-only
+        * @since 1.31
+        */
+       public static function defaultStoresAreReadOnly() {
+               global $wgDefaultExternalStore;
+
+               $tryStores = (array)$wgDefaultExternalStore;
+               if ( !$tryStores ) {
+                       return false; // no stores exists which can be "read only"
+               }
+
+               foreach ( $tryStores as $storeUrl ) {
+                       list( $proto, $path ) = explode( '://', $storeUrl, 2 );
+                       $store = self::getStoreObject( $proto, [] );
+                       if ( !$store->isReadOnly( $path ) ) {
+                               return false; // at least one store is not read-only
+                       }
+               }
+
+               return true; // all stores are read-only
+       }
+
        /**
         * @param string $data
         * @param string $wiki
index f1eaa93..da7752b 100644 (file)
@@ -32,7 +32,8 @@ abstract class ExternalStoreMedium {
        protected $params = [];
 
        /**
-        * @param array $params Options
+        * @param array $params Usage context options:
+        *   - wiki: the domain ID of the wiki this is being used for [optional]
         */
        public function __construct( array $params = [] ) {
                $this->params = $params;
index 7cf2749..263e45b 100644 (file)
@@ -24,6 +24,7 @@
 use MediaWiki\Logger\LoggerFactory;
 use Wikimedia\Rdbms\Database;
 use Wikimedia\Rdbms\IDatabase;
+use MediaWiki\MediaWikiServices;
 
 /**
  * Class to represent a local file in the wiki's own database
@@ -1275,6 +1276,10 @@ class LocalFile extends File {
        ) {
                if ( $this->getRepo()->getReadOnlyReason() !== false ) {
                        return $this->readOnlyFatalStatus();
+               } elseif ( MediaWikiServices::getInstance()->getRevisionStore()->isReadOnly() ) {
+                       // Check this in advance to avoid writing to FileBackend and the file tables,
+                       // only to fail on insert the revision due to the text store being unavailable.
+                       return $this->readOnlyFatalStatus();
                }
 
                $srcPath = ( $src instanceof FSFile ) ? $src->getPath() : $src;