Merge "rdbms: make MySQLMasterPos handle inactive GTIDs"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 16 Feb 2018 00:11:48 +0000 (00:11 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 16 Feb 2018 00:11:48 +0000 (00:11 +0000)
includes/libs/rdbms/database/position/MySQLMasterPos.php
tests/phpunit/includes/libs/rdbms/database/DatabaseMysqlBaseTest.php

index e5bb2c0..62809cd 100644 (file)
@@ -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
index b2eabb1..ce067aa 100644 (file)
@@ -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
                        ],
                ];