*/
$wgDebugDumpSqlLength = 500;
+/**
+ * Performance expectations for DB usage
+ *
+ * @since 1.26
+ */
+$wgTrxProfilerLimits = array(
+ // Basic GET and POST requests
+ 'GET' => array( 'masterConns' => 0, 'writes' => 0, 'readQueryTime' => 5 ),
+ 'POST' => array( 'maxAffected' => 500, 'readQueryTime' => 5, 'writeQueryTime' => 1 ),
+ // Background job runner
+ 'JobRunner' => array( 'maxAffected' => 500, 'readQueryTime' => 30, 'writeQueryTime' => 5 ),
+ // Command-line scripts
+ 'Maintenance' => array( 'maxAffected' => 1000, 'writeQueryTime' => 5 )
+);
+
/**
* Map of string log group names to log destinations.
*
}
private function main() {
- global $wgTitle;
+ global $wgTitle, $wgTrxProfilerLimits;
$request = $this->context->getRequest();
if ( !$request->wasPosted()
&& in_array( $action, array( 'view', 'edit', 'history' ) )
) {
- $trxProfiler->setExpectation( 'masterConns', 0, __METHOD__ );
- $trxProfiler->setExpectation( 'writes', 0, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['GET'], __METHOD__ );
} else {
- $trxProfiler->setExpectation( 'maxAffected', 500, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['POST'], __METHOD__ );
}
// If the user has forceHTTPS set to true, or if the user
* @return array Summary response that can easily be JSON serialized
*/
public function run( array $options ) {
- global $wgJobClasses;
+ global $wgJobClasses, $wgTrxProfilerLimits;
$response = array( 'jobs' => array(), 'reached' => 'none-ready' );
// Catch huge single updates that lead to slave lag
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
- $trxProfiler->setExpectation( 'maxAffected', 500, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['JobRunner'], __METHOD__ );
// Bail out if there is too much DB lag.
// This check should not block as we want to try other wiki queues.
use Psr\Log\LoggerInterface;
use Psr\Log\LoggerAwareInterface;
use Psr\Log\NullLogger;
+
/**
* Helper class that detects high-contention DB queries via profiling calls
*
);
/** @var array */
protected $expect = array(
- 'writes' => INF,
- 'queries' => INF,
- 'conns' => INF,
- 'masterConns' => INF,
- 'maxAffected' => INF
+ 'writes' => INF,
+ 'queries' => INF,
+ 'conns' => INF,
+ 'masterConns' => INF,
+ 'maxAffected' => INF,
+ 'readQueryTime' => INF,
+ 'writeQueryTime' => INF,
);
/** @var array */
protected $expectBy = array();
/**
* Set performance expectations
*
- * With conflicting expect, the most specific ones will be used
+ * With conflicting expectations, the most narrow ones will be used
*
* @param string $event (writes,queries,conns,mConns)
* @param integer $value Maximum count of the event
}
}
+ /**
+ * Set multiple performance expectations
+ *
+ * With conflicting expectations, the most narrow ones will be used
+ *
+ * @param array $expects Map of (event => limit)
+ * @param $fname
+ * @since 1.26
+ */
+ public function setExpectations( array $expects, $fname ) {
+ foreach ( $expects as $event => $value ) {
+ $this->setExpectation( $event, $value, $fname );
+ }
+ }
+
/**
* Reset performance expectations and hit counters
*
$elapsed = ( $eTime - $sTime );
if ( $isWrite && $n > $this->expect['maxAffected'] ) {
- $this->logger->info( "Query affected $n row(s):\n" . $query . "\n" . wfBacktrace( true ) );
+ $this->logger->info( "Query affected $n row(s):\n" . $query . "\n" .
+ wfBacktrace( true ) );
}
// Report when too many writes/queries happen...
if ( $isWrite && $this->hits['writes']++ == $this->expect['writes'] ) {
$this->reportExpectationViolated( 'writes', $query );
}
+ // Report slow queries...
+ if ( !$isWrite && $elapsed > $this->expect['readQueryTime'] ) {
+ $this->reportExpectationViolated( 'readQueryTime', $query );
+ }
+ if ( $isWrite && $elapsed > $this->expect['writeQueryTime'] ) {
+ $this->reportExpectationViolated( 'writeQueryTime', $query );
+ }
if ( !$this->dbTrxHoldingLocks ) {
// Short-circuit
$n = $this->expect[$expect];
$by = $this->expectBy[$expect];
$this->logger->info(
- "[{$wgRequest->getMethod()}] Expectation ($expect <= $n) by $by not met:\n$query\n" . wfBacktrace( true )
+ "[{$wgRequest->getMethod()}] Expectation ($expect <= $n) by $by not met:\n$query\n" .
+ wfBacktrace( true )
);
}
}
* Activate the profiler (assuming $wgProfiler is set)
*/
protected function activateProfiler() {
- global $wgProfiler;
+ global $wgProfiler, $wgTrxProfilerLimits;
$output = $this->getOption( 'profiler' );
if ( $output && is_array( $wgProfiler ) && isset( $wgProfiler['class'] ) ) {
$trxProfiler = Profiler::instance()->getTransactionProfiler();
$trxProfiler->setLogger( LoggerFactory::getInstance( 'DBPerformance' ) );
- # Catch huge single updates that lead to slave lag
- $trxProfiler->setExpectation( 'maxAffected', 1000, __METHOD__ );
+ $trxProfiler->setExpectations( $wgTrxProfilerLimits['Maintenance'], __METHOD__ );
}
/**