MediaWiki REL1_39
SiteStats.php
Go to the documentation of this file.
1<?php
28
32class SiteStats {
34 private static $row;
35
39 public static function unload() {
40 self::$row = null;
41 }
42
43 protected static function load() {
44 if ( self::$row === null ) {
45 self::$row = self::loadAndLazyInit();
46 }
47 }
48
52 protected static function loadAndLazyInit() {
53 $config = MediaWikiServices::getInstance()->getMainConfig();
54
55 $lb = self::getLB();
56 $dbr = $lb->getConnectionRef( DB_REPLICA );
57 wfDebug( __METHOD__ . ": reading site_stats from replica DB" );
58 $row = self::doLoadFromDB( $dbr );
59
60 if ( !self::isRowSensible( $row ) && $lb->hasOrMadeRecentPrimaryChanges() ) {
61 // Might have just been initialized during this request? Underflow?
62 wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB" );
63 $row = self::doLoadFromDB( $lb->getConnectionRef( DB_PRIMARY ) );
64 }
65
66 if ( !self::isRowSensible( $row ) ) {
67 if ( $config->get( MainConfigNames::MiserMode ) ) {
68 // Start off with all zeroes, assuming that this is a new wiki or any
69 // repopulations where done manually via script.
71 } else {
72 // Normally the site_stats table is initialized at install time.
73 // Some manual construction scenarios may leave the table empty or
74 // broken, however, for instance when importing from a dump into a
75 // clean schema with mwdumper.
76 wfDebug( __METHOD__ . ": initializing damaged or missing site_stats" );
78 }
79
80 $row = self::doLoadFromDB( $lb->getConnectionRef( DB_PRIMARY ) );
81 }
82
83 if ( !self::isRowSensible( $row ) ) {
84 wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O" );
85 // Always return a row-like object
86 $row = self::salvageIncorrectRow( $row );
87 }
88
89 return $row;
90 }
91
95 public static function edits() {
96 self::load();
97
98 return (int)self::$row->ss_total_edits;
99 }
100
104 public static function articles() {
105 self::load();
106
107 return (int)self::$row->ss_good_articles;
108 }
109
113 public static function pages() {
114 self::load();
115
116 return (int)self::$row->ss_total_pages;
117 }
118
122 public static function users() {
123 self::load();
124
125 return (int)self::$row->ss_users;
126 }
127
131 public static function activeUsers() {
132 self::load();
133
134 return (int)self::$row->ss_active_users;
135 }
136
140 public static function images() {
141 self::load();
142
143 return (int)self::$row->ss_images;
144 }
145
151 public static function numberingroup( $group ) {
152 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
153 $fname = __METHOD__;
154
155 return $cache->getWithSetCallback(
156 $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
157 $cache::TTL_HOUR,
158 function ( $oldValue, &$ttl, array &$setOpts ) use ( $group, $fname ) {
159 $dbr = self::getLB()->getConnectionRef( DB_REPLICA );
160 $setOpts += Database::getCacheSetOptions( $dbr );
161 return (int)$dbr->newSelectQueryBuilder()
162 ->select( 'COUNT(*)' )
163 ->from( 'user_groups' )
164 ->where(
165 [
166 'ug_group' => $group,
167 'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
168 ]
169 )
170 ->caller( $fname )
171 ->fetchField();
172 },
173 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
174 );
175 }
176
181 public static function jobs() {
182 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
183
184 return $cache->getWithSetCallback(
185 $cache->makeKey( 'SiteStats', 'jobscount' ),
186 $cache::TTL_MINUTE,
187 static function ( $oldValue, &$ttl, array &$setOpts ) {
188 try {
189 $jobs = array_sum( MediaWikiServices::getInstance()->getJobQueueGroup()->getQueueSizes() );
190 } catch ( JobQueueError $e ) {
191 $jobs = 0;
192 }
193 return $jobs;
194 },
195 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
196 );
197 }
198
203 public static function pagesInNs( $ns ) {
204 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
205 $fname = __METHOD__;
206
207 return $cache->getWithSetCallback(
208 $cache->makeKey( 'SiteStats', 'page-in-namespace', $ns ),
209 $cache::TTL_HOUR,
210 function ( $oldValue, &$ttl, array &$setOpts ) use ( $ns, $fname ) {
211 $dbr = self::getLB()->getConnectionRef( DB_REPLICA );
212 $setOpts += Database::getCacheSetOptions( $dbr );
213
214 return (int)$dbr->selectField(
215 'page',
216 'COUNT(*)',
217 [ 'page_namespace' => $ns ],
218 $fname
219 );
220 },
221 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
222 );
223 }
224
228 public static function selectFields() {
229 return [
230 'ss_total_edits',
231 'ss_good_articles',
232 'ss_total_pages',
233 'ss_users',
234 'ss_active_users',
235 'ss_images',
236 ];
237 }
238
243 private static function doLoadFromDB( IDatabase $db ) {
244 $fields = self::selectFields();
245 $rows = $db->newSelectQueryBuilder()
246 ->select( $fields )
247 ->from( 'site_stats' )
248 ->caller( __METHOD__ )
249 ->fetchResultSet();
250 $finalRow = new stdClass();
251 foreach ( $rows as $row ) {
252 foreach ( $fields as $field ) {
253 $finalRow->$field = $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
298 private static function salvageIncorrectRow( $row ) {
299 $map = $row ? (array)$row : [];
300 // Fill in any missing values with zero
301 $map += array_fill_keys( self::selectFields(), 0 );
302 // Convert negative values to zero
303 foreach ( $map as $field => $value ) {
304 $map[$field] = max( 0, $value );
305 }
306
307 return (object)$row;
308 }
309
313 private static function getLB() {
314 return MediaWikiServices::getInstance()->getDBLoadBalancer();
315 }
316}
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.
Service locator for MediaWiki core services.
static doAllAndCommit( $database, array $options=[])
Do all updates and commit them.
static doPlaceholderInit()
Insert a dummy row with all zeroes if no row is present.
Static accessor class for site_stats and related things.
Definition SiteStats.php:32
static articles()
static jobs()
Total number of jobs in the job queue.
static pagesInNs( $ns)
static images()
static load()
Definition SiteStats.php:43
static selectFields()
static edits()
Definition SiteStats.php:95
static loadAndLazyInit()
Definition SiteStats.php:52
static users()
static pages()
static unload()
Trigger a reload next time a field is accessed.
Definition SiteStats.php:39
static numberingroup( $group)
Find the number of users in a given user group.
static activeUsers()
Basic database interface for live and lazy-loaded relation database handles.
Definition IDatabase.php:39
newSelectQueryBuilder()
Create an empty SelectQueryBuilder which can be used to run queries against this connection.
Create and track the database connections and transactions for a given database cluster.
$cache
Definition mcc.php:33
const DB_REPLICA
Definition defines.php:26
const DB_PRIMARY
Definition defines.php:28