/**
  * Wait for the slave to catch up to a given master position.
  * @todo Return values for this and base class are rubbish
  *
  * @param DBMasterPos|MySQLMasterPos $pos
  * @param int $timeout The maximum number of seconds to wait for synchronisation
  * @return int Zero if the slave was past that position already,
  *   greater than zero if we waited for some period of time, less than
  *   zero if we timed out.
  */
 function masterPosWait(DBMasterPos $pos, $timeout)
 {
     if ($this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached($pos)) {
         return '0';
         // http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html
     }
     # Commit any open transactions
     $this->commit(__METHOD__, 'flush');
     # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
     $encFile = $this->addQuotes($pos->file);
     $encPos = intval($pos->pos);
     $sql = "SELECT MASTER_POS_WAIT({$encFile}, {$encPos}, {$timeout})";
     $res = $this->doQuery($sql);
     $status = false;
     if ($res) {
         $row = $this->fetchRow($res);
         if ($row) {
             $status = $row[0];
             // can be NULL, -1, or 0+ per the MySQL manual
             if (ctype_digit($status)) {
                 // success
                 $this->lastKnownSlavePos = $pos;
             }
         }
     }
     return $status;
 }
 function masterPosWait(DBMasterPos $pos, $timeout)
 {
     if (!$pos instanceof MySQLMasterPos) {
         throw new InvalidArgumentException("Position not an instance of MySQLMasterPos");
     }
     if ($this->getLBInfo('is static') === true) {
         return 0;
         // this is a copy of a read-only dataset with no master DB
     } elseif ($this->lastKnownReplicaPos && $this->lastKnownReplicaPos->hasReached($pos)) {
         return 0;
         // already reached this point for sure
     }
     // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
     if ($this->useGTIDs && $pos->gtids) {
         // Wait on the GTID set (MariaDB only)
         $gtidArg = $this->addQuotes(implode(',', $pos->gtids));
         $res = $this->doQuery("SELECT MASTER_GTID_WAIT({$gtidArg}, {$timeout})");
     } else {
         // Wait on the binlog coordinates
         $encFile = $this->addQuotes($pos->file);
         $encPos = intval($pos->pos);
         $res = $this->doQuery("SELECT MASTER_POS_WAIT({$encFile}, {$encPos}, {$timeout})");
     }
     $row = $res ? $this->fetchRow($res) : false;
     if (!$row) {
         throw new DBExpectedError($this, "Failed to query MASTER_POS_WAIT()");
     }
     // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
     $status = $row[0] !== null ? intval($row[0]) : null;
     if ($status === null) {
         // T126436: jobs programmed to wait on master positions might be referencing binlogs
         // with an old master hostname. Such calls make MASTER_POS_WAIT() return null. Try
         // to detect this and treat the replica DB as having reached the position; a proper master
         // switchover already requires that the new master be caught up before the switch.
         $replicationPos = $this->getReplicaPos();
         if ($replicationPos && !$replicationPos->channelsMatch($pos)) {
             $this->lastKnownReplicaPos = $replicationPos;
             $status = 0;
         }
     } elseif ($status >= 0) {
         // Remember that this position was reached to save queries next time
         $this->lastKnownReplicaPos = $pos;
     }
     return $status;
 }
Beispiel #3
0
 /**
  * Wait for the slave to catch up to a given master position.
  * @todo Return values for this and base class are rubbish
  *
  * @param DBMasterPos|MySQLMasterPos $pos
  * @param int $timeout The maximum number of seconds to wait for synchronisation
  * @return int Zero if the slave was past that position already,
  *   greater than zero if we waited for some period of time, less than
  *   zero if we timed out.
  */
 function masterPosWait(DBMasterPos $pos, $timeout)
 {
     if ($this->lastKnownSlavePos && $this->lastKnownSlavePos->hasReached($pos)) {
         return '0';
         // http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html
     }
     wfProfileIn(__METHOD__);
     # Commit any open transactions
     $this->commit(__METHOD__, 'flush');
     if (!is_null($this->mFakeSlaveLag)) {
         $wait = intval(($pos->pos - microtime(true) + $this->mFakeSlaveLag) * 1000000.0);
         if ($wait > $timeout * 1000000.0) {
             wfDebug("Fake slave timed out waiting for {$pos} ({$wait} us)\n");
             wfProfileOut(__METHOD__);
             return -1;
         } elseif ($wait > 0) {
             wfDebug("Fake slave waiting {$wait} us\n");
             usleep($wait);
             wfProfileOut(__METHOD__);
             return 1;
         } else {
             wfDebug("Fake slave up to date ({$wait} us)\n");
             wfProfileOut(__METHOD__);
             return 0;
         }
     }
     # Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
     $encFile = $this->addQuotes($pos->file);
     $encPos = intval($pos->pos);
     $sql = "SELECT MASTER_POS_WAIT({$encFile}, {$encPos}, {$timeout})";
     $res = $this->doQuery($sql);
     $status = false;
     if ($res && ($row = $this->fetchRow($res))) {
         $status = $row[0];
         // can be NULL, -1, or 0+ per the MySQL manual
         if (ctype_digit($status)) {
             // success
             $this->lastKnownSlavePos = $pos;
         }
     }
     wfProfileOut(__METHOD__);
     return $status;
 }