From ab46e904fe67161ff4e017fb16ab5146a754fa10 Mon Sep 17 00:00:00 2001 From: Aaron Schulz Date: Fri, 9 Feb 2018 14:12:44 -0800 Subject: [PATCH] rdbms: make MySQLMasterPos handle inactive GTIDs Change-Id: I328142a9fe10bccb2717a0a392e0c50d0c070390 --- .../database/position/MySQLMasterPos.php | 23 +++--- .../rdbms/database/DatabaseMysqlBaseTest.php | 70 ++++++++++++++++--- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/includes/libs/rdbms/database/position/MySQLMasterPos.php b/includes/libs/rdbms/database/position/MySQLMasterPos.php index e5bb2c0147..62809cd4a8 100644 --- a/includes/libs/rdbms/database/position/MySQLMasterPos.php +++ b/includes/libs/rdbms/database/position/MySQLMasterPos.php @@ -54,14 +54,18 @@ class MySQLMasterPos implements DBMasterPos { $thisPosByDomain = $this->getGtidCoordinates(); $thatPosByDomain = $pos->getGtidCoordinates(); if ( $thisPosByDomain && $thatPosByDomain ) { - $reached = true; - // Check that this has positions GTE all of those in $pos for all domains in $pos + $comparisons = []; + // Check that this has positions reaching those in $pos for all domains in common foreach ( $thatPosByDomain as $domain => $thatPos ) { - $thisPos = isset( $thisPosByDomain[$domain] ) ? $thisPosByDomain[$domain] : -1; - $reached = $reached && ( $thatPos <= $thisPos ); + if ( isset( $thisPosByDomain[$domain] ) ) { + $comparisons[] = ( $thatPos <= $thisPosByDomain[$domain] ); + } } - - return $reached; + // Check that $this has a GTID for at least one domain also in $pos; due to MariaDB + // quirks, prior master switch-overs may result in inactive garbage GTIDs that cannot + // be cleaned up. Assume that the domains in both this and $pos cover the relevant + // active channels. + return ( $comparisons && !in_array( false, $comparisons, true ) ); } // Fallback to the binlog file comparisons @@ -84,8 +88,11 @@ class MySQLMasterPos implements DBMasterPos { $thisPosDomains = array_keys( $this->getGtidCoordinates() ); $thatPosDomains = array_keys( $pos->getGtidCoordinates() ); if ( $thisPosDomains && $thatPosDomains ) { - // Check that this has GTIDs for all domains in $pos - return !array_diff( $thatPosDomains, $thisPosDomains ); + // Check that $this has a GTID for at least one domain also in $pos; due to MariaDB + // quirks, prior master switch-overs may result in inactive garbage GTIDs that cannot + // easily be cleaned up. Assume that the domains in both this and $pos cover the + // relevant active channels. + return array_intersect( $thatPosDomains, $thisPosDomains ) ? true : false; } // Fallback to the binlog file comparisons diff --git a/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php b/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php index b2eabb1fc2..ce067aaa33 100644 --- a/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php +++ b/tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php @@ -228,13 +228,20 @@ class DatabaseMysqlBaseTest extends PHPUnit_Framework_TestCase { * @dataProvider provideComparePositions * @covers Wikimedia\Rdbms\MySQLMasterPos */ - public function testHasReached( MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos, $match ) { + public function testHasReached( + MySQLMasterPos $lowerPos, MySQLMasterPos $higherPos, $match, $hetero + ) { if ( $match ) { $this->assertTrue( $lowerPos->channelsMatch( $higherPos ) ); - $this->assertTrue( $higherPos->hasReached( $lowerPos ) ); - $this->assertTrue( $higherPos->hasReached( $higherPos ) ); + if ( $hetero ) { + // Each position is has one channel higher than the other + $this->assertFalse( $higherPos->hasReached( $lowerPos ) ); + } else { + $this->assertTrue( $higherPos->hasReached( $lowerPos ) ); + } $this->assertTrue( $lowerPos->hasReached( $lowerPos ) ); + $this->assertTrue( $higherPos->hasReached( $higherPos ) ); $this->assertFalse( $lowerPos->hasReached( $higherPos ) ); } else { // channels don't match $this->assertFalse( $lowerPos->channelsMatch( $higherPos ) ); @@ -252,48 +259,93 @@ class DatabaseMysqlBaseTest extends PHPUnit_Framework_TestCase { [ new MySQLMasterPos( 'db1034-bin.000976/843431247', $now ), new MySQLMasterPos( 'db1034-bin.000976/843431248', $now ), - true + true, + false ], [ new MySQLMasterPos( 'db1034-bin.000976/999', $now ), new MySQLMasterPos( 'db1034-bin.000976/1000', $now ), - true + true, + false ], [ new MySQLMasterPos( 'db1034-bin.000976/999', $now ), new MySQLMasterPos( 'db1035-bin.000976/1000', $now ), + false, false ], // MySQL GTID style [ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:23', $now ), new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:24', $now ), - true + true, + false ], [ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:99', $now ), new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:100', $now ), - true + true, + false ], [ new MySQLMasterPos( '3E11FA47-71CA-11E1-9E33-C80AA9429562:99', $now ), new MySQLMasterPos( '1E11FA47-71CA-11E1-9E33-C80AA9429562:100', $now ), + false, false ], // MariaDB GTID style [ new MySQLMasterPos( '255-11-23', $now ), new MySQLMasterPos( '255-11-24', $now ), - true + true, + false ], [ new MySQLMasterPos( '255-11-99', $now ), new MySQLMasterPos( '255-11-100', $now ), - true + true, + false ], [ new MySQLMasterPos( '255-11-999', $now ), new MySQLMasterPos( '254-11-1000', $now ), + false, + false + ], + [ + new MySQLMasterPos( '255-11-23,256-12-50', $now ), + new MySQLMasterPos( '255-11-24', $now ), + true, + false + ], + [ + new MySQLMasterPos( '255-11-99,256-12-50,257-12-50', $now ), + new MySQLMasterPos( '255-11-1000', $now ), + true, + false + ], + [ + new MySQLMasterPos( '255-11-23,256-12-50', $now ), + new MySQLMasterPos( '255-11-24,155-52-63', $now ), + true, + false + ], + [ + new MySQLMasterPos( '255-11-99,256-12-50,257-12-50', $now ), + new MySQLMasterPos( '255-11-1000,256-12-51', $now ), + true, + false + ], + [ + new MySQLMasterPos( '255-11-99,256-12-50', $now ), + new MySQLMasterPos( '255-13-1000,256-14-49', $now ), + true, + true + ], + [ + new MySQLMasterPos( '253-11-999,255-11-999', $now ), + new MySQLMasterPos( '254-11-1000', $now ), + false, false ], ]; -- 2.20.1