search: Make DB-backed search engines use ICP instead of LB/LBF

Bug: T330641
Change-Id: I5eff8865d77bbcca78b891a440fdde9f312a013c
This commit is contained in:
Amir Sarabadani 2023-07-12 17:29:13 +02:00
parent 0c01872114
commit 5eae1de53f
8 changed files with 43 additions and 57 deletions

View file

@ -229,6 +229,9 @@ because of Phabricator reports.
* Public access to the DifferenceEngine properties mOldid, mNewid, mOldRev,
mNewRev, mOldPage, mNewPage, mOldContent, mNewContent, mRevisionsLoaded,
mTextLoaded and mCacheHit, deprecated in 1.32, was removed.
* SearchDatabase::db, deprecated since 1.38, has been removed.
* SearchDatabase::lb has been removed without deprecation, use ::dbProvider
instead.
* Title::newFromTitleValue(), deprecated since 1.34, has been removed.
* SpecialPageAction has been removed without deprecation. There were no known
uses outside of core.

View file

@ -1857,7 +1857,7 @@ return [
return new SearchEngineFactory(
$services->getSearchEngineConfig(),
$services->getHookContainer(),
$services->getDBLoadBalancer()
$services->getDBLoadBalancerFactory()
);
},

View file

@ -21,8 +21,7 @@
* @ingroup Search
*/
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
/**
* Base search engine base class for database-backed searches
@ -31,23 +30,17 @@ use Wikimedia\Rdbms\ILoadBalancer;
* @since 1.23
*/
abstract class SearchDatabase extends SearchEngine {
/** @var ILoadBalancer */
protected $lb;
/** @var IDatabase (backwards compatibility) */
protected $db;
/**
* @var string[] search terms
*/
protected $searchTerms = [];
protected IConnectionProvider $dbProvider;
/**
* @param ILoadBalancer $lb The load balancer for the DB cluster to search on
* @param IConnectionProvider $dbProvider
*/
public function __construct( ILoadBalancer $lb ) {
$this->lb = $lb;
// @TODO: remove this deprecated field in 1.35
$this->db = $lb->getConnectionRef( DB_REPLICA ); // b/c
public function __construct( IConnectionProvider $dbProvider ) {
$this->dbProvider = $dbProvider;
}
/**

View file

@ -2,8 +2,7 @@
use MediaWiki\HookContainer\HookContainer;
use Wikimedia\ObjectFactory\ObjectFactory;
use Wikimedia\Rdbms\IDatabase;
use Wikimedia\Rdbms\ILoadBalancer;
use Wikimedia\Rdbms\IConnectionProvider;
/**
* Factory class for SearchEngine.
@ -19,22 +18,21 @@ class SearchEngineFactory {
/** @var HookContainer */
private $hookContainer;
/** @var ILoadBalancer */
private $loadBalancer;
private IConnectionProvider $dbProvider;
/**
* @param SearchEngineConfig $config
* @param HookContainer $hookContainer
* @param ILoadBalancer $loadBalancer
* @param IConnectionProvider $dbProvider
*/
public function __construct(
SearchEngineConfig $config,
HookContainer $hookContainer,
ILoadBalancer $loadBalancer
IConnectionProvider $dbProvider
) {
$this->config = $config;
$this->hookContainer = $hookContainer;
$this->loadBalancer = $loadBalancer;
$this->dbProvider = $dbProvider;
}
/**
@ -52,7 +50,7 @@ class SearchEngineFactory {
} elseif ( $configuredClass !== null ) {
$class = $configuredClass;
} else {
$class = self::getSearchEngineClass( $this->loadBalancer );
$class = self::getSearchEngineClass( $this->dbProvider );
}
$mappings = $this->config->getSearchMappings();
@ -63,7 +61,7 @@ class SearchEngineFactory {
$args = [];
if ( isset( $spec['class'] ) && is_subclass_of( $spec['class'], SearchDatabase::class ) ) {
$args['extraArgs'][] = $this->loadBalancer;
$args['extraArgs'][] = $this->dbProvider;
}
// ObjectFactory::getObjectFromSpec accepts an array, not just a callable (phan bug)
@ -75,14 +73,12 @@ class SearchEngineFactory {
}
/**
* @param IDatabase|ILoadBalancer $dbOrLb
* @param IConnectionProvider $dbProvider
* @return string SearchEngine subclass name
* @since 1.28
*/
public static function getSearchEngineClass( $dbOrLb ) {
$type = ( $dbOrLb instanceof IDatabase )
? $dbOrLb->getType()
: $dbOrLb->getServerType( $dbOrLb->getWriterIndex() );
public static function getSearchEngineClass( IConnectionProvider $dbProvider ) {
$type = $dbProvider->getReplicaDatabase()->getType();
switch ( $type ) {
case 'sqlite':

View file

@ -128,7 +128,7 @@ class SearchMySQL extends SearchDatabase {
wfDebug( __METHOD__ . ": Can't understand search query '{$filteredText}'" );
}
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$searchon = $dbr->addQuotes( $searchon );
$field = $this->getIndexField( $fulltext );
return [
@ -191,7 +191,7 @@ class SearchMySQL extends SearchDatabase {
$filteredTerm = $this->filter( $term );
$query = $this->getQuery( $filteredTerm, $fulltext );
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$resultSet = $dbr->select(
$query['tables'], $query['fields'], $query['conds'],
__METHOD__, $query['options'], $query['joins']
@ -230,7 +230,7 @@ class SearchMySQL extends SearchDatabase {
protected function queryFeatures( &$query ) {
foreach ( $this->features as $feature => $value ) {
if ( $feature === 'title-suffix-filter' && $value ) {
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$query['conds'][] = 'page_title' . $dbr->buildLike( $dbr->anyString(), $value );
}
}
@ -346,8 +346,7 @@ class SearchMySQL extends SearchDatabase {
* @param string $text
*/
public function update( $id, $title, $text ) {
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw->replace(
$this->dbProvider->getPrimaryDatabase()->replace(
'searchindex',
'si_page',
[
@ -367,8 +366,7 @@ class SearchMySQL extends SearchDatabase {
* @param string $title
*/
public function updateTitle( $id, $title ) {
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw->newUpdateQueryBuilder()
$this->dbProvider->getPrimaryDatabase()->newUpdateQueryBuilder()
->update( 'searchindex' )
->set( [ 'si_title' => $this->normalizeText( $title ) ] )
->where( [ 'si_page' => $id ] )
@ -383,8 +381,7 @@ class SearchMySQL extends SearchDatabase {
* @param string $title Title of page that was deleted
*/
public function delete( $id, $title ) {
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw->newDeleteQueryBuilder()
$this->dbProvider->getPrimaryDatabase()->newDeleteQueryBuilder()
->delete( 'searchindex' )
->where( [ 'si_page' => $id ] )
->caller( __METHOD__ )->execute();
@ -451,7 +448,7 @@ class SearchMySQL extends SearchDatabase {
if ( self::$mMinSearchLength === null ) {
$sql = "SHOW GLOBAL VARIABLES LIKE 'ft\\_min\\_word\\_len'";
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
// phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
$result = $dbr->query( $sql, __METHOD__ );
$row = $result->fetchObject();

View file

@ -43,7 +43,7 @@ class SearchPostgres extends SearchDatabase {
protected function doSearchTitleInDB( $term ) {
$q = $this->searchQuery( $term, 'titlevector' );
$olderror = error_reporting( E_ERROR );
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
// phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
$resultSet = $dbr->query( $q, 'SearchPostgres', IDatabase::QUERY_SILENCE_ERRORS );
error_reporting( $olderror );
@ -53,7 +53,7 @@ class SearchPostgres extends SearchDatabase {
protected function doSearchTextInDB( $term ) {
$q = $this->searchQuery( $term, 'textvector' );
$olderror = error_reporting( E_ERROR );
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
// phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
$resultSet = $dbr->query( $q, 'SearchPostgres', IDatabase::QUERY_SILENCE_ERRORS );
error_reporting( $olderror );
@ -116,7 +116,7 @@ class SearchPostgres extends SearchDatabase {
$searchstring = preg_replace( '/^[\'"](.*)[\'"]$/', "$1", $searchstring );
// Quote the whole thing
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$searchstring = $dbr->addQuotes( $searchstring );
wfDebug( "parseQuery returned: $searchstring" );
@ -136,7 +136,7 @@ class SearchPostgres extends SearchDatabase {
// We need a separate query here so gin does not complain about empty searches
$sql = "SELECT to_tsquery($searchstring)";
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
// phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
$res = $dbr->query( $sql, __METHOD__ );
if ( !$res ) {
@ -209,7 +209,7 @@ class SearchPostgres extends SearchDatabase {
" AND c.content_id = s.slot_content_id " .
" ORDER BY old_rev_text_id DESC OFFSET 1)";
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$dbw->query( $sql, __METHOD__ );
return true;

View file

@ -34,7 +34,7 @@ class SearchSqlite extends SearchDatabase {
* @return bool
*/
private function fulltextSearchSupported() {
$dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$sql = (string)$dbr->selectField(
$dbr->addIdentifierQuotes( 'sqlite_master' ),
'sql',
@ -131,7 +131,7 @@ class SearchSqlite extends SearchDatabase {
wfDebug( __METHOD__ . ": Can't understand search query '{$filteredText}'" );
}
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$searchon = $dbr->addQuotes( $searchon );
$field = $this->getIndexField( $fulltext );
@ -191,7 +191,7 @@ class SearchSqlite extends SearchDatabase {
$filteredTerm =
$this->filter( MediaWikiServices::getInstance()->getContentLanguage()->lc( $term ) );
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
// phpcs:ignore MediaWiki.Usage.DbrQueryUsage.DbrQueryFound
$resultSet = $dbr->query( $this->getQuery( $filteredTerm, $fulltext ), __METHOD__ );
@ -218,7 +218,7 @@ class SearchSqlite extends SearchDatabase {
if ( $this->namespaces === [] ) {
$namespaces = NS_MAIN;
} else {
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$namespaces = $dbr->makeList( $this->namespaces );
}
return 'AND page_namespace IN (' . $namespaces . ')';
@ -230,9 +230,7 @@ class SearchSqlite extends SearchDatabase {
* @return string
*/
private function limitResult( $sql ) {
$dbr = $this->lb->getConnectionRef( DB_REPLICA );
return $dbr->limitResult( $sql, $this->limit, $this->offset );
return $this->dbProvider->getReplicaDatabase()->limitResult( $sql, $this->limit, $this->offset );
}
/**
@ -267,7 +265,7 @@ class SearchSqlite extends SearchDatabase {
*/
private function queryMain( $filteredTerm, $fulltext ) {
$match = $this->parseQuery( $filteredTerm, $fulltext );
$dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$page = $dbr->tableName( 'page' );
$searchindex = $dbr->tableName( 'searchindex' );
return "SELECT $searchindex.rowid, page_namespace, page_title " .
@ -277,7 +275,7 @@ class SearchSqlite extends SearchDatabase {
private function getCountQuery( $filteredTerm, $fulltext ) {
$match = $this->parseQuery( $filteredTerm, $fulltext );
$dbr = $this->lb->getMaintenanceConnectionRef( DB_REPLICA );
$dbr = $this->dbProvider->getReplicaDatabase();
$page = $dbr->tableName( 'page' );
$searchindex = $dbr->tableName( 'searchindex' );
return "SELECT COUNT(*) AS c " .
@ -300,7 +298,7 @@ class SearchSqlite extends SearchDatabase {
}
// @todo find a method to do it in a single request,
// couldn't do it so far due to typelessness of FTS3 tables.
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$dbw->newDeleteQueryBuilder()
->delete( 'searchindex' )
->where( [ 'rowid' => $id ] )
@ -325,7 +323,7 @@ class SearchSqlite extends SearchDatabase {
return;
}
$dbw = $this->lb->getConnectionRef( DB_PRIMARY );
$dbw = $this->dbProvider->getPrimaryDatabase();
$dbw->newUpdateQueryBuilder()
->update( 'searchindex' )
->set( [ 'si_title' => $title ] )

View file

@ -1,7 +1,6 @@
<?php
use MediaWiki\MainConfigNames;
use Wikimedia\Rdbms\LoadBalancerSingle;
/**
* @group Search
@ -32,8 +31,9 @@ class SearchEngineTest extends MediaWikiLangTestCase {
if ( !$dbSupported ) {
$this->markTestSkipped( "MySQL or SQLite with FTS3 only" );
}
$dbProvider = $this->getServiceContainer()->getDBLoadBalancerFactory();
$searchType = SearchEngineFactory::getSearchEngineClass( $this->db );
$searchType = SearchEngineFactory::getSearchEngineClass( $dbProvider );
$this->overrideConfigValues( [
MainConfigNames::SearchType => $searchType,
MainConfigNames::CapitalLinks => true,
@ -42,8 +42,7 @@ class SearchEngineTest extends MediaWikiLangTestCase {
],
] );
$lb = LoadBalancerSingle::newFromConnection( $this->db );
$this->search = new $searchType( $lb );
$this->search = new $searchType( $dbProvider );
$this->search->setHookContainer( $this->getServiceContainer()->getHookContainer() );
}