Daniel Kinzler has uploaded a new change for review. https://gerrit.wikimedia.org/r/55887
Change subject: Fix misleading output of Special:DispatchStats. ...................................................................... Fix misleading output of Special:DispatchStats. Previously, the notions of "touched time" (time since last dispatch) was confused with the "lag time" (time between last dispatched change and most recent change). Change-Id: I914bbf5aa7965a6d98d2033e5b1ef83da340cb15 --- M repo/Wikibase.i18n.php M repo/includes/specials/SpecialDispatchStats.php M repo/includes/store/sql/DispatchStats.php M repo/tests/phpunit/includes/store/sql/DispatchStatsTest.php 4 files changed, 142 insertions(+), 79 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Wikibase refs/changes/87/55887/1 diff --git a/repo/Wikibase.i18n.php b/repo/Wikibase.i18n.php index 176aaa0..096a4ed 100644 --- a/repo/Wikibase.i18n.php +++ b/repo/Wikibase.i18n.php @@ -179,8 +179,11 @@ 'wikibase-dispatchstats-oldest-change' => 'Oldest', 'wikibase-dispatchstats-newest-change' => 'Newest', 'wikibase-dispatchstats-site-id' => 'Site', + 'wikibase-dispatchstats-pos' => 'Position', 'wikibase-dispatchstats-lag-num' => 'Pending', 'wikibase-dispatchstats-lag-time' => 'Lag', + 'wikibase-dispatchstats-touched' => 'Touched', + 'wikibase-dispatchstats-large-lag' => '(very large)', 'wikibase-dispatchstats-freshest' => 'Freshest', 'wikibase-dispatchstats-stalest' => 'Stalest', 'wikibase-dispatchstats-median' => 'Median', @@ -717,9 +720,12 @@ {{Identical|Newest}}', 'wikibase-dispatchstats-site-id' => 'Column header for site IDs. {{Identical|Site}}', + 'wikibase-dispatchstats-pos' => 'Column header for dispatch position (given as change ID).', 'wikibase-dispatchstats-lag-num' => 'Column header for the number of changes not yet dispatched to this client wiki. {{Identical|Pending}}', - 'wikibase-dispatchstats-lag-time' => 'Column header for the time since a dispatcher visited this client wiki', + 'wikibase-dispatchstats-lag-time' => 'Column header for the time since between the change last dispatched to the client and the latest known change on the repo.', + 'wikibase-dispatchstats-touched' => 'Column header for the time a dispatcher last visited this client wiki', + 'wikibase-dispatchstats-large-lag' => 'Shown instead of the actual lag if the lag is so large that the relevant change records were already pruned', 'wikibase-dispatchstats-freshest' => 'Row header for the freshest (most recently updated) client wiki. See also: @@ -2613,11 +2619,13 @@ 'wikibase-dispatchstats-oldest-change' => 'Älteste', 'wikibase-dispatchstats-newest-change' => 'Neueste', 'wikibase-dispatchstats-site-id' => 'Website', + 'wikibase-dispatchstats-pos' => 'Stand', 'wikibase-dispatchstats-lag-num' => 'Ausstehend', - 'wikibase-dispatchstats-lag-time' => 'Verzögerung', + 'wikibase-dispatchstats-lag-time' => 'Rückstand', + 'wikibase-dispatchstats-touched' => 'Letzte Verarbeitung', 'wikibase-dispatchstats-freshest' => 'Neueste', 'wikibase-dispatchstats-stalest' => 'Älteste', - 'wikibase-dispatchstats-median' => 'Mittel', + 'wikibase-dispatchstats-median' => 'Zentralwert', 'wikibase-dispatchstats-average' => 'Durchschnitt', 'special-listdatatypes' => 'Liste aller verfügbaren Datentypen', 'wikibase-listdatatypes-intro' => 'Dies ist eine Liste aller Datentypen, die derzeit in dieser Installation verwendet werden:', diff --git a/repo/includes/specials/SpecialDispatchStats.php b/repo/includes/specials/SpecialDispatchStats.php index 2acfc3a..3273d3c 100644 --- a/repo/includes/specials/SpecialDispatchStats.php +++ b/repo/includes/specials/SpecialDispatchStats.php @@ -61,9 +61,15 @@ $this->outputRow( array( $label, - isset( $state->chd_site ) ? $state->chd_site : '', - $lang->formatNum( $state->chd_dist ), - $lang->formatDuration( $state->chd_lag ), + isset( $state->chd_site ) ? $state->chd_site : '-', + isset( $state->chd_seen ) ? $state->chd_seen : '-', + $lang->formatNum( $state->chd_pending ), + $state->chd_lag === null + ? wfMessage( 'wikibase-dispatchstats-large-lag' )->text() + : $lang->formatDuration( $state->chd_lag, array( 'days', 'hours', 'minutes' ) ), + isset( $state->chd_touched ) + ? $lang->timeanddate( $state->chd_touched ) + : '-', ) ); } @@ -118,8 +124,10 @@ $this->outputRow( array( '', $this->msg( 'wikibase-dispatchstats-site-id' )->text(), + $this->msg( 'wikibase-dispatchstats-pos' )->text(), $this->msg( 'wikibase-dispatchstats-lag-num' )->text(), $this->msg( 'wikibase-dispatchstats-lag-time' )->text(), + $this->msg( 'wikibase-dispatchstats-touched' )->text(), ), 'th' ); $this->outputStateRow( diff --git a/repo/includes/store/sql/DispatchStats.php b/repo/includes/store/sql/DispatchStats.php index f2add33..036fb1c 100644 --- a/repo/includes/store/sql/DispatchStats.php +++ b/repo/includes/store/sql/DispatchStats.php @@ -73,10 +73,14 @@ * Loads the current dispatch status from the database and calculates statistics. * Before this method is called, the behavior of the getters is undefined. * + * @param int|string $now: Timestamp to consider the current time. Mostly useful for testing. + * * @return int the number of client wikis. */ - public function load() { + public function load( $now = 0 ) { $db = wfGetDB( DB_SLAVE ); // XXX: use master? + + $now = wfTimestamp( TS_UNIX, $now ); $this->changeStats = $db->selectRow( $this->changesTableName, @@ -90,13 +94,18 @@ __METHOD__ ); - $res = $db->select( $this->dispatchTableName, + $res = $db->select( + array ( + $this->dispatchTableName, + $this->changesTableName + ), array( 'chd_site', 'chd_db', 'chd_seen', 'chd_touched', 'chd_lock', 'chd_disabled', + 'change_time', ), array( 'chd_disabled' => 0 @@ -104,29 +113,51 @@ __METHOD__, array( 'ORDER BY' => 'chd_seen ASC' + ), + array( + $this->changesTableName => array( 'LEFT JOIN', 'chd_seen = change_id' ) ) ); $this->average = new \stdClass(); + $this->average->chd_untouched = 0; + $this->average->chd_pending = 0; $this->average->chd_lag = 0; - $this->average->chd_dist = 0; $this->clientStates = array(); while ( $row = $res->fetchObject() ) { if ( $this->changeStats ) { - $row->chd_lag = max( 0, (int)wfTimestamp( TS_UNIX, $this->changeStats->max_time ) + // time between last dispatch and now + $row->chd_untouched = max( 0, $now - (int)wfTimestamp( TS_UNIX, $row->chd_touched ) ); - $row->chd_dist = (int)$this->changeStats->max_id - $row->chd_seen; + // time between the timestamp of the last changed processed and the last change recorded. + if ( $row->change_time === null ) { + // the change was already pruned, lag is "big". + $row->chd_lag = null; + } else { + $row->chd_lag = max( 0, (int)wfTimestamp( TS_UNIX, $this->changeStats->max_time ) + - (int)wfTimestamp( TS_UNIX, $row->change_time ) ); + } + + // number of changes that have not been processed yet + $row->chd_pending = (int)$this->changeStats->max_id - $row->chd_seen; } else { // if there are no changes, there is no lag + $row->chd_untouched = 0; + $row->chd_pending = 0; $row->chd_lag = 0; - $row->chd_dist = 0; } - $this->average->chd_lag += $row->chd_lag; - $this->average->chd_dist += $row->chd_dist; + $this->average->chd_untouched += $row->chd_untouched; + $this->average->chd_pending += $row->chd_pending; + + if ( $row->chd_lag === null || $this->average->chd_lag === null ) { + $this->average->chd_lag = null; + } else { + $this->average->chd_lag += $row->chd_lag; + } $this->clientStates[] = $row; } @@ -134,8 +165,10 @@ $n = count( $this->clientStates ); if ( $n > 0 ) { - $this->average->chd_lag = intval( $this->average->chd_lag / $n ); - $this->average->chd_dist = intval( $this->average->chd_dist / $n ); + $this->average->chd_untouched = intval( $this->average->chd_untouched / $n ); + $this->average->chd_pending = intval( $this->average->chd_pending / $n ); + $this->average->chd_lag = $this->average->chd_lag === null + ? null : intval( $this->average->chd_lag / $n ); } return $n; @@ -150,8 +183,12 @@ * The state for each wiki is returned as an object containing the following fields: * * * chd_site: the client wiki's site ID - * * chd_lag: seconds since that client was last touched by a dispatcher - * * chd_dist: number of changes not yet dispatched to that client + * * chd_untouched: seconds since that client was last touched by a dispatcher + * * chd_pending: number of changes not yet dispatched to that client + * * chd_lag: seconds between the timestamp of the last change that got dispatched + * and the latest change recorded. May be null if some of the pending changes + * have already been pruned. This indicates that the average could not be + * determined, but the lag is large. * * chd_lock: the name of the lock currently in effect for that wiki * * @return array|null A list of objects representing the dispatch state @@ -218,8 +255,12 @@ * Returns a pseudo-status object representing the average (mean) dispatch * lag. The status object has the following fields: * - * * chd_lag: seconds since that client was last touched by a dispatcher - * * chd_dist: number of changes not yet dispatched to that client + * * chd_untouched: seconds since that client was last touched by a dispatcher + * * chd_pending: number of changes not yet dispatched to that client + * * chd_lag: seconds between the timestamp of the last change that got dispatched + * and the latest change recorded. May be null if some of the pending changes + * have already been pruned. This indicates that the average could not be + * determined, but the lag is large. * * @return object */ diff --git a/repo/tests/phpunit/includes/store/sql/DispatchStatsTest.php b/repo/tests/phpunit/includes/store/sql/DispatchStatsTest.php index 179a9f2..195c65f 100644 --- a/repo/tests/phpunit/includes/store/sql/DispatchStatsTest.php +++ b/repo/tests/phpunit/includes/store/sql/DispatchStatsTest.php @@ -37,22 +37,27 @@ class EntityChangeTest extends \MediaWikiTestCase { /** - * Injects the given $changes and $states into the database, - * then creates and loads a DispatchStats object. - * - * @param array $changes - * @param array $states - * @param string|int $now the value of now. + * Creates and loads a DispatchStats object, injecting test data into + * the database as needed. * * @return DispatchStats */ - protected function getDispatchStats( $changes, $states ) { + protected function getDispatchStats() { + $data = self::getTestData(); + $now = $data['now']; + $changes = $data['changes']; + $states = $data['states']; + $dbw = wfGetDB( DB_MASTER ); // write to dummy tables $dbw->query( "truncate " . $dbw->tableName( 'wb_changes' ) ); $dbw->query( "truncate " . $dbw->tableName( 'wb_changes_dispatch' ) ); foreach ( $changes as $row ) { + if ( $row === null ) { + continue; + } + $dbw->insert( 'wb_changes', $row, __METHOD__ @@ -60,6 +65,10 @@ } foreach ( $states as $row ) { + if ( $row === null ) { + continue; + } + $dbw->insert( 'wb_changes_dispatch', $row, __METHOD__ @@ -67,7 +76,7 @@ } $stats = new DispatchStats(); - $stats->load(); + $stats->load( $now ); return $stats; } @@ -108,19 +117,19 @@ ), ), 'changes' => array( - array( + 2 => array( 'change_id' => 2, 'change_time' => '20130303000200', 'change_type' => 'test', 'change_object_id' => 'test', ), - array( + 3 => array( 'change_id' => 3, 'change_time' => '20130303000300', 'change_type' => 'test', 'change_object_id' => 'test', ), - array( + 1 => array( 'change_id' => 1, 'change_time' => '20130303000100', 'change_type' => 'test', @@ -128,28 +137,33 @@ ), ), + 'now' => '20130303000400', + 'expected' => array( 'getClientStates' => array( array( 'chd_site' => 'frwiki', 'chd_seen' => 1, 'chd_touched' => '20130303000110', - 'chd_lag' => 110, - 'chd_dist' => 2, + 'chd_untouched' => 170, + 'chd_pending' => 2, + 'chd_lag' => 120, ), array( 'chd_site' => 'dewiki', 'chd_seen' => 2, 'chd_touched' => '20130303000220', - 'chd_lag' => 40, - 'chd_dist' => 1, + 'chd_untouched' => 100, + 'chd_pending' => 1, + 'chd_lag' => 60, ), array( 'chd_site' => 'enwiki', 'chd_seen' => 3, 'chd_touched' => '20130303000330', + 'chd_untouched' => 30, + 'chd_pending' => 0, 'chd_lag' => 0, - 'chd_dist' => 0, ), ), @@ -165,26 +179,30 @@ 'chd_site' => 'enwiki', 'chd_seen' => 3, 'chd_touched' => '20130303000330', + 'chd_untouched' => 30, + 'chd_pending' => 0, 'chd_lag' => 0, - 'chd_dist' => 0, ), 'getStalest' => array( 'chd_site' => 'frwiki', 'chd_seen' => 1, 'chd_touched' => '20130303000110', - 'chd_lag' => 110, - 'chd_dist' => 2, + 'chd_untouched' => 170, + 'chd_pending' => 2, + 'chd_lag' => 120, ), 'getMedian' => array( 'chd_site' => 'dewiki', 'chd_seen' => 2, 'chd_touched' => '20130303000220', - 'chd_lag' => 40, - 'chd_dist' => 1, + 'chd_untouched' => 100, + 'chd_pending' => 1, + 'chd_lag' => 60, ), 'getAverage' => array( - 'chd_lag' => 30, - 'chd_dist' => 1, + 'chd_untouched' => 100, + 'chd_pending' => 1, + 'chd_lag' => 60, ), ), ); @@ -195,8 +213,6 @@ return array( array( - $data['changes'], - $data['states'], $data['expected']['getClientStates'], ) ); @@ -205,8 +221,8 @@ /** * @dataProvider provideGetClientStates */ - public function testGetClientStates( $changes, $states, $expected ) { - $stats = $this->getDispatchStats( $changes, $states ); + public function testGetClientStates( $expected ) { + $stats = $this->getDispatchStats(); $states = $stats->getClientStates(); @@ -240,11 +256,11 @@ } if ( isset( $expected['lag'] ) ) { - $this->assertEquals( $expected['lag'], $actual>chd_lag, "lag/$suffix" ); + $this->assertEquals( $expected['lag'], $actual>chd_untouched, "lag/$suffix" ); } if ( isset( $expected['dist'] ) ) { - $this->assertEquals( $expected['dist'], $actual>chd_dist, "dist/$suffix" ); + $this->assertEquals( $expected['dist'], $actual>chd_pending, "dist/$suffix" ); } } @@ -253,7 +269,6 @@ return array( array( - $data['states'], $data['expected']['getClientCount'], ) ); @@ -262,8 +277,8 @@ /** * @dataProvider provideGetClientCount */ - public function testGetClientCount( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetClientCount( $expected ) { + $stats = $this->getDispatchStats( ); $this->assertEquals( $expected, $stats->getClientCount() ); } @@ -273,7 +288,6 @@ return array( array( - $data['states'], $data['expected']['getLockedCount'], ) ); @@ -282,8 +296,8 @@ /** * @dataProvider provideGetLockedCount */ - public function testGetLockedCount( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetLockedCount( $expected ) { + $stats = $this->getDispatchStats(); $this->assertEquals( $expected, $stats->getLockedCount() ); } @@ -293,7 +307,6 @@ return array( array( - $data['changes'], $data['expected']['getMinChangeId'], ) ); @@ -302,8 +315,8 @@ /** * @dataProvider provideGetMinChangeId */ - public function testGetMinChangeId( $changes, $expected ) { - $stats = $this->getDispatchStats( $changes, array() ); + public function testGetMinChangeId( $expected ) { + $stats = $this->getDispatchStats(); $this->assertEquals( $expected, $stats->getMinChangeId() ); } @@ -313,7 +326,6 @@ return array( array( - $data['changes'], $data['expected']['getMaxChangeId'], ) ); @@ -322,8 +334,8 @@ /** * @dataProvider provideGetMaxChangeId */ - public function testGetMaxChangeId( $changes, $expected ) { - $stats = $this->getDispatchStats( $changes, array() ); + public function testGetMaxChangeId( $expected ) { + $stats = $this->getDispatchStats(); $this->assertEquals( $expected, $stats->getMaxChangeId() ); } @@ -333,7 +345,6 @@ return array( array( - $data['changes'], $data['expected']['getMinChangeTimestamp'], ) ); @@ -342,8 +353,8 @@ /** * @dataProvider provideGetMinChangeTimestamp */ - public function testGetMinChangeTimestamp( $changes, $expected ) { - $stats = $this->getDispatchStats( $changes, array() ); + public function testGetMinChangeTimestamp( $expected ) { + $stats = $this->getDispatchStats(); $this->assertEquals( $expected, $stats->getMinChangeTimestamp() ); } @@ -353,7 +364,6 @@ return array( array( - $data['changes'], $data['expected']['getMaxChangeTimestamp'], ) ); @@ -362,8 +372,8 @@ /** * @dataProvider provideGetMaxChangeTimestamp */ - public function testGetMaxChangeTimestamp( $changes, $expected ) { - $stats = $this->getDispatchStats( $changes, array() ); + public function testGetMaxChangeTimestamp( $expected ) { + $stats = $this->getDispatchStats(); $this->assertEquals( $expected, $stats->getMaxChangeTimestamp() ); } @@ -373,7 +383,6 @@ return array( array( - $data['states'], $data['expected']['getFreshest'], ) ); @@ -382,8 +391,8 @@ /** * @dataProvider provideGetFreshest */ - public function testGetFreshest( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetFreshest( $expected ) { + $stats = $this->getDispatchStats(); $this->assertStateEquals( $expected, $stats->getFreshest()); } @@ -393,7 +402,6 @@ return array( array( - $data['states'], $data['expected']['getStalest'], ) ); @@ -402,8 +410,8 @@ /** * @dataProvider provideGetStalest */ - public function testGetStalest( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetStalest( $expected ) { + $stats = $this->getDispatchStats(); $this->assertStateEquals( $expected, $stats->getStalest()); } @@ -413,7 +421,6 @@ return array( array( - $data['states'], $data['expected']['getAverage'], ) ); @@ -422,8 +429,8 @@ /** * @dataProvider provideGetAverage */ - public function testGetAverage( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetAverage( $expected ) { + $stats = $this->getDispatchStats(); $this->assertStateEquals( $expected, $stats->getStalest()); } @@ -433,7 +440,6 @@ return array( array( - $data['states'], $data['expected']['getMedian'], ) ); @@ -442,8 +448,8 @@ /** * @dataProvider provideGetMedian */ - public function testGetMedian( $states, $expected ) { - $stats = $this->getDispatchStats( array(), $states ); + public function testGetMedian( $expected ) { + $stats = $this->getDispatchStats(); $this->assertStateEquals( $expected, $stats->getStalest()); } -- To view, visit https://gerrit.wikimedia.org/r/55887 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I914bbf5aa7965a6d98d2033e5b1ef83da340cb15 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Wikibase Gerrit-Branch: master Gerrit-Owner: Daniel Kinzler <daniel.kinz...@wikimedia.de> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits