From: Aaron Schulz Date: Thu, 22 Feb 2018 08:48:42 +0000 (-0800) Subject: Make LocalFile check early if the revision store is available X-Git-Tag: 1.31.0-rc.0~530 X-Git-Url: https://git.heureux-cyclage.org/?p=lhc%2Fweb%2Fwiklou.git;a=commitdiff_plain;h=d9ba7cd0050d531c4f016fda285793568fa133c7 Make LocalFile check early if the revision store is available 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 --- diff --git a/includes/Storage/BlobStore.php b/includes/Storage/BlobStore.php index 28caf3a412..8b1112b277 100644 --- a/includes/Storage/BlobStore.php +++ b/includes/Storage/BlobStore.php @@ -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(); } diff --git a/includes/Storage/RevisionStore.php b/includes/Storage/RevisionStore.php index 2992211630..db06afee7e 100644 --- a/includes/Storage/RevisionStore.php +++ b/includes/Storage/RevisionStore.php @@ -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 */ diff --git a/includes/Storage/SqlBlobStore.php b/includes/Storage/SqlBlobStore.php index b890e5acaa..0ff7c13343 100644 --- a/includes/Storage/SqlBlobStore.php +++ b/includes/Storage/SqlBlobStore.php @@ -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 ); + } } diff --git a/includes/externalstore/ExternalStore.php b/includes/externalstore/ExternalStore.php index 2ac6f7e82f..de7d1a4c48 100644 --- a/includes/externalstore/ExternalStore.php +++ b/includes/externalstore/ExternalStore.php @@ -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 diff --git a/includes/externalstore/ExternalStoreMedium.php b/includes/externalstore/ExternalStoreMedium.php index f1eaa93b9f..da7752b745 100644 --- a/includes/externalstore/ExternalStoreMedium.php +++ b/includes/externalstore/ExternalStoreMedium.php @@ -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; diff --git a/includes/filerepo/file/LocalFile.php b/includes/filerepo/file/LocalFile.php index 7cf2749f00..263e45b015 100644 --- a/includes/filerepo/file/LocalFile.php +++ b/includes/filerepo/file/LocalFile.php @@ -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;