wiki.techinc.nl/includes/deferred/SiteStatsUpdate.php
James D. Forrester df5eb22f83 Replace uses of DB_MASTER with DB_PRIMARY
Just an auto-replace from codesniffer for now.

Change-Id: I5240dc9ac5929d291b0ef1c743ea2bfd3f428266
2021-04-29 09:24:31 -07:00

167 lines
4.8 KiB
PHP

<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
use MediaWiki\MediaWikiServices;
use Wikimedia\Assert\Assert;
use Wikimedia\Rdbms\IDatabase;
/**
* Class for handling updates to the site_stats table
*/
class SiteStatsUpdate implements DeferrableUpdate, MergeableUpdate {
/** @var int */
protected $edits = 0;
/** @var int */
protected $pages = 0;
/** @var int */
protected $articles = 0;
/** @var int */
protected $users = 0;
/** @var int */
protected $images = 0;
/** @var string[] Map of (table column => counter type) */
private const COUNTERS = [
'ss_total_edits' => 'edits',
'ss_total_pages' => 'pages',
'ss_good_articles' => 'articles',
'ss_users' => 'users',
'ss_images' => 'images'
];
// @todo deprecate this constructor
public function __construct( $views, $edits, $good, $pages = 0, $users = 0 ) {
$this->edits = $edits;
$this->articles = $good;
$this->pages = $pages;
$this->users = $users;
}
public function merge( MergeableUpdate $update ) {
/** @var SiteStatsUpdate $update */
Assert::parameterType( __CLASS__, $update, '$update' );
'@phan-var SiteStatsUpdate $update';
foreach ( self::COUNTERS as $field ) {
$this->$field += $update->$field;
}
}
/**
* @param int[] $deltas Map of (counter type => integer delta)
* @return SiteStatsUpdate
* @throws UnexpectedValueException
*/
public static function factory( array $deltas ) {
$update = new self( 0, 0, 0 );
foreach ( $deltas as $name => $unused ) {
if ( !in_array( $name, self::COUNTERS ) ) { // T187585
throw new UnexpectedValueException( __METHOD__ . ": no field called '$name'" );
}
}
foreach ( self::COUNTERS as $field ) {
$update->$field = $deltas[$field] ?? 0;
}
return $update;
}
public function doUpdate() {
$services = MediaWikiServices::getInstance();
$stats = $services->getStatsdDataFactory();
$deltaByType = [];
foreach ( self::COUNTERS as $type ) {
$delta = $this->$type;
if ( $delta !== 0 ) {
$stats->updateCount( "site.$type", $delta );
}
$deltaByType[$type] = $delta;
}
( new AutoCommitUpdate(
$services->getDBLoadBalancer()->getConnectionRef( DB_PRIMARY ),
__METHOD__,
static function ( IDatabase $dbw, $fname ) use ( $deltaByType ) {
$set = [];
foreach ( self::COUNTERS as $field => $type ) {
$delta = (int)$deltaByType[$type];
if ( $delta > 0 ) {
$set[] = "$field=" . $dbw->buildGreatest(
[ $field => $dbw->addIdentifierQuotes( $field ) . '+' . abs( $delta ) ],
0
);
} elseif ( $delta < 0 ) {
$set[] = "$field=" . $dbw->buildGreatest(
[ 'new' => $dbw->addIdentifierQuotes( $field ) . '-' . abs( $delta ) ],
0
);
}
}
if ( $set ) {
$dbw->update( 'site_stats', $set, [ 'ss_row_id' => 1 ], $fname );
}
}
) )->doUpdate();
// Invalidate cache used by parser functions
SiteStats::unload();
}
/**
* @param IDatabase $dbw
* @return bool|mixed
*/
public static function cacheUpdate( IDatabase $dbw ) {
$services = MediaWikiServices::getInstance();
$config = $services->getMainConfig();
$dbr = $services->getDBLoadBalancer()->getConnectionRef( DB_REPLICA, 'vslow' );
# Get non-bot users than did some recent action other than making accounts.
# If account creation is included, the number gets inflated ~20+ fold on enwiki.
$activeUsers = $dbr->newSelectQueryBuilder()
->select( 'COUNT(DISTINCT rc_actor)' )
->from( 'recentchanges' )
->join( 'actor', 'actor', 'actor_id=rc_actor' )
->where( [
'rc_type != ' . $dbr->addQuotes( RC_EXTERNAL ), // Exclude external (Wikidata)
'actor_user IS NOT NULL',
'rc_bot' => 0,
'rc_log_type != ' . $dbr->addQuotes( 'newusers' ) . ' OR rc_log_type IS NULL',
'rc_timestamp >= ' . $dbr->addQuotes(
$dbr->timestamp( time() - $config->get( 'ActiveUserDays' ) * 24 * 3600 ) ),
] )
->caller( __METHOD__ )
->fetchField();
$dbw->update(
'site_stats',
[ 'ss_active_users' => intval( $activeUsers ) ],
[ 'ss_row_id' => 1 ],
__METHOD__
);
// Invalid cache used by parser functions
SiteStats::unload();
return $activeUsers;
}
}