Page MenuHomePhabricator

maintenance/update.php fails with error if populateArchiveRevId.php finds duplicate ar_rev_id values in archive table
Closed, DeclinedPublic

Description

I'm trying to upgrade a group of wikis from MW 1.31 to MW 1.35; the update.sh scripts are finding duplicate entries both in the archive table (multiple existing records with same ar_rev_id) and the ipblocks table (multiple existing blocks applied to the same username or IP address).

Because the MW 1.35 "upgrade" is applying new indexes to existing tables, and expecting those indexes to be unique, the maintenance/update.php is failing repeatedly with errors. I have no idea how the duplicates got in there originally (the site was originally on MW 1.6 back in 2006 or so, with multiple upgrades since then) but they're there and update.php is breaking on these.

In theory, the code in maintenance/populateArchiveRevId.php should be attempting to fix T202032 and T193180 by generating a series of "dummy rows" as a source of new ar_rev_id's, then reassigning the duplicate records to those new ID's so that they don't break the unique index on the archive table. That gives this sort of operation:

Running maintenance/deduplicateArchiveRevId.php...
Deduplicating ar_rev_id...
... 170-10169
Row 1869 conflicts with archive row 1867 for rev_id 10832, reassigning
Row 2045 conflicts with revision row for rev_id 11776, reassigning
Row 2284 conflicts with revision row for rev_id 13617, reassigning

which the script tries to handle by creating a series of "dummy rows" in function: PopulateArchiveRevId::reassignArRevIds

Query:

INSERT INTO `revision` (rev_page,rev_text_id,rev_comment,rev_user,rev_user_text,rev_timestamp,rev_minor_edit,rev_deleted,rev_len,rev_parent_id,rev_sha1,rev_content_format,rev_content_model) 
VALUES ('82','550','Dummy row',0,'0.0.0.0','11111111121133','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL)`...

The dummy rows which the scripts attempt to insert look like:

('82','550','Dummy row',0,'0.0.0.0','11111111111111','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL),
('82','550','Dummy row',0,'0.0.0.0','11111111111111','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL),
('82','550','Dummy row',0,'0.0.0.0','11111111111111','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL),
('82','550','Dummy row',0,'0.0.0.0','11111111111111','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL),
('82','550','Dummy row',0,'0.0.0.0','11111111111111','0','0','288','0','ny4bcb69oxm234276d084yov5hjutzm',NULL,NULL)`

which fail with:

Error 1062: Duplicate entry '0.0.0.0-11111111111111-82' for key 'usertext_timestamp' (localhost)

because all of the new dummy records are identical.

The identical records are being created in maintenance/populateArchiveRevId.php lines 157-184, which generate one $dummyRev and use it as array_fill() fodder to populate multiple, identical dummy records.

public static function reassignArRevIds( IDatabase $dbw, array $arIds, array $conds = [] ) {
        if ( !self::$dummyRev ) {
                self::$dummyRev = self::makeDummyRevisionRow( $dbw );
        }

        $updates = $dbw->doAtomicSection( __METHOD__, function ( IDatabase $dbw, $fname ) use ( $arIds ) {
                // Create new rev_ids by inserting dummy rows into revision and then deleting them.
                $dbw->insert( 'revision', array_fill( 0, count( $arIds ), self::$dummyRev ), $fname );
                $revIds = $dbw->selectFieldValues(
                        'revision',
                        'rev_id',
                        // @phan-suppress-next-line PhanTypeArraySuspiciousNullable
                        [ 'rev_timestamp' => self::$dummyRev['rev_timestamp'] ],
                        $fname
                );
                if ( !is_array( $revIds ) ) {
                        throw new UnexpectedValueException( 'Failed to insert dummy revisions' );

At this point, maintenance/update.php simply dies with an error.

Is there a requirement that the indices on this table be unique? If so, how to stop the script from creating identical dummy records - which appear to be failing in such a way as to break the "upgrade"?

Event Timeline

The index which SQL is expecting to be UNIQUE is on the revision table, as
usertext_timestamp (BTREE, unique) on fields: (rev_user_text, rev_timestamp, rev_page)

Inserting multiple, identical dummy records at any point ensures this won't be unique, so it fails.

If I set that index to be not unique for just long enough to run the update script, then set it back, the script gets past this point and breaks later - when it detects that there are still duplicates even after the renumber operation.

Adding index ar_revid_uniq to table archive ...Wikimedia\Rdbms\DBQueryError from line 1699 of .../includes/libs/rdbms/database/Database.php: Error 1062: Duplicate entry '15420' for key 'ar_revid_uniq' (localhost)
Function: Wikimedia\Rdbms\Database::sourceFile( .../maintenance/archives/patch-archive-ar_rev_id-unique.sql )
Query: CREATE UNIQUE INDEX ar_revid_uniq ON archive (ar_rev_id)

It's possible to find these duplicates with something like:

SELECT DISTINCT ar_rev_id, SUM(1) as count from archive group by ar_rev_id having count > 1 order by count desc, ar_rev_id limit 50 

...and then try to kill them off manually. Ouch.