MediaWiki master
SiteStats.php
Go to the documentation of this file.
1<?php
24
28use stdClass;
32
36class SiteStats {
38 private static $row;
39
43 public static function unload() {
44 self::$row = null;
45 }
46
47 protected static function load() {
48 if ( self::$row === null ) {
49 self::$row = self::loadAndLazyInit();
50 }
51 }
52
56 protected static function loadAndLazyInit() {
57 $config = MediaWikiServices::getInstance()->getMainConfig();
58
59 $lb = self::getLB();
60 $dbr = $lb->getConnection( DB_REPLICA );
61 wfDebug( __METHOD__ . ": reading site_stats from replica DB" );
62 $row = self::doLoadFromDB( $dbr );
63
64 if ( !self::isRowSensible( $row ) && $lb->hasOrMadeRecentPrimaryChanges() ) {
65 // Might have just been initialized during this request? Underflow?
66 wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB" );
67 $row = self::doLoadFromDB( $lb->getConnection( DB_PRIMARY ) );
68 }
69
70 if ( !self::isRowSensible( $row ) ) {
71 if ( $config->get( MainConfigNames::MiserMode ) ) {
72 // Start off with all zeroes, assuming that this is a new wiki or any
73 // repopulations where done manually via script.
75 } else {
76 // Normally the site_stats table is initialized at install time.
77 // Some manual construction scenarios may leave the table empty or
78 // broken, however, for instance when importing from a dump into a
79 // clean schema with mwdumper.
80 wfDebug( __METHOD__ . ": initializing damaged or missing site_stats" );
82 }
83
84 $row = self::doLoadFromDB( $lb->getConnection( DB_PRIMARY ) );
85 }
86
87 return $row;
88 }
89
93 public static function edits() {
94 self::load();
95
96 return (int)self::$row->ss_total_edits;
97 }
98
102 public static function articles() {
103 self::load();
104
105 return (int)self::$row->ss_good_articles;
106 }
107
111 public static function pages() {
112 self::load();
113
114 return (int)self::$row->ss_total_pages;
115 }
116
120 public static function users() {
121 self::load();
122
123 return (int)self::$row->ss_users;
124 }
125
129 public static function activeUsers() {
130 self::load();
131
132 return (int)self::$row->ss_active_users;
133 }
134
138 public static function images() {
139 self::load();
140
141 return (int)self::$row->ss_images;
142 }
143
149 public static function numberingroup( $group ) {
150 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
151 $fname = __METHOD__;
152
153 return $cache->getWithSetCallback(
154 $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
155 $cache::TTL_HOUR,
156 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $group, $fname ) {
157 $dbr = self::getLB()->getConnection( DB_REPLICA );
158 $setOpts += Database::getCacheSetOptions( $dbr );
159 return (int)$dbr->newSelectQueryBuilder()
160 ->select( 'COUNT(*)' )
161 ->from( 'user_groups' )
162 ->where(
163 [
164 'ug_group' => $group,
165 $dbr->expr( 'ug_expiry', '=', null )->or( 'ug_expiry', '>=', $dbr->timestamp() )
166 ]
167 )
168 ->caller( $fname )
169 ->fetchField();
170 },
171 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
172 );
173 }
174
179 public static function jobs() {
180 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
181
182 return $cache->getWithSetCallback(
183 $cache->makeKey( 'SiteStats', 'jobscount' ),
184 $cache::TTL_MINUTE,
185 static function ( $oldValue, &$ttl, array &$setOpts ) {
186 try {
187 $jobs = array_sum( MediaWikiServices::getInstance()->getJobQueueGroup()->getQueueSizes() );
188 } catch ( JobQueueError $e ) {
189 $jobs = 0;
190 }
191 return $jobs;
192 },
193 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
194 );
195 }
196
201 public static function pagesInNs( $ns ) {
202 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
203 $fname = __METHOD__;
204
205 return $cache->getWithSetCallback(
206 $cache->makeKey( 'SiteStats', 'page-in-namespace', $ns ),
207 $cache::TTL_HOUR,
208 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $ns, $fname ) {
209 $dbr = self::getLB()->getConnection( DB_REPLICA );
210 $setOpts += Database::getCacheSetOptions( $dbr );
211
212 return (int)$dbr->newSelectQueryBuilder()
213 ->select( 'COUNT(*)' )
214 ->from( 'page' )
215 ->where( [ 'page_namespace' => $ns ] )
216 ->caller( $fname )->fetchField();
217 },
218 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
219 );
220 }
221
225 public static function selectFields() {
226 return [
227 'ss_total_edits',
228 'ss_good_articles',
229 'ss_total_pages',
230 'ss_users',
231 'ss_active_users',
232 'ss_images',
233 ];
234 }
235
240 private static function doLoadFromDB( IReadableDatabase $db ) {
241 $fields = self::selectFields();
242 $rows = $db->newSelectQueryBuilder()
243 ->select( $fields )
244 ->from( 'site_stats' )
245 ->caller( __METHOD__ )
246 ->fetchResultSet();
247 if ( !$rows->numRows() ) {
248 return false;
249 }
250 $finalRow = new stdClass();
251 foreach ( $rows as $row ) {
252 foreach ( $fields as $field ) {
253 $finalRow->$field ??= 0;
254 if ( $row->$field ) {
255 $finalRow->$field += $row->$field;
256 }
257 }
258
259 }
260 return $finalRow;
261 }
262
271 private static function isRowSensible( $row ) {
272 if ( $row === false
273 || $row->ss_total_pages < $row->ss_good_articles
274 || $row->ss_total_edits < $row->ss_total_pages
275 ) {
276 return false;
277 }
278 // Now check for underflow/overflow
279 foreach ( [
280 'ss_total_edits',
281 'ss_good_articles',
282 'ss_total_pages',
283 'ss_users',
284 'ss_images',
285 ] as $member ) {
286 if ( $row->$member < 0 ) {
287 return false;
288 }
289 }
290
291 return true;
292 }
293
297 private static function getLB() {
298 return MediaWikiServices::getInstance()->getDBLoadBalancer();
299 }
300}
301
303class_alias( SiteStats::class, 'SiteStats' );
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
A class containing constants representing the names of configuration variables.
const MiserMode
Name constant for the MiserMode setting, for use with Config::get()
Service locator for MediaWiki core services.
static getInstance()
Returns the global default instance of the top level service locator.
static doPlaceholderInit()
Insert a dummy row with all zeroes if no row is present.
static doAllAndCommit( $database, array $options=[])
Do all updates and commit them.
Static accessor class for site_stats and related things.
Definition SiteStats.php:36
static unload()
Trigger a reload next time a field is accessed.
Definition SiteStats.php:43
static jobs()
Total number of jobs in the job queue.
static numberingroup( $group)
Find the number of users in a given user group.
static getCacheSetOptions(?IReadableDatabase ... $dbs)
Merge the result of getSessionLagStatus() for several DBs using the most pessimistic values to estima...
This class is a delegate to ILBFactory for a given database cluster.
A database connection without write operations.
newSelectQueryBuilder()
Create an empty SelectQueryBuilder which can be used to run queries against this connection.
const DB_REPLICA
Definition defines.php:26
const DB_PRIMARY
Definition defines.php:28