X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=maintenance%2FpopulateArchiveRevId.php;h=c03eb24853090fb089fbe52913b233aeb8c6cb85;hb=cba0fb1c1576324e87b27b6d31ee4359195025c8;hp=e493506237b8c0d2203fd97a6ddcbe4a75e8f574;hpb=490377185c02c25a961a9370f1b69b6c0dec6f7d;p=lhc%2Fweb%2Fwiklou.git diff --git a/maintenance/populateArchiveRevId.php b/maintenance/populateArchiveRevId.php index e493506237..c03eb24853 100644 --- a/maintenance/populateArchiveRevId.php +++ b/maintenance/populateArchiveRevId.php @@ -21,6 +21,7 @@ * @ingroup Maintenance */ +use Wikimedia\Rdbms\DBQueryError; use Wikimedia\Rdbms\IDatabase; require_once __DIR__ . '/Maintenance.php'; @@ -49,6 +50,7 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance { protected function doDBUpdates() { $this->output( "Populating ar_rev_id...\n" ); $dbw = $this->getDB( DB_MASTER ); + self::checkMysqlAutoIncrementBug( $dbw ); // Quick exit if there are no rows needing updates. $any = $dbw->selectField( @@ -86,6 +88,53 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance { } } + /** + * Check for (and work around) a MySQL auto-increment bug + * + * (T202032) MySQL until 8.0 and MariaDB until some version after 10.1.34 + * don't save the auto-increment value to disk, so on server restart it + * might reuse IDs from deleted revisions. We can fix that with an insert + * with an explicit rev_id value, if necessary. + * + * @param IDatabase $dbw + */ + public static function checkMysqlAutoIncrementBug( IDatabase $dbw ) { + if ( $dbw->getType() !== 'mysql' ) { + return; + } + + if ( !self::$dummyRev ) { + self::$dummyRev = self::makeDummyRevisionRow( $dbw ); + } + + $ok = false; + while ( !$ok ) { + try { + $dbw->doAtomicSection( __METHOD__, function ( $dbw, $fname ) { + $dbw->insert( 'revision', self::$dummyRev, $fname ); + $id = $dbw->insertId(); + $toDelete[] = $id; + + $maxId = max( + (int)$dbw->selectField( 'archive', 'MAX(ar_rev_id)', [], __METHOD__ ), + (int)$dbw->selectField( 'slots', 'MAX(slot_revision_id)', [], __METHOD__ ) + ); + if ( $id <= $maxId ) { + $dbw->insert( 'revision', [ 'rev_id' => $maxId + 1 ] + self::$dummyRev, $fname ); + $toDelete[] = $maxId + 1; + } + + $dbw->delete( 'revision', [ 'rev_id' => $toDelete ], $fname ); + } ); + $ok = true; + } catch ( DBQueryError $e ) { + if ( $e->errno != 1062 ) { // 1062 is "duplicate entry", ignore it and retry + throw $e; + } + } + } + } + /** * Assign new ar_rev_ids to a set of ar_ids. * @param IDatabase $dbw @@ -171,7 +220,43 @@ class PopulateArchiveRevId extends LoggedUpdateMaintenance { ); } if ( !$rev ) { - throw new UnexpectedValueException( 'No revisions are available to copy' ); + // Since no revisions are available to copy, generate a dummy + // revision to a dummy page, then rollback the commit + wfDebug( __METHOD__ . ": No revisions are available to copy\n" ); + + $dbw->begin(); + + // Make a title and revision and insert them + $title = Title::newFromText( "PopulateArchiveRevId_4b05b46a81e29" ); + $page = WikiPage::factory( $title ); + $updater = $page->newPageUpdater( + User::newSystemUser( 'Maintenance script', [ 'steal' => true ] ) + ); + $updater->setContent( + 'main', + ContentHandler::makeContent( "Content for dummy rev", $title ) + ); + $updater->saveRevision( + CommentStoreComment::newUnsavedComment( 'dummy rev summary' ), + EDIT_NEW | EDIT_SUPPRESS_RC + ); + + // get the revision row just inserted + $rev = $dbw->selectRow( + 'revision', + '*', + [], + __METHOD__, + [ 'ORDER BY' => 'rev_timestamp ASC' ] + ); + + $dbw->rollback(); + } + if ( !$rev ) { + // This should never happen. + throw new UnexpectedValueException( + 'No revisions are available to copy, and one couldn\'t be created' + ); } unset( $rev->rev_id );