MediaWiki
REL1_24
|
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 }