diff options
author | Stefan Giehl <stefan@matomo.org> | 2020-03-15 22:35:27 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-03-15 22:35:27 +0300 |
commit | c7dc542e63645f57886d49fc288b792ee60785d0 (patch) | |
tree | cc79c3f7e74281c3229bbd7417fe6d618cb854a6 /plugins | |
parent | 7b053e85b5b037619dbee4fbcf3e7a9ca2bf8589 (diff) |
respect max execution time limit for transitions plugin (#15652)
Diffstat (limited to 'plugins')
-rw-r--r-- | plugins/Live/Model.php | 89 | ||||
-rw-r--r-- | plugins/Live/tests/Integration/ModelTest.php | 11 | ||||
-rw-r--r-- | plugins/Transitions/API.php | 58 |
3 files changed, 77 insertions, 81 deletions
diff --git a/plugins/Live/Model.php b/plugins/Live/Model.php index 89c32d2b12..fe167fcf33 100644 --- a/plugins/Live/Model.php +++ b/plugins/Live/Model.php @@ -16,6 +16,7 @@ use Piwik\Config; use Piwik\Container\StaticContainer; use Piwik\Date; use Piwik\Db; +use Piwik\DbHelper; use Piwik\Period; use Piwik\Period\Range; use Piwik\Piwik; @@ -121,7 +122,7 @@ class Model try { $visits = $readerDb->fetchAll($sql, $bind); } catch (Exception $e) { - $this->handleMaxExecutionTimeError($readerDb, $e, $sql, $bind, $segment, $dateStart, $dateEnd, $minTimestamp, $limit); + $this->handleMaxExecutionTimeError($readerDb, $e, $segment, $dateStart, $dateEnd, $minTimestamp, $limit, ['sql' => $sql, 'bind' => $bind,]); throw $e; } return $visits; @@ -130,17 +131,16 @@ class Model /** * @param \Piwik\Tracker\Db|\Piwik\Db\AdapterInterface|\Piwik\Db $readerDb * @param Exception $e - * @param $sql - * @param array $bind * @param $segment * @param $dateStart * @param $dateEnd * @param $minTimestamp * @param $limit + * @param $parameters * * @throws MaxExecutionTimeExceededException */ - public function handleMaxExecutionTimeError($readerDb, $e, $sql, $bind, $segment, $dateStart, $dateEnd, $minTimestamp, $limit) + public static function handleMaxExecutionTimeError($readerDb, $e, $segment, $dateStart, $dateEnd, $minTimestamp, $limit, $parameters) { // we also need to check for the 'maximum statement execution time exceeded' text as the query might be // aborted at different stages and we can't really know all the possible codes at which it may be aborted etc @@ -148,39 +148,41 @@ class Model || $readerDb->isErrNo($e, DbMigration::ERROR_CODE_MAX_EXECUTION_TIME_EXCEEDED_SORT_ABORTED) || strpos($e->getMessage(), 'maximum statement execution time exceeded') !== false; - if ($isMaxExecutionTimeError) { - $message = ''; + if (false === $isMaxExecutionTimeError) { + return; + } + + $message = ''; - if ($this->isLookingAtMoreThanOneDay($dateStart, $dateEnd, $minTimestamp)) { - $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonDateRange'); - } + if (self::isLookingAtMoreThanOneDay($dateStart, $dateEnd, $minTimestamp)) { + $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonDateRange'); + } - if (!empty($segment)) { - $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonSegment'); - } + if (!empty($segment)) { + $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonSegment'); + } - $limitThatCannotBeSelectedInUiButOnlyApi = 550; - if ($limit > $limitThatCannotBeSelectedInUiButOnlyApi) { - $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededLimit'); - } + $limitThatCannotBeSelectedInUiButOnlyApi = 550; + if ($limit > $limitThatCannotBeSelectedInUiButOnlyApi) { + $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededLimit'); + } - if (empty($message)) { - $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonUnknown'); - } + if (empty($message)) { + $message .= ' ' . Piwik::translate('Live_QueryMaxExecutionTimeExceededReasonUnknown'); + } - $message = Piwik::translate('Live_QueryMaxExecutionTimeExceeded') . ' ' . $message; + $message = Piwik::translate('Live_QueryMaxExecutionTimeExceeded') . ' ' . $message; - $params = array( - 'sql' => $sql, 'bind' => $bind, 'segment' => $segment, 'limit' => $limit - ); + $params = array_merge($parameters, [ + 'segment' => $segment, 'limit' => $limit + ]); - /** - * @ignore - * @internal - */ - Piwik::postEvent('Live.queryMaxExecutionTimeExceeded', array($params)); - throw new MaxExecutionTimeExceededException($message); - } + /** + * @ignore + * @internal + */ + Piwik::postEvent('Live.queryMaxExecutionTimeExceeded', array($params)); + throw new MaxExecutionTimeExceededException($message); } /** @@ -190,7 +192,7 @@ class Model * @return bool * @throws Exception */ - public function isLookingAtMoreThanOneDay($dateStart, $dateEnd, $minTimestamp) + public static function isLookingAtMoreThanOneDay($dateStart, $dateEnd, $minTimestamp) { if (!$dateStart) { if (!$minTimestamp) { @@ -493,35 +495,14 @@ class Model $bind = $innerQuery['bind']; - $maxExecutionTimeHint = $this->getMaxExecutionTimeMySQLHint(); - if ($visitorId) { + if (!$visitorId) { // for now let's not apply when looking for a specific visitor - $maxExecutionTimeHint = ''; - } - if ($maxExecutionTimeHint) { - $innerQuery['sql'] = trim($innerQuery['sql']); - $pos = stripos($innerQuery['sql'], 'SELECT'); - if ($pos !== false) { - $innerQuery['sql'] = substr_replace($innerQuery['sql'], 'SELECT ' . $maxExecutionTimeHint, $pos, strlen('SELECT')); - } + $innerQuery['sql'] = DbHelper::addMaxExecutionTimeHintToQuery($innerQuery['sql'], Config::getInstance()->General['live_query_max_execution_time']); } return array($innerQuery['sql'], $bind); } - private function getMaxExecutionTimeMySQLHint() - { - $general = Config::getInstance()->General; - $maxExecutionTime = $general['live_query_max_execution_time']; - $maxExecutionTimeHint = ''; - if (is_numeric($maxExecutionTime) && $maxExecutionTime > 0) { - $timeInMs = $maxExecutionTime * 1000; - $timeInMs = (int) $timeInMs; - $maxExecutionTimeHint = ' /*+ MAX_EXECUTION_TIME('.$timeInMs.') */ '; - } - return $maxExecutionTimeHint; - } - /** * @param $idSite * @return Site diff --git a/plugins/Live/tests/Integration/ModelTest.php b/plugins/Live/tests/Integration/ModelTest.php index eeede80c97..19bc97e82b 100644 --- a/plugins/Live/tests/Integration/ModelTest.php +++ b/plugins/Live/tests/Integration/ModelTest.php @@ -82,8 +82,7 @@ class ModelTest extends IntegrationTestCase $dateEnd = Date::now(); $minTimestamp = 1; $limit = 50; - $model = new Model(); - $model->handleMaxExecutionTimeError($db, $e, $sql, $bind, $segment, $dateStart, $dateEnd, $minTimestamp, $limit); + Model::handleMaxExecutionTimeError($db, $e, $segment, $dateStart, $dateEnd, $minTimestamp, $limit, [$sql, $bind]); $this->assertTrue(true); } @@ -102,8 +101,7 @@ class ModelTest extends IntegrationTestCase $dateEnd = Date::now(); $minTimestamp = null; $limit = 50; - $model = new Model(); - $model->handleMaxExecutionTimeError($db, $e, $sql, $bind, $segment, $dateStart, $dateEnd, $minTimestamp, $limit); + Model::handleMaxExecutionTimeError($db, $e, $segment, $dateStart, $dateEnd, $minTimestamp, $limit, [$sql, $bind]); } /** @@ -114,15 +112,12 @@ class ModelTest extends IntegrationTestCase { $db = Db::get(); $e = new \Exception('Query execution was interrupted, maximum statement execution time exceeded'); - $sql = 'SELECT 1'; - $bind = array(); $segment = 'userId>=1'; $dateStart = Date::now()->subDay(10); $dateEnd = Date::now(); $minTimestamp = null; $limit = 5000; - $model = new Model(); - $model->handleMaxExecutionTimeError($db, $e, $sql, $bind, $segment, $dateStart, $dateEnd, $minTimestamp, $limit); + Model::handleMaxExecutionTimeError($db, $e, $segment, $dateStart, $dateEnd, $minTimestamp, $limit, ['param' => 'value']); } public function test_getStandAndEndDate() diff --git a/plugins/Transitions/API.php b/plugins/Transitions/API.php index 88bca868ef..b26b0bdc39 100644 --- a/plugins/Transitions/API.php +++ b/plugins/Transitions/API.php @@ -12,15 +12,18 @@ namespace Piwik\Plugins\Transitions; use Exception; use Piwik\ArchiveProcessor; use Piwik\Common; +use Piwik\Config; use Piwik\DataAccess\LogAggregator; use Piwik\DataArray; use Piwik\DataTable; use Piwik\DataTable\Row; +use Piwik\Db; use Piwik\Metrics; use Piwik\Period; use Piwik\Piwik; use Piwik\Plugins\Actions\Actions; use Piwik\Plugins\Actions\ArchivingHelper; +use Piwik\Plugins\Live\Model; use Piwik\RankingQuery; use Piwik\Segment; use Piwik\Segment\SegmentExpression; @@ -81,25 +84,40 @@ class API extends \Piwik\Plugin\API 'date' => Period\Factory::build($period->getLabel(), $date)->getLocalizedShortString() ); - $partsArray = explode(',', $parts); - if ($parts == 'all' || in_array('internalReferrers', $partsArray)) { - $this->addInternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping); - } - if ($parts == 'all' || in_array('followingActions', $partsArray)) { - $includeLoops = $parts != 'all' && !in_array('internalReferrers', $partsArray); - $this->addFollowingActions($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops); - } - if ($parts == 'all' || in_array('externalReferrers', $partsArray)) { - $this->addExternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping); - } + try { + $partsArray = explode(',', $parts); + if ($parts == 'all' || in_array('internalReferrers', $partsArray)) { + $this->addInternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping); + } + if ($parts == 'all' || in_array('followingActions', $partsArray)) { + $includeLoops = $parts != 'all' && !in_array('internalReferrers', $partsArray); + $this->addFollowingActions($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping, $includeLoops); + } + if ($parts == 'all' || in_array('externalReferrers', $partsArray)) { + $this->addExternalReferrers($logAggregator, $report, $idaction, $actionType, $limitBeforeGrouping); + } - // derive the number of exits from the other metrics - if ($parts == 'all') { - $report['pageMetrics']['exits'] = $report['pageMetrics']['pageviews'] - - $this->getTotalTransitionsToFollowingActions() - - $report['pageMetrics']['loops']; + // derive the number of exits from the other metrics + if ($parts == 'all') { + $report['pageMetrics']['exits'] = $report['pageMetrics']['pageviews'] + - $this->getTotalTransitionsToFollowingActions() + - $report['pageMetrics']['loops']; + } + } catch (\Exception $e) { + Model::handleMaxExecutionTimeError( + Db::getReader(), + $e, + $segment->getString(), + $period->getDateStart(), + $period->getDateEnd(), + 0, + Config::getInstance()->General['live_query_max_execution_time'], + ['method' => 'Transitions.getTransitionsForAction', 'actionName' => $actionName, 'actionType' => $actionType] + ); + throw $e; } + // replace column names in the data tables $reportNames = array( 'previousPages' => true, @@ -290,7 +308,8 @@ class API extends \Piwik\Plugin\API $metrics, $rankingQuery, $joinLogActionColumn, - $secondaryOrderBy = "`name`" + $secondaryOrderBy = "`name`", + Config::getInstance()->General['live_query_max_execution_time'] ); $dataTables = $this->makeDataTablesFollowingActions($types, $data); @@ -342,7 +361,7 @@ class API extends \Piwik\Plugin\API $where = 'visit_entry_idaction_' . $type . ' = ' . intval($idaction); $metrics = array(Metrics::INDEX_NB_VISITS); - $data = $logAggregator->queryVisitsByDimension($dimensions, $where, $selects, $metrics, $rankingQuery); + $data = $logAggregator->queryVisitsByDimension($dimensions, $where, $selects, $metrics, $rankingQuery, false, Config::getInstance()->General['live_query_max_execution_time']); $referrerData = array(); $referrerSubData = array(); @@ -433,7 +452,8 @@ class API extends \Piwik\Plugin\API $metrics, $rankingQuery, $joinLogActionOn, - $secondaryOrderBy = "`name`" + $secondaryOrderBy = "`name`", + Config::getInstance()->General['live_query_max_execution_time'] ); $loops = 0; |