MediaWiki  REL1_24
ViewCountUpdate.php
Go to the documentation of this file.
00001 <?php
00030 class ViewCountUpdate implements DeferrableUpdate {
00032     protected $id;
00033 
00039     public function __construct( $id ) {
00040         $this->id = intval( $id );
00041     }
00042 
00046     public function doUpdate() {
00047         global $wgHitcounterUpdateFreq;
00048 
00049         $dbw = wfGetDB( DB_MASTER );
00050 
00051         if ( $wgHitcounterUpdateFreq <= 1 || $dbw->getType() == 'sqlite' ) {
00052             $id = $this->id;
00053             $method = __METHOD__;
00054             $dbw->onTransactionIdle( function () use ( $dbw, $id, $method ) {
00055                 try {
00056                     $dbw->update( 'page',
00057                         array( 'page_counter = page_counter + 1' ),
00058                         array( 'page_id' => $id ),
00059                         $method
00060                     );
00061                 } catch ( DBError $e ) {
00062                     MWExceptionHandler::logException( $e );
00063                 }
00064             } );
00065             return;
00066         }
00067 
00068         # Not important enough to warrant an error page in case of failure
00069         try {
00070             // Since `hitcounter` is non-transactional, the contention is minimal
00071             $dbw->insert( 'hitcounter', array( 'hc_id' => $this->id ), __METHOD__ );
00072             $checkfreq = intval( $wgHitcounterUpdateFreq / 25 + 1 );
00073             if ( rand() % $checkfreq == 0 && $dbw->lastErrno() == 0 ) {
00074                 $this->collect();
00075             }
00076         } catch ( DBError $e ) {
00077             MWExceptionHandler::logException( $e );
00078         }
00079     }
00080 
00081     protected function collect() {
00082         global $wgHitcounterUpdateFreq;
00083 
00084         $dbw = wfGetDB( DB_MASTER );
00085 
00086         $rown = $dbw->selectField( 'hitcounter', 'COUNT(*)', array(), __METHOD__ );
00087         if ( $rown < $wgHitcounterUpdateFreq ) {
00088             return;
00089         }
00090 
00091         wfProfileIn( __METHOD__ . '-collect' );
00092         $old_user_abort = ignore_user_abort( true );
00093 
00094         $dbType = $dbw->getType();
00095         $tabletype = $dbType == 'mysql' ? "ENGINE=HEAP " : '';
00096         $hitcounterTable = $dbw->tableName( 'hitcounter' );
00097         $acchitsTable = $dbw->tableName( 'acchits' );
00098         $pageTable = $dbw->tableName( 'page' );
00099 
00100         $dbw->lockTables( array(), array( 'hitcounter' ), __METHOD__, false );
00101         $dbw->query( "CREATE TEMPORARY TABLE $acchitsTable $tabletype AS " .
00102             "SELECT hc_id,COUNT(*) AS hc_n FROM $hitcounterTable " .
00103             'GROUP BY hc_id', __METHOD__ );
00104         $dbw->delete( 'hitcounter', '*', __METHOD__ );
00105         $dbw->unlockTables( __METHOD__ );
00106 
00107         if ( $dbType == 'mysql' ) {
00108             $dbw->query( "UPDATE $pageTable,$acchitsTable SET page_counter=page_counter + hc_n " .
00109                 'WHERE page_id = hc_id', __METHOD__ );
00110         } else {
00111             $dbw->query( "UPDATE $pageTable SET page_counter=page_counter + hc_n " .
00112                 "FROM $acchitsTable WHERE page_id = hc_id", __METHOD__ );
00113         }
00114         $dbw->query( "DROP TABLE $acchitsTable", __METHOD__ );
00115 
00116         ignore_user_abort( $old_user_abort );
00117         wfProfileOut( __METHOD__ . '-collect' );
00118     }
00119 }