MediaWiki  REL1_24
SiteStats.php
Go to the documentation of this file.
00001 <?php
00026 class SiteStats {
00028     private static $row;
00029 
00031     private static $loaded = false;
00032 
00034     private static $jobs;
00035 
00037     private static $pageCount = array();
00038 
00040     private static $groupMemberCounts = array();
00041 
00042     static function recache() {
00043         self::load( true );
00044     }
00045 
00049     static function load( $recache = false ) {
00050         if ( self::$loaded && !$recache ) {
00051             return;
00052         }
00053 
00054         self::$row = self::loadAndLazyInit();
00055 
00056         # This code is somewhat schema-agnostic, because I'm changing it in a minor release -- TS
00057         if ( !isset( self::$row->ss_total_pages ) && self::$row->ss_total_pages == -1 ) {
00058             # Update schema
00059             $u = new SiteStatsUpdate( 0, 0, 0 );
00060             $u->doUpdate();
00061             self::$row = self::doLoad( wfGetDB( DB_SLAVE ) );
00062         }
00063 
00064         self::$loaded = true;
00065     }
00066 
00070     static function loadAndLazyInit() {
00071         wfDebug( __METHOD__ . ": reading site_stats from slave\n" );
00072         $row = self::doLoad( wfGetDB( DB_SLAVE ) );
00073 
00074         if ( !self::isSane( $row ) ) {
00075             // Might have just been initialized during this request? Underflow?
00076             wfDebug( __METHOD__ . ": site_stats damaged or missing on slave\n" );
00077             $row = self::doLoad( wfGetDB( DB_MASTER ) );
00078         }
00079 
00080         if ( !self::isSane( $row ) ) {
00081             // Normally the site_stats table is initialized at install time.
00082             // Some manual construction scenarios may leave the table empty or
00083             // broken, however, for instance when importing from a dump into a
00084             // clean schema with mwdumper.
00085             wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
00086 
00087             SiteStatsInit::doAllAndCommit( wfGetDB( DB_SLAVE ) );
00088 
00089             $row = self::doLoad( wfGetDB( DB_MASTER ) );
00090         }
00091 
00092         if ( !self::isSane( $row ) ) {
00093             wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O\n" );
00094         }
00095         return $row;
00096     }
00097 
00102     static function doLoad( $db ) {
00103         return $db->selectRow( 'site_stats', array(
00104                 'ss_row_id',
00105                 'ss_total_views',
00106                 'ss_total_edits',
00107                 'ss_good_articles',
00108                 'ss_total_pages',
00109                 'ss_users',
00110                 'ss_active_users',
00111                 'ss_images',
00112             ), false, __METHOD__ );
00113     }
00114 
00118     static function views() {
00119         self::load();
00120         return self::$row->ss_total_views;
00121     }
00122 
00126     static function edits() {
00127         self::load();
00128         return self::$row->ss_total_edits;
00129     }
00130 
00134     static function articles() {
00135         self::load();
00136         return self::$row->ss_good_articles;
00137     }
00138 
00142     static function pages() {
00143         self::load();
00144         return self::$row->ss_total_pages;
00145     }
00146 
00150     static function users() {
00151         self::load();
00152         return self::$row->ss_users;
00153     }
00154 
00158     static function activeUsers() {
00159         self::load();
00160         return self::$row->ss_active_users;
00161     }
00162 
00166     static function images() {
00167         self::load();
00168         return self::$row->ss_images;
00169     }
00170 
00176     static function numberingroup( $group ) {
00177         if ( !isset( self::$groupMemberCounts[$group] ) ) {
00178             global $wgMemc;
00179             $key = wfMemcKey( 'SiteStats', 'groupcounts', $group );
00180             $hit = $wgMemc->get( $key );
00181             if ( !$hit ) {
00182                 $dbr = wfGetDB( DB_SLAVE );
00183                 $hit = $dbr->selectField(
00184                     'user_groups',
00185                     'COUNT(*)',
00186                     array( 'ug_group' => $group ),
00187                     __METHOD__
00188                 );
00189                 $wgMemc->set( $key, $hit, 3600 );
00190             }
00191             self::$groupMemberCounts[$group] = $hit;
00192         }
00193         return self::$groupMemberCounts[$group];
00194     }
00195 
00199     static function jobs() {
00200         if ( !isset( self::$jobs ) ) {
00201             $dbr = wfGetDB( DB_SLAVE );
00202             self::$jobs = array_sum( JobQueueGroup::singleton()->getQueueSizes() );
00207             if ( self::$jobs == 1 ) {
00208                 self::$jobs = 0;
00209             }
00210         }
00211         return self::$jobs;
00212     }
00213 
00219     static function pagesInNs( $ns ) {
00220         wfProfileIn( __METHOD__ );
00221         if ( !isset( self::$pageCount[$ns] ) ) {
00222             $dbr = wfGetDB( DB_SLAVE );
00223             self::$pageCount[$ns] = (int)$dbr->selectField(
00224                 'page',
00225                 'COUNT(*)',
00226                 array( 'page_namespace' => $ns ),
00227                 __METHOD__
00228             );
00229         }
00230         wfProfileOut( __METHOD__ );
00231         return self::$pageCount[$ns];
00232     }
00233 
00243     private static function isSane( $row ) {
00244         if ( $row === false
00245             || $row->ss_total_pages < $row->ss_good_articles
00246             || $row->ss_total_edits < $row->ss_total_pages
00247         ) {
00248             return false;
00249         }
00250         // Now check for underflow/overflow
00251         foreach ( array(
00252             'ss_total_views',
00253             'ss_total_edits',
00254             'ss_good_articles',
00255             'ss_total_pages',
00256             'ss_users',
00257             'ss_images',
00258         ) as $member ) {
00259             if ( $row->$member > 2000000000 || $row->$member < 0 ) {
00260                 return false;
00261             }
00262         }
00263         return true;
00264     }
00265 }
00266 
00270 class SiteStatsInit {
00271 
00272     // Database connection
00273     private $db;
00274 
00275     // Various stats
00276     private $mEdits = null, $mArticles = null, $mPages = null;
00277     private $mUsers = null, $mViews = null, $mFiles = null;
00278 
00285     public function __construct( $database = false ) {
00286         if ( $database instanceof DatabaseBase ) {
00287             $this->db = $database;
00288         } else {
00289             $this->db = wfGetDB( $database ? DB_MASTER : DB_SLAVE );
00290         }
00291     }
00292 
00297     public function edits() {
00298         $this->mEdits = $this->db->selectField( 'revision', 'COUNT(*)', '', __METHOD__ );
00299         $this->mEdits += $this->db->selectField( 'archive', 'COUNT(*)', '', __METHOD__ );
00300         return $this->mEdits;
00301     }
00302 
00307     public function articles() {
00308         global $wgArticleCountMethod;
00309 
00310         $tables = array( 'page' );
00311         $conds = array(
00312             'page_namespace' => MWNamespace::getContentNamespaces(),
00313             'page_is_redirect' => 0,
00314         );
00315 
00316         if ( $wgArticleCountMethod == 'link' ) {
00317             $tables[] = 'pagelinks';
00318             $conds[] = 'pl_from=page_id';
00319         } elseif ( $wgArticleCountMethod == 'comma' ) {
00320             // To make a correct check for this, we would need, for each page,
00321             // to load the text, maybe uncompress it, maybe decode it and then
00322             // check if there's one comma.
00323             // But one thing we are sure is that if the page is empty, it can't
00324             // contain a comma :)
00325             $conds[] = 'page_len > 0';
00326         }
00327 
00328         $this->mArticles = $this->db->selectField( $tables, 'COUNT(DISTINCT page_id)',
00329             $conds, __METHOD__ );
00330         return $this->mArticles;
00331     }
00332 
00337     public function pages() {
00338         $this->mPages = $this->db->selectField( 'page', 'COUNT(*)', '', __METHOD__ );
00339         return $this->mPages;
00340     }
00341 
00346     public function users() {
00347         $this->mUsers = $this->db->selectField( 'user', 'COUNT(*)', '', __METHOD__ );
00348         return $this->mUsers;
00349     }
00350 
00355     public function views() {
00356         $this->mViews = $this->db->selectField( 'page', 'SUM(page_counter)', '', __METHOD__ );
00357         return $this->mViews;
00358     }
00359 
00364     public function files() {
00365         $this->mFiles = $this->db->selectField( 'image', 'COUNT(*)', '', __METHOD__ );
00366         return $this->mFiles;
00367     }
00368 
00380     public static function doAllAndCommit( $database, array $options = array() ) {
00381         $options += array( 'update' => false, 'views' => true, 'activeUsers' => false );
00382 
00383         // Grab the object and count everything
00384         $counter = new SiteStatsInit( $database );
00385 
00386         $counter->edits();
00387         $counter->articles();
00388         $counter->pages();
00389         $counter->users();
00390         $counter->files();
00391 
00392         // Only do views if we don't want to not count them
00393         if ( $options['views'] ) {
00394             $counter->views();
00395         }
00396 
00397         $counter->refresh();
00398 
00399         // Count active users if need be
00400         if ( $options['activeUsers'] ) {
00401             SiteStatsUpdate::cacheUpdate( wfGetDB( DB_MASTER ) );
00402         }
00403     }
00404 
00409     public function refresh() {
00410         $values = array(
00411             'ss_row_id' => 1,
00412             'ss_total_edits' => ( $this->mEdits === null ? $this->edits() : $this->mEdits ),
00413             'ss_good_articles' => ( $this->mArticles === null ? $this->articles() : $this->mArticles ),
00414             'ss_total_pages' => ( $this->mPages === null ? $this->pages() : $this->mPages ),
00415             'ss_users' => ( $this->mUsers === null ? $this->users() : $this->mUsers ),
00416             'ss_images' => ( $this->mFiles === null ? $this->files() : $this->mFiles ),
00417         ) + (
00418             $this->mViews ? array( 'ss_total_views' => $this->mViews ) : array()
00419         );
00420 
00421         $dbw = wfGetDB( DB_MASTER );
00422         $dbw->upsert( 'site_stats', $values, array( 'ss_row_id' ), $values, __METHOD__ );
00423     }
00424 }