MediaWiki master
SiteStats.php
Go to the documentation of this file.
1<?php
10
14use stdClass;
18
22class SiteStats {
24 private static $row;
25
29 public static function unload() {
30 self::$row = null;
31 }
32
33 protected static function load() {
34 if ( self::$row === null ) {
35 self::$row = self::loadAndLazyInit();
36 }
37 }
38
42 protected static function loadAndLazyInit() {
43 $config = MediaWikiServices::getInstance()->getMainConfig();
44
45 $lb = self::getLB();
46 $dbr = $lb->getConnection( DB_REPLICA );
47 wfDebug( __METHOD__ . ": reading site_stats from replica DB" );
48 $row = self::doLoadFromDB( $dbr );
49
50 if ( !self::isRowSensible( $row ) && $lb->hasOrMadeRecentPrimaryChanges() ) {
51 // Might have just been initialized during this request? Underflow?
52 wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB" );
53 $row = self::doLoadFromDB( $lb->getConnection( DB_PRIMARY ) );
54 }
55
56 if ( !self::isRowSensible( $row ) ) {
57 if ( $config->get( MainConfigNames::MiserMode ) ) {
58 // Start off with all zeroes, assuming that this is a new wiki or any
59 // repopulations where done manually via script.
61 } else {
62 // Normally the site_stats table is initialized at install time.
63 // Some manual construction scenarios may leave the table empty or
64 // broken, however, for instance when importing from a dump into a
65 // clean schema with mwdumper.
66 wfDebug( __METHOD__ . ": initializing damaged or missing site_stats" );
68 }
69
70 $row = self::doLoadFromDB( $lb->getConnection( DB_PRIMARY ) );
71 }
72
73 return $row;
74 }
75
79 public static function edits() {
80 self::load();
81
82 return (int)self::$row->ss_total_edits;
83 }
84
88 public static function articles() {
89 self::load();
90
91 return (int)self::$row->ss_good_articles;
92 }
93
97 public static function pages() {
98 self::load();
99
100 return (int)self::$row->ss_total_pages;
101 }
102
106 public static function users() {
107 self::load();
108
109 return (int)self::$row->ss_users;
110 }
111
115 public static function activeUsers() {
116 self::load();
117
118 return (int)self::$row->ss_active_users;
119 }
120
124 public static function images() {
125 self::load();
126
127 return (int)self::$row->ss_images;
128 }
129
135 public static function numberingroup( $group ) {
136 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
137 $fname = __METHOD__;
138
139 return $cache->getWithSetCallback(
140 $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
141 $cache::TTL_HOUR,
142 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $group, $fname ) {
143 $dbr = self::getLB()->getConnection( DB_REPLICA );
144 $setOpts += Database::getCacheSetOptions( $dbr );
145 return (int)$dbr->newSelectQueryBuilder()
146 ->select( 'COUNT(*)' )
147 ->from( 'user_groups' )
148 ->where(
149 [
150 'ug_group' => $group,
151 $dbr->expr( 'ug_expiry', '=', null )->or( 'ug_expiry', '>=', $dbr->timestamp() )
152 ]
153 )
154 ->caller( $fname )
155 ->fetchField();
156 },
157 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
158 );
159 }
160
165 public static function jobs() {
166 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
167
168 return $cache->getWithSetCallback(
169 $cache->makeKey( 'SiteStats', 'jobscount' ),
170 $cache::TTL_MINUTE,
171 static function ( $oldValue, &$ttl, array &$setOpts ) {
172 try {
173 $jobs = array_sum( MediaWikiServices::getInstance()->getJobQueueGroup()->getQueueSizes() );
174 } catch ( JobQueueError ) {
175 $jobs = 0;
176 }
177 return $jobs;
178 },
179 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
180 );
181 }
182
187 public static function pagesInNs( $ns ) {
188 $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
189 $fname = __METHOD__;
190
191 return $cache->getWithSetCallback(
192 $cache->makeKey( 'SiteStats', 'page-in-namespace', $ns ),
193 $cache::TTL_HOUR,
194 static function ( $oldValue, &$ttl, array &$setOpts ) use ( $ns, $fname ) {
195 $dbr = self::getLB()->getConnection( DB_REPLICA );
196 $setOpts += Database::getCacheSetOptions( $dbr );
197
198 return (int)$dbr->newSelectQueryBuilder()
199 ->select( 'COUNT(*)' )
200 ->from( 'page' )
201 ->where( [ 'page_namespace' => $ns ] )
202 ->caller( $fname )->fetchField();
203 },
204 [ 'pcTTL' => $cache::TTL_PROC_LONG ]
205 );
206 }
207
211 public static function selectFields() {
212 return [
213 'ss_total_edits',
214 'ss_good_articles',
215 'ss_total_pages',
216 'ss_users',
217 'ss_active_users',
218 'ss_images',
219 ];
220 }
221
226 private static function doLoadFromDB( IReadableDatabase $db ) {
227 $fields = self::selectFields();
228 $rows = $db->newSelectQueryBuilder()
229 ->select( $fields )
230 ->from( 'site_stats' )
231 ->caller( __METHOD__ )
232 ->fetchResultSet();
233 if ( !$rows->numRows() ) {
234 return false;
235 }
236 $finalRow = new stdClass();
237 foreach ( $rows as $row ) {
238 foreach ( $fields as $field ) {
239 $finalRow->$field ??= 0;
240 if ( $row->$field ) {
241 $finalRow->$field += $row->$field;
242 }
243 }
244
245 }
246 return $finalRow;
247 }
248
257 private static function isRowSensible( $row ) {
258 if ( $row === false
259 || $row->ss_total_pages < $row->ss_good_articles
260 || $row->ss_total_edits < $row->ss_total_pages
261 ) {
262 return false;
263 }
264 // Now check for underflow/overflow
265 foreach ( [
266 'ss_total_edits',
267 'ss_good_articles',
268 'ss_total_pages',
269 'ss_users',
270 'ss_images',
271 ] as $member ) {
272 if ( $row->$member < 0 ) {
273 return false;
274 }
275 }
276
277 return true;
278 }
279
283 private static function getLB() {
284 return MediaWikiServices::getInstance()->getDBLoadBalancer();
285 }
286}
287
289class_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.
const DB_REPLICA
Definition defines.php:26
const DB_PRIMARY
Definition defines.php:28
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:22
static unload()
Trigger a reload next time a field is accessed.
Definition SiteStats.php:29
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.