143 public function silenceForScope(
string $type = self::EXPECTATION_ANY ): ScopedCallback {
144 if ( $type === self::EXPECTATION_REPLICAS_ONLY ) {
146 foreach ( [
'writes',
'masterConns' ] as $event ) {
147 if ( $this->expect[$event][self::FLD_LIMIT] === 0 ) {
152 $events = self::EVENT_NAMES;
155 foreach ( $events as $event ) {
156 ++$this->silenced[$event];
159 return new ScopedCallback(
function () use ( $events ) {
160 foreach ( $events as $event ) {
161 --$this->silenced[$event];
359 ?
string $serverName =
null,
360 ?
string $fname =
null,
362 $eTime = $this->getCurrentTime();
363 $elapsed = ( $eTime - $sTime );
365 if ( $isWrite && $this->isAboveThreshold( $rowCount,
'maxAffected' ) ) {
366 $this->reportExpectationViolated(
'maxAffected', $query, $rowCount, $trxId, $serverName );
367 } elseif ( !$isWrite && $this->isAboveThreshold( $rowCount,
'readQueryRows' ) ) {
368 $this->reportExpectationViolated(
'readQueryRows', $query, $rowCount, $trxId, $serverName );
372 if ( $this->pingAndCheckThreshold(
'queries' ) ) {
373 $this->reportExpectationViolated(
'queries', $query, $this->hits[
'queries'], $trxId, $serverName );
375 if ( $isWrite && $this->pingAndCheckThreshold(
'writes' ) ) {
376 $this->reportExpectationViolated(
'writes', $query, $this->hits[
'writes'], $trxId, $serverName );
378 if ( $fname !==
null && $this->pingAndCheckThresholdFname(
'queriesPerCaller', $fname ) ) {
379 $this->reportExpectationViolated(
382 $this->hitsFName[
'queriesPerCaller'][$fname] .
' by ' . $fname,
388 if ( !$isWrite && $this->isAboveThreshold( $elapsed,
'readQueryTime' ) ) {
389 $this->reportExpectationViolated(
'readQueryTime', $query, $elapsed, $trxId, $serverName );
391 if ( $isWrite && $this->isAboveThreshold( $elapsed,
'writeQueryTime' ) ) {
392 $this->reportExpectationViolated(
'writeQueryTime', $query, $elapsed, $trxId, $serverName );
395 if ( !$this->dbTrxHoldingLocks ) {
398 } elseif ( !$isWrite && $elapsed < self::EVENT_THRESHOLD_SEC ) {
403 foreach ( $this->dbTrxHoldingLocks as $name => $info ) {
404 $lastQuery = end( $this->dbTrxMethodTimes[$name] );
407 $lastEnd = $lastQuery[2];
408 if ( $sTime >= $lastEnd ) {
409 if ( ( $sTime - $lastEnd ) > self::EVENT_THRESHOLD_SEC ) {
411 $this->dbTrxMethodTimes[$name][] = [
'...delay...', $lastEnd, $sTime ];
413 $this->dbTrxMethodTimes[$name][] = [ $query, $sTime, $eTime ];
417 if ( $sTime >= $info[
'start'] ) {
418 $this->dbTrxMethodTimes[$name][] = [ $query, $sTime, $eTime ];
445 $name =
"{$db} {$server} TRX#$id";
446 if ( !isset( $this->dbTrxMethodTimes[$name] ) ) {
447 $this->logger->warning(
"Detected no transaction for '$name' - out of sync." );
454 if ( $this->isAboveThreshold( $writeTime,
'writeQueryTime' ) ) {
455 $this->reportExpectationViolated(
457 "[transaction writes to {$db} at {$server}]",
464 if ( $this->isAboveThreshold( $affected,
'maxAffected' ) ) {
465 $this->reportExpectationViolated(
467 "[transaction writes to {$db} at {$server}]",
473 $lastQuery = end( $this->dbTrxMethodTimes[$name] );
475 $now = $this->getCurrentTime();
476 $lastEnd = $lastQuery[2];
477 if ( ( $now - $lastEnd ) > self::EVENT_THRESHOLD_SEC ) {
478 $this->dbTrxMethodTimes[$name][] = [
'...delay...', $lastEnd, $now ];
482 foreach ( $this->dbTrxMethodTimes[$name] as $info ) {
483 $elapsed = ( $info[2] - $info[1] );
484 if ( $elapsed >= self::DB_LOCK_THRESHOLD_SEC ) {
491 foreach ( $this->dbTrxMethodTimes[$name] as $i => [ $query, $sTime, $end ] ) {
493 "%-2d %.3fs %s\n", $i, ( $end - $sTime ), $this->getGeneralizedSql( $query ) );
495 $this->logger->warning(
"Suboptimal transaction [{dbs}]:\n{trace}", [
496 'dbs' => implode(
', ', array_keys( $this->dbTrxHoldingLocks[$name][
'conns'] ) ),
497 'trace' => mb_substr( $trace, 0, 2000 )
500 unset( $this->dbTrxHoldingLocks[$name] );
501 unset( $this->dbTrxMethodTimes[$name] );