MediaWiki REL1_30
SiteStats.php
Go to the documentation of this file.
1<?php
26
30class SiteStats {
32 private static $row;
33
35 private static $loaded = false;
36
38 private static $pageCount = [];
39
40 static function unload() {
41 self::$loaded = false;
42 }
43
44 static function recache() {
45 self::load( true );
46 }
47
51 static function load( $recache = false ) {
52 if ( self::$loaded && !$recache ) {
53 return;
54 }
55
56 self::$row = self::loadAndLazyInit();
57
58 # This code is somewhat schema-agnostic, because I'm changing it in a minor release -- TS
59 if ( !isset( self::$row->ss_total_pages ) && self::$row->ss_total_pages == -1 ) {
60 # Update schema
61 $u = new SiteStatsUpdate( 0, 0, 0 );
62 $u->doUpdate();
63 self::$row = self::doLoad( wfGetDB( DB_REPLICA ) );
64 }
65
66 self::$loaded = true;
67 }
68
72 static function loadAndLazyInit() {
73 global $wgMiserMode;
74
75 wfDebug( __METHOD__ . ": reading site_stats from replica DB\n" );
77
78 if ( !self::isSane( $row ) ) {
79 $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
80 if ( $lb->hasOrMadeRecentMasterChanges() ) {
81 // Might have just been initialized during this request? Underflow?
82 wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB\n" );
84 }
85 }
86
87 if ( !$wgMiserMode && !self::isSane( $row ) ) {
88 // Normally the site_stats table is initialized at install time.
89 // Some manual construction scenarios may leave the table empty or
90 // broken, however, for instance when importing from a dump into a
91 // clean schema with mwdumper.
92 wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
93
95
97 }
98
99 if ( !self::isSane( $row ) ) {
100 wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O\n" );
101 }
102
103 return $row;
104 }
105
110 static function doLoad( $db ) {
111 return $db->selectRow( 'site_stats', [
112 'ss_row_id',
113 'ss_total_edits',
114 'ss_good_articles',
115 'ss_total_pages',
116 'ss_users',
117 'ss_active_users',
118 'ss_images',
119 ], [], __METHOD__ );
120 }
121
130 static function views() {
131 wfDeprecated( __METHOD__, '1.25' );
132 return 0;
133 }
134
138 static function edits() {
139 self::load();
140 return self::$row->ss_total_edits;
141 }
142
146 static function articles() {
147 self::load();
148 return self::$row->ss_good_articles;
149 }
150
154 static function pages() {
155 self::load();
156 return self::$row->ss_total_pages;
157 }
158
162 static function users() {
163 self::load();
164 return self::$row->ss_users;
165 }
166
170 static function activeUsers() {
171 self::load();
172 return self::$row->ss_active_users;
173 }
174
178 static function images() {
179 self::load();
180 return self::$row->ss_images;
181 }
182
188 static function numberingroup( $group ) {
189 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
190 return $cache->getWithSetCallback(
191 $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
192 $cache::TTL_HOUR,
193 function ( $oldValue, &$ttl, array &$setOpts ) use ( $group ) {
195
196 $setOpts += Database::getCacheSetOptions( $dbr );
197
198 return $dbr->selectField(
199 'user_groups',
200 'COUNT(*)',
201 [
202 'ug_group' => $group,
203 'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
204 ],
205 __METHOD__
206 );
207 },
208 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
209 );
210 }
211
216 static function jobs() {
217 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
218 return $cache->getWithSetCallback(
219 $cache->makeKey( 'SiteStats', 'jobscount' ),
220 $cache::TTL_MINUTE,
221 function ( $oldValue, &$ttl, array &$setOpts ) {
222 try{
223 $jobs = array_sum( JobQueueGroup::singleton()->getQueueSizes() );
224 } catch ( JobQueueError $e ) {
225 $jobs = 0;
226 }
227 return $jobs;
228 },
229 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
230 );
231 }
232
238 static function pagesInNs( $ns ) {
239 if ( !isset( self::$pageCount[$ns] ) ) {
241 self::$pageCount[$ns] = (int)$dbr->selectField(
242 'page',
243 'COUNT(*)',
244 [ 'page_namespace' => $ns ],
245 __METHOD__
246 );
247 }
248 return self::$pageCount[$ns];
249 }
250
260 private static function isSane( $row ) {
261 if ( $row === false
262 || $row->ss_total_pages < $row->ss_good_articles
263 || $row->ss_total_edits < $row->ss_total_pages
264 ) {
265 return false;
266 }
267 // Now check for underflow/overflow
268 foreach ( [
269 'ss_total_edits',
270 'ss_good_articles',
271 'ss_total_pages',
272 'ss_users',
273 'ss_images',
274 ] as $member ) {
275 if ( $row->$member > 2000000000 || $row->$member < 0 ) {
276 return false;
277 }
278 }
279 return true;
280 }
281}
282
287
288 // Database connection
289 private $db;
290
291 // Various stats
292 private $mEdits = null, $mArticles = null, $mPages = null;
293 private $mUsers = null, $mFiles = null;
294
300 public function __construct( $database = false ) {
301 if ( $database instanceof IDatabase ) {
302 $this->db = $database;
303 } elseif ( $database ) {
304 $this->db = wfGetDB( DB_MASTER );
305 } else {
306 $this->db = wfGetDB( DB_REPLICA, 'vslow' );
307 }
308 }
309
314 public function edits() {
315 $this->mEdits = $this->db->selectField( 'revision', 'COUNT(*)', '', __METHOD__ );
316 $this->mEdits += $this->db->selectField( 'archive', 'COUNT(*)', '', __METHOD__ );
317 return $this->mEdits;
318 }
319
324 public function articles() {
326
327 $tables = [ 'page' ];
328 $conds = [
329 'page_namespace' => MWNamespace::getContentNamespaces(),
330 'page_is_redirect' => 0,
331 ];
332
333 if ( $wgArticleCountMethod == 'link' ) {
334 $tables[] = 'pagelinks';
335 $conds[] = 'pl_from=page_id';
336 } elseif ( $wgArticleCountMethod == 'comma' ) {
337 // To make a correct check for this, we would need, for each page,
338 // to load the text, maybe uncompress it, maybe decode it and then
339 // check if there's one comma.
340 // But one thing we are sure is that if the page is empty, it can't
341 // contain a comma :)
342 $conds[] = 'page_len > 0';
343 }
344
345 $this->mArticles = $this->db->selectField( $tables, 'COUNT(DISTINCT page_id)',
346 $conds, __METHOD__ );
347 return $this->mArticles;
348 }
349
354 public function pages() {
355 $this->mPages = $this->db->selectField( 'page', 'COUNT(*)', '', __METHOD__ );
356 return $this->mPages;
357 }
358
363 public function users() {
364 $this->mUsers = $this->db->selectField( 'user', 'COUNT(*)', '', __METHOD__ );
365 return $this->mUsers;
366 }
367
372 public function files() {
373 $this->mFiles = $this->db->selectField( 'image', 'COUNT(*)', '', __METHOD__ );
374 return $this->mFiles;
375 }
376
387 public static function doAllAndCommit( $database, array $options = [] ) {
388 $options += [ 'update' => false, 'activeUsers' => false ];
389
390 // Grab the object and count everything
391 $counter = new SiteStatsInit( $database );
392
393 $counter->edits();
394 $counter->articles();
395 $counter->pages();
396 $counter->users();
397 $counter->files();
398
399 $counter->refresh();
400
401 // Count active users if need be
402 if ( $options['activeUsers'] ) {
404 }
405 }
406
410 public function refresh() {
411 $values = [
412 'ss_row_id' => 1,
413 'ss_total_edits' => ( $this->mEdits === null ? $this->edits() : $this->mEdits ),
414 'ss_good_articles' => ( $this->mArticles === null ? $this->articles() : $this->mArticles ),
415 'ss_total_pages' => ( $this->mPages === null ? $this->pages() : $this->mPages ),
416 'ss_users' => ( $this->mUsers === null ? $this->users() : $this->mUsers ),
417 'ss_images' => ( $this->mFiles === null ? $this->files() : $this->mFiles ),
418 ];
419
420 $dbw = wfGetDB( DB_MASTER );
421 $dbw->upsert( 'site_stats', $values, [ 'ss_row_id' ], $values, __METHOD__ );
422 }
423}
$wgArticleCountMethod
Method used to determine if a page in a content namespace should be counted as a valid article.
$wgMiserMode
Disable database-intensive features.
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
wfDeprecated( $function, $version=false, $component=false, $callerOffset=2)
Throws a warning that $function is deprecated.
static singleton( $wiki=false)
MediaWikiServices is the service locator for the application scope of MediaWiki.
Class designed for counting of stats.
edits()
Count the total number of edits.
pages()
Count total pages.
articles()
Count pages in article space(s)
static doAllAndCommit( $database, array $options=[])
Do all updates and commit them.
files()
Count total files.
refresh()
Refresh site_stats.
users()
Count total users.
__construct( $database=false)
Class for handling updates to the site_stats table.
static cacheUpdate( $dbw)
Static accessor class for site_stats and related things.
Definition SiteStats.php:30
static isSane( $row)
Is the provided row of site stats sane, or should it be regenerated?
static articles()
static jobs()
Total number of jobs in the job queue.
static pagesInNs( $ns)
static images()
static views()
Return the total number of page views.
static load( $recache=false)
Definition SiteStats.php:51
static edits()
static bool $loaded
Definition SiteStats.php:35
static loadAndLazyInit()
Definition SiteStats.php:72
static bool stdClass $row
Definition SiteStats.php:32
static recache()
Definition SiteStats.php:44
static users()
static int[] $pageCount
Definition SiteStats.php:38
static pages()
static unload()
Definition SiteStats.php:40
static doLoad( $db)
static numberingroup( $group)
Find the number of users in a given user group.
static activeUsers()
Relational database abstraction object.
Definition Database.php:45
if(! $regexes) $dbr
Definition cleanup.php:94
when a variable name is used in a function
Definition design.txt:94
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
Definition hooks.txt:1013
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped & $options
Definition hooks.txt:1971
processing should stop and the error should be shown to the user * false
Definition hooks.txt:187
returning false will NOT prevent logging $e
Definition hooks.txt:2146
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:40
$cache
Definition mcc.php:33
MediaWiki has optional support for a high distributed memory object caching system For general information on but for a larger site with heavy load
Definition memcached.txt:6
const DB_REPLICA
Definition defines.php:25
const DB_MASTER
Definition defines.php:26