api: Use RevisionStore::newRevisionsFromBatch to fetch revision records

This bundles the slot queries from RevisionRecords into one query for
all revisions requested for the module.
Before for each revision a query for the slots was needed

Change-Id: I2c08d0437a51de252d53a59269e1d701c475d403
This commit is contained in:
Umherirrender 2023-04-22 09:54:49 +02:00
parent 489874ef72
commit 704ba8ed5f
5 changed files with 56 additions and 4 deletions

View file

@ -357,6 +357,7 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
if ( $resultPageSet === null ) {
$this->executeGenderCacheFromResultWrapper( $res, __METHOD__, 'ar' );
$revisions = $this->getRevisionRecords( $res, 'archive' );
}
$pageMap = []; // Maps ns&title to array index
@ -393,7 +394,8 @@ class ApiQueryAllDeletedRevisions extends ApiQueryRevisionsBase {
$generated[] = $row->ar_rev_id;
}
} else {
$revision = $this->revisionStore->newRevisionFromArchiveRow( $row );
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable Set when used
$revision = $revisions[$row->ar_rev_id];
$rev = $this->extractRevisionInfo( $revision, $row );
if ( !isset( $pageMap[$row->ar_namespace][$row->ar_title] ) ) {

View file

@ -217,6 +217,7 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
if ( $resultPageSet === null ) {
$this->executeGenderCacheFromResultWrapper( $res, __METHOD__ );
$revisions = $this->getRevisionRecords( $res );
}
$pageMap = []; // Maps rev_page to array index
@ -249,7 +250,8 @@ class ApiQueryAllRevisions extends ApiQueryRevisionsBase {
$generated[] = $row->rev_id;
}
} else {
$revision = $this->revisionStore->newRevisionFromRow( $row, 0, Title::newFromRow( $row ) );
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable Set when used
$revision = $revisions[$row->rev_id];
$rev = $this->extractRevisionInfo( $revision, $row );
if ( !isset( $pageMap[$row->rev_page] ) ) {

View file

@ -239,6 +239,11 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
$this->addWhereRange( 'ar_id', $dir, null, null );
$res = $this->select( __METHOD__ );
if ( $resultPageSet === null ) {
$revisions = $this->getRevisionRecords( $res, 'archive' );
}
$count = 0;
$generated = [];
foreach ( $res as $row ) {
@ -276,7 +281,8 @@ class ApiQueryDeletedRevisions extends ApiQueryRevisionsBase {
$fit = $this->addPageSubItem(
$pageMap[$row->ar_namespace][$row->ar_title],
$this->extractRevisionInfo( $this->revisionStore->newRevisionFromArchiveRow( $row ), $row ),
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable Set when used
$this->extractRevisionInfo( $revisions[$row->ar_rev_id], $row ),
'rev'
);
if ( !$fit ) {

View file

@ -403,6 +403,10 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
$hookData = [];
$res = $this->select( __METHOD__, [], $hookData );
if ( $resultPageSet === null ) {
$revisions = $this->getRevisionRecords( $res );
}
foreach ( $res as $row ) {
if ( ++$count > $this->limit ) {
// We've reached the one extra which shows that there are
@ -422,7 +426,8 @@ class ApiQueryRevisions extends ApiQueryRevisionsBase {
if ( $resultPageSet !== null ) {
$generated[] = $row->rev_id;
} else {
$revision = $this->revisionStore->newRevisionFromRow( $row, 0, Title::newFromRow( $row ) );
// @phan-suppress-next-line PhanTypeArraySuspiciousNullable Set when used
$revision = $revisions[$row->rev_id];
$rev = $this->extractRevisionInfo( $revision, $row );
$fit = $this->processRow( $row, $rev, $hookData ) &&
$this->addPageSubItem( $row->rev_page, $rev, 'rev' );

View file

@ -36,6 +36,7 @@ use MediaWiki\Title\Title;
use Wikimedia\ParamValidator\ParamValidator;
use Wikimedia\ParamValidator\TypeDef\EnumDef;
use Wikimedia\ParamValidator\TypeDef\IntegerDef;
use Wikimedia\Rdbms\IResultWrapper;
/**
* A base class for functions common to producing a list of revisions.
@ -297,6 +298,42 @@ abstract class ApiQueryRevisionsBase extends ApiQueryGeneratorBase {
return $ret;
}
/**
* Create RevisionRecord objects with the RevisionStore
* @param IResultWrapper $res
* @param string|null $mode 'archive' or omit
* @return RevisionRecord[]
*/
protected function getRevisionRecords( $res, $mode = null ) {
$result = $this->revisionStore->newRevisionsFromBatch( $res, [
'slots' => $this->needSlots ? ( $this->slotRoles ?? [ SlotRecord::MAIN ] ) : null,
'archive' => $mode === 'archive',
// RevisionStore::newRevisionsFromBatch also supports a 'content' option to prefetch the content of
// all revisions. This can be problematic for big list of revisions as the content does not fit into
// MainConfigNames::APIMaxResultSize and the module produce a continue parameter to get the next content
// with the next request, but internally all contents are already fetched, which could be huge blobs.
// Also this loads content of revdeleted content, which is not used later
// Also failures on loading blobs would make the whole batch invalid and needs extra checking
// how to handle that in the module
// 'content' => $this->fetchContent,
] );
if ( !$result->isOK() ) {
// RevisionStore can set some internalerror_info
ApiBase::dieDebug( __METHOD__, Status::wrap( $result )->getWikiText( false, false, 'en' ) );
}
// Assert that all ids are set
$revisions = $result->getValue();
$idField = $mode !== 'archive' ? 'rev_id' : 'ar_rev_id';
foreach ( $res as $row ) {
if ( !isset( $revisions[$row->$idField] ) ) {
ApiBase::dieDebug( __METHOD__, 'RevisionStore does not return record for ' . $row->$idField );
}
}
return $revisions;
}
/**
* Extract information from the RevisionRecord
*