MediaWiki  master
SiteStats.php
Go to the documentation of this file.
1 <?php
27 
31 class SiteStats {
33  private static $row;
34 
38  public static function unload() {
39  self::$row = null;
40  }
41 
42  protected static function load() {
43  if ( self::$row === null ) {
44  self::$row = self::loadAndLazyInit();
45  }
46  }
47 
51  protected static function loadAndLazyInit() {
52  $config = MediaWikiServices::getInstance()->getMainConfig();
53 
54  $lb = self::getLB();
55  $dbr = $lb->getConnectionRef( DB_REPLICA );
56  wfDebug( __METHOD__ . ": reading site_stats from replica DB\n" );
57  $row = self::doLoadFromDB( $dbr );
58 
59  if ( !self::isRowSane( $row ) && $lb->hasOrMadeRecentMasterChanges() ) {
60  // Might have just been initialized during this request? Underflow?
61  wfDebug( __METHOD__ . ": site_stats damaged or missing on replica DB\n" );
62  $row = self::doLoadFromDB( $lb->getConnectionRef( DB_MASTER ) );
63  }
64 
65  if ( !self::isRowSane( $row ) ) {
66  if ( $config->get( 'MiserMode' ) ) {
67  // Start off with all zeroes, assuming that this is a new wiki or any
68  // repopulations where done manually via script.
70  } else {
71  // Normally the site_stats table is initialized at install time.
72  // Some manual construction scenarios may leave the table empty or
73  // broken, however, for instance when importing from a dump into a
74  // clean schema with mwdumper.
75  wfDebug( __METHOD__ . ": initializing damaged or missing site_stats\n" );
77  }
78 
79  $row = self::doLoadFromDB( $lb->getConnectionRef( DB_MASTER ) );
80  }
81 
82  if ( !self::isRowSane( $row ) ) {
83  wfDebug( __METHOD__ . ": site_stats persistently nonsensical o_O\n" );
84  // Always return a row-like object
85  $row = self::salvageInsaneRow( $row );
86  }
87 
88  return $row;
89  }
90 
94  public static function edits() {
95  self::load();
96 
97  return (int)self::$row->ss_total_edits;
98  }
99 
103  public static function articles() {
104  self::load();
105 
106  return (int)self::$row->ss_good_articles;
107  }
108 
112  public static function pages() {
113  self::load();
114 
115  return (int)self::$row->ss_total_pages;
116  }
117 
121  public static function users() {
122  self::load();
123 
124  return (int)self::$row->ss_users;
125  }
126 
130  public static function activeUsers() {
131  self::load();
132 
133  return (int)self::$row->ss_active_users;
134  }
135 
139  public static function images() {
140  self::load();
141 
142  return (int)self::$row->ss_images;
143  }
144 
150  public static function numberingroup( $group ) {
151  $cache = MediaWikiServices::getInstance()->getMainWANObjectCache();
152  $fname = __METHOD__;
153 
154  return $cache->getWithSetCallback(
155  $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
156  $cache::TTL_HOUR,
157  function ( $oldValue, &$ttl, array &$setOpts ) use ( $group, $fname ) {
158  $dbr = self::getLB()->getConnectionRef( DB_REPLICA );
159  $setOpts += Database::getCacheSetOptions( $dbr );
160 
161  return (int)$dbr->selectField(
162  'user_groups',
163  'COUNT(*)',
164  [
165  'ug_group' => $group,
166  'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
167  ],
168  $fname
169  );
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  function ( $oldValue, &$ttl, array &$setOpts ) {
186  try{
187  $jobs = array_sum( JobQueueGroup::singleton()->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  function ( $oldValue, &$ttl, array &$setOpts ) use ( $ns, $fname ) {
209  $dbr = self::getLB()->getConnectionRef( DB_REPLICA );
210  $setOpts += Database::getCacheSetOptions( $dbr );
211 
212  return (int)$dbr->selectField(
213  'page',
214  'COUNT(*)',
215  [ 'page_namespace' => $ns ],
216  $fname
217  );
218  },
219  [ 'pcTTL' => $cache::TTL_PROC_LONG ]
220  );
221  }
222 
226  public static function selectFields() {
227  return [
228  'ss_total_edits',
229  'ss_good_articles',
230  'ss_total_pages',
231  'ss_users',
232  'ss_active_users',
233  'ss_images',
234  ];
235  }
236 
241  private static function doLoadFromDB( IDatabase $db ) {
242  return $db->selectRow(
243  'site_stats',
244  self::selectFields(),
245  [ 'ss_row_id' => 1 ],
246  __METHOD__
247  );
248  }
249 
258  private static function isRowSane( $row ) {
259  if ( $row === false
260  || $row->ss_total_pages < $row->ss_good_articles
261  || $row->ss_total_edits < $row->ss_total_pages
262  ) {
263  return false;
264  }
265  // Now check for underflow/overflow
266  foreach ( [
267  'ss_total_edits',
268  'ss_good_articles',
269  'ss_total_pages',
270  'ss_users',
271  'ss_images',
272  ] as $member ) {
273  if ( $row->$member < 0 ) {
274  return false;
275  }
276  }
277 
278  return true;
279  }
280 
285  private static function salvageInsaneRow( $row ) {
286  $map = $row ? (array)$row : [];
287  // Fill in any missing values with zero
288  $map += array_fill_keys( self::selectFields(), 0 );
289  // Convert negative values to zero
290  foreach ( $map as $field => $value ) {
291  $map[$field] = max( 0, $value );
292  }
293 
294  return (object)$row;
295  }
296 
300  private static function getLB() {
301  return MediaWikiServices::getInstance()->getDBLoadBalancer();
302  }
303 }
static doPlaceholderInit()
Insert a dummy row with all zeroes if no row is present.
static jobs()
Total number of jobs in the job queue.
Definition: SiteStats.php:179
static getLB()
Definition: SiteStats.php:300
static activeUsers()
Definition: SiteStats.php:130
static loadAndLazyInit()
Definition: SiteStats.php:51
static load()
Definition: SiteStats.php:42
const DB_MASTER
Definition: defines.php:26
static unload()
Trigger a reload next time a field is accessed.
Definition: SiteStats.php:38
static numberingroup( $group)
Find the number of users in a given user group.
Definition: SiteStats.php:150
selectRow( $table, $vars, $conds, $fname=__METHOD__, $options=[], $join_conds=[])
Wrapper to IDatabase::select() that only fetches one row (via LIMIT)
static edits()
Definition: SiteStats.php:94
static pagesInNs( $ns)
Definition: SiteStats.php:201
wfDebug( $text, $dest='all', array $context=[])
Sends a line to the debug log if enabled or, optionally, to a comment in output.
$cache
Definition: mcc.php:33
Static accessor class for site_stats and related things.
Definition: SiteStats.php:31
static images()
Definition: SiteStats.php:139
static selectFields()
Definition: SiteStats.php:226
static salvageInsaneRow( $row)
Definition: SiteStats.php:285
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
static doLoadFromDB(IDatabase $db)
Definition: SiteStats.php:241
static articles()
Definition: SiteStats.php:103
static pages()
Definition: SiteStats.php:112
static doAllAndCommit( $database, array $options=[])
Do all updates and commit them.
static singleton( $domain=false)
static stdClass $row
Definition: SiteStats.php:33
const DB_REPLICA
Definition: defines.php:25
static isRowSane( $row)
Is the provided row of site stats sane, or should it be regenerated?
Definition: SiteStats.php:258
static users()
Definition: SiteStats.php:121