# Pre-fill content with error message so that if something
# fails we'll have something telling us what we intended.
- //XXX: this isn't page content but a UI message. horrible.
+ // XXX: this isn't page content but a UI message. horrible.
$this->mContentObject = new MessageContent( 'missing-revision', array( $oldid ) );
if ( $oldid ) {
// to get the recentchanges row belonging to that entry
// (with rc_new = 1).
- // Check for cached results
- if ( $cache->get( wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() ) ) ) {
- return false;
- }
-
if ( $this->mRevision
&& !RecentChange::isInRCLifespan( $this->mRevision->getTimestamp(), 21600 )
) {
return false;
}
+ // Check for cached results
+ $key = wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() );
+ if ( $cache->get( $key ) ) {
+ return false;
+ }
+
$dbr = wfGetDB( DB_SLAVE );
$oldestRevisionTimestamp = $dbr->selectField(
'revision',
'rc_new' => 1,
'rc_timestamp' => $oldestRevisionTimestamp,
'rc_namespace' => $this->getTitle()->getNamespace(),
- 'rc_cur_id' => $this->getTitle()->getArticleID(),
- 'rc_patrolled' => 0
+ 'rc_cur_id' => $this->getTitle()->getArticleID()
),
- __METHOD__,
- array( 'USE INDEX' => 'new_name_timestamp' )
+ __METHOD__
);
+ } else {
+ // Cache the information we gathered above in case we can't patrol
+ // Don't cache in case we can patrol as this could change
+ $cache->set( $key, '1' );
}
if ( !$rc ) {
- // No RC entry around
+ // Don't cache: This can be hit if the page gets accessed very fast after
+ // its creation or in case we have high slave lag. In case the revision is
+ // too old, we will already return above.
+ return false;
+ }
+
+ if ( $rc->getAttribute( 'rc_patrolled' ) ) {
+ // Patrolled RC entry around
// Cache the information we gathered above in case we can't patrol
// Don't cache in case we can patrol as this could change
- $cache->set( wfMemcKey( 'NotPatrollablePage', $this->getTitle()->getArticleID() ), '1' );
+ $cache->set( $key, '1' );
return false;
}
Hooks::run( 'ShowMissingArticle', array( $this ) );
- // Give extensions a chance to hide their (unrelated) log entries
- $logTypes = array( 'delete', 'move' );
- $conds = array( "log_action != 'revision'" );
- Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
-
- # Show delete and move logs
- LogEventsList::showLogExtract( $outputPage, $logTypes, $title, '',
- array( 'lim' => 10,
- 'conds' => $conds,
- 'showIfEmpty' => false,
- 'msgKey' => array( 'moveddeleted-notice' ) )
- );
+ # Show delete and move logs if there were any such events.
+ # The logging query can DOS the site when bots/crawlers cause 404 floods,
+ # so be careful showing this. 404 pages must be cheap as they are hard to cache.
+ $cache = ObjectCache::getMainStashInstance();
+ $key = wfMemcKey( 'page-recent-delete', md5( $title->getPrefixedText() ) );
+ $loggedIn = $this->getContext()->getUser()->isLoggedIn();
+ if ( $loggedIn || $cache->get( $key ) ) {
+ $logTypes = array( 'delete', 'move' );
+ $conds = array( "log_action != 'revision'" );
+ // Give extensions a chance to hide their (unrelated) log entries
+ Hooks::run( 'Article::MissingArticleConditions', array( &$conds, $logTypes ) );
+ LogEventsList::showLogExtract(
+ $outputPage,
+ $logTypes,
+ $title,
+ '',
+ array(
+ 'lim' => 10,
+ 'conds' => $conds,
+ 'showIfEmpty' => false,
+ 'msgKey' => array( $loggedIn
+ ? 'moveddeleted-notice'
+ : 'moveddeleted-notice-recent'
+ )
+ )
+ );
+ }
if ( !$this->mPage->hasViewableContent() && $wgSend404Code && !$validUserPage ) {
// If there's no backing content, send a 404 Not Found
* @return ParserOutput|bool ParserOutput or false if the given revision ID is not found
*/
public function getParserOutput( $oldid = null, User $user = null ) {
- //XXX: bypasses mParserOptions and thus setParserOptions()
+ // XXX: bypasses mParserOptions and thus setParserOptions()
if ( $user === null ) {
$parserOptions = $this->getParserOptions();
*/
public function __get( $fname ) {
if ( property_exists( $this->mPage, $fname ) ) {
- #wfWarn( "Access to raw $fname field " . __CLASS__ );
+ # wfWarn( "Access to raw $fname field " . __CLASS__ );
return $this->mPage->$fname;
}
trigger_error( 'Inaccessible property via __get(): ' . $fname, E_USER_NOTICE );
*/
public function __set( $fname, $fvalue ) {
if ( property_exists( $this->mPage, $fname ) ) {
- #wfWarn( "Access to raw $fname field of " . __CLASS__ );
+ # wfWarn( "Access to raw $fname field of " . __CLASS__ );
$this->mPage->$fname = $fvalue;
// Note: extensions may want to toss on new fields
} elseif ( !in_array( $fname, array( 'mContext', 'mPage' ) ) ) {
*/
public function __call( $fname, $args ) {
if ( is_callable( array( $this->mPage, $fname ) ) ) {
- #wfWarn( "Call to " . __CLASS__ . "::$fname; please use WikiPage instead" );
+ # wfWarn( "Call to " . __CLASS__ . "::$fname; please use WikiPage instead" );
return call_user_func_array( array( $this->mPage, $fname ), $args );
}
trigger_error( 'Inaccessible function via __call(): ' . $fname, E_USER_ERROR );