This is causing warnings about inappropriate primary DB connections on GET requests (about 1000 in the last 24 hours, at the time of writing).
UI messages
Typical stack trace:
from /srv/mediawiki/php-1.37.0-wmf.6/includes/libs/rdbms/TransactionProfiler.php(444) #0 /srv/mediawiki/php-1.37.0-wmf.6/includes/libs/rdbms/TransactionProfiler.php(224): Wikimedia\Rdbms\TransactionProfiler->reportExpectationViolated(string, string, integer) #1 /srv/mediawiki/php-1.37.0-wmf.6/includes/libs/rdbms/loadbalancer/LoadBalancer.php(1010): Wikimedia\Rdbms\TransactionProfiler->recordConnection(string, string, boolean) #2 /srv/mediawiki/php-1.37.0-wmf.6/includes/libs/rdbms/loadbalancer/LoadBalancer.php(964): Wikimedia\Rdbms\LoadBalancer->getServerConnection(integer, string, integer) #3 /srv/mediawiki/php-1.37.0-wmf.6/includes/libs/rdbms/loadbalancer/LoadBalancer.php(1130): Wikimedia\Rdbms\LoadBalancer->getConnection(integer, array, string, integer) #4 /srv/mediawiki/php-1.37.0-wmf.6/includes/GlobalFunctions.php(2307): Wikimedia\Rdbms\LoadBalancer->getMaintenanceConnectionRef(integer, array, string) #5 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/DBStore.php(135): wfGetDB(integer) #6 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/DBStore.php(139): MediaWiki\Extensions\SecurePoll\DBStore->getDB() #7 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Entities/Election.php(404): MediaWiki\Extensions\SecurePoll\DBStore->getQuestionInfo(string) #8 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Entities/Election.php(166): MediaWiki\Extensions\SecurePoll\Entities\Election->getQuestions() #9 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Entities/Entity.php(100): MediaWiki\Extensions\SecurePoll\Entities\Election->getChildren() #10 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Entities/Entity.php(119): MediaWiki\Extensions\SecurePoll\Entities\Entity->getDescendants() #11 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Entities/Entity.php(167): MediaWiki\Extensions\SecurePoll\Entities\Entity->loadMessages(string) #12 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/Pages/ListPage.php(43): MediaWiki\Extensions\SecurePoll\Entities\Entity->getMessage(string) #13 /srv/mediawiki/php-1.37.0-wmf.6/extensions/SecurePoll/includes/SpecialSecurePoll.php(70): MediaWiki\Extensions\SecurePoll\Pages\ListPage->execute(array) #14 /srv/mediawiki/php-1.37.0-wmf.6/includes/specialpage/SpecialPage.php(646): MediaWiki\Extensions\SecurePoll\SpecialSecurePoll->execute(string) #15 /srv/mediawiki/php-1.37.0-wmf.6/includes/specialpage/SpecialPageFactory.php(1390): SpecialPage->run(string) #16 /srv/mediawiki/php-1.37.0-wmf.6/includes/MediaWiki.php(314): MediaWiki\SpecialPage\SpecialPageFactory->executePath(string, RequestContext) #17 /srv/mediawiki/php-1.37.0-wmf.6/includes/MediaWiki.php(917): MediaWiki->performRequest() #18 /srv/mediawiki/php-1.37.0-wmf.6/includes/MediaWiki.php(551): MediaWiki->main() #19 /srv/mediawiki/php-1.37.0-wmf.6/index.php(53): MediaWiki->run() #20 /srv/mediawiki/php-1.37.0-wmf.6/index.php(46): wfIndexMain() #21 /srv/mediawiki/w/index.php(3): require(string) #22 {main}
Entity::getMessage calls DBStore::getQuestionInfo, which always queries the primary database:
public function getDB( $index = DB_PRIMARY ) { return wfGetDB( $this->forceMaster ? DB_PRIMARY : $index ); } public function getQuestionInfo( $electionId ) { $db = $this->getDB(); $res = $db->select( // etc. ); // etc. }
Entity::getMessage is used by most subpages of Special:SecurePoll, e.g. to display an election's title. In these cases, it should query the replicas.
Checking for election admins
Typical stack trace:
from /srv/mediawiki/php-1.37.0-wmf.5/includes/libs/rdbms/TransactionProfiler.php(432) #0 /srv/mediawiki/php-1.37.0-wmf.5/includes/libs/rdbms/TransactionProfiler.php(212): Wikimedia\Rdbms\TransactionProfiler->reportExpectationViolated(string, string, integer) #1 /srv/mediawiki/php-1.37.0-wmf.5/includes/libs/rdbms/loadbalancer/LoadBalancer.php(1010): Wikimedia\Rdbms\TransactionProfiler->recordConnection(string, string, boolean) #2 /srv/mediawiki/php-1.37.0-wmf.5/includes/libs/rdbms/loadbalancer/LoadBalancer.php(964): Wikimedia\Rdbms\LoadBalancer->getServerConnection(integer, string, integer) #3 /srv/mediawiki/php-1.37.0-wmf.5/includes/libs/rdbms/loadbalancer/LoadBalancer.php(1130): Wikimedia\Rdbms\LoadBalancer->getConnection(integer, array, string, integer) #4 /srv/mediawiki/php-1.37.0-wmf.5/includes/GlobalFunctions.php(2307): Wikimedia\Rdbms\LoadBalancer->getMaintenanceConnectionRef(integer, array, string) #5 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/DBStore.php(135): wfGetDB(integer) #6 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/DBStore.php(60): MediaWiki\Extensions\SecurePoll\DBStore->getDB() #7 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/Entities/Entity.php(132): MediaWiki\Extensions\SecurePoll\DBStore->getProperties(array) #8 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/Entities/Entity.php(238): MediaWiki\Extensions\SecurePoll\Entities\Entity->loadProperties() #9 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/Entities/Election.php(361): MediaWiki\Extensions\SecurePoll\Entities\Entity->getProperty(string) #10 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/Pages/ElectionPager.php(127): MediaWiki\Extensions\SecurePoll\Entities\Election->isAdmin(User) #11 /srv/mediawiki/php-1.37.0-wmf.5/includes/pager/IndexPager.php(611): MediaWiki\Extensions\SecurePoll\Pages\ElectionPager->formatRow(stdClass) #12 /srv/mediawiki/php-1.37.0-wmf.5/includes/pager/TablePager.php(94): IndexPager->getBody() #13 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/Pages/EntryPage.php(38): TablePager->getBodyOutput() #14 /srv/mediawiki/php-1.37.0-wmf.5/extensions/SecurePoll/includes/SpecialSecurePoll.php(70): MediaWiki\Extensions\SecurePoll\Pages\EntryPage->execute(array) #15 /srv/mediawiki/php-1.37.0-wmf.5/includes/specialpage/SpecialPage.php(646): MediaWiki\Extensions\SecurePoll\SpecialSecurePoll->execute(string) #16 /srv/mediawiki/php-1.37.0-wmf.5/includes/specialpage/SpecialPageFactory.php(1396): SpecialPage->run(NULL) #17 /srv/mediawiki/php-1.37.0-wmf.5/includes/MediaWiki.php(313): MediaWiki\SpecialPage\SpecialPageFactory->executePath(string, RequestContext) #18 /srv/mediawiki/php-1.37.0-wmf.5/includes/MediaWiki.php(916): MediaWiki->performRequest() #19 /srv/mediawiki/php-1.37.0-wmf.5/includes/MediaWiki.php(550): MediaWiki->main() #20 /srv/mediawiki/php-1.37.0-wmf.5/index.php(53): MediaWiki->run() #21 /srv/mediawiki/php-1.37.0-wmf.5/index.php(46): wfIndexMain() #22 /srv/mediawiki/w/index.php(3): require(string) #23 {main}
Election::isAdmin calls DBStore::getProperties, which always queries the primary database:
public function getProperties( $ids ) { // See DBStore::getDB above $db = $this->getDB(); $res = $db->select( // etc. ); //etc. }
Election::isAdmin is used for permissions checks when displaying forms and links. In these cases, it should query the replicas.
Possible solutions
We might need to allow passing which database to query when calling getQuestionInfo and getProperties.
Interestingly, a similar method getElectionInfo was changed to always query the replicas in https://gerrit.wikimedia.org/r/c/mediawiki/extensions/SecurePoll/+/332952. (...Though it seems unlikely we could do this with getProperties, since admin checks may be performed when admins are actually trying to perform an action.)