Index: trunk/extensions/FlaggedRevs/maintenance/cachePendingRevs.php |
— | — | @@ -0,0 +1,59 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * This script precaches parser output related data of pending revs |
| 5 | + * |
| 6 | + * @ingroup Maintenance |
| 7 | + */ |
| 8 | + |
| 9 | +if ( getenv( 'MW_INSTALL_PATH' ) ) { |
| 10 | + $IP = getenv( 'MW_INSTALL_PATH' ); |
| 11 | +} else { |
| 12 | + $IP = dirname(__FILE__).'/../../..'; |
| 13 | +} |
| 14 | + |
| 15 | +require_once( "$IP/maintenance/Maintenance.php" ); |
| 16 | + |
| 17 | +class CachePendingRevs extends Maintenance { |
| 18 | + public function __construct() { |
| 19 | + parent::__construct(); |
| 20 | + $this->mDescription = "Cache pending revision data"; |
| 21 | + } |
| 22 | + |
| 23 | + public function execute() { |
| 24 | + global $wgUser; |
| 25 | + $dbr = wfGetDB( DB_SLAVE ); |
| 26 | + $ret = $dbr->select( |
| 27 | + array( 'flaggedpages', 'revision', 'page' ), |
| 28 | + array_merge( Revision::selectFields(), array( $dbr->tableName( 'page' ) . '.*' ) ), |
| 29 | + array( 'fp_pending_since IS NOT NULL', |
| 30 | + 'page_id = fp_page_id', |
| 31 | + 'rev_page = fp_page_id', |
| 32 | + 'rev_timestamp >= fp_pending_since' |
| 33 | + ), |
| 34 | + __METHOD__ |
| 35 | + ); |
| 36 | + foreach ( $ret as $row ) { |
| 37 | + $title = Title::newFromRow( $row ); |
| 38 | + $article = new Article( $title ); |
| 39 | + $rev = new Revision( $row ); |
| 40 | + // Trigger cache regeneration |
| 41 | + $start = microtime( true ); |
| 42 | + RevisionReviewForm::getRevIncludes( $article, $rev, $wgUser, 'regen' ); |
| 43 | + $elapsed = intval( ( microtime( true ) - $start ) * 1000 ); |
| 44 | + $this->cachePendingRevsLog( |
| 45 | + $title->getPrefixedDBkey() . " rev:" . $rev->getId() . " {$elapsed}ms" ); |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Log the cache message |
| 51 | + * @param $msg String The message to log |
| 52 | + */ |
| 53 | + private function cachePendingRevsLog( $msg ) { |
| 54 | + $this->output( wfTimestamp( TS_DB ) . " $msg\n" ); |
| 55 | + wfDebugLog( 'cachePendingRevs', $msg ); |
| 56 | + } |
| 57 | +} |
| 58 | + |
| 59 | +$maintClass = "CachePendingRevs"; |
| 60 | +require_once( RUN_MAINTENANCE_IF_MAIN ); |
Property changes on: trunk/extensions/FlaggedRevs/maintenance/cachePendingRevs.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 61 | + native |
Index: trunk/extensions/FlaggedRevs/dataclasses/FlaggedRevs.class.php |
— | — | @@ -714,9 +714,9 @@ |
715 | 715 | # ################ Other utility functions ################# |
716 | 716 | |
717 | 717 | /** |
| 718 | + * Get a memcache storage object |
718 | 719 | * @param string $val |
719 | 720 | * @return Object (val,time) tuple |
720 | | - * Get a memcache storage object |
721 | 721 | */ |
722 | 722 | public static function makeMemcObj( $val ) { |
723 | 723 | $data = (object) array(); |
— | — | @@ -726,14 +726,17 @@ |
727 | 727 | } |
728 | 728 | |
729 | 729 | /** |
| 730 | + * Return memc value if not expired |
730 | 731 | * @param object|false $data makeMemcObj() tuple |
731 | 732 | * @param Article $article |
| 733 | + * @param $allowStale Use 'allowStale' to skip page_touched check |
732 | 734 | * @return mixed |
733 | | - * Return memc value if not expired |
734 | 735 | */ |
735 | | - public static function getMemcValue( $data, Article $article ) { |
736 | | - if ( is_object( $data ) && $data->time >= $article->getTouched() ) { |
737 | | - return $data->value; |
| 736 | + public static function getMemcValue( $data, Article $article, $allowStale = '' ) { |
| 737 | + if ( is_object( $data ) ) { |
| 738 | + if ( $allowStale === 'allowStale' || $data->time >= $article->getTouched() ) { |
| 739 | + return $data->value; |
| 740 | + } |
738 | 741 | } |
739 | 742 | return false; |
740 | 743 | } |
Index: trunk/extensions/FlaggedRevs/business/RevisionReviewForm.php |
— | — | @@ -581,30 +581,33 @@ |
582 | 582 | * @param Article $article |
583 | 583 | * @param Revision $rev |
584 | 584 | * @param User $user |
| 585 | + * @param string $regen use 'regen' to force regeneration |
585 | 586 | * @return array( templateIds, fileSHA1Keys ) |
586 | 587 | * templateIds like ParserOutput->mTemplateIds |
587 | 588 | * fileSHA1Keys like ParserOutput->mImageTimeKeys |
588 | 589 | */ |
589 | | - public static function getRevIncludes( Article $article, Revision $rev, User $user ) { |
| 590 | + public static function getRevIncludes( |
| 591 | + Article $article, Revision $rev, User $user, $regen = '' |
| 592 | + ) { |
590 | 593 | global $wgParser, $wgMemc; |
591 | | - static $versionCache = array(); |
592 | 594 | wfProfileIn( __METHOD__ ); |
| 595 | + $versions = false; |
593 | 596 | $hash = md5( $article->getTitle()->getPrefixedDBkey() ); |
594 | 597 | # Check process cache first... |
595 | | - $vKey = $rev->getId()."-$hash"; |
596 | | - if ( isset( $versionCache[$vKey] ) ) { |
597 | | - wfProfileOut( __METHOD__ ); |
598 | | - return $versionCache[$vKey]; // hit |
| 598 | + $key = wfMemcKey( 'flaggedrevs', 'revIncludes', $rev->getId(), $hash ); |
| 599 | + if ( $regen !== 'regen' ) { |
| 600 | + $versions = FlaggedRevs::getMemcValue( $wgMemc->get( $key ), $article, 'allowStale' ); |
599 | 601 | } |
600 | | - $key = wfMemcKey( 'flaggedrevs', 'revIncludes', $rev->getId(), $hash ); |
601 | | - $val = FlaggedRevs::getMemcValue( $wgMemc->get( $key ), $article ); |
602 | | - if ( is_array( $val ) ) { |
603 | | - $versions = $val; // cache hit |
604 | | - } else { |
| 602 | + if ( !is_array( $versions ) ) { // cache miss |
605 | 603 | $pOut = false; |
606 | | - if ( $rev->isCurrent() ) { // try current version parser cache |
| 604 | + if ( $rev->isCurrent() ) { |
607 | 605 | $parserCache = ParserCache::singleton(); |
| 606 | + # Try current version parser cache (as anon)... |
608 | 607 | $pOut = $parserCache->get( $article, $article->makeParserOptions( $user ) ); |
| 608 | + if ( $pOut == false && $rev->getUser() ) { // try the user who saved the change |
| 609 | + $author = User::newFromId( $rev->getUser() ); |
| 610 | + $pOut = $parserCache->get( $article, $article->makeParserOptions( $author ) ); |
| 611 | + } |
609 | 612 | } |
610 | 613 | if ( $pOut == false ) { |
611 | 614 | $title = $article->getTitle(); |
— | — | @@ -620,13 +623,25 @@ |
621 | 624 | $versions = array( $pOut->getTemplateIds(), $pOut->getImageTimeKeys() ); |
622 | 625 | # Save to cache... |
623 | 626 | $data = FlaggedRevs::makeMemcObj( $versions ); |
624 | | - $wgMemc->set( $key, $data, 3600 ); // inclusions may be dynamic |
625 | | - } |
626 | | - # Save to process cache... |
627 | | - if ( count( $versionCache ) > 100 ) { |
628 | | - $versionCache = array(); // sanity |
629 | | - } |
630 | | - $versionCache[$vKey] = $versions; |
| 627 | + $wgMemc->set( $key, $data, 24*3600 ); // inclusions may be dynamic |
| 628 | + } else { |
| 629 | + # Do a link batch query for page_latest... |
| 630 | + $lb = new LinkBatch(); |
| 631 | + foreach ( $versions as $ns => $tmps ) { |
| 632 | + foreach ( $tmps as $dbKey => $revIdDraft ) { |
| 633 | + $lb->add( $ns, $dbKey ); |
| 634 | + } |
| 635 | + } |
| 636 | + $lb->execute(); |
| 637 | + # Update array with the current page_latest values. |
| 638 | + # This kludge is there since $newTemplates (thus $revIdDraft) is cached. |
| 639 | + foreach ( $versions as $ns => $tmps ) { |
| 640 | + foreach ( $tmps as $dbKey => &$revIdDraft ) { |
| 641 | + $title = new Title( $ns, $dbKey ); |
| 642 | + $revIdDraft = (int)$title->getLatestRevID(); |
| 643 | + } |
| 644 | + } |
| 645 | + } |
631 | 646 | wfProfileOut( __METHOD__ ); |
632 | 647 | return $versions; |
633 | 648 | } |
Index: trunk/extensions/FlaggedRevs/presentation/FlaggedPageView.php |
— | — | @@ -7,6 +7,7 @@ |
8 | 8 | protected $article = null; |
9 | 9 | |
10 | 10 | protected $diffRevs = null; // assoc array of old and new Revisions for diffs |
| 11 | + protected $oldRevIncludes = null; // ( array of templates, array of file) |
11 | 12 | protected $isReviewableDiff = false; |
12 | 13 | protected $isDiffFromStable = false; |
13 | 14 | protected $isMultiPageDiff = false; |
— | — | @@ -1082,6 +1083,8 @@ |
1083 | 1084 | # RevisionReviewForm will fetch them as needed however. |
1084 | 1085 | if ( $this->out->getRevisionId() == $rev->getId() ) { |
1085 | 1086 | $form->setIncludeVersions( $this->out->getTemplateIds(), $this->out->getImageTimeKeys() ); |
| 1087 | + } elseif ( $this->oldRevIncludes ) { |
| 1088 | + $form->setIncludeVersions( $this->oldRevIncludes[0], $this->oldRevIncludes[1] ); |
1086 | 1089 | } |
1087 | 1090 | list( $html, $status ) = $form->getHtml(); |
1088 | 1091 | # Diff action: place the form at the top of the page |
— | — | @@ -1372,6 +1375,7 @@ |
1373 | 1376 | $changeList = self::fetchTemplateChanges( $srev, $incs[0] ); |
1374 | 1377 | # Add a list of links to each changed file... |
1375 | 1378 | $changeList = array_merge( $changeList, self::fetchFileChanges( $srev, $incs[1] ) ); |
| 1379 | + $this->oldRevIncludes = $incs; // process cache |
1376 | 1380 | } |
1377 | 1381 | # If there are pending revs or templates/files changes, notify the user... |
1378 | 1382 | if ( $this->article->revsArePending() || count( $changeList ) ) { |