22use Wikimedia\Assert\Assert;
40 private const SHARDS_OFF = 1;
44 private const COUNTERS = [
45 'ss_total_edits' =>
'edits',
46 'ss_total_pages' =>
'pages',
47 'ss_good_articles' =>
'articles',
48 'ss_users' =>
'users',
49 'ss_images' =>
'images'
55 public function __construct( $views, $edits, $good, $pages = 0, $users = 0 ) {
57 $this->articles = $good;
64 Assert::parameterType( __CLASS__, $update,
'$update' );
65 '@phan-var SiteStatsUpdate $update';
67 foreach ( self::COUNTERS as $field ) {
68 $this->$field += $update->$field;
85 public static function factory( array $deltas ) {
86 $update =
new self( 0, 0, 0 );
88 foreach ( $deltas as $name => $unused ) {
89 if ( !in_array( $name, self::COUNTERS ) ) {
90 throw new UnexpectedValueException( __METHOD__ .
": no field called '$name'" );
94 foreach ( self::COUNTERS as $field ) {
95 $update->$field = $deltas[$field] ?? 0;
102 $services = MediaWikiServices::getInstance();
103 $stats = $services->getStatsdDataFactory();
104 $shards = $services->getMainConfig()->get( MainConfigNames::MultiShardSiteStats ) ?
105 self::SHARDS_ON : self::SHARDS_OFF;
108 foreach ( self::COUNTERS as
$type ) {
109 $delta = $this->$type;
110 if ( $delta !== 0 ) {
111 $stats->updateCount(
"site.$type", $delta );
113 $deltaByType[
$type] = $delta;
117 $services->getDBLoadBalancer()->getConnectionRef(
DB_PRIMARY ),
119 static function (
IDatabase $dbw, $fname ) use ( $deltaByType, $shards ) {
123 $shard = mt_rand( 1, $shards );
128 $hasNegativeDelta =
false;
129 foreach ( self::COUNTERS as $field =>
$type ) {
130 $delta = (int)$deltaByType[
$type];
131 $initValues[$field] = $delta;
137 } elseif ( $delta < 0 ) {
138 $hasNegativeDelta =
true;
147 if ( $hasNegativeDelta ) {
148 $dbw->
update(
'site_stats', $set, [
'ss_row_id' => $shard ], $fname );
152 array_merge( [
'ss_row_id' => $shard ], $initValues ),
171 $services = MediaWikiServices::getInstance();
172 $config = $services->getMainConfig();
174 $dbr = $services->getDBLoadBalancer()->getConnectionRef(
DB_REPLICA,
'vslow' );
175 # Get non-bot users than did some recent action other than making accounts.
176 # If account creation is included, the number gets inflated ~20+ fold on enwiki.
177 $activeUsers =
$dbr->newSelectQueryBuilder()
178 ->select(
'COUNT(DISTINCT rc_actor)' )
179 ->from(
'recentchanges' )
180 ->join(
'actor',
'actor',
'actor_id=rc_actor' )
183 'actor_user IS NOT NULL',
185 'rc_log_type != ' .
$dbr->addQuotes(
'newusers' ) .
' OR rc_log_type IS NULL',
186 'rc_timestamp >= ' .
$dbr->addQuotes(
187 $dbr->timestamp( time() - $config->get( MainConfigNames::ActiveUserDays ) * 24 * 3600 ) ),
189 ->caller( __METHOD__ )
193 [
'ss_active_users' => intval( $activeUsers ) ],
194 [
'ss_row_id' => 1 ],
Deferrable Update for closure/callback updates that should use auto-commit mode.
A class containing constants representing the names of configuration variables.
Class for handling updates to the site_stats table.
static factory(array $deltas)
doUpdate()
Perform the actual work.
__construct( $views, $edits, $good, $pages=0, $users=0)
static cacheUpdate(IDatabase $dbw)
merge(MergeableUpdate $update)
Merge this enqueued update with a new MergeableUpdate of the same qualified class name.
static unload()
Trigger a reload next time a field is accessed.
Interface that deferrable updates should implement.
Interface that deferrable updates can implement to signal that updates can be combined.