Skip to content
This repository has been archived by the owner on Nov 25, 2020. It is now read-only.

Commit

Permalink
Core performances:
Browse files Browse the repository at this point in the history
. AJXP_Controller: Minimize xPath calls by implementating a hookCache
. AJXP_Plugin: reduce serialization - TODO: check cache upgrade
. AJXP_PluginService: Try to use cache for softLoad operation (still return a cloned version of the cached plugin)
. AJXP_Utils: cache the result of cleanDibiDriverParameters() function as it is called many times.
  • Loading branch information
cdujeu committed Mar 10, 2015
1 parent 62d9795 commit 5f629ef
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 102 deletions.
93 changes: 53 additions & 40 deletions core/src/core/classes/class.AJXP_Controller.php
Expand Up @@ -40,6 +40,8 @@ class AJXP_Controller
*/
private static $includeHooks = array();

private static $hooksCache = array();

/**
* Initialize the queryable xPath object
* @static
Expand All @@ -59,6 +61,7 @@ private static function initXPath()

public static function registryReset(){
self::$xPath = null;
self::$hooksCache = array();
}

/**
Expand Down Expand Up @@ -189,7 +192,7 @@ public static function checkParams(&$parameters, $callbackNode, $xPath)
* @param array $httpVars
* @param array $fileVars
* @param DOMNode $action
* @return bool
* @return mixed
*/
public static function findActionAndApply($actionName, $httpVars, $fileVars, &$action = null)
{
Expand All @@ -207,7 +210,7 @@ public static function findActionAndApply($actionName, $httpVars, $fileVars, &$a
}
}
self::$lastActionNeedsAuth = true;
return ;
return null;
}
$xPath = self::initXPath();
if ($action == null) {
Expand Down Expand Up @@ -274,22 +277,22 @@ public static function findActionAndApply($actionName, $httpVars, $fileVars, &$a
if ($preCalls !== false) {
foreach ($preCalls as $preCall) {
// A Preprocessing callback can modify its input arguments (passed by ref)
$preResult = self::applyCallback($xPath, $preCall, $actionName, $httpVars, $fileVars);
$preResult = self::applyCallback($preCall, $actionName, $httpVars, $fileVars);
if (isSet($params)) {
$params["pre_processor_results"][$preCall->getAttribute("pluginId")] = $preResult;
}
}
}
if ($mainCall) {
$result = self::applyCallback($xPath, $mainCall, $actionName, $httpVars, $fileVars);
$result = self::applyCallback($mainCall, $actionName, $httpVars, $fileVars);
if (isSet($params)) {
$params["processor_result"] = $result;
}
}
if ($postCalls !== false) {
foreach ($postCalls as $postCall) {
// A Preprocessing callback can modify its input arguments (passed by ref)
$postResult = self::applyCallback($xPath, $postCall, $actionName, $httpVars, $fileVars);
$postResult = self::applyCallback($postCall, $actionName, $httpVars, $fileVars);
if (isSet($params)) {
$params["post_processor_results"][$postCall->getAttribute("pluginId")] = $postResult;
}
Expand All @@ -299,11 +302,12 @@ public static function findActionAndApply($actionName, $httpVars, $fileVars, &$a
$params["ob_output"] = ob_get_contents();
ob_end_clean();
foreach ($captureCalls as $captureCall) {
self::applyCallback($xPath, $captureCall, $actionName, $httpVars, $params);
self::applyCallback($captureCall, $actionName, $httpVars, $params);
}
} else {
if(isSet($result)) return $result;
}
return null;
}

/**
Expand Down Expand Up @@ -352,25 +356,6 @@ public static function applyActionInBackground($currentRepositoryId, $actionName
}

return self::runCommandInBackground($cmd, $logFile);
/*
if (PHP_OS == "WIN32" || PHP_OS == "WINNT" || PHP_OS == "Windows") {
if(AJXP_SERVER_DEBUG) $cmd .= " > ".$logFile;
if (class_exists("COM") && ConfService::getCoreConf("CLI_USE_COM")) {
$WshShell = new COM("WScript.Shell");
$oExec = $WshShell->Run("cmd /C $cmd", 0, false);
} else {
$tmpBat = implode(DIRECTORY_SEPARATOR, array( $robustInstallPath, "data","tmp", md5(time()).".bat"));
$cmd .= "\n DEL ".chr(34).$tmpBat.chr(34);
AJXP_Logger::debug("Writing file $cmd to $tmpBat");
file_put_contents($tmpBat, $cmd);
pclose(popen('start /b "CLI" "'.$tmpBat.'"', 'r'));
}
} else {
$process = new UnixProcess($cmd, (AJXP_SERVER_DEBUG?$logFile:null));
AJXP_Logger::debug("Starting process and sending output dev null");
return $process;
}
*/
}

/**
Expand Down Expand Up @@ -410,7 +395,7 @@ public static function runCommandInBackground($cmd, $logFile)
* @param array $httpVars
* @param array $fileVars
* @param bool $multiple
* @return DOMNode|bool
* @return DOMElement|bool
*/
private static function getCallbackNode($xPath, $actionNode, $query ,$actionName, $httpVars, $fileVars, $multiple = true)
{
Expand All @@ -436,7 +421,7 @@ private static function getCallbackNode($xPath, $actionNode, $query ,$actionName
* Check in the callback node if an applyCondition XML attribute exists, and eval its content.
* The content must set an $apply boolean as result
* @static
* @param DOMNode $callback
* @param DOMElement $callback
* @param string $actionName
* @param array $httpVars
* @param array $fileVars
Expand All @@ -455,21 +440,25 @@ private static function appliesCondition($callback, $actionName, $httpVars, $fil
/**
* Applies a callback node
* @static
* @param DOMXPath $xPath
* @param DOMNode $callback
* @param DOMElement|Array $callback The DOM Node or directly an array of attributes
* @param String $actionName
* @param Array $httpVars
* @param Array $fileVars
* @param null $variableArgs
* @param bool $defer
* @throws AJXP_Exception* @throw AJXP_Exception
* @return void
* @throws AJXP_Exception* @internal param \DOMXPath $xPath
* @return mixed
*/
private static function applyCallback($xPath, $callback, &$actionName, &$httpVars, &$fileVars, &$variableArgs = null, $defer = false)
private static function applyCallback($callback, &$actionName, &$httpVars, &$fileVars, &$variableArgs = null, $defer = false)
{
//Processing
$plugId = $xPath->query("@pluginId", $callback)->item(0)->value;
$methodName = $xPath->query("@methodName", $callback)->item(0)->value;
if(is_array($callback)){
$plugId = $callback["pluginId"];
$methodName = $callback["methodName"];
}else{
$plugId = $callback->getAttribute("pluginId");
$methodName = $callback->getAttribute("methodName");
}
$plugInstance = AJXP_PluginsService::findPluginById($plugId);
//return call_user_func(array($plugInstance, $methodName), $actionName, $httpVars, $fileVars);
// Do not use call_user_func, it cannot pass parameters by reference.
Expand Down Expand Up @@ -498,19 +487,43 @@ private static function applyCallback($xPath, $callback, &$actionName, &$httpVar
*/
public static function applyHook($hookName, $args, $forceNonDefer = false)
{
if(isSet(self::$hooksCache[$hookName])){
$hooks = self::$hooksCache[$hookName];
foreach($hooks as $hook){
if (isSet($hook["applyCondition"]) && $hook["applyCondition"]!="") {
$apply = false;
eval($hook["applyCondition"]);
if(!$apply) continue;
}
$defer = $hook["defer"];
if($defer && $forceNonDefer) $defer = false;
self::applyCallback($hook, $fake1, $fake2, $fake3, $args, $defer);
}
return;
}
$xPath = self::initXPath();
$callbacks = $xPath->query("hooks/serverCallback[@hookName='$hookName']");
if(!$callbacks->length) return ;
self::$hooksCache[$hookName] = array();
foreach ($callbacks as $callback) {
if ($callback->getAttribute("applyCondition")!="") {
$defer = ($callback->getAttribute("defer") === "true");
$applyCondition = $callback->getAttribute("applyCondition");
$plugId = $callback->getAttribute("pluginId");
$methodName = $callback->getAttribute("methodName");
$hookCallback = array(
"defer" => $defer,
"applyCondition" => $applyCondition,
"pluginId" => $plugId,
"methodName" => $methodName
);
self::$hooksCache[$hookName][] = $hookCallback;
if (!empty($applyCondition)) {
$apply = false;
eval($callback->getAttribute("applyCondition"));
eval($applyCondition);
if(!$apply) continue;
}
//$fake1; $fake2; $fake3;
$defer = ($callback->attributes->getNamedItem("defer") != null && $callback->attributes->getNamedItem("defer")->nodeValue == "true");
}
if($defer && $forceNonDefer) $defer = false;
self::applyCallback($xPath, $callback, $fake1, $fake2, $fake3, $args, $defer);
self::applyCallback($hookCallback, $fake1, $fake2, $fake3, $args, $defer);
}
}

Expand Down
9 changes: 5 additions & 4 deletions core/src/core/classes/class.AJXP_Plugin.php
Expand Up @@ -416,11 +416,11 @@ public function getManifestDescription()
public function serialize()
{
if ($this->manifestDoc != null) {
$this->manifestXML = base64_encode($this->manifestDoc->saveXML());
$this->manifestXML = serialize(base64_encode($this->manifestDoc->saveXML()));
}
$serialArray = array();
foreach ($this->serializableAttributes as $attr) {
$serialArray[$attr] = serialize($this->$attr);
$serialArray[$attr] = $this->$attr;
}
return serialize($serialArray);
}
Expand All @@ -434,12 +434,12 @@ public function unserialize($string)
{
$serialArray = unserialize($string);
foreach ($serialArray as $key => $value) {
$this->$key = unserialize($value);
$this->$key = $value;
}
if ($this->manifestXML != NULL) {
//$this->manifestDoc = DOMDocument::loadXML(base64_decode($this->manifestXML));
$this->manifestDoc = new DOMDocument(1.0, "UTF-8");
$this->manifestDoc->loadXML(base64_decode($this->manifestXML));
$this->manifestDoc->loadXML(base64_decode(unserialize($this->manifestXML)));
$this->reloadXPath();
unset($this->manifestXML);
}
Expand All @@ -451,6 +451,7 @@ public function unserialize($string)
* on the manifest.
* @param string $xmlNodeName
* @param string $format
* @param bool $externalFiles
* @return DOMElement|DOMNodeList|string
*/
public function getManifestRawContent($xmlNodeName = "", $format = "string", $externalFiles = false)
Expand Down
103 changes: 45 additions & 58 deletions core/src/core/classes/class.AJXP_PluginsService.php
Expand Up @@ -30,7 +30,6 @@ class AJXP_PluginsService
private static $instance;
private $registry = array();
private $required_files = array();
private $tmpDependencies = array();
private $activePlugins = array();
private $streamWrapperPlugins = array();
private $registeredWrappers = array();
Expand All @@ -44,36 +43,56 @@ class AJXP_PluginsService
private $mixinsDoc;
private $mixinsXPath;


/**
* Loads the full registry, from the cache or not
* @param String $pluginFolder
* @param AbstractConfDriver $confStorage
* @param bool $rewriteCache Force a cache rewriting
* @return bool
*/
public function loadPluginsRegistry($pluginFolder, $confStorage, $rewriteCache = false)
{
if (!$rewriteCache && (!defined("AJXP_SKIP_CACHE") || AJXP_SKIP_CACHE === false)) {
private function loadRegistryFromCache(){

if((!defined("AJXP_SKIP_CACHE") || AJXP_SKIP_CACHE === false)){
$reqs = AJXP_Utils::loadSerialFile(AJXP_PLUGINS_REQUIRES_FILE);
if (count($reqs)) {
foreach ($reqs as $filename) {
if (!is_file($filename)) {
// CACHE IS OUT OF SYNC WITH REQUIRES
$this->loadPluginsRegistry($pluginFolder, $confStorage, true);
return;
// Cache is out of sync
return false;
}
require_once($filename);
}
$res = AJXP_Utils::loadSerialFile(AJXP_PLUGINS_CACHE_FILE);
$this->registry = $res;
// Refresh streamWrapperPlugins
foreach ($this->registry as $pType => $plugs) {
foreach ($this->registry as $plugs) {
foreach ($plugs as $plugin) {
if (method_exists($plugin, "detectStreamWrapper") && $plugin->detectStreamWrapper(false) !== false) {
$this->streamWrapperPlugins[] = $plugin->getId();
}
}
}
return ;
return true;
}else{
return false;
}
}else{
return false;
}

}

/**
* Loads the full registry, from the cache or not
* @param String $pluginFolder
* @param AbstractConfDriver $confStorage
* @param bool $rewriteCache Force a cache rewriting
*/
public function loadPluginsRegistry($pluginFolder, $confStorage, $rewriteCache = false)
{
if(!$rewriteCache){
if(!empty($this->registry)){
return;
}
if($this->loadRegistryFromCache()){
return;
}
}
if (is_string($pluginFolder)) {
Expand Down Expand Up @@ -149,50 +168,6 @@ private function recursiveLoadPlugin($plugin, $pluginsPool)
$plugin->loadingState = "loaded";
}

/**
* Save the plugins order in a cache
*
* @param array $sortedPlugins
* @return bool|void
*/
private function cachePlugSort($sortedPlugins)
{
if(!AJXP_PLUGINS_CACHE_FILE) return false;
$indexes = array();
$i = 0;
foreach ($sortedPlugins as $plugin) {
$indexes[$i] = $plugin->getId();
$i++;
}
AJXP_Utils::saveSerialFile(AJXP_PLUGINS_CACHE_FILE, $indexes, false, true);
}

/**
* Load the cache, check that all registered plugins
* are known by the cache, and in that case sort the array.
*
* @param array $sortedPlugins
* @return mixed
*/
private function loadPlugCache($sortedPlugins)
{
if(!AJXP_PLUGINS_CACHE_FILE) return false;
$cache = AJXP_Utils::loadSerialFile(AJXP_PLUGINS_CACHE_FILE);
if(!count($cache)) return false;
// Break if one plugin is not present in cache
foreach ($sortedPlugins as $index => $plugin) {
if (!in_array($plugin->getId(), $cache)) {return false;}
}
$sorted = array();
foreach ($cache as $id => $plugId) {
// Walk the cache and add the plugins in right order.
if (isSet($sortedPlugins[$plugId])) {
$sorted[] = $sortedPlugins[$plugId];
}
}
return $sorted;
}

public function loadFromPluginQueriesCache($key)
{
if(AJXP_SKIP_CACHE) return null;
Expand Down Expand Up @@ -220,6 +195,18 @@ public function storeToPluginQueriesCache($key, $value)
*/
public function softLoad($pluginId, $pluginOptions)
{
if(empty($this->registry)){
$this->loadRegistryFromCache();
}
// Try to get from cache
list($type, $name) = explode(".", $pluginId);
if(!empty($this->registry) && isSet($this->registry[$type][$name])) {
$plugin = $this->registry[$type][$name];
$plugin->init($pluginOptions);
return clone $plugin;
}


$plugin = new AJXP_Plugin($pluginId, AJXP_INSTALL_PATH."/".AJXP_PLUGINS_FOLDER."/".$pluginId);
$plugin->loadManifest();
$plugin = $this->instanciatePluginClass($plugin);
Expand Down Expand Up @@ -704,7 +691,7 @@ public static function searchAllManifests($query, $stringOrNodeFormat = "string"

/**
* Central function of the registry construction, merges some nodes into the existing registry.
* @param $original
* @param DOMDocument $original
* @param $parentName
* @param $uuidAttr
* @param $childrenNodes
Expand Down

0 comments on commit 5f629ef

Please sign in to comment.