Introduce DBAccessObjectUtils::getDBFromRecency()

And general clean up of db connection handling in core

Bug: T354194
Change-Id: Icb3685f1d7f8d1f4bcadf8e292ddf9450180fcdb
This commit is contained in:
Amir Sarabadani 2024-01-15 22:26:35 +01:00
parent 3ced5b1bf0
commit 72a8c3b433
12 changed files with 66 additions and 64 deletions

View file

@ -71,7 +71,6 @@ use WANObjectCache;
use Wikimedia\Assert\Assert;
use Wikimedia\IPUtils;
use Wikimedia\Rdbms\Database;
use Wikimedia\Rdbms\DBConnRef;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IReadableDatabase;
@ -256,20 +255,23 @@ class RevisionStore
/**
* @param int $queryFlags a bit field composed of READ_XXX flags
*
* @return DBConnRef
* @return IDatabase
*/
private function getDBConnectionRefForQueryFlags( $queryFlags ) {
[ $mode, ] = DBAccessObjectUtils::getDBOptions( $queryFlags );
return $this->getDBConnectionRef( $mode );
if ( ( $queryFlags & IDBAccessObject::READ_LATEST ) == IDBAccessObject::READ_LATEST ) {
return $this->getDBConnection( DB_PRIMARY );
} else {
return $this->getDBConnection( DB_REPLICA );
}
}
/**
* @param int $mode DB_PRIMARY or DB_REPLICA
* @param string|array $groups
* @return DBConnRef
* @return IDatabase
*/
private function getDBConnectionRef( $mode, $groups = [] ) {
return $this->loadBalancer->getConnectionRef( $mode, $groups, $this->wikiId );
private function getDBConnection( $mode, $groups = [] ) {
return $this->loadBalancer->getConnection( $mode, $groups, $this->wikiId );
}
/**
@ -1435,7 +1437,7 @@ class RevisionStore
$revQuery = $this->getSlotsQueryInfo( [ 'content' ] );
[ $dbMode, $dbOptions ] = DBAccessObjectUtils::getDBOptions( $queryFlags );
$db = $this->getDBConnectionRef( $dbMode );
$db = $this->getDBConnection( $dbMode );
$res = $db->select(
$revQuery['tables'],
@ -2335,7 +2337,7 @@ class RevisionStore
&& $this->loadBalancer->hasOrMadeRecentPrimaryChanges()
) {
$flags = IDBAccessObject::READ_LATEST;
$dbw = $this->getDBConnectionRef( DB_PRIMARY );
$dbw = $this->getDBConnection( DB_PRIMARY );
$rev = $this->loadRevisionFromConds( $dbw, $conditions, $flags, $page, $options );
}
@ -2672,7 +2674,7 @@ class RevisionStore
* of the corresponding revision.
*/
public function getRevisionSizes( array $revIds ) {
$dbr = $this->getDBConnectionRef( DB_REPLICA );
$dbr = $this->getDBConnection( DB_REPLICA );
$revLens = [];
if ( !$revIds ) {
return $revLens; // empty
@ -2716,7 +2718,7 @@ class RevisionStore
}
[ $dbType, ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = $this->getDBConnectionRef( $dbType );
$db = $this->getDBConnection( $dbType );
$ts = $rev->getTimestamp() ?? $this->getTimestampFromId( $revisionIdValue, $flags );
if ( $ts === false ) {
@ -2958,7 +2960,7 @@ class RevisionStore
* @return RevisionRecord|false Returns false if missing
*/
public function getKnownCurrentRevision( PageIdentity $page, $revId = 0 ) {
$db = $this->getDBConnectionRef( DB_REPLICA );
$db = $this->getDBConnection( DB_REPLICA );
$revIdPassed = $revId;
$pageId = $this->getArticleId( $page );
if ( !$pageId ) {
@ -3260,7 +3262,7 @@ class RevisionStore
}
}
$dbr = $this->getDBConnectionRef( DB_REPLICA );
$dbr = $this->getDBConnection( DB_REPLICA );
$conds = array_merge(
[
'rev_page' => $pageId,
@ -3362,7 +3364,7 @@ class RevisionStore
return 0;
}
$dbr = $this->getDBConnectionRef( DB_REPLICA );
$dbr = $this->getDBConnection( DB_REPLICA );
$conds = array_merge(
[
'rev_page' => $pageId,
@ -3401,7 +3403,7 @@ class RevisionStore
int $searchLimit
): ?RevisionRecord {
$revision->assertWiki( $this->wikiId );
$db = $this->getDBConnectionRef( DB_REPLICA );
$db = $this->getDBConnection( DB_REPLICA );
$revQuery = $this->getQueryInfo();
$subquery = $db->buildSelectSubquery(
$revQuery['tables'],

View file

@ -2495,7 +2495,7 @@ return [
return new WikiPageFactory(
$services->getTitleFactory(),
new HookRunner( $services->getHookContainer() ),
$services->getDBLoadBalancer()
$services->getDBLoadBalancerFactory()
);
},

View file

@ -190,8 +190,7 @@ class LocalPasswordPrimaryAuthenticationProvider
return false;
}
[ $mode, ] = \DBAccessObjectUtils::getDBOptions( $flags );
$db = \DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $mode );
$db = \DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
return (bool)$db->newSelectQueryBuilder()
->select( [ 'user_id' ] )
->from( 'user' )

View file

@ -207,8 +207,7 @@ class TemporaryPasswordPrimaryAuthenticationProvider
return false;
}
[ $mode, ] = \DBAccessObjectUtils::getDBOptions( $flags );
$db = \DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $mode );
$db = \DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
return (bool)$db->newSelectQueryBuilder()
->select( [ 'user_id' ] )
->from( 'user' )

View file

@ -100,4 +100,17 @@ class DBAccessObjectUtils implements IDBAccessObject {
throw new InvalidArgumentException( '$index must be either DB_REPLICA or DB_PRIMARY' );
}
}
/**
* @param IConnectionProvider $dbProvider
* @param int $recency IDBAccessObject::READ_* constant
* @return IReadableDatabase
* @since 1.42
*/
public static function getDBFromRecency( IConnectionProvider $dbProvider, int $recency ): IReadableDatabase {
if ( self::hasFlags( $recency, IDBAccessObject::READ_LATEST ) ) {
return $dbProvider->getPrimaryDatabase();
}
return $dbProvider->getReplicaDatabase();
}
}

View file

@ -10,7 +10,7 @@ use MediaWiki\Title\TitleFactory;
use stdClass;
use WikiCategoryPage;
use WikiFilePage;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
use WikiPage;
/**
@ -23,22 +23,22 @@ class WikiPageFactory {
private $titleFactory;
/** @var WikiPageFactoryHook */
private $wikiPageFactoryHookRunner;
/** @var ILoadBalancer */
private $loadBalancer;
/** @var IConnectionProvider */
private $dbProvider;
/**
* @param TitleFactory $titleFactory
* @param WikiPageFactoryHook $wikiPageFactoryHookRunner
* @param ILoadBalancer $loadBalancer
* @param IConnectionProvider $dbProvider
*/
public function __construct(
TitleFactory $titleFactory,
WikiPageFactoryHook $wikiPageFactoryHookRunner,
ILoadBalancer $loadBalancer
IConnectionProvider $dbProvider
) {
$this->titleFactory = $titleFactory;
$this->wikiPageFactoryHookRunner = $wikiPageFactoryHookRunner;
$this->loadBalancer = $loadBalancer;
$this->dbProvider = $dbProvider;
}
/**
@ -127,10 +127,7 @@ class WikiPageFactory {
if ( $id < 1 ) {
return null;
}
$from = WikiPage::convertSelectType( $from );
[ $index ] = DBAccessObjectUtils::getDBOptions( $from );
$db = $this->loadBalancer->getMaintenanceConnectionRef( $index );
$db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, WikiPage::convertSelectType( $from ) );
$pageQuery = WikiPage::getQueryInfo();
$row = $db->selectRow(
$pageQuery['tables'], $pageQuery['fields'], [ 'page_id' => $id ], __METHOD__,

View file

@ -546,8 +546,11 @@ class Title implements LinkTarget, PageIdentity, IDBAccessObject {
public static function newFromID( $id, $flags = 0 ) {
$flags |= ( $flags & self::GAID_FOR_UPDATE ) ? self::READ_LATEST : 0; // b/c
$pageStore = MediaWikiServices::getInstance()->getPageStore();
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$row = wfGetDB( $index )->newSelectQueryBuilder()
$dbr = DBAccessObjectUtils::getDBFromRecency(
MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
$flags
);
$row = $dbr->newSelectQueryBuilder()
->select( $pageStore->getSelectFields() )
->from( 'page' )
->where( [ 'page_id' => $id ] )

View file

@ -96,8 +96,7 @@ class LocalIdLookup extends CentralIdLookup {
return [];
}
$audience = $this->checkAudience( $audience );
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $index );
$db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
$queryBuilder = $db->newSelectQueryBuilder();
$queryBuilder
->select( [ 'user_id', 'user_name' ] )
@ -125,8 +124,7 @@ class LocalIdLookup extends CentralIdLookup {
}
$audience = $this->checkAudience( $audience );
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $index );
$db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
$queryBuilder = $db->newSelectQueryBuilder();
$queryBuilder
->select( [ 'user_id', 'user_name' ] )

View file

@ -543,8 +543,7 @@ class UserOptionsManager extends UserOptionsLookup {
): array {
if ( $prefetchedOptions === null ) {
$this->logger->debug( 'Loading options from database', [ 'user_id' => $user->getId() ] );
[ $mode, ] = DBAccessObjectUtils::getDBOptions( $queryFlags );
$dbr = DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $mode );
$dbr = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $queryFlags );
$res = $dbr->newSelectQueryBuilder()
->select( [ 'up_property', 'up_value' ] )
->from( 'user_properties' )

View file

@ -400,8 +400,11 @@ class User implements Authority, UserIdentity, UserEmailContact {
$this->queryFlagsUsed = $flags;
}
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$queryBuilder = wfGetDB( $index )->newSelectQueryBuilder()
$dbr = DBAccessObjectUtils::getDBFromRecency(
MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
$flags
);
$queryBuilder = $dbr->newSelectQueryBuilder()
->select( [ 'actor_id', 'actor_user', 'actor_name' ] )
->from( 'actor' )
->recency( $flags );
@ -1094,9 +1097,10 @@ class User implements Authority, UserIdentity, UserEmailContact {
return false;
}
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = wfGetDB( $index );
$db = DBAccessObjectUtils::getDBFromRecency(
MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
$flags
);
$row = self::newQueryBuilder( $db )
->where( [ 'user_id' => $this->mId ] )
->recency( $flags )
@ -2557,9 +2561,10 @@ class User implements Authority, UserIdentity, UserEmailContact {
return 0;
}
[ $index, ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = wfGetDB( $index );
$db = DBAccessObjectUtils::getDBFromRecency(
MediaWikiServices::getInstance()->getDBLoadBalancerFactory(),
$flags
);
$id = $db->newSelectQueryBuilder()
->select( 'user_id' )
->from( 'user' )

View file

@ -163,9 +163,7 @@ class UserEditTracker {
if ( !$user->getId() ) {
return false;
}
[ $index ] = DBAccessObjectUtils::getDBOptions( $flags );
$db = DBAccessObjectUtils::getDBFromIndex( $this->dbProvider, $index );
$db = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $flags );
$actorWhere = $this->actorMigration->getWhere( $db, 'rev_user', $user );
$sortOrder = ( $type === self::FIRST_EDIT ) ? 'ASC' : 'DESC';

View file

@ -373,7 +373,7 @@ class UserGroupManager implements IDBAccessObject {
return [];
}
$res = $this->getDBConnectionRefForQueryFlags( $queryFlags )->newSelectQueryBuilder()
$res = DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $queryFlags )->newSelectQueryBuilder()
->select( 'ufg_group' )
->from( 'user_former_groups' )
->where( [ 'ufg_user' => $user->getId( $this->wikiId ) ] )
@ -765,7 +765,9 @@ class UserGroupManager implements IDBAccessObject {
return [];
}
$queryBuilder = $this->newQueryBuilder( $this->getDBConnectionRefForQueryFlags( $queryFlags ) );
$queryBuilder = $this->newQueryBuilder(
DBAccessObjectUtils::getDBFromRecency( $this->dbProvider, $queryFlags )
);
$res = $queryBuilder
->where( [ 'ug_user' => $user->getId( $this->wikiId ) ] )
->caller( __METHOD__ )
@ -1212,19 +1214,6 @@ class UserGroupManager implements IDBAccessObject {
unset( $this->queryFlagsUsedForCaching[$userKey][$cacheKind] );
}
/**
* @param int $queryFlags a bit field composed of READ_XXX flags
* @return IReadableDatabase
*/
private function getDBConnectionRefForQueryFlags( int $queryFlags ): IReadableDatabase {
[ $mode, ] = DBAccessObjectUtils::getDBOptions( $queryFlags );
if ( $mode === DB_PRIMARY ) {
return $this->dbProvider->getPrimaryDatabase( $this->wikiId );
} else {
return $this->dbProvider->getReplicaDatabase( $this->wikiId );
}
}
/**
* Gets a unique key for various caches.
* @param UserIdentity $user