PluginManager: Improved startup performance when loading many plugins

for some reason we were reading and parsing the plugin.yml at least twice for every plugin loaded.
We were repeating work already done by the initial loadPlugins() triage (discovering correct loader, loading plugin.yml from disk, parsing plugin.yml, validating plugin.yml) every time loadPlugin() was called with that plugin.
This commit is contained in:
Dylan K. Taylor 2021-10-11 01:11:59 +01:00
parent e1ee320c8d
commit 6d728e8d98
No known key found for this signature in database
GPG Key ID: 8927471A91CAFD3D
2 changed files with 120 additions and 74 deletions

View File

@ -0,0 +1,42 @@
<?php
/*
*
* ____ _ _ __ __ _ __ __ ____
* | _ \ ___ ___| | _____| |_| \/ (_)_ __ ___ | \/ | _ \
* | |_) / _ \ / __| |/ / _ \ __| |\/| | | '_ \ / _ \_____| |\/| | |_) |
* | __/ (_) | (__| < __/ |_| | | | | | | | __/_____| | | | __/
* |_| \___/ \___|_|\_\___|\__|_| |_|_|_| |_|\___| |_| |_|_|
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* @author PocketMine Team
* @link http://www.pocketmine.net/
*
*
*/
declare(strict_types=1);
namespace pocketmine\plugin;
/**
* @internal
*/
final class PluginLoadTriageEntry{
public function __construct(
private string $file,
private PluginLoader $loader,
private PluginDescription $description
){}
public function getFile() : string{ return $this->file; }
public function getLoader() : PluginLoader{ return $this->loader; }
public function getDescription() : PluginDescription{ return $this->description; }
}

View File

@ -178,6 +178,15 @@ class PluginManager{
if($loader->canLoadPlugin($path)){ if($loader->canLoadPlugin($path)){
$description = $loader->getPluginDescription($path); $description = $loader->getPluginDescription($path);
if($description instanceof PluginDescription){ if($description instanceof PluginDescription){
$this->internalLoadPlugin($path, $loader, $description);
}
}
}
return null;
}
private function internalLoadPlugin(string $path, PluginLoader $loader, PluginDescription $description) : ?Plugin{
$language = $this->server->getLanguage(); $language = $this->server->getLanguage();
$this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName()))); $this->server->getLogger()->info($this->server->getLanguage()->translate(KnownTranslationFactory::pocketmine_plugin_load($description->getFullName())));
@ -250,11 +259,6 @@ class PluginManager{
return $plugin; return $plugin;
} }
}
}
return null;
}
/** /**
* @param string[]|null $newLoaders * @param string[]|null $newLoaders
@ -330,7 +334,7 @@ class PluginManager{
))); )));
continue; continue;
} }
$plugins[$name] = $file; $plugins[$name] = new PluginLoadTriageEntry($file, $loader, $description);
$softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend()); $softDependencies[$name] = array_merge($softDependencies[$name] ?? [], $description->getSoftDepend());
$dependencies[$name] = $description->getDepend(); $dependencies[$name] = $description->getDepend();
@ -347,7 +351,7 @@ class PluginManager{
while(count($plugins) > 0){ while(count($plugins) > 0){
$loadedThisLoop = 0; $loadedThisLoop = 0;
foreach($plugins as $name => $file){ foreach($plugins as $name => $entry){
if(isset($dependencies[$name])){ if(isset($dependencies[$name])){
foreach($dependencies[$name] as $key => $dependency){ foreach($dependencies[$name] as $key => $dependency){
if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){ if(isset($loadedPlugins[$dependency]) or $this->getPlugin($dependency) instanceof Plugin){
@ -389,7 +393,7 @@ class PluginManager{
if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){ if(!isset($dependencies[$name]) and !isset($softDependencies[$name])){
unset($plugins[$name]); unset($plugins[$name]);
$loadedThisLoop++; $loadedThisLoop++;
if(($plugin = $this->loadPlugin($file, $loaders)) instanceof Plugin){ if(($plugin = $this->internalLoadPlugin($entry->getFile(), $entry->getLoader(), $entry->getDescription())) instanceof Plugin){
$loadedPlugins[$name] = $plugin; $loadedPlugins[$name] = $plugin;
} }
} }