MediaWiki
REL1_23
|
00001 <?php 00026 class SiteStats { 00027 static $row, $loaded = false; 00028 static $jobs; 00029 static $pageCount = array(); 00030 static $groupMemberCounts = array(); 00031 00032 static function recache() { 00033 self::load( true ); 00034 } 00035 00039 static function load( $recache = false ) { 00040 if ( self::$loaded && !$recache ) { 00041 return; 00042 } 00043 00044 self::$row = self::loadAndLazyInit(); 00045 00046 # This code is somewhat schema-agnostic, because I'm changing it in a minor release -- TS 00047 if ( !isset( self::$row->ss_total_pages ) && self::$row->ss_total_pages == -1 ) { 00048 # Update schema 00049 $u = new SiteStatsUpdate( 0, 0, 0 ); 00050 $u->doUpdate(); 00051 self::$row = self::doLoad( wfGetDB( DB_SLAVE ) ); 00052 } 00053 00054 self::$loaded = true; 00055 } 00056 00060 static function loadAndLazyInit() { 00061 wfDebug( __METHOD__ . ": reading site_stats from slave\n" ); 00062 $row = self::doLoad( wfGetDB( DB_SLAVE ) ); 00063 00064 if ( !self::isSane( $row ) ) { 00065 // Might have just been initialized during this request? Underflow? 00066 wfDebug( __METHOD__ . ": site_stats damaged or missing on slave\n" ); 00067 $row = self::doLoad( wfGetDB( DB_MASTER ) ); 00068 } 00069 00070 if ( !self::isSane( $row ) ) { 00071 // Normally the site_stats table is initialized at install time. 00072 // Some manual construction scenarios may leave the table empty or 00073 // broken, however, for instance when importing from a dump into a 00074 // clean schema with mwdumper. 00075 wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" ); 00076 00077 SiteStatsInit::doAllAndCommit( wfGetDB( DB_SLAVE ) ); 00078 00079 $row = self::doLoad( wfGetDB( DB_MASTER ) ); 00080 } 00081 00082 if ( !self::isSane( $row ) ) { 00083 wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O\n" ); 00084 } 00085 return $row; 00086 } 00087 00092 static function doLoad( $db ) { 00093 return $db->selectRow( 'site_stats', array( 00094 'ss_row_id', 00095 'ss_total_views', 00096 'ss_total_edits', 00097 'ss_good_articles', 00098 'ss_total_pages', 00099 'ss_users', 00100 'ss_active_users', 00101 'ss_images', 00102 ), false, __METHOD__ ); 00103 } 00104 00108 static function views() { 00109 self::load(); 00110 return self::$row->ss_total_views; 00111 } 00112 00116 static function edits() { 00117 self::load(); 00118 return self::$row->ss_total_edits; 00119 } 00120 00124 static function articles() { 00125 self::load(); 00126 return self::$row->ss_good_articles; 00127 } 00128 00132 static function pages() { 00133 self::load(); 00134 return self::$row->ss_total_pages; 00135 } 00136 00140 static function users() { 00141 self::load(); 00142 return self::$row->ss_users; 00143 } 00144 00148 static function activeUsers() { 00149 self::load(); 00150 return self::$row->ss_active_users; 00151 } 00152 00156 static function images() { 00157 self::load(); 00158 return self::$row->ss_images; 00159 } 00160 00166 static function numberingroup( $group ) { 00167 if ( !isset( self::$groupMemberCounts[$group] ) ) { 00168 global $wgMemc; 00169 $key = wfMemcKey( 'SiteStats', 'groupcounts', $group ); 00170 $hit = $wgMemc->get( $key ); 00171 if ( !$hit ) { 00172 $dbr = wfGetDB( DB_SLAVE ); 00173 $hit = $dbr->selectField( 00174 'user_groups', 00175 'COUNT(*)', 00176 array( 'ug_group' => $group ), 00177 __METHOD__ 00178 ); 00179 $wgMemc->set( $key, $hit, 3600 ); 00180 } 00181 self::$groupMemberCounts[$group] = $hit; 00182 } 00183 return self::$groupMemberCounts[$group]; 00184 } 00185 00189 static function jobs() { 00190 if ( !isset( self::$jobs ) ) { 00191 $dbr = wfGetDB( DB_SLAVE ); 00192 self::$jobs = array_sum( JobQueueGroup::singleton()->getQueueSizes() ); 00193 /* Zero rows still do single row read for row that doesn't exist, but people are annoyed by that */ 00194 if ( self::$jobs == 1 ) { 00195 self::$jobs = 0; 00196 } 00197 } 00198 return self::$jobs; 00199 } 00200 00206 static function pagesInNs( $ns ) { 00207 wfProfileIn( __METHOD__ ); 00208 if ( !isset( self::$pageCount[$ns] ) ) { 00209 $dbr = wfGetDB( DB_SLAVE ); 00210 self::$pageCount[$ns] = (int)$dbr->selectField( 00211 'page', 00212 'COUNT(*)', 00213 array( 'page_namespace' => $ns ), 00214 __METHOD__ 00215 ); 00216 } 00217 wfProfileOut( __METHOD__ ); 00218 return self::$pageCount[$ns]; 00219 } 00220 00230 private static function isSane( $row ) { 00231 if ( $row === false 00232 || $row->ss_total_pages < $row->ss_good_articles 00233 || $row->ss_total_edits < $row->ss_total_pages 00234 ) { 00235 return false; 00236 } 00237 // Now check for underflow/overflow 00238 foreach ( array( 00239 'ss_total_views', 00240 'ss_total_edits', 00241 'ss_good_articles', 00242 'ss_total_pages', 00243 'ss_users', 00244 'ss_images', 00245 ) as $member ) { 00246 if ( $row->$member > 2000000000 || $row->$member < 0 ) { 00247 return false; 00248 } 00249 } 00250 return true; 00251 } 00252 } 00253 00257 class SiteStatsInit { 00258 00259 // Database connection 00260 private $db; 00261 00262 // Various stats 00263 private $mEdits = null, $mArticles = null, $mPages = null; 00264 private $mUsers = null, $mViews = null, $mFiles = null; 00265 00272 public function __construct( $database = false ) { 00273 if ( $database instanceof DatabaseBase ) { 00274 $this->db = $database; 00275 } else { 00276 $this->db = wfGetDB( $database ? DB_MASTER : DB_SLAVE ); 00277 } 00278 } 00279 00284 public function edits() { 00285 $this->mEdits = $this->db->selectField( 'revision', 'COUNT(*)', '', __METHOD__ ); 00286 $this->mEdits += $this->db->selectField( 'archive', 'COUNT(*)', '', __METHOD__ ); 00287 return $this->mEdits; 00288 } 00289 00294 public function articles() { 00295 global $wgArticleCountMethod; 00296 00297 $tables = array( 'page' ); 00298 $conds = array( 00299 'page_namespace' => MWNamespace::getContentNamespaces(), 00300 'page_is_redirect' => 0, 00301 ); 00302 00303 if ( $wgArticleCountMethod == 'link' ) { 00304 $tables[] = 'pagelinks'; 00305 $conds[] = 'pl_from=page_id'; 00306 } elseif ( $wgArticleCountMethod == 'comma' ) { 00307 // To make a correct check for this, we would need, for each page, 00308 // to load the text, maybe uncompress it, maybe decode it and then 00309 // check if there's one comma. 00310 // But one thing we are sure is that if the page is empty, it can't 00311 // contain a comma :) 00312 $conds[] = 'page_len > 0'; 00313 } 00314 00315 $this->mArticles = $this->db->selectField( $tables, 'COUNT(DISTINCT page_id)', 00316 $conds, __METHOD__ ); 00317 return $this->mArticles; 00318 } 00319 00324 public function pages() { 00325 $this->mPages = $this->db->selectField( 'page', 'COUNT(*)', '', __METHOD__ ); 00326 return $this->mPages; 00327 } 00328 00333 public function users() { 00334 $this->mUsers = $this->db->selectField( 'user', 'COUNT(*)', '', __METHOD__ ); 00335 return $this->mUsers; 00336 } 00337 00342 public function views() { 00343 $this->mViews = $this->db->selectField( 'page', 'SUM(page_counter)', '', __METHOD__ ); 00344 return $this->mViews; 00345 } 00346 00351 public function files() { 00352 $this->mFiles = $this->db->selectField( 'image', 'COUNT(*)', '', __METHOD__ ); 00353 return $this->mFiles; 00354 } 00355 00367 public static function doAllAndCommit( $database, array $options = array() ) { 00368 $options += array( 'update' => false, 'views' => true, 'activeUsers' => false ); 00369 00370 // Grab the object and count everything 00371 $counter = new SiteStatsInit( $database ); 00372 00373 $counter->edits(); 00374 $counter->articles(); 00375 $counter->pages(); 00376 $counter->users(); 00377 $counter->files(); 00378 00379 // Only do views if we don't want to not count them 00380 if ( $options['views'] ) { 00381 $counter->views(); 00382 } 00383 00384 $counter->refresh(); 00385 00386 // Count active users if need be 00387 if ( $options['activeUsers'] ) { 00388 SiteStatsUpdate::cacheUpdate( wfGetDB( DB_MASTER ) ); 00389 } 00390 } 00391 00396 public function refresh() { 00397 $values = array( 00398 'ss_row_id' => 1, 00399 'ss_total_edits' => ( $this->mEdits === null ? $this->edits() : $this->mEdits ), 00400 'ss_good_articles' => ( $this->mArticles === null ? $this->articles() : $this->mArticles ), 00401 'ss_total_pages' => ( $this->mPages === null ? $this->pages() : $this->mPages ), 00402 'ss_users' => ( $this->mUsers === null ? $this->users() : $this->mUsers ), 00403 'ss_images' => ( $this->mFiles === null ? $this->files() : $this->mFiles ), 00404 ) + ( 00405 $this->mViews ? array( 'ss_total_views' => $this->mViews ) : array() 00406 ); 00407 00408 $dbw = wfGetDB( DB_MASTER ); 00409 $dbw->upsert( 'site_stats', $values, array( 'ss_row_id' ), $values, __METHOD__ ); 00410 } 00411 }