$e->report(); // display the GUI error
}
} catch ( Exception $e ) {
+ $context = $this->context;
+ if (
+ $e instanceof DBConnectionError &&
+ $context->hasTitle() &&
+ $context->getTitle()->canExist() &&
+ $context->getRequest()->getVal( 'action', 'view' ) === 'view' &&
+ HTMLFileCache::useFileCache( $this->context, HTMLFileCache::MODE_OUTAGE )
+ ) {
+ // Try to use any (even stale) file during outages...
+ $cache = new HTMLFileCache( $context->getTitle(), 'view' );
+ if ( $cache->isCached() ) {
+ $cache->loadFromFileCache( $context, HTMLFileCache::MODE_OUTAGE );
+ print MWExceptionRenderer::getHTML( $e );
+ exit;
+ }
+
+ }
+
MWExceptionHandler::handleException( $e );
}
}
}
- if ( $this->config->get( 'UseFileCache' ) && $title->getNamespace() >= 0 ) {
- if ( HTMLFileCache::useFileCache( $this->context ) ) {
- // Try low-level file cache hit
- $cache = new HTMLFileCache( $title, $action );
- if ( $cache->isCacheGood( /* Assume up to date */ ) ) {
- // Check incoming headers to see if client has this cached
- $timestamp = $cache->cacheTimestamp();
- if ( !$output->checkLastModified( $timestamp ) ) {
- $cache->loadFromFileCache( $this->context );
- }
- // Do any stats increment/watchlist stuff
- // Assume we're viewing the latest revision (this should always be the case with file cache)
- $this->context->getWikiPage()->doViewUpdates( $this->context->getUser() );
- // Tell OutputPage that output is taken care of
- $output->disable();
-
- return;
+ if ( $title->canExist() && HTMLFileCache::useFileCache( $this->context ) ) {
+ // Try low-level file cache hit
+ $cache = new HTMLFileCache( $title, $action );
+ if ( $cache->isCacheGood( /* Assume up to date */ ) ) {
+ // Check incoming headers to see if client has this cached
+ $timestamp = $cache->cacheTimestamp();
+ if ( !$output->checkLastModified( $timestamp ) ) {
+ $cache->loadFromFileCache( $this->context );
}
+ // Do any stats increment/watchlist stuff, assuming user is viewing the
+ // latest revision (which should always be the case for file cache)
+ $this->context->getWikiPage()->doViewUpdates( $this->context->getUser() );
+ // Tell OutputPage that output is taken care of
+ $output->disable();
+
+ return;
}
}
* @ingroup Cache
*/
class HTMLFileCache extends FileCacheBase {
+ const MODE_NORMAL = 0; // normal cache mode
+ const MODE_OUTAGE = 1; // fallback cache for DB outages
+
/**
* Construct an HTMLFileCache object from a Title and an action
*
/**
* Check if pages can be cached for this request/user
* @param IContextSource $context
+ * @param integer $mode One of the HTMLFileCache::MODE_* constants
* @return bool
*/
- public static function useFileCache( IContextSource $context ) {
+ public static function useFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
global $wgUseFileCache, $wgDebugToolbar, $wgContLang;
+
if ( !$wgUseFileCache ) {
return false;
}
return false;
}
+
$user = $context->getUser();
// Check for non-standard user language; this covers uselang,
// and extensions for auto-detecting user language.
$ulang = $context->getLanguage();
// Check that there are no other sources of variation
- if ( $user->getId() || $user->getNewtalk() || !$ulang->equals( $wgContLang ) ) {
+ if ( $user->getId() || !$ulang->equals( $wgContLang ) ) {
return false;
}
+
+ if ( $mode === self::MODE_NORMAL ) {
+ if ( $user->getNewtalk() ) {
+ return false;
+ }
+ }
+
// Allow extensions to disable caching
return Hooks::run( 'HTMLFileCache::useFileCache', [ $context ] );
}
/**
* Read from cache to context output
* @param IContextSource $context
+ * @param integer $mode One of the HTMLFileCache::MODE_* constants
* @return void
*/
- public function loadFromFileCache( IContextSource $context ) {
+ public function loadFromFileCache( IContextSource $context, $mode = self::MODE_NORMAL ) {
global $wgMimeType, $wgLanguageCode;
wfDebug( __METHOD__ . "()\n" );
$filename = $this->cachePath();
+ if ( $mode === self::MODE_OUTAGE ) {
+ // Avoid DB errors for queries in sendCacheControl()
+ $context->getTitle()->resetArticleID( 0 );
+ }
+
$context->getOutput()->sendCacheControl();
header( "Content-Type: $wgMimeType; charset=UTF-8" );
header( "Content-Language: $wgLanguageCode" );
* @param Exception $e
* @return string Html to output
*/
- private static function getHTML( Exception $e ) {
+ public static function getHTML( Exception $e ) {
if ( self::showBackTrace( $e ) ) {
$html = "<div class=\"errorbox\"><p>" .
nl2br( htmlspecialchars( MWExceptionHandler::getLogMessage( $e ) ) ) .