25 use Psr\Log\LoggerInterface;
26 use Psr\Log\NullLogger;
27 use Wikimedia\ScopedCallback;
32 use InvalidArgumentException;
120 const CONN_HELD_WARN_THRESHOLD = 10;
123 const MAX_LAG_DEFAULT = 10;
125 const TTL_CACHE_READONLY = 5;
136 if ( !isset(
$params[
'servers'] ) ) {
137 throw new InvalidArgumentException( __CLASS__ .
': missing servers parameter' );
139 $this->mServers =
$params[
'servers'];
140 foreach ( $this->mServers
as $i => $server ) {
142 $this->mServers[$i][
'master'] =
true;
144 $this->mServers[$i][
'replica'] =
true;
148 $this->localDomain = isset(
$params[
'localDomain'] )
153 if ( $this->localDomain->getTablePrefix() !=
'' ) {
154 $this->localDomainIdAlias =
155 $this->localDomain->getDatabase() .
'-' . $this->localDomain->getTablePrefix();
157 $this->localDomainIdAlias = $this->localDomain->getDatabase();
160 $this->mWaitTimeout = isset(
$params[
'waitTimeout'] ) ?
$params[
'waitTimeout'] : 10;
162 $this->mReadIndex = -1;
165 self::KEY_LOCAL => [],
166 self::KEY_FOREIGN_INUSE => [],
167 self::KEY_FOREIGN_FREE => [],
169 self::KEY_LOCAL_NOROUND => [],
170 self::KEY_FOREIGN_INUSE_NOROUND => [],
171 self::KEY_FOREIGN_FREE_NOROUND => []
174 $this->mWaitForPos =
false;
175 $this->mAllowLagged =
false;
177 if ( isset(
$params[
'readOnlyReason'] ) && is_string(
$params[
'readOnlyReason'] ) ) {
178 $this->readOnlyReason =
$params[
'readOnlyReason'];
181 if ( isset(
$params[
'loadMonitor'] ) ) {
182 $this->loadMonitorConfig =
$params[
'loadMonitor'];
184 $this->loadMonitorConfig = [
'class' =>
'LoadMonitorNull' ];
187 foreach (
$params[
'servers']
as $i => $server ) {
188 $this->mLoads[$i] = $server[
'load'];
189 if ( isset( $server[
'groupLoads'] ) ) {
190 foreach ( $server[
'groupLoads']
as $group => $ratio ) {
191 if ( !isset( $this->mGroupLoads[$group] ) ) {
192 $this->mGroupLoads[$group] = [];
194 $this->mGroupLoads[$group][$i] = $ratio;
199 if ( isset(
$params[
'srvCache'] ) ) {
200 $this->srvCache =
$params[
'srvCache'];
204 if ( isset(
$params[
'wanCache'] ) ) {
205 $this->wanCache =
$params[
'wanCache'];
209 $this->profiler = isset(
$params[
'profiler'] ) ?
$params[
'profiler'] :
null;
210 if ( isset(
$params[
'trxProfiler'] ) ) {
211 $this->trxProfiler =
$params[
'trxProfiler'];
216 $this->errorLogger = isset(
$params[
'errorLogger'] )
218 :
function ( Exception
$e ) {
219 trigger_error( get_class(
$e ) .
': ' .
$e->getMessage(), E_USER_WARNING );
222 foreach ( [
'replLogger',
'connLogger',
'queryLogger',
'perfLogger' ]
as $key ) {
223 $this->$key = isset(
$params[$key] ) ?
$params[$key] :
new NullLogger();
226 $this->host = isset(
$params[
'hostname'] )
228 : ( gethostname() ?:
'unknown' );
229 $this->cliMode = isset(
$params[
'cliMode'] ) ?
$params[
'cliMode'] : PHP_SAPI ===
'cli';
232 if ( isset(
$params[
'chronologyProtector'] ) ) {
233 $this->chronProt =
$params[
'chronologyProtector'];
243 if ( !isset( $this->loadMonitor ) ) {
250 $class = $this->loadMonitorConfig[
'class'];
251 if ( isset( $compat[$class] ) ) {
252 $class = $compat[$class];
255 $this->loadMonitor =
new $class(
256 $this, $this->srvCache, $this->wanCache, $this->loadMonitorConfig );
257 $this->loadMonitor->setLogger( $this->replLogger );
272 # Unset excessively lagged servers
273 foreach ( $lags
as $i => $lag ) {
275 # How much lag this server nominally is allowed to have
276 $maxServerLag = isset( $this->mServers[$i][
'max lag'] )
277 ? $this->mServers[$i][
'max lag']
278 : self::MAX_LAG_DEFAULT;
279 # Constrain that futher by $maxLag argument
280 $maxServerLag = min( $maxServerLag, $maxLag );
283 if ( $lag ===
false && !is_infinite( $maxServerLag ) ) {
284 $this->replLogger->error(
285 "Server {host} is not replicating?", [
'host' =>
$host ] );
287 } elseif ( $lag > $maxServerLag ) {
288 $this->replLogger->debug(
290 ": server {host} has {lag} seconds of lag (>= {maxlag})",
291 [
'host' =>
$host,
'lag' => $lag,
'maxlag' => $maxServerLag ]
298 # Find out if all the replica DBs with non-zero load are lagged
300 foreach ( $loads
as $load ) {
304 # No appropriate DB servers except maybe the master and some replica DBs with zero load
305 # Do NOT use the master
306 # Instead, this function will return false, triggering read-only mode,
307 # and a lagged replica DB will be used instead.
311 if (
count( $loads ) == 0 ) {
315 # Return a random representative of the remainder
320 if (
count( $this->mServers ) == 1 ) {
323 } elseif ( $group ===
false && $this->mReadIndex >= 0 ) {
328 if ( $group !==
false ) {
330 if ( isset( $this->mGroupLoads[$group] ) ) {
331 $loads = $this->mGroupLoads[$group];
334 $this->connLogger->info( __METHOD__ .
": no loads for group $group" );
348 if ( $i ===
false ) {
358 if ( !$this->
doWait( $i ) ) {
363 if ( $this->mReadIndex <= 0 && $this->mLoads[$i] > 0 && $group ===
false ) {
365 $this->mReadIndex = $i;
368 $this->laggedReplicaMode =
true;
373 $this->connLogger->debug( __METHOD__ .
": using server $serverName for group '$group'" );
384 if ( !
count( $loads ) ) {
385 throw new InvalidArgumentException(
"Empty server array given to LoadBalancer" );
394 $currentLoads = $loads;
395 while (
count( $currentLoads ) ) {
400 if ( $this->mWaitForPos && $this->mWaitForPos->asOfTime() ) {
404 $ago = microtime(
true ) - $this->mWaitForPos->asOfTime();
408 if ( $i ===
false ) {
412 if ( $i ===
false &&
count( $currentLoads ) != 0 ) {
414 $this->replLogger->error(
"All replica DBs lagged. Switch to read-only mode" );
420 if ( $i ===
false ) {
424 $this->connLogger->debug( __METHOD__ .
": pickRandom() returned false" );
426 return [
false,
false ];
430 $this->connLogger->debug( __METHOD__ .
": Using reader #$i: $serverName..." );
434 $this->connLogger->warning( __METHOD__ .
": Failed connecting to $i/$domain" );
435 unset( $currentLoads[$i] );
442 if ( $domain !==
false ) {
451 if ( !
count( $currentLoads ) ) {
452 $this->connLogger->error(
"All servers down" );
461 $this->mWaitForPos = $pos;
465 if ( !$this->
doWait( $i ) ) {
466 $this->laggedReplicaMode =
true;
478 $this->mWaitForPos = $pos;
485 $readLoads = array_filter( $readLoads );
490 $ok = $this->
doWait( $i,
true, $timeout );
495 # Restore the old position, as this is not used for lag-protection but for throttling
496 $this->mWaitForPos = $oldPos;
505 $this->mWaitForPos = $pos;
506 $serverCount =
count( $this->mServers );
509 for ( $i = 1; $i < $serverCount; $i++ ) {
510 if ( $this->mLoads[$i] > 0 ) {
511 $ok = $this->
doWait( $i,
true, $timeout ) && $ok;
515 # Restore the old position, as this is not used for lag-protection but for throttling
516 $this->mWaitForPos = $oldPos;
530 if ( !$this->mWaitForPos || $pos->hasReached( $this->mWaitForPos ) ) {
531 $this->mWaitForPos = $pos;
540 foreach ( $this->mConns
as $connsByServer ) {
541 if ( !empty( $connsByServer[$i] ) ) {
543 $serverConns = $connsByServer[$i];
545 return reset( $serverConns );
559 protected function doWait( $index, $open =
false, $timeout =
null ) {
564 $key = $this->srvCache->makeGlobalKey( __CLASS__,
'last-known-pos', $server,
'v1' );
566 $knownReachedPos = $this->srvCache->get( $key );
569 $knownReachedPos->
hasReached( $this->mWaitForPos )
571 $this->replLogger->debug( __METHOD__ .
572 ": replica DB $server known to be caught up (pos >= $knownReachedPos)." );
580 $this->replLogger->debug( __METHOD__ .
": no connection open for $server" );
586 $this->replLogger->warning( __METHOD__ .
": failed to connect to $server" );
596 $this->replLogger->info( __METHOD__ .
": Waiting for replica DB $server to catch up..." );
598 $result = $conn->masterPosWait( $this->mWaitForPos, $timeout );
602 $this->replLogger->warning(
603 __METHOD__ .
": Timed out waiting on {host} pos {$this->mWaitForPos}",
604 [
'host' => $server ]
608 $this->replLogger->info( __METHOD__ .
": Done" );
622 if ( $i ===
null || $i ===
false ) {
623 throw new InvalidArgumentException(
'Attempt to call ' . __METHOD__ .
624 ' with invalid server index' );
631 $groups = ( $groups ===
false || $groups === [] )
641 # Try to find an available server in any the query groups (in order)
642 foreach ( $groups
as $group ) {
644 if ( $groupIndex !==
false ) {
651 # Operation-based index
653 $this->mLastError =
'Unknown error';
654 # Try the general server pool if $groups are unavailable.
655 $i = ( $groups === [
false ] )
658 # Couldn't find a working server in getReaderIndex()?
659 if ( $i ===
false ) {
667 # Now we have an explicit index into the servers array
675 # Profile any new connections that happen
676 if ( $this->connsOpened > $oldConnsOpened ) {
677 $host = $conn->getServer();
678 $dbname = $conn->getDBname();
679 $this->trxProfiler->recordConnection(
$host, $dbname, $masterOnly );
683 # Make master-requested DB handles inherit any read-only mode setting
684 $conn->setLBInfo(
'readOnlyReason', $this->
getReadOnlyReason( $domain, $conn ) );
691 $serverIndex = $conn->getLBInfo(
'serverIndex' );
692 $refCount = $conn->getLBInfo(
'foreignPoolRefCount' );
693 if ( $serverIndex ===
null || $refCount ===
null ) {
705 } elseif ( $conn instanceof
DBConnRef ) {
708 $this->connLogger->error( __METHOD__ .
": got DBConnRef instance.\n" .
709 (
new RuntimeException() )->getTraceAsString() );
714 if ( $this->disabled ) {
718 if ( $conn->getLBInfo(
'autoCommitOnly' ) ) {
726 $domain = $conn->getDomainID();
727 if ( !isset( $this->mConns[$connInUseKey][$serverIndex][$domain] ) ) {
728 throw new InvalidArgumentException( __METHOD__ .
729 ": connection $serverIndex/$domain not found; it may have already been freed." );
730 } elseif ( $this->mConns[$connInUseKey][$serverIndex][$domain] !== $conn ) {
731 throw new InvalidArgumentException( __METHOD__ .
732 ": connection $serverIndex/$domain mismatched; it may have already been freed." );
735 $conn->setLBInfo(
'foreignPoolRefCount', --$refCount );
736 if ( $refCount <= 0 ) {
737 $this->mConns[$connFreeKey][$serverIndex][$domain] = $conn;
738 unset( $this->mConns[$connInUseKey][$serverIndex][$domain] );
739 if ( !$this->mConns[$connInUseKey][$serverIndex] ) {
740 unset( $this->mConns[$connInUseKey][$serverIndex] );
742 $this->connLogger->debug( __METHOD__ .
": freed connection $serverIndex/$domain" );
744 $this->connLogger->debug( __METHOD__ .
745 ": reference count for $serverIndex/$domain reduced to $refCount" );
750 $domain = ( $domain !==
false ) ? $domain : $this->localDomain;
756 $domain = ( $domain !==
false ) ? $domain : $this->localDomain;
762 $domain = ( $domain !==
false ) ? $domain : $this->localDomain;
773 if ( !$this->chronProtInitialized && $this->chronProt ) {
774 $this->connLogger->debug( __METHOD__ .
': calling initLB() before first connection.' );
776 $this->chronProtInitialized =
true;
777 $this->chronProt->initLB( $this );
784 $autoCommit = ( (
$flags & self::CONN_TRX_AUTO ) == self::CONN_TRX_AUTO );
786 if ( $domain !==
false ) {
792 if ( isset( $this->mConns[$connKey][$i][0] ) ) {
793 $conn = $this->mConns[$connKey][$i][0];
795 if ( !isset( $this->mServers[$i] ) || !is_array( $this->mServers[$i] ) ) {
796 throw new InvalidArgumentException(
"No server with index '$i'." );
799 $server = $this->mServers[$i];
800 $server[
'serverIndex'] = $i;
801 $server[
'autoCommitOnly'] = $autoCommit;
804 if ( $conn->isOpen() ) {
805 $this->connLogger->debug(
"Connected to database $i at '$host'." );
806 $this->mConns[$connKey][$i][0] = $conn;
808 $this->connLogger->warning(
"Failed to connect to database $i at '$host'." );
809 $this->errorConnection = $conn;
820 $this->errorConnection = $conn;
824 if ( $autoCommit && $conn instanceof
IDatabase ) {
854 $dbName = $domainInstance->getDatabase();
855 $prefix = $domainInstance->getTablePrefix();
856 $autoCommit = ( (
$flags & self::CONN_TRX_AUTO ) == self::CONN_TRX_AUTO );
866 if ( isset( $this->mConns[$connInUseKey][$i][$domain] ) ) {
868 $conn = $this->mConns[$connInUseKey][$i][$domain];
869 $this->connLogger->debug( __METHOD__ .
": reusing connection $i/$domain" );
870 } elseif ( isset( $this->mConns[$connFreeKey][$i][$domain] ) ) {
872 $conn = $this->mConns[$connFreeKey][$i][$domain];
873 unset( $this->mConns[$connFreeKey][$i][$domain] );
874 $this->mConns[$connInUseKey][$i][$domain] = $conn;
875 $this->connLogger->debug( __METHOD__ .
": reusing free connection $i/$domain" );
876 } elseif ( !empty( $this->mConns[$connFreeKey][$i] ) ) {
878 $conn = reset( $this->mConns[$connFreeKey][$i] );
879 $oldDomain =
key( $this->mConns[$connFreeKey][$i] );
882 if ( strlen( $dbName ) && !$conn->selectDB( $dbName ) ) {
883 $this->mLastError =
"Error selecting database '$dbName' on server " .
884 $conn->getServer() .
" from client host {$this->host}";
885 $this->errorConnection = $conn;
888 $conn->tablePrefix( $prefix );
889 unset( $this->mConns[$connFreeKey][$i][$oldDomain] );
890 $this->mConns[$connInUseKey][$i][$domain] = $conn;
891 $this->connLogger->debug( __METHOD__ .
892 ": reusing free connection from $oldDomain for $domain" );
895 if ( !isset( $this->mServers[$i] ) || !is_array( $this->mServers[$i] ) ) {
896 throw new InvalidArgumentException(
"No server with index '$i'." );
899 $server = $this->mServers[$i];
900 $server[
'serverIndex'] = $i;
901 $server[
'foreignPoolRefCount'] = 0;
902 $server[
'foreign'] =
true;
903 $server[
'autoCommitOnly'] = $autoCommit;
905 if ( !$conn->isOpen() ) {
906 $this->connLogger->warning( __METHOD__ .
": connection error for $i/$domain" );
907 $this->errorConnection = $conn;
910 $conn->tablePrefix( $prefix );
911 $this->mConns[$connInUseKey][$i][$domain] = $conn;
912 $this->connLogger->debug( __METHOD__ .
": opened new connection for $i/$domain" );
918 $refCount = $conn->getLBInfo(
'foreignPoolRefCount' );
919 $conn->setLBInfo(
'foreignPoolRefCount', $refCount + 1 );
933 if ( !is_integer( $index ) ) {
952 if ( $this->disabled ) {
956 if ( $dbNameOverride !==
false ) {
957 $server[
'dbname'] = $dbNameOverride;
962 $server[
'clusterMasterHost'] = $masterName;
965 if ( ++$this->connsOpened >= self::CONN_HELD_WARN_THRESHOLD ) {
966 $this->perfLogger->warning( __METHOD__ .
": " .
967 "{$this->connsOpened}+ connections made (master=$masterName)" );
993 $db->setLBInfo( $server );
994 $db->setLazyMasterHandle(
997 $db->setTableAliases( $this->tableAliases );
1000 if ( $this->trxRoundId !==
false ) {
1003 foreach ( $this->trxRecurringCallbacks
as $name => $callback ) {
1004 $db->setTransactionListener(
$name, $callback );
1017 'method' => __METHOD__,
1022 $context[
'db_server'] = $conn->getServer();
1023 $this->connLogger->warning(
1024 "Connection error: {last_error} ({db_server})",
1029 $conn->reportConnectionError(
"{$this->mLastError} ({$context['db_server']})" );
1032 $this->connLogger->error(
1033 "LB failure with no last connection. Connection error: {last_error}",
1047 return array_key_exists( $i, $this->mServers );
1051 return array_key_exists( $i, $this->mServers ) && $this->mLoads[$i] != 0;
1055 return count( $this->mServers );
1059 if ( isset( $this->mServers[$i][
'hostName'] ) ) {
1060 $name = $this->mServers[$i][
'hostName'];
1061 } elseif ( isset( $this->mServers[$i][
'host'] ) ) {
1062 $name = $this->mServers[$i][
'host'];
1067 return (
$name !=
'' ) ?
$name :
'localhost';
1071 return isset( $this->mServers[$i][
'type'] ) ? $this->mServers[$i][
'type'] :
'unknown';
1079 if ( isset( $this->mServers[$i] ) ) {
1080 return $this->mServers[$i];
1091 $this->mServers[$i] = $serverInfo;
1095 # If this entire request was served from a replica DB without opening a connection to the
1096 # master (however unlikely that may be), then we can fetch the position from the replica DB.
1098 if ( !$masterConn ) {
1099 $serverCount =
count( $this->mServers );
1100 for ( $i = 1; $i < $serverCount; $i++ ) {
1103 return $conn->getReplicaPos();
1107 return $masterConn->getMasterPos();
1115 $this->disabled =
true;
1121 $this->connLogger->debug(
"Closing connection to database '$host'." );
1126 self::KEY_LOCAL => [],
1127 self::KEY_FOREIGN_INUSE => [],
1128 self::KEY_FOREIGN_FREE => [],
1129 self::KEY_LOCAL_NOROUND => [],
1130 self::KEY_FOREIGN_INUSE_NOROUND => [],
1131 self::KEY_FOREIGN_FREE_NOROUND => []
1133 $this->connsOpened = 0;
1137 $serverIndex = $conn->
getLBInfo(
'serverIndex' );
1138 foreach ( $this->mConns
as $type => $connsByServer ) {
1139 if ( !isset( $connsByServer[$serverIndex] ) ) {
1143 foreach ( $connsByServer[$serverIndex]
as $i => $trackedConn ) {
1144 if ( $conn === $trackedConn ) {
1146 $this->connLogger->debug(
"Closing connection to database $i at '$host'." );
1147 unset( $this->mConns[
$type][$serverIndex][$i] );
1160 $restore = ( $this->trxRoundId !==
false );
1161 $this->trxRoundId =
false;
1167 call_user_func( $this->errorLogger,
$e );
1168 $failures[] =
"{$conn->getServer()}: {$e->getMessage()}";
1170 if ( $restore && $conn->
getLBInfo(
'master' ) ) {
1179 "Commit failed on server(s) " . implode(
"\n", array_unique( $failures ) )
1195 $limit = isset(
$options[
'maxWriteDuration'] ) ?
$options[
'maxWriteDuration'] : 0;
1203 "Explicit transaction still active. A caller may have caught an error."
1209 if ( $limit > 0 &&
$time > $limit ) {
1212 "Transaction spent $time second(s) in writes, exceeding the limit of $limit.",
1221 "A connection to the {$conn->getDBname()} database was lost before commit."
1228 if ( $this->trxRoundId !==
false ) {
1231 "$fname: Transaction round '{$this->trxRoundId}' already started."
1234 $this->trxRoundId =
$fname;
1243 call_user_func( $this->errorLogger,
$e );
1244 $failures[] =
"{$conn->getServer()}: {$e->getMessage()}";
1254 "$fname: Flush failed on server(s) " . implode(
"\n", array_unique( $failures ) )
1265 $restore = ( $this->trxRoundId !==
false );
1266 $this->trxRoundId =
false;
1272 } elseif ( $restore ) {
1276 call_user_func( $this->errorLogger,
$e );
1277 $failures[] =
"{$conn->getServer()}: {$e->getMessage()}";
1288 "$fname: Commit failed on server(s) " . implode(
"\n", array_unique( $failures ) )
1301 $this->queryLogger->info( __METHOD__ .
": found writes/callbacks pending." );
1313 }
catch ( Exception $ex ) {
1318 }
catch ( Exception $ex ) {
1327 $restore = ( $this->trxRoundId !==
false );
1328 $this->trxRoundId =
false;
1351 if ( $conn->
getLBInfo(
'autoCommitOnly' ) ) {
1369 if ( $conn->
getLBInfo(
'autoCommitOnly' ) ) {
1394 return (
bool)$pending;
1407 $age = ( $age === null ) ? $this->mWaitTimeout : $age;
1424 if ( !$this->laggedReplicaMode && $this->
getServerCount() > 1 ) {
1431 $this->allReplicasDownMode =
true;
1432 $this->laggedReplicaMode =
true;
1462 if ( $this->readOnlyReason !==
false ) {
1465 if ( $this->allReplicasDownMode ) {
1466 return 'The database has been automatically locked ' .
1467 'until the replica database servers become available';
1469 return 'The database has been automatically locked ' .
1470 'while the replica database servers catch up to the master.';
1473 return 'The database master is running in read-only mode.';
1488 return (
bool)
$cache->getWithSetCallback(
1489 $cache->makeGlobalKey( __CLASS__,
'server-read-only', $masterServer ),
1490 self::TTL_CACHE_READONLY,
1491 function ()
use ( $domain, $conn ) {
1492 $old = $this->trxProfiler->setSilenced(
true );
1495 $readOnly = (int)$dbw->serverIsReadOnly();
1502 $this->trxProfiler->setSilenced( $old );
1505 [
'pcTTL' => $cache::TTL_PROC_LONG,
'busyValue' => 0 ]
1510 if ( $mode ===
null ) {
1513 $this->mAllowLagged = $mode;
1521 if ( !$conn->
ping() ) {
1530 foreach ( $this->mConns
as $connsByServer ) {
1531 foreach ( $connsByServer
as $serverConns ) {
1532 foreach ( $serverConns
as $conn ) {
1533 $mergedParams = array_merge( [ $conn ],
$params );
1534 call_user_func_array( $callback, $mergedParams );
1542 foreach ( $this->mConns
as $connsByServer ) {
1543 if ( isset( $connsByServer[$masterIndex] ) ) {
1545 foreach ( $connsByServer[$masterIndex]
as $conn ) {
1546 $mergedParams = array_merge( [ $conn ],
$params );
1547 call_user_func_array( $callback, $mergedParams );
1554 foreach ( $this->mConns
as $connsByServer ) {
1555 foreach ( $connsByServer
as $i => $serverConns ) {
1559 foreach ( $serverConns
as $conn ) {
1560 $mergedParams = array_merge( [ $conn ],
$params );
1561 call_user_func_array( $callback, $mergedParams );
1573 return [
$host, $maxLag, $maxIndex ];
1577 foreach ( $lagTimes
as $i => $lag ) {
1578 if ( $this->mLoads[$i] > 0 && $lag > $maxLag ) {
1580 $host = $this->mServers[$i][
'host'];
1585 return [
$host, $maxLag, $maxIndex ];
1593 $knownLagTimes = [];
1594 $indexesWithLag = [];
1595 foreach ( $this->mServers
as $i => $server ) {
1596 if ( empty( $server[
'is static'] ) ) {
1597 $indexesWithLag[] = $i;
1599 $knownLagTimes[$i] = 0;
1603 return $this->
getLoadMonitor()->getLagTimes( $indexesWithLag, $domain ) + $knownLagTimes;
1628 if ( $masterConn ) {
1629 $pos = $masterConn->getMasterPos();
1632 $pos = $masterConn->getMasterPos();
1640 $msg = __METHOD__ .
": Timed out waiting on {$conn->getServer()} pos {$pos}";
1641 $this->replLogger->warning(
"$msg" );
1644 $this->replLogger->info( __METHOD__ .
": Done" );
1649 $this->replLogger->error(
"Could not get master pos for {$conn->getServer()}." );
1657 $this->trxRecurringCallbacks[
$name] = $callback;
1659 unset( $this->trxRecurringCallbacks[
$name] );
1669 $this->tableAliases = $aliases;
1678 if ( $conn->
getLBInfo(
'foreignPoolRefCount' ) > 0 ) {
1684 if ( $domainsInUse ) {
1685 $domains = implode(
', ', $domainsInUse );
1687 "Foreign domain connections are still in use ($domains)." );
1691 $this->localDomain->getDatabase(),
1708 if ( PHP_SAPI !=
'cli' ) {
1709 $old = ignore_user_abort(
true );
1710 return new ScopedCallback(
function ()
use ( $old ) {
1711 ignore_user_abort( $old );