/** * @url GET stats/performance/conjuncts * @param string $groupBy * @param int $from * @param int $to */ public function conjPerfStats($groupBy = 'conjuncts', $from = 0, $to = 10) { try { if (Config::get('productionEnv')) { throw new Exception("Performance tests are not allowed in production environment", 403); } $performanceArr = array(); // run all conjuncts (from - to) for ($i = $from; $i <= $to; $i++) { $conj = RuleEngine::getConjunct('conj_' . $i); $startTimeStamp = microtime(true); // true means get as float instead of string RuleEngine::checkConjunct('conj_' . $i, false); $endTimeStamp = microtime(true); $performanceArr['conj_' . $i] = array('id' => 'conj_' . $i, 'start' => $startTimeStamp, 'end' => $endTimeStamp, 'duration' => $endTimeStamp - $startTimeStamp, 'invariantRules' => implode(';', $conj['invariantRuleNames']), 'signalRules' => implode(';', $conj['signalRuleNames'])); } switch ($groupBy) { case 'conjuncts': return array_values($performanceArr); break; case 'rules': $ruleArr = array(); foreach (RuleEngine::getAllRules() as $rule) { $duration = 0; foreach ($rule['conjunctIds'] as $conj) { $duration += $performanceArr[$conj]['duration']; } $ruleArr[] = array('ruleName' => $rule['name'], 'duration' => $duration, 'conjuncts' => implode(';', $rule['conjunctIds'])); } return $ruleArr; break; case 'relations': $relArr = array(); foreach (Relation::getAllRelations() as $sig => $rel) { $duration = 0; $conjuncts = array_merge($rel['affectedInvConjunctIds'], $rel['affectedSigConjunctIds']); foreach ($conjuncts as $conj) { $duration += $performanceArr[$conj]['duration']; } $relArr[] = array('relationSignature' => $sig, 'duration' => $duration, 'conjuncts' => implode(';', $conjuncts)); } return $relArr; break; default: throw new Exception("Unknown groupBy argument", 500); break; } } catch (Exception $e) { throw new RestException($e->getCode(), $e->getMessage()); } }
public static function checkConjunct($conjunctId, $cacheConjuncts = true) { Notifications::addLog("Checking conjunct '" . $conjunctId . "' cache:" . var_export($cacheConjuncts, true), 'RuleEngine'); try { // If conjunct is already evaluated and conjunctCach may be used -> return violations if (array_key_exists($conjunctId, self::$conjunctViolations) && $cacheConjuncts) { Notifications::addLog("Conjunct is already evaluated, getting violations from cache", 'RuleEngine'); return self::$conjunctViolations[$conjunctId]; // Otherwise evaluate conjunct, cache and return violations } else { $db = Database::singleton(); $violations = array(); // Evaluate conjunct $conjunct = RuleEngine::getConjunct($conjunctId); $violations = (array) $db->Exe($conjunct['violationsSQL']); // Cache violations if ($cacheConjuncts) { self::$conjunctViolations[$conjunctId] = $violations; } if (count($violations) == 0) { Notifications::addLog("Conjunct '" . $conjunctId . "' holds", 'RuleEngine'); // Remove "old" conjunct violations from database $query = "DELETE FROM `__all_signals__` WHERE `conjId` = '{$conjunctId}'"; $db->Exe($query); } elseif ($cacheConjuncts) { Notifications::addLog("Conjunct '" . $conjunctId . "' broken, caching violations in database", 'RuleEngine'); // Remove "old" conjunct violations from database $query = "DELETE FROM `__all_signals__` WHERE `conjId` = '{$conjunctId}'"; $db->Exe($query); // Add new conjunct violation to database table __all_signals__ $query = "INSERT IGNORE INTO `__all_signals__` (`conjId`, `src`, `tgt`) VALUES "; foreach ($violations as $violation) { $values[] = "('" . $conjunctId . "', '" . $violation['src'] . "', '" . $violation['tgt'] . "')"; } $query .= implode(',', $values); $db->Exe($query); } else { Notifications::addLog("Conjunct '" . $conjunctId . "' broken", 'RuleEngine'); } return $violations; } } catch (Exception $e) { Notifications::addError("While checking conjunct '" . $conjunctId . "': " . $e->getMessage()); } }
public static function run($allRules = false) { $database = Database::singleton(); Notifications::addLog('------------------------- EXEC ENGINE STARTED -------------------------', 'ExecEngine'); // Load the execEngine functions (security hazard :P) $files = getDirectoryList(__DIR__ . '/functions'); foreach ($files as $file) { if (substr($file, -3) !== 'php') { continue; } require_once __DIR__ . '/functions/' . $file; Notifications::addLog('Included file: ' . __DIR__ . '/functions/' . $file, 'ExecEngine'); } self::$roleName = Config::get('execEngineRoleName', 'execEngine'); $role = Role::getRoleByName(self::$roleName); $maxRunCount = Config::get('maxRunCount', 'execEngine'); self::$runCount = 0; self::$autoRerun = Config::get('autoRerun', 'execEngine'); if ($role) { // Get all rules that are maintained by the ExecEngine while (self::$doRun) { self::$doRun = false; self::$runCount++; if (self::$runCount > $maxRunCount) { throw new Exception('Maximum reruns exceeded for ExecEngine (rules with violations:' . implode(', ', $rulesThatHaveViolations) . ')', 500); } Notifications::addLog("ExecEngine run #" . self::$runCount . " (auto rerun: " . var_export(self::$autoRerun, true) . ") for role '" . $role->label . "'", 'ExecEngine'); // Determine affected rules that must be checked by the exec engine $affectedConjuncts = (array) RuleEngine::getAffectedInvConjuncts($database->getAffectedConcepts(), $database->getAffectedRelations()); $affectedConjuncts = array_merge($affectedConjuncts, (array) RuleEngine::getAffectedSigConjuncts($database->getAffectedConcepts(), $database->getAffectedRelations())); $affectedRules = array(); foreach ($affectedConjuncts as $conjunctId) { $conjunct = RuleEngine::getConjunct($conjunctId); foreach ($conjunct['invariantRuleNames'] as $ruleName) { $affectedRules[] = $ruleName; } foreach ($conjunct['signalRuleNames'] as $ruleName) { $affectedRules[] = $ruleName; } } // Check rules $rulesThatHaveViolations = array(); foreach ($role->maintains() as $ruleName) { if (!in_array($ruleName, $affectedRules) && !$allRules) { continue; } // skip this rule $rule = RuleEngine::getRule($ruleName); $violations = RuleEngine::checkRule($rule, false); if (count($violations)) { $rulesThatHaveViolations[] = $rule['name']; // Fix violations for every rule ExecEngine::fixViolations($rule, $violations); // Conjunct violations are not cached, because they are fixed by the ExecEngine // If $autoRerun, set $doRun to true because violations have been fixed (this may fire other execEngine rules) if (self::$autoRerun) { self::$doRun = true; } } } } } else { Notifications::addInfo("ExecEngine extension included but role '" . self::$roleName . "' not found."); } Notifications::addLog('------------------------- END OF EXEC ENGINE -------------------------', 'ExecEngine'); }