26use Psr\Log\LoggerInterface;
27use Psr\Log\LoggerAwareInterface;
28use Psr\Log\NullLogger;
65 'readQueryTime' => INF,
66 'writeQueryTime' => INF
107 $this->expect[$event] = isset( $this->expect[$event] )
108 ? min( $this->expect[$event],
$value )
110 if ( $this->expect[$event] ==
$value ) {
111 $this->expectBy[$event] =
$fname;
125 foreach ( $expects as $event =>
$value ) {
136 foreach ( $this->hits as &$val ) {
140 foreach ( $this->expect as &$val ) {
144 $this->expectBy = [];
158 if ( $this->hits[
'conns']++ >= $this->expect[
'conns'] ) {
160 'conns',
"[connect to $server ($db)]", $this->hits[
'conns'] );
162 if ( $isMaster && $this->hits[
'masterConns']++ >= $this->expect[
'masterConns'] ) {
164 'masterConns',
"[connect to $server ($db)]", $this->hits[
'masterConns'] );
178 $name =
"{$server} ({$db}) (TRX#$id)";
179 if ( isset( $this->dbTrxHoldingLocks[$name] ) ) {
180 $this->logger->info(
"Nested transaction for '$name' - out of sync." );
182 $this->dbTrxHoldingLocks[
$name] = [
183 'start' => microtime(
true ),
186 $this->dbTrxMethodTimes[
$name] = [];
188 foreach ( $this->dbTrxHoldingLocks as $name => &$info ) {
190 $info[
'conns'][
$name] = 1;
205 $eTime = microtime(
true );
206 $elapsed = ( $eTime - $sTime );
208 if ( $isWrite && $n > $this->expect[
'maxAffected'] ) {
210 "Query affected $n row(s):\n" .
$query .
"\n" .
211 (
new RuntimeException() )->getTraceAsString() );
215 if ( $this->hits[
'queries']++ >= $this->expect[
'queries'] ) {
218 if ( $isWrite && $this->hits[
'writes']++ >= $this->expect[
'writes'] ) {
222 if ( !$isWrite && $elapsed > $this->expect[
'readQueryTime'] ) {
225 if ( $isWrite && $elapsed > $this->expect[
'writeQueryTime'] ) {
229 if ( !$this->dbTrxHoldingLocks ) {
232 } elseif ( !$isWrite && $elapsed < $this->eventThreshold ) {
237 foreach ( $this->dbTrxHoldingLocks as $name => $info ) {
238 $lastQuery = end( $this->dbTrxMethodTimes[$name] );
241 $lastEnd = $lastQuery[2];
242 if ( $sTime >= $lastEnd ) {
243 if ( ( $sTime - $lastEnd ) > $this->eventThreshold ) {
245 $this->dbTrxMethodTimes[
$name][] = [
'...delay...', $lastEnd, $sTime ];
247 $this->dbTrxMethodTimes[
$name][] = [
$query, $sTime, $eTime ];
251 if ( $sTime >= $info[
'start'] ) {
252 $this->dbTrxMethodTimes[
$name][] = [
$query, $sTime, $eTime ];
272 $name =
"{$server} ({$db}) (TRX#$id)";
273 if ( !isset( $this->dbTrxMethodTimes[$name] ) ) {
274 $this->logger->info(
"Detected no transaction for '$name' - out of sync." );
281 if ( $writeTime > $this->expect[
'writeQueryTime'] ) {
284 "[transaction $id writes to {$server} ({$db})]",
290 if ( $affected > $this->expect[
'maxAffected'] ) {
293 "[transaction $id writes to {$server} ({$db})]",
298 $lastQuery = end( $this->dbTrxMethodTimes[$name] );
300 $now = microtime(
true );
301 $lastEnd = $lastQuery[2];
302 if ( ( $now - $lastEnd ) > $this->eventThreshold ) {
303 $this->dbTrxMethodTimes[
$name][] = [
'...delay...', $lastEnd, $now ];
307 foreach ( $this->dbTrxMethodTimes[$name] as $info ) {
308 $elapsed = ( $info[2] - $info[1] );
309 if ( $elapsed >= $this->dbLockThreshold ) {
316 foreach ( $this->dbTrxMethodTimes[$name] as $i => $info ) {
318 $trace .= sprintf(
"%d\t%.6f\t%s\n", $i, ( $end - $sTime ),
$query );
320 $this->logger->info(
"Sub-optimal transaction on DB(s) [{dbs}]: \n{trace}", [
321 'dbs' => implode(
', ', array_keys( $this->dbTrxHoldingLocks[$name][
'conns'] ) ),
325 unset( $this->dbTrxHoldingLocks[$name] );
326 unset( $this->dbTrxMethodTimes[$name] );
335 if ( $this->silenced ) {
340 "Expectation ({measure} <= {max}) by {by} not met (actual: {actual}):\n{query}\n" .
341 (
new RuntimeException() )->getTraceAsString(),
344 'max' => $this->expect[
$expect],
345 'by' => $this->expectBy[
$expect],
if(!defined( 'MEDIAWIKI')) $fname
This file is not a valid entry point, perform no further processing unless MEDIAWIKI is defined.
deferred txt A few of the database updates required by various functions here can be deferred until after the result page is displayed to the user For updating the view updating the linked to tables after a etc PHP does not yet have any way to tell the server to actually return and disconnect while still running these but it might have such a feature in the future We handle these by creating a deferred update object and putting those objects on a global list
Allows to change the fields on the form that will be generated $name
null for the local wiki Added should default to null in handler for backwards compatibility add a value to it if you want to add a cookie that have to vary cache options can modify $query