file = $file; $this->pos = $pos; $this->gtids = array_map( 'trim', explode( ',', $gtid ) ); $this->asOfTime = microtime( true ); } /** * @return string /, e.g db1034-bin.000976/843431247 */ function __toString() { return "{$this->file}/{$this->pos}"; } function asOfTime() { return $this->asOfTime; } function hasReached( DBMasterPos $pos ) { if ( !( $pos instanceof self ) ) { throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ ); } // Prefer GTID comparisons, which work with multi-tier replication $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 foreach ( $thatPosByDomain as $domain => $thatPos ) { $thisPos = isset( $thisPosByDomain[$domain] ) ? $thisPosByDomain[$domain] : -1; $reached = $reached && ( $thatPos <= $thisPos ); } return $reached; } // Fallback to the binlog file comparisons $thisBinPos = $this->getBinlogCoordinates(); $thatBinPos = $pos->getBinlogCoordinates(); if ( $thisBinPos && $thatBinPos && $thisBinPos['binlog'] === $thatBinPos['binlog'] ) { return ( $thisBinPos['pos'] >= $thatBinPos['pos'] ); } // Comparing totally different binlogs does not make sense return false; } function channelsMatch( DBMasterPos $pos ) { if ( !( $pos instanceof self ) ) { throw new InvalidArgumentException( "Position not an instance of " . __CLASS__ ); } // Prefer GTID comparisons, which work with multi-tier replication $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 ); } // Fallback to the binlog file comparisons $thisBinPos = $this->getBinlogCoordinates(); $thatBinPos = $pos->getBinlogCoordinates(); return ( $thisBinPos && $thatBinPos && $thisBinPos['binlog'] === $thatBinPos['binlog'] ); } /** * @note: this returns false for multi-source replication GTID sets * @see https://mariadb.com/kb/en/mariadb/gtid * @see https://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html * @return array Map of (domain => integer position) or false */ protected function getGtidCoordinates() { $gtidInfos = []; foreach ( $this->gtids as $gtid ) { $m = []; // MariaDB style: -- if ( preg_match( '!^(\d+)-\d+-(\d+)$!', $gtid, $m ) ) { $gtidInfos[(int)$m[1]] = (int)$m[2]; // MySQL style: : } elseif ( preg_match( '!^(\w{8}-\w{4}-\w{4}-\w{4}-\w{12}):(\d+)$!', $gtid, $m ) ) { $gtidInfos[$m[1]] = (int)$m[2]; } else { $gtidInfos = []; break; // unrecognized GTID } } return $gtidInfos; } /** * @see http://dev.mysql.com/doc/refman/5.7/en/show-master-status.html * @see http://dev.mysql.com/doc/refman/5.7/en/show-slave-status.html * @return array|bool (binlog, (integer file number, integer position)) or false */ protected function getBinlogCoordinates() { $m = []; if ( preg_match( '!^(.+)\.(\d+)/(\d+)$!', (string)$this, $m ) ) { return [ 'binlog' => $m[1], 'pos' => [ (int)$m[2], (int)$m[3] ] ]; } return false; } }