3 * Accessors and mutators for the site-wide statistics.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
23 use Wikimedia\Rdbms\Database
;
24 use Wikimedia\Rdbms\IDatabase
;
25 use MediaWiki\MediaWikiServices
;
26 use Wikimedia\Rdbms\LoadBalancer
;
29 * Static accessor class for site_stats and related things
36 * Trigger a reload next time a field is accessed
38 public static function unload() {
42 protected static function load() {
43 if ( self
::$row === null ) {
44 self
::$row = self
::loadAndLazyInit();
51 protected static function loadAndLazyInit() {
52 $config = MediaWikiServices
::getInstance()->getMainConfig();
55 $dbr = $lb->getConnection( DB_REPLICA
);
56 wfDebug( __METHOD__
. ": reading site_stats from replica DB\n" );
57 $row = self
::doLoadFromDB( $dbr );
59 if ( !self
::isSane( $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->getConnection( DB_MASTER
) );
65 if ( !self
::isSane( $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.
69 SiteStatsInit
::doPlaceholderInit();
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" );
76 SiteStatsInit
::doAllAndCommit( $dbr );
79 $row = self
::doLoadFromDB( $lb->getConnection( DB_MASTER
) );
82 if ( !self
::isSane( $row ) ) {
83 wfDebug( __METHOD__
. ": site_stats persistently nonsensical o_O\n" );
84 // Always return a row-like object
85 $row = (object)array_fill_keys( self
::selectFields(), 0 );
92 * @param IDatabase $db
93 * @return stdClass|bool
95 private static function doLoadFromDB( IDatabase
$db ) {
96 return $db->selectRow(
107 public static function edits() {
110 return self
::$row->ss_total_edits
;
116 public static function articles() {
119 return self
::$row->ss_good_articles
;
125 public static function pages() {
128 return self
::$row->ss_total_pages
;
134 public static function users() {
137 return self
::$row->ss_users
;
143 public static function activeUsers() {
146 return self
::$row->ss_active_users
;
152 public static function images() {
155 return self
::$row->ss_images
;
159 * Find the number of users in a given user group.
160 * @param string $group Name of group
163 public static function numberingroup( $group ) {
164 $cache = MediaWikiServices
::getInstance()->getMainWANObjectCache();
166 return $cache->getWithSetCallback(
167 $cache->makeKey( 'SiteStats', 'groupcounts', $group ),
169 function ( $oldValue, &$ttl, array &$setOpts ) use ( $group ) {
170 $dbr = self
::getLB()->getConnection( DB_REPLICA
);
171 $setOpts +
= Database
::getCacheSetOptions( $dbr );
173 return (int)$dbr->selectField(
177 'ug_group' => $group,
178 'ug_expiry IS NULL OR ug_expiry >= ' . $dbr->addQuotes( $dbr->timestamp() )
183 [ 'pcTTL' => $cache::TTL_PROC_LONG
]
188 * Total number of jobs in the job queue.
191 public static function jobs() {
192 $cache = MediaWikiServices
::getInstance()->getMainWANObjectCache();
194 return $cache->getWithSetCallback(
195 $cache->makeKey( 'SiteStats', 'jobscount' ),
197 function ( $oldValue, &$ttl, array &$setOpts ) {
199 $jobs = array_sum( JobQueueGroup
::singleton()->getQueueSizes() );
200 } catch ( JobQueueError
$e ) {
205 [ 'pcTTL' => $cache::TTL_PROC_LONG
]
213 public static function pagesInNs( $ns ) {
214 $cache = MediaWikiServices
::getInstance()->getMainWANObjectCache();
216 return $cache->getWithSetCallback(
217 $cache->makeKey( 'SiteStats', 'page-in-namespace', $ns ),
219 function ( $oldValue, &$ttl, array &$setOpts ) use ( $ns ) {
220 $dbr = self
::getLB()->getConnection( DB_REPLICA
);
221 $setOpts +
= Database
::getCacheSetOptions( $dbr );
223 return (int)$dbr->selectField(
226 [ 'page_namespace' => $ns ],
230 [ 'pcTTL' => $cache::TTL_PROC_LONG
]
237 public static function selectFields() {
249 * Is the provided row of site stats sane, or should it be regenerated?
251 * Checks only fields which are filled by SiteStatsInit::refresh.
253 * @param bool|object $row
256 private static function isSane( $row ) {
258 ||
$row->ss_total_pages
< $row->ss_good_articles
259 ||
$row->ss_total_edits
< $row->ss_total_pages
263 // Now check for underflow/overflow
271 if ( $row->$member > 2000000000 ||
$row->$member < 0 ) {
280 * @return LoadBalancer
282 private static function getLB() {
283 return MediaWikiServices
::getInstance()->getDBLoadBalancer();